JavaScript が無効です。有効にしてください。
ななよんのホームページ
トップ > 電子工作 > PIC マイコン > PIC マイコンで電源電圧を測定する

PIC マイコンで電源電圧を測定する

最終更新日さいしゅうこうしんび:2023-09-05
注意
電源電圧を変動させて実験を行う場合は、絶対最大定格を超えてしまわないよう注意してください。PIC 自身は良くても表示装置や UART 変換器の I/O 電圧を超える可能性もあります。

 PIC マイコンでは、電源電圧を直接測定することはできませんが、ADC と基準電圧(固定電圧リファレンス)があり基準電圧を ADC チャンネルに選択できる PIC では、計算で電源電圧を求めることができます。今回はその実験を行ってみました。仕様の異なる以下の 3 種類の PIC で実験を行いますが、ほかの PIC でも同様に電源電圧を測定できるはずです。

型番 ファミリ FVR 電圧 [V] ADC 分解能 [bit]
PIC10F222 ベースライン 0.6 8
PIC16F687 ミッドレンジ 0.6 10
PIC16F1827 Enhanced 1.024/2.048/4.096 (selectable) 10
今回実験する 3 種類の PIC が写った写真

概要

 PIC に内蔵されている FVR(Fixed Voltage Reference:固定電圧リファレンス)は、ADC の入力チャンネルとして選択可能です。ADC の基準電圧を VDD にすれば、VDDと FVR の比から VDD を測定できます。10F222 は 8 ビットですしプログラムメモリも少ないので、正確な測定は難しいです。大まかな電池残量を知る程度ならば 8 ビットでも十分だと思います。自己の電圧が測定できれば、電池切れ通知や電圧異常をお知らせすることができるようになります。応用が広がりそうですね。

計算方法

 「FVR 電圧 : VDD = ADC 値 : ADC 最大値」という比の等式を変形することで電源電圧を求める計算式を導出できます。比率の計算は、内側と外側をかけることで行えます(中学数学)。例えば、PIC16F687 の場合 FVR 電圧が 0.6 V で ADC 分解能が 10 ビット(最大値は 1023)ですので、以下の手順で導出します:

  1. 0.6 : VDD = ADRES : 1023
  2. VDD x ADRES = 0.6 x 1023 = 613.8
  3. 変形して VDD = 613.8 / ADRES
  4. 1000 倍して整数化 VDD[mV] = 613800 / ADRES

 ADRES は ADC 値(生の値)です。FVR を AD 変換するので、ADC 値は FVR 電圧になります。そして、ADC が最大値であるというのは ADC の基準電圧と等しいということを意味しますが、基準電圧に VDD を使用するので、ADC 最大値は VDD になります。したがって、このような式を立てることができます。

 同じ考え方で、8 ビットの場合や FVR 電圧が異なる場合でも VDD を算出できます。

実験してみる。

PIC16F687

 UART 9600 bps で PC に測定値を 1 秒おきに送信するプログラムを作成しました。TeraTerm 等で受信をモニタします。

#include <xc.h>

#define _XTAL_FREQ 8000000      // 内蔵クロック 8 MHz

#pragma config FOSC = INTRCIO
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = ON
#pragma config IESO = ON
#pragma config FCMEN = ON

// UART 送信関数
void transmit(uint8_t data) {
    while(!PIR1bits.TXIF);
    if(PIR1bits.TXIF) TXREG = data;
}

void main(void) {
    // システム設定
    OSCCON = 0b01110001;        // 内蔵クロックを 8 MHz に設定
    OPTION_REG = 0b10000010;    // 内蔵プルアップ無効、TMR0 プリスケーラ 1:8
    
    // PORT 設定
    ANSEL = 0b00000000;         // アナログ無効(デジタルとして使用)
    ANSELH = 0b00000000;        // アナログ無効(デジタルとして使用)
    TRISA = 0b00001000;         // 入力専用ピン以外出力
    TRISB = 0b00100000;         // RX 以外出力
    TRISC = 0b00000000;         // 出力
    
    // アナログ設定
    ADCON0 = 0b10000001;        // アナログ有効
    ADCON1 = 0b01110000;        // アナログクロックを FRC に
    
    // UART 設定
    RCSTA = 0b10010000;
    BAUDCTL = 0b00000000;
    TXSTA = 0b00100000;         // 8 ビット、パリティなし
    SPBRG = 12;                 // 9600 baud
    
    while(1) {        
        ADCON0 = 0b10110111;    // 0.6 V 固定電圧リファレンス
        while(ADCON0bits.GO);   // AD 変換待ち
        
        uint16_t raw = ADRESH*256 | ADRESL;     // ADC 値
        int voltage = 613800 / raw;             // 電圧計算
        
        transmit((voltage/1000)%10 +'0');   // 千位
        transmit((voltage/100)%10 +'0');    // 百位
        transmit((voltage/10)%10 +'0');     // 十位
        transmit(voltage%10 +'0');          // 一位
        transmit('m');                      // ミリ
        transmit('V');                      // ボルト
        transmit(0x0D);                     // CR
        transmit(0x0A);                     // LF
        
        __delay_ms(1000);       // 1 秒待ち
    }
}

 PC の USB バスパワで動作させたところ、DMM(テスタ)での実測値が 5.10 V、PIC での測定値は 5201 mV でした。差は 0.101 V で、ほぼ同じ電圧を示しています。簡易チェックには十分でしょう。


