今回は電圧を測定します。PICのアナログ入力と分圧回路を使用して、測定対象の電圧を測定します。電圧の測定範囲は0[V]~10[V]としています。
回路図およびプログラムに関する各種詳細は、以下の記事を参考にしてください。
1.今回使用するPICについて
今回使用するPICは「PIC12F1822」です。
2.回路
2.1 電子回路図
2.2 電子回路の写真
2.3 回路説明
基本的な回路の考え方(AD変換方法)は「温度センサ」を参考にしてください。
2.3.1 使用するパーツ一覧
パーツ名 | 説明 | 使用数 |
---|---|---|
PIC12F1822 | PIC本体 | 1 |
抵抗(10[kΩ]) | 分圧回路 | 2 |
2.3.2 PICの配線
PICのピン | 接続 | 補足 |
---|---|---|
VDD | 電源 | 5[V] |
RA0 | シリアル通信(TxD:送信) | 7セグメントディスプレイへデータ転送 |
RA1 | -未使用- | |
RA2 | -未使用- | |
RA3 | -未使用- | |
RA4 | 分圧回路からの入力 | 電圧の測定 |
RA5 | -未使用- | |
VSS | グランド |
2.3.3 電源(VDD)について
今回、回路を作成しPICで測定した際、測定電圧に大きな誤差(0.2[V]くらい)が発生しました。誤差の原因は電源でした。
使い勝手がよく楽ということから、スマホなどの充電に使用するバッテリを電源として利用しています。このようなバッテリは安定して5[V]を出力してくれると思っていたのですが、意外と安定していませんでした。電源が安定していないせいで、AD変換時に誤差が生じてしまい、測定電圧の誤差につながりました。
バッテリなどを電源として利用する場合、以上のような問題が発生する可能性があるので、注意してください。そもそもこのようなバッテリを電源にしているのが問題なのでは?という突込みは置いといて、使用する場合、安定しているか確認する、または安定するような回路を追加するようにしてください。
電源を変えたところ、誤差は0.02[V]程度になりました。
2.3.4 電圧測定方法
分圧回路(回路図の左下の抵抗が2つある部分)を通してPICが取得した電圧をもとに入力電圧を求めます。
記号 | 説明 |
---|---|
Vin | 測定対象の電圧 分圧回路に入力(回路図の0V~10Vと書かれている部分)している電圧 |
Vout | PICに出力する電圧(分圧回路からPICにつながっている部分) |
R1 | 分圧回路の上についている抵抗(入力電圧側) |
R2 | 分圧回路の下についている抵抗(グランド側) |
測定対象のVinの電圧を求めるにはオームの法則を利用し、以下の式を解くことで求めることができます。
Vin : Vout = (R1 + R2) : R2
Vin × R2 = Vout × (R1 + R2)
Vin = Vout × (R1 + R2) / R2
PICが入力した電圧をVoutに代入することでVinを求めることができます。
注:抵抗値は使用するマイコンや測定したい電圧により変更する必要があります。
3.プログラム
プログラムの基本的な部分は以下の記事を参考にしてください。
3.1 プログラムの説明
プログラムを見ながら以下の説明を見てください。ソースコードは次の節にあるので、そちらを参照してください。
3.1.1 グローバル変数の宣言
#define _XTAL_FREQ 32000000 #define TX_UART_SIZE 3 //#define VOLTAGE_REFERENCE 5000 #define VOLTAGE_REFERENCE 4930 #define VOLTAGE_RESOLUTION 1024 //#define R1_OHM 10000 #define R1_OHM 9960 //#define R2_OHM 10000 #define R2_OHM 9960 volatile unsigned char uart_tx_msg[TX_UART_SIZE] = {0}; volatile unsigned char uart_tx_cnt = 0;
定数の宣言およびグローバル変数の宣言。グローバル変数は7セグメントディスプレイへのシリアル通信でのデータ転送用です。
3.1.2 シリアル通信の割り込み処理
void interrupt isr_ctrl( void ) { if( TXIF ) { if( uart_tx_cnt < TX_UART_SIZE ) { TXREG = uart_tx_msg[ uart_tx_cnt ]; uart_tx_cnt++; } else { TXIE = 0; } if( uart_tx_cnt >= TX_UART_SIZE ) { uart_tx_cnt = 0; TXIE = 0; } TXIF = 0; } }
シリアル通信でのデータ転送処理です。
3.1.3 PICの初期設定
unsigned short ad_data; long ad_volt,input_volt; short i,work1,work2,work3; OSCCON = 0b01110000 ; // 内部クロック8MHz ANSELA = 0b00010000 ; // AN3をアナログにし、他はデジタルI/Oに割当てる TRISA = 0b00011010 ; // RA1,3,4を入力にし、他は出力に割当てる PORTA = 0b00000000 ; // 出力ピンの初期化(全てLOWにする) ADCON1 = 0b10100000 ; // 右寄せ、Fosc/32,VDDをリファレンスにする ADCON0 = 0b00001101 ; // AN3を使用する __delay_us(5); // ch設定後、反映待ち TXSTA = 0x24; // 送信情報設定:非同期モード 8ビット・ノンパリティ RCSTA = 0x90; // 受信情報設定 BAUDCON = 0x08; // 16bit SPBRG = 0x40; // ボーレートを9600(高速モード)に設定 SPBRGH = 0x03; RXDTSEL = 0; TXCKSEL = 0; TXIE = 0; TXIF = 0; PEIE = 1; GIE = 1;
各種初期設定です。周波数、ポート設定、シリアル通信設定などを行っています。
3.1.4 AD変換
// AD 変換 GO_nDONE = 1; // 変換開始 // アナログをデジタルに変換 while( GO_nDONE ) { // wait } ad_data = ADRESH; ad_data = (ad_data << 8) | ADRESL;
AD変換し電圧の取得を行っています。
3.1.5 電圧計算
// 計算 ad_volt = ((long)VOLTAGE_REFERENCE * (long)ad_data) / VOLTAGE_RESOLUTION; input_volt = ad_volt * ((long)R1_OHM + (long)R2_OHM) / (long)R2_OHM;
取得した電圧から入力電圧を求めています。
3.1.6 7セグメントディスプレイへ送信処理
// 位で分割(小数点2桁を有効) work1 = input_volt / 10; work3 = work1 % 10; work1 /= 10; work2 = work1 % 10; work1 /= 10; // 送信データ構築 uart_tx_msg[0] = 0x04; // 少数点位置の設定 uart_tx_msg[1] = 0x0f & work1; uart_tx_msg[2] = (work2<< 4) | work3; uart_tx_cnt = 0; TXIE = 1; // 送信開始
測定した電圧をシリアル通信を使用して7セグメントディスプレイに送信するためのデータを作成しています。
3.2 ソースコード
プログラムの全文を掲載します。
<注意>
ファイル名は必要に応じて変更し利用してください。
本サイトの注意事項を確認してください。
ソースコードや回路図などを使用する場合、上記注意とともに、自己責任でお願いします。
4.動作確認
電圧の測定対象はニッケル水素充電池を6本直列接続したものです。テスターと比べてみても最大0.02[V]の誤差で収まっています。
<更新履歴>
日付 | 内容 |
2015年11月17日 | 新規作成 |
2016年10月7日 | フォーマット変更 |
実際にはブレッドボードの隣のPIC16F1826で、7seg表示されていますよね?
説明が無いのは何故ですか?
電圧の測定はPIC12F1822で行っています。
その出力値を7セグで表示するためにPIC16F1826を使っています。
同ページの「2.3.2 PICの配線」の「シリアル通信(TxD:送信)(補足:7セグメントディスプレイへデータ転送)」がPIC16F1826につなげている配線になります。