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 変換手順
設定
- TRISA レジスタで AN0 ~ AN7 のピンの入出力モードを決定 (アナログ入力ピンを 1(入力) にする)
- ADCON0 レジスタを設定
- A/D 変換クロックの設定 (bit7-6) (ADCS1:ADCS0)
- アナログチャネルをセレクト (bit5-3) (CHS2:CHS0)
- A/D モジュールを使用するにセット (bit0) (ADON=1 にする)
- ADCON1 レジスタを設定
- 結果は左詰か右詰か (bit7) (ADFM)
- A/D ポートの構成 (bit3-0) (PCFG3:PCFG0)
- 割り込みを使うなら、割り込み設定
- ADIF = 0
- ADIE = 1
- GIE = 1
変換実行
- アクィジション時間待つ
- 8 ビット変換なら 12μsec
- 10 ビット変換なら 20μsec
- A/D 変換開始 (ADCON0<GO/DONE> をセット)
- A/D 変換の終了を待つ (次のどちらかの方法で)
- GO/DONE ビットがクリアされるまでループで待機する
- A/D 割り込みを待つ
- 結果 (ADRESH:ADRESL) をリードする (必要なら ADIF をクリア)
以降の変換は、変換に使用したいアナログチャネルをセレクト (CHS2:CHS0) して繰り返します。
A/D 変換のサンプルプログラム
AN0 からの入力を A/D 変換した結果を、USART を使ってシリアルで PC に送信するプログラムの例です。
- デバイス : PIC16F873
- 通信スピード : 9600bps
- データ長 : 8bit
- ストップビット : 1bit
- フロー制御 : なし
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; 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