まくまくいろいろノート
A/D 変換を実行する ─ PIC めもめも
2002-08-01

A/D 変換モジュール

PIC16F873/876 (28ピン)、PIC16F874/877 (40ピン) などには A/D 変換モジュールが付いています。 28 ピンモジュールには 5 入力、40 ピンモジュールには 8 入力あります。 5 入力全部使えば、3 軸加速度センサと 2 軸ジャイロセンサの出力を 1 つの PIC で A/D 変換することができます(入力が多いほど A/D 変換に時間はかかります)。

A/D 変換モジュールには次の 4 つのレジスタがあります。

  • A/D 変換制御レジスタ 0 ・・・ ADCON0
  • A/D 変換制御レジスタ 1 ・・・ ADCON1
  • A/D 変換結果 High レジスタ ・・・ ADRESH
  • A/D 変換結果 Low レジスタ ・・・ ADRESL

A/D 変換制御用レジスタ ─ ADCON0 レジスタの構成

ADCON0 レジスタ (1Fh : Bank0) は、クロック、チャンネルの指定、A/D 変換開始などに使用します。

ADCS1
(7)
ADCS0
(6)
CHS2
(5)
CHS1
(4)
CHS0
(3)
GO/DONE
(2)

(1)
ADON
(0)

ADCS1(7) ~ ADCS0(6): AD 変換クロックセレクトビット

  • 00 ・・・ Fosc/2
  • 01 ・・・ Fosc/8
  • 10 ・・・ Fosc/32
  • 11 ・・・ FRC (RC 発振)

CHS2(5) ~ CHS0(3): アナログチャネルセレクトビット

  • 000 ・・・ channel 0, (RA0/AN0)
  • 001 ・・・ channel 1, (RA1/AN1)
  • 010 ・・・ channel 2, (RA2/AN2)
  • 011 ・・・ channel 3, (RA3/AN3)
  • 100 ・・・ channel 4, (RA5/AN4)
  • 101 ・・・ channel 5, (RE0/AN5) (※ 28pin デバイスにはありません)
  • 110 ・・・ channel 6, (RE1/AN6) (※ 28pin デバイスにはありません)
  • 111 ・・・ channel 7, (RE2/AN7) (※ 28pin デバイスにはありません)

A/D 変換は 1 度に 1 つのポートからの入力に対してしか行なえないので、この 3 bit でどのポートからの入力を変換するか切り替えます。

GO/DONE(2): A/D 変換ステータスビット

  • If ADON = 1
    • 1 ・・・ A/D 変換中(このビットをセットすると A/D 変換が開始します)
    • 0 ・・・ A/D 変換中ではない(このビットは A/D 変換が終了する自動的にハードウェアでクリアされます)

A/D 変換の設定が終わったら、このビットをセットすることによって実際に A/D を開始します。 A/D が終了すると、このビットは自動的にクリアされます。 割り込みを使わなくても、このフラグをループで監視することで、A/D 変換が終了したことを知ることができます(A/D 変換にはほとんど時間がかからないので、割り込みを使う必要はないかも)。

なし(1)

このビットは常に 「0」 とリードされます。

ADON(0): A/D ON ビット

  • 1 ・・・ A/D 変換器モジュールは動作中
  • 0 ・・・ A/D 変換器モジュールはオフになり、消費電流無し

A/D 変換器モジュールを動作させるかを指定します(実際に A/D 変換を開始する時は GO/DONE(2) をセットします)。 A/D 変換を行なう必要のない場合は、電力の消費を抑えるために停止しておくとよいです。

A/D 変換制御用レジスタ ─ ADCON1 レジスタの構成

ADCON1 レジスタ (9Fh : Bank1) では、アナログ入力用ポートの指定を行います。

ADFM
(7)

(6)

(5)

(4)
PCFG3
(3)
PCFG2
(2)
PCFG1
(1)
PCFG0
(0)

ADFM(7): A/D 変換結果フォーマットセレクト

  • 0 ・・・ 左詰。ADRESL の 6LSb は 「0」 とリードされる。
  • 1 ・・・ 右詰。ADRESH の 6MSb は 「0」 とリードされる。
     左詰の場合              右詰の場合
+--------+--------+    +--------+--------+
+xxxxxxxx|xx000000|    +000000xx|xxxxxxxx|
+--------+--------+    +--------+--------+
  ADRESH   ADRESL        ADRESH   ADRESL

PIC16F87x では、A/D 変換後の値が 10bit で得られるので、ADRESH、ADRESL の計 16bit に右詰か左詰どちらで結果を格納するか指定します。 あまり細かい精度まで求める必要がない場合は、左詰めにして ADRESH の 8bit だけ参照すればよいでしょう。

なし(6~4):

常に 「0」 とリードされます。

PCFG3(3) ~ PCFG0(0): A/D ポート構成コントロールビット

省略。

A/D 変換手順

設定

  1. TRISA レジスタで AN0 ~ AN7 のピンの入出力モードを決定 (アナログ入力ピンを 1(入力) にする)
  2. ADCON0 レジスタを設定
    • A/D 変換クロックの設定 (bit7-6) (ADCS1:ADCS0)
    • アナログチャネルをセレクト (bit5-3) (CHS2:CHS0)
    • A/D モジュールを使用するにセット (bit0) (ADON=1 にする)
  3. ADCON1 レジスタを設定
    • 結果は左詰か右詰か (bit7) (ADFM)
    • A/D ポートの構成 (bit3-0) (PCFG3:PCFG0)
  4. 割り込みを使うなら、割り込み設定
    • ADIF = 0
    • ADIE = 1
    • GIE = 1