広告

PIC16F1827

 私は比較的安価で高機能な F1 ファミリの使用を推奨していますので、この方法を使うことが多くなると思います。設定は MCC で行いました。FVR は 2 個ありますが、ADC 用に使われるのは Buffer 1 ですので、FVR_Buffer1 Gain を 1x(1.024 V)に設定します。ADC モジュールでは、AD 変換結果を右詰めにし、クロックに Frc を選択します。もちろん、VREF は VDD にします。測定値は UART で送信しますので、USART モジュールの設定も必要です。

 FVR 電圧が 1.024 V ですから、先ほどの比率の式に 1.024 を代入して計算すると、VDD[mV] = 1047552 / ADRES で求めることができます。

#include "mcc_generated_files/mcc.h"

void main(void) {
    SYSTEM_Initialize();
    
    while (1) {
        uint16_t raw = ADC_GetConversion(channel_FVR);  // ADC 値取得
        int voltage = 1047552 / raw;                    // 電圧計算
        
        EUSART_Write((voltage/1000)%10 +'0');   // 千位
        EUSART_Write((voltage/100)%10 +'0');    // 百位
        EUSART_Write((voltage/10)%10 +'0');     // 十位
        EUSART_Write(voltage%10 +'0');          // 一位
        EUSART_Write('m');                      // ミリ
        EUSART_Write('V');                      // ボルト
        EUSART_Write(0x0D);                     // CR
        EUSART_Write(0x0A);                     // LF
        
        __delay_ms(1000);       // 待ち
    }
}

 先ほどと同様 USB から給電、テスタでは 5.10 V で、PIC での測定値は 5085 mV でした。16F687 のときよりも精度が高いですね。

PIC10F222

 10F222 のスペックでは電源電圧を計算して表示、ということは難しいので、電圧に応じて3 段階で LED を点灯させる方式にします:

  • 赤;3 V 以上
  • 黄;4 V 以上
  • 緑;5 V 以上

 電源電圧を計算して if するのでは PIC10F222 のプログラムメモリではできませんでした。そこで、電源電圧に変換せず、ADC 値(生の値)を比較します。10F222 の ADC は 8 ビットですので、1023 ではなく 255 で計算すると、「VDD[mV] = 153000 / ADRES」になりました。LED を点灯させる閾値は、以下のようになります:

  • 3 V:51
  • 4 V:38.25
  • 5 V:30.6

 この値よりも小さければ、電圧が高いことになります。小数はありませんので、四捨五入しておよその電圧を表示するようにします。

#include <xc.h>

#define _XTAL_FREQ 8000000

#pragma config IOSCFS = 8MHZ
#pragma config MCPU = OFF
#pragma config WDTE = OFF
#pragma config CP = OFF
#pragma config MCLRE = OFF

void main(void) {
    OPTION = 0b10000000;
    ADCON0 = 0b00000001;    // ピンはデジタル
    TRISGPIO = 0b00001000;  // 入力専用ピン以外出力
    GPIO = 0;               // ポート初期化
    
    while(1) {
        ADCON0 = 0b00001111;    // FVR をチャンネルに指定して変換開始
        while(ADCON0bits.GO);   // ADC 変換待ち
        uint8_t raw = ADRES;    // 変換結果
        
        // 表示
        if(raw<31) {
            // 約 5 V 以上
            GPIO = 0b000000111;
        } else if(raw<38) {
            // 約 4 V 以上
            GPIO = 0b000000110;
        } else if(raw<51) {
            // 3 V 以上
            GPIO = 0b000000100;
        } else {
            // 3 V 未満
            GPIO = 0b000000000;
        }
        
        __delay_ms(100);
    }
}

 直流安定化電源を所有していないため、正確に調べることはできませんでしたが、USB バスパワや電池 2~3 本、へたった電池と、電源を変えてみると表示も変化しました。

実験結果

 誤差はあるものの、大まかな電源電圧を取得できていることを確認しました。I/O ピンを消費していないので、プログラムメモリに余裕があれば電源電圧測定機能を付加することが可能です。アイデア次第でいろいろな応用ができそうですね。


戻る
広告

右メニュー

【表示がおかしい・崩れる場合】PC では Shift と F5 を同時押し。スマホではキャッシュを削除してみてください。



とうサイトでは Cookieくっきー使用しようします。くわしくは上記じょうきの「プライバシーポリシー・免責事項等めんせきじこうとう」もご確認かくにんください。



上へ戻る