PIC12F1822には、内部温度を示す温度インジケータが内蔵されています。
温度インジケータは、次の図のような構造で、シリコンダイオードの順方向電圧が温度が高くなると小さくなることを利用しています。
FVRCONレジスタのbit5(TSEN)を1にすることで、温度インジケータが有効になります。
シリコンダイオードを2個にするか4個にするかは、同じくFVRCONのbit4(TSRNG)で選択し、0で2個(mode=2)、1で4個(mode≂4)になります。
この回路は、VDDに接続されていて、VDD>=3.6Vでは、mode=4、VDD<=3.6Vではmode=2とします。
温度インジケータをA/Dコンバータに接続するには、ADCON0のbit7-bit2を11101とします。
今回はは、VDDは乾電池2本(3V)としますので、mode=2にセットします。(TSRNG=0)
では、実際にA/Dコンバータの数値を測定してみます。VDD=3.03V , Temp=20℃ の時A/Dコンバータの変換値は、597でした。
理論値は、上の2式(VtempとADCresultの式)に各値を代入して計算すると631となります。
また、寒い部屋にこれらを移動して温度を7.3℃の時の値を測定しました。
VDD=3.02V Temp=7.3℃で、A/Dコンバータの値は、584でした。以上を下の表にまとめました。
しかし、この温度インジケータには、いくつか問題点があります。上の式からも分かるように、測定値がVDDの変化に大きく影響をうけます。VDDを安定な電圧で使用しなければなりません。
次に、A/D変換値から温度を計算するには、上記のTemp(℃)の式で計算しなければなりません。(A/D変換値と温度をテーブルにしておいて、表引きする方法もあります)
計算するには、浮動小数点計算が必要になり、PICでは負担が大きいです。そこまでして計算する価値のある温度インジケータとは思えません。
外付けの温度センサーを付けて、A/D変換する方がはるかに簡単です。
以上からこの温度インジケータは、温度測定に使用するより、PICの内部温度異常を検出するモニタ程度の利用法かなと思いました。
参考までにmain関数を下に掲載します。
----------------------------------------------
void main() {
OSCCON = 0b01110000 ; // 内部クロック8MHz
ANSELA = 0b00000000 ; // アナログは使わない
TRISA = 0b00001110 ; // RA1,RA2,RA3は入力、RA0,RA4RA5は出力
PORTA = 0b00000000 ; // PORTの初期化
LATA = 0b00000000;
OSCCON = 0b01110000 ; // 内部クロック8MHz
ANSELA = 0b00000000 ; // アナログは使わない
TRISA = 0b00001110 ; // RA1,RA2,RA3は入力、RA0,RA4RA5は出力
PORTA = 0b00000000 ; // PORTの初期化
LATA = 0b00000000;
I2C_init();
LCD_init();
putstr("TempTEST");
/* A/Dコンバータ関係の設定 */
ADCON0 = 0b01110101; //温度インジケータをselect,ADCイネーブル
ADCON1 = 0b10100000; //ADFM=1(右詰め),クロックFosc/32,VREF=VDD
FVRCON = 0b00100000; //FVR OFF ,温度インジケータ有効,Vout=VDD-2Vt
while(1){
__delay_us(20);
GO = 1; //ADCスタート
while(GO); //ADC完了まで待つ
unsigned int val = ADRESH;
val = (val<<8) | ADRESL;
LCD_2line();
printf("%4d",val);
__delay_ms(500);
}
}
----------------------------------------------
LCD_init();
putstr("TempTEST");
/* A/Dコンバータ関係の設定 */
ADCON0 = 0b01110101; //温度インジケータをselect,ADCイネーブル
ADCON1 = 0b10100000; //ADFM=1(右詰め),クロックFosc/32,VREF=VDD
FVRCON = 0b00100000; //FVR OFF ,温度インジケータ有効,Vout=VDD-2Vt
while(1){
__delay_us(20);
GO = 1; //ADCスタート
while(GO); //ADC完了まで待つ
unsigned int val = ADRESH;
val = (val<<8) | ADRESL;
LCD_2line();
printf("%4d",val);
__delay_ms(500);
}
}
----------------------------------------------
I2C関係とLCD関係の関数は、前の記事を参照してください。