変換実行

  1. アクィジション時間待つ
    • 8 ビット変換なら 12μsec
    • 10 ビット変換なら 20μsec
  2. A/D 変換開始 (ADCON0<GO/DONE> をセット)
  3. A/D 変換の終了を待つ (次のどちらかの方法で)
    • GO/DONE ビットがクリアされるまでループで待機する
    • A/D 割り込みを待つ
  4. 結果 (ADRESH:ADRESL) をリードする (必要なら ADIF をクリア)

以降の変換は、変換に使用したいアナログチャネルをセレクト (CHS2:CHS0) して繰り返します。

A/D 変換のサンプルプログラム

AN0 からの入力を A/D 変換した結果を、USART を使ってシリアルで PC に送信するプログラムの例です。

  • デバイス : PIC16F873
  • 通信スピード : 9600bps
  • データ長 : 8bit
  • ストップビット : 1bit
  • フロー制御 : なし

ad_convert.asm

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; AN0 からの入力を A/D 変換した結果を、
; USART を使ってシリアルで PC に送信するサンプルプログラム
;
;   デバイス      : PIC16F873
;   通信スピード  : 9600bps
;   データ長      : 8bit
;   ストップビット: 1bit
;   フロー制御    : なし
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    LIST        P=PIC16F873
    INCLUDE     "P16F873.INC"

;==============================================================================
; Variable Definition
;==============================================================================
TEMP    EQU    020H
TCNT    EQU    021H    ; 遅延サブルーチン用の変数

    ORG     0
;==============================================================================
; 初期設定
;==============================================================================
INIT
    BSF     STATUS, RP0         ; Bank1 に切り替え
;**** 入出力ポートの設定 (TRISA) ****
    MOVLW   B'00000001'         ; RA0 は入力(センサから)
    MOVWF   TRISA               ;
;**** アナログ入力にするポート、左詰右詰を決定 (ADCON1) ****
    MOVLW   B'00000010'         ; 左詰、AN0~AN4 全部アナログ入力
    MOVWF   ADCON1
;**** USART 用入出力ポートの設定 (TRISC) ****
    BCF     TRISC, 6            ; PortC<6> (TX) is an output
;    BSF     TRISC, 7            ; PortC<7> (RX) is an input
;**** USART 送信ステータスの設定 (TXSTA) ****
    MOVLW   B'00100000'         ; Async mode
    MOVWF   TXSTA               ;
;**** USART ボーレートの設定 (SPBRG) ****
    MOVLW   0FH                 ;9600bps 10MHz BRGH=0(低速)
    MOVWF   SPBRG

    BCF     STATUS, RP0         ; Bank0 に戻す
;**** USART 受信ステータスの設定 (RCSTA) ****
    MOVLW   B'10010000'         ;
    MOVWF   RCSTA               ;
;**** AD 変換クロックを指定。AD 変換を有効に (ADCON0) ****
    MOVLW   B'10000001'         ; Fosc/32, CH0, ADON=1
    MOVWF   ADCON0

;==============================================================================
; A/D 変換を行うアナログ入力ポートを選択
;==============================================================================
SELECT_AD_CHANNEL
    ;今回は AN0 からの入力だけを変換するの切り替える必要なし

;==============================================================================
; セレクトしたポートに対して A/D 変換を実行
; チャンネルをセレクトしてからCholdに電圧を蓄積するまで待機する必要がある
;    8bit 変換の時 … 12μsec
;   10bit 変換の時 … 20μsec
;==============================================================================
AD_CONVERT
    CALL    WAIT20_10MHZ        ;コンデンサの充電まち (20μsec, 10MHz)
    BSF     ADCON0, GO          ;A/D 変換スタート
WAIT_AD_FINISH
    BTFSC   ADCON0, GO          ;GO ビットがクリアされたら A/D 変換終了
    GOTO    WAIT_AD_FINISH
    MOVF    ADRESH, W            ;A/D 変換の結果を取得 (上位8bit)

;==============================================================================
; A/D 変換結果をシリアルで送信
;==============================================================================
    CALL    SEND_USART

; 1 を送ってみる(テスト用)
;    MOVLW   1
;    CALL    SEND_USART
;**** チャンネルセレクトへもどる ****
    GOTO    SELECT_AD_CHANNEL

;==============================================================================
; シリアル送信サブルーチン
; TXSTA<TRMT(1)> を監視し、W レジスタのデータ (8 bit) をシリアルで送信します。
; (TEMP を Bank0 の汎用レジスタに指定してあることを前提とします。
;  このルーチンを呼び出す時は Bank0 に切り替えてから呼び出すこと)
;==============================================================================
SEND_USART
    MOVWF   TEMP                ;W レジスタを保存
    BSF     STATUS, RP0         ;Bank1 に切り替え
SEND_USART_LOOP
    BTFSS   TXSTA, TRMT         ;TXSTA<TRMT(1)>  が 1 になるまで待機
    GOTO    SEND_USART_LOOP
    BCF     STATUS, RP0         ;Bank0 に戻す
    MOVF    TEMP, W             ;W レジスタの復旧
    MOVWF   TXREG               ;TXREG レジスタにセット (実際の送信開始)
    RETURN

;==============================================================================
; 20μsec の遅延時間 ─ 10MHz (周期 0.4μsec) の時
;==============================================================================
WAIT20_10MHZ
    MOVLW  D'14'     ; 20 / 0.4 = 50
    MOVWF  TCNT      ; (50 - 6) / 3 = 14 余り 2
WAIT20_10MHZ_LOOP
    DECFSZ TCNT, F   ;
    GOTO   WAIT20_10MHZ_LOOP
    NOP              ; 余り 2 だから NOP は 2 つ
    NOP              ;
    RETURN           ;

;==============================================================================
; End Program
;==============================================================================
    END
2002-08-01