PCでログ収集 AVR マイコン温度測定
(c) 2009. Mi-Take/t.minobe
1.はじめに
アンプ等の自作や改造をやっていると、温度上昇や温度の経過を測定したい場合が良くあります。
それほどシビアでなくても、85℃を超えているのか60℃位に収まっているのか・・・・・ 等の確認時に
手軽に使えるツールとして、作成しました。
Vectorで連携ソフト公開中
MI-TAKE で検索
2.想定する仕様条件(要求仕様) < ↓ できた仕様 ↓ >
・測定温度範囲:0℃〜105℃ 以上広いこと =>-40℃〜125℃ となりました
・液晶表示器等、単体での使用が可能なこと =>定番の16文字x2行の液晶がつながります
・PCに測定データを送れること (ターミナルソフトなどで手軽に受けることが可能) =>RS-232Cです (USBは敷居が高い)
・測定する時間間隔が設定できること =>1秒〜999秒で設定できます
・温度設定で外部機器(SW回路)を制御可能なこと =>オープンコレクタのトランジスタで制御
・各種設定値(時間間隔、温度設定)が電源を切っても保持できること。 =>EEPROMに書き込み保存
3.使用マイコンの選定
上記条件を満足する手軽なマイコンと言うことで AVR mega8を採用します。
mega8の主なスペックは
・Flash/8KB
・SRAM/1024byte
・EEPROM/512byte
・max 23 I/Oポート
・8ch/10bitのDAポート
・USARTあり
・パッケージ=スリム28P DIP タイプ
4.回路の設計
上記 2.項を満足する回路として下記回路としました。
回路上の主なポイントは
1.電源は転がっているACアダプタの流用を想定し、5Vの安定化電源を設ける。
2.DACのリファレンスは、TL431を使用し精度をあげる。 => LM60+LM358+TL431の組み合わせで -40℃〜125℃確保
3.温度センサは、LM60を使用し測定温度範囲を確保する。
4.外部機器の制御用として、オープンコレクタ(ドレイン)の出力を設ける
5.設定値は、AVRマイコンのEEPROMに保存する。
6.各種設定等の為に、UP/DOWN/SET の3個のタクトSWおよび項目切替用として 2個のトグルSW 使用
7.スタンドアローン使用のための表示器として、16文字x2行のLCD使用
8.PCとの接続は、USARTを使用しRS-232C接続とする。 レベル変換にはmax232相当の変換IC使用。ストレート接続。
5.基板の設計
手作りのため、片面基板として設計。 パターン/部品配置は下図。
< パターン図> 但し部品面からの透視図
<部品配置図(シルク)>
<部品を実装した写真>
センサのLM60はソケットに挿入。実際の使用時には、リード線で引き出すことが可能。
D-SUBコネクタの基板用が無かったので線材で引き出してコネクタに半田付けしている。
6.ソフトの設計
ソフト設計のポイントは
1.WinAVRによるC言語で開発
2.リセットおよびクロックはマイコン内部の機能を使用。
3.クロックは、USARTでの通信速度確保のため、8MHzに設定(1/8分周fuseOFF)
RS-232C設定値:9600,non,8,1
4.測定間隔等はクロック分周とタイマー割込で作成 (精度は高くないが)
5.リセット時の初期値は、EEPROMから持ってくる。
1バイト目をIDとして記録し、IDが異なる場合はデーター無効としソフト内部のデフォルト値とする。
6.動作設定範囲
温 度 :0℃〜105℃ (デフォルト 27℃)
時間間隔:1〜99秒 (2秒)
7.温度の分解能:0.1886℃ (125+40)/(1024-148-1)=0.1886℃
ページの最後にソースを掲載します。
7.使い方
1.周辺機器等との接続
・電源に、8-12V程度のアダブターを繋ぐ。
・5Vの電源がある場合は、安定化電源を通さない端子に電源を接続。
・PCとの接続は、RS-232Cストレートケーブルで接続
2. 設定はトグルSWにより、温度設定 :設定温度を超えると、制御用トランジスタがOFF (制御TRのベースがLow)
インターバル時間設定 :設定時間で制御用トランジスタ ON-OFFの繰り返し
となるので、制御したい対象をつなぐ。出力のタイプは オープンコレクタ(オープンドレイン)である。
2-1.温度設定
トグルSWの温度設定SWを onするとLCDの表示は下の写真の表示となるので、タクトSWのau-downで
設定を行う。
温度設定モード時の表示
2-2.インターバル時間設定
トグルSWのインターバル設定SWを onするとLCDの表示は下の写真の表示となるので、タクトSWのau-downで
設定を行う。
測定時間間隔(interval)設定の表示
3.温度SW、インターバル時間SWは、先にonした方のみ有効で、後から入れたswは無視される。
4.EEPROMへの書き込みは、温度SW、インターバル時間SWのどちらのSWもoffの状態で、書き込み用タクトSWの
押下で書き込まれる。2秒以上押し続けること。 押下時間が短い場合は、書き込み中止となる。
これは、誤操作防止用に書き込み時にタイマーをかけて長押しで確認を取っているためである。
書き込み完了の表示
書き込み中止の表示
5.出力モニターとして、LEDがあるがLEDの点灯時は制御用TRのベースはLOWすなわち、OFFした状態であるので注意されたい。
LED点灯 => 制御用トランジスタ OFF
LED消灯 => 制御用トランジスタ ON
6.PCとの接続時、インターバルで決めた時間間隔で温度データを送出する。 9600,n,8,1が通信条件です。
汎用のターミナルソフトで受信すると
>A 26.20
>A 26.00
>A 26.00
の様に頭に Aがついて表示されます。無視してください。(あるいはソースを書き換えてください)
無視できない方は、別途掲載されている(VectorでもVisual C# のソースつきで公開) H8TempRec をご使用ください。
PCのソフト側で各種設定し温度データ収集ができるソフトです。
このソフトとの組み合わせを想定してますので、Aが出るのは 「エ〜として!!」
8.ソースリスト
//
//----------------------------------------------------------------------------
// temperature measure and Control.
(c)Mi-take/t.minobe
// mega8 + LM60
2009.4.13.-2009.4.15.
//----------------------------------------------------------------------------
//
/*
#include <avr/io.h>
#include <stdlib.h>
#include <string.h>
#define F_CPU 8000000UL
// MHz clock ; delay.h requiered
define.
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdint.h>
#include <avr/eeprom.h>
char buff[5];
int tempMinus=0;
int setTempMode=0,setTimeMode=0;
unsignedint timeDefault=2; // 1 to 999
unsignedchar tempDefault=27; //
0min to 105max
unsignedint timer0Count=0; // timer0
counter
int currentTemp,timerLedFlug=0;
#define FOSC 8000000 // 8MHz
#define BAUD 9600
// 9600bps
#define m8baud FOSC/16/BAUD-1 // UART baud rate
#define sbi(PORT,BIT) (PORT |= _BV(BIT)) // bit set
#define cbi(PORT,BIT) (PORT &=~_BV(BIT)) //
bit crear
#define lcd_port
PORTD
#define lcd_port_d
DDRD
#define LCDControlPort PORTD
#define LCDStrob 0x08 // control bit enable
#define LCDRSHig (LCDControlPort|=0x04) // LCD RS high:char data
mode
#define LCDRSLow (LCDControlPort&=(~0x04)) // LCD RS low :instruction reg.
write mode
void port_int(void);
void PortInitialize(void);
void waitMsecond(int t);
void waitUsecond(int t);
void LCDStrobOutput();
void BinToAscii(int nn,char *buf);
void put4BitsLCD( unsignedchar bitdata);
void locateLCD(char tx ,char ty);
void putByteLCD( unsignedchar ch);
void putStringsLCD(char *str);
void clearLCD();
void initializeLCD(void);
void
BinToAscii2digit( unsignedchar num);
void
Int0InterruptSet(void);
void BinToAsciiZero(int nn,char *buf);
void addCRLF(char *buf,char *buf2,char ch);
void sciTXsub(char *str);
//-----------------------------------------------------------
// all port initialize
//-----------------------------------------------------------
void port_int(void)
{
DDRC = 0x00; //portC input mode
PORTC = 0xff; // pullup
DDRB =
0xff; //portB oputput
mode
PORTB = 0xff; //
DDRD
= 0xfc; //portD output mode
PORTD = 0xff; //
}
//----------------------------------------------------------
//waiting loop
void
waitMsecond(int t)
{ while (t--) _delay_ms(1 );}
void waitUsecond(int t)
{ while (t--) _delay_us(12 );}
//8 is not enough,may be x1.5=12;
int RXdataCount=0;
unsignedchar RXchar[32];
//----------------------------------------------------------
// inturupt RxD
ISR(USART_RXC_vect) //mega8 int_vector name=USART_RXC_vect
{
RXchar[RXdataCount ++]= UDR;
//RingBuffer
if(RXdataCount>31) RXdataCount=0;
}
//----------------------------------------------------------
//inturupt timer0
ISR(TIMER0_OVF_vect)
{
char buf[10],buf2[16];
timer0Count++;
if(timer0Count>( unsignedint)(timeDefault*30.5)){
timer0Count=0;
if(timerLedFlug==1){
timerLedFlug=0;
PORTB &=
0b11111101;
}
else{
timerLedFlug=1;
PORTB |=
0b00000010;
}
BinToAsciiZero(currentTemp,buf);
addCRLF(buf,buf2,'A');
sciTXsub(buf2);
}
}
//---------------------------------------------------------
//
void sciTXsub(char *str)
{
char ch;
while(0 !=(ch =*str)){
while (!(UCSRA & 0b00100000 ));
// data reg NULL : UDRE=1 is rady
UDR =(ch);
waitMsecond(1);
str++;
}
}
//---------------------------------------------------------
//
int ADCsub()
{
int i,tSum;
int tempV;
ADMUX = 0b00000000; // ADC0, right-justify,
ext-Ref
waitMsecond(5); // wait MPX
stabirity
tSum=0;
for(i=0;
i<10;i++){
ADCSRA =
0b11000110; // AD
enable, and stert(singl mode), clock=1/64
while( ADCSRA & 0b01000000 ); // finish?
tSum
+= ADC;
}
tSum /= 10; //average
tempV =(int)(((tSum-149)*0.188-43+0.05 )* 10); // triming to data
// tempV
=(int)(((tSum-148)*0.189-40) * 10); // Convert
tempV *=10; // round about 0.2℃ step
if(tempV<0 ){
tempV *=-1;
tempMinus=1;
}
else tempMinus=0;
return(tempV);
}
//-----------------------------------------------------------
//lcd strobe
void
LCDStrobOutput()
{
waitUsecond(1);
LCDControlPort |= LCDStrob; // high
waitUsecond(1);
LCDControlPort &=(~LCDStrob); // low
waitUsecond(1);
}
//-----------------------------------------------------------
// string to char conv.
// binary
to decimal&Ascii (max 8 column)
void
BinToAscii(int nn,char
*buf)
{
int i,j,d[10];
for(i=0 ;
i<8 ;i++){
d[i ]= nn%10;
nn = nn/10;
}
while(d[--i ]== 0 );
for(j=0
; j<=i ; j++) buf[j ]=
d[i-j ]+ '0';
if(j==0){ buf[0]='0'; buf[1]='\0' ;}
else buf[j ]= '\0';
}
//
-----------------------------------------------------------
//LCD 4bit data output
// argc:
lower bitdata (DD4-7)
void
put4BitsLCD( unsignedchar bitdata)
{
bitdata
<<=4;
//shift PORTD
4-7
LCDControlPort =(bitdata |(LCDControlPort & 0x0f)); // old data clear +new
data
LCDStrobOutput(); // write data
}
//-----------------------------------------------------------
// LCD display cursor posion set.
// argv:char tx => x position
// argv:char ty => y position. 4line lcd is
already
void locateLCD(char tx ,char ty)
{
char pos;
LCDRSLow;
// instruction reg.
mode
waitUsecond(1);
if(ty == 1)
ty = 0x40;
if(ty ==
2) ty = 0x14;
if(ty == 3)
ty = 0x54;
pos =(ty +
tx); // DispData
Adrress
pos |= 0x80; // cursor pos command
bit set
putByteLCD(pos);
LCDRSHig;
// data
mode
waitUsecond(1);
}
//-----------------------------------------------------------
//LCD 1byte output
// argc: LCD
module output char data
void
putByteLCD( unsignedchar ch)
{
unsignedchar ch1;
ch1= ch >> 4;
put4BitsLCD(ch1); // upper 4bit output
ch1=
ch & 0x0f;
put4BitsLCD(ch1); // lower 4bit
output
}
//-----------------------------------------------------------
//LCD char str. disp
//
argc:character pointer(*str)
void
putStringsLCD(char *str)
{
LCDRSHig; // data mode
immediate
while(*str != 0 ){
putByteLCD (*str );
str++;
}
}
//-----------------------------------------------------------
//LCD all cls
void
clearLCD()
{
LCDRSLow; // instruction reg.
write mode
waitUsecond(1);
putByteLCD( 0x01 ); // Display
Clear
waitUsecond(1520); // minmum wait time is
1.52mS
LCDRSHig; // data mode
}
//-----------------------------------------------------------
//LCD initialize
void
initializeLCD(void)
{
waitMsecond(15); // pow-supply sw-on
delay
LCDRSLow; // instruction reg. write mode
put4BitsLCD(3);
waitUsecond(4100);
put4BitsLCD(3);
waitUsecond(150);
put4BitsLCD(3);
waitUsecond(150);
put4BitsLCD(2);
waitUsecond(100);
putByteLCD(0x28);
putByteLCD(12);
putByteLCD(6);
putByteLCD(1);
waitUsecond(1520);
LCDRSHig; // data
mode
}
//-----------------------------------------------------------
// string to 4digit char with Zero & dot
ex.113=>01.13
//
void BinToAsciiZero(int nn,char *buf)
{
buf[5 ]= nn%10+'0'; nn /=10;
buf[4 ]=
nn%10+'0'; nn /=10;
buf[3 ]= '.';
buf[2 ]=
nn%10+'0'; nn /=10;
buf[1 ]=
nn%10+'0'; nn /=10;
if(nn==0
&& buf[1]=='0') buf[1]=' ';
buf[0 ]= nn%10+'0';
if(buf[0]=='0') buf[0]='
';
if(tempMinus==1) buf[0]='-';
buf[6 ]= '\0';
}
//---------------------------------------------------------
//
void addCRLF(char *buf,char *buf2,char ch)
{
int i=1;
buf2[0]=ch;
do{
buf2[i]=buf[i-1];
i++;
} while(buf[i-1]);
buf2[i++]='\r'; buf2[i++]='\n'; buf2[i++]='\0';
}
//---------------------------------------------------------
//
void USART_Init( unsignedint baud)
{
UBRRH =( unsignedchar)(baud>>8); //boud data
high-byte
UBRRL =( unsignedchar)baud; //boud data
low-byte
UCSRC = 0b10000110; // non,8,1
(URSEL=1)
UCSRB = 0b10011000; // Rx/Tx enable,Rx
interrupt enable
}
//---------------------------------------------------------
//
void timer0_Init()
{
TCNT0 = 0; // タイマ0初期値
TCCR0 =(1<<CS02)|(0<<CS01)|(1<<CS00); // prescaler 1/1024
sbi(TIMSK,TOIE0);
// TIMRE0 overFlow int
enable
}
//---------------------------------------------------------
//
void startLCD()
{
clearLCD();
putStringsLCD("Mega8 USART&ADC");
locateLCD(0,1);
putStringsLCD("TEMP = ");
}
//---------------------------------------------------------
//
void
settingDataInput()
{
char buf[16];
int swSpeed=300,upFlug=0,dnFlug=0;
cli();
while ((((PINC>>4)&1)&((PINC>>5)&1 ))== 0){
locateLCD(0,0);
putStringsLCD("Set mode:");
while((PINC&0x10)==0){ //time sw on
locateLCD(9,0); putStringsLCD("timeIntval");
locateLCD(0,1); putStringsLCD("set time=");
BinToAscii(timeDefault,buf);
putStringsLCD(buf);
putStringsLCD("
");
if((PINC&0x08)==0 ){
timeDefault++;
waitMsecond(swSpeed);
if(timeDefault>999) timeDefault=999;
if(upFlug) swSpeed -=30; if(swSpeed<10) swSpeed=10;
upFlug=1;
}
elseif((PINC&0x08)&&upFlug){
upFlug=0; swSpeed=300;
}
if((PINC&0x04)==0 ){
timeDefault--;
waitMsecond(swSpeed);
if(timeDefault<1) timeDefault=1;
if(dnFlug) swSpeed -=30; if(swSpeed<10) swSpeed=10;
dnFlug=1;
}
elseif((PINC&0x04)&&dnFlug){
dnFlug=0; swSpeed=300;
}
}
while (((PINC>>5)&1)==0){
locateLCD(9,0); putStringsLCD("SW tempre.");
locateLCD(0,1); putStringsLCD("set temp=");
BinToAscii(tempDefault,buf);
putStringsLCD(buf);
putStringsLCD("
");
if((PINC&0x08)==0 ){
tempDefault++;
waitMsecond(swSpeed);
if(tempDefault>105) tempDefault=105;
if(upFlug) swSpeed -=30; if(swSpeed<10) swSpeed=10;
upFlug=1;
}
elseif((PINC&0x08)&&upFlug){
upFlug=0; swSpeed=300;
}
if((PINC&0x04)==0 ){
tempDefault--;
waitMsecond(swSpeed);
if(tempDefault<0) tempDefault=0;
if(dnFlug) swSpeed -=30; if(swSpeed<10) swSpeed=10;
dnFlug=1;
}
elseif((PINC&0x04)&&dnFlug){
dnFlug=0; swSpeed=300;
}
}
}
startLCD();
sei();
}
//---------------------------------------------------------
//
unsignedchar EEPROM_read( unsignedint uiAddress)
{
while(EECR &(1<<EEWE)); //EEPROM rady ?
EEAR
= uiAddress; //EEPROM adress set
EECR |=(1<<EERE); //EEPROM read start
return(EEDR);
}
//---------------------------------------------------------
//
void EEPROM_write( unsignedint uiAddress, unsignedchar ucData)
{
while(EECR &(1<<EEWE)); //EEPROM rady ?
EEAR =
uiAddress; //EEPROM
adress set
EEDR = ucData; //EEPROM write data
set
EECR |=(1<<EEMWE); //EEPROM write mode
enable
EECR |=(1<<EEWE); //EEPROM
write
}
//---------------------------------------------------------
//EEPROM data set & call
void setEEPROMdata()
{
int writeFlug;
int timeH = timeDefault / 256;
int timeL = timeDefault % 256;
locateLCD(0,0); putStringsLCD("EEPROM write default");
writeFlug=0;
do{
waitMsecond(1000);
locateLCD(0,1);
if((PINC&0x02)==0){
eeprom_busy_wait();
//EEPROM rady
?
EEPROM_write(0x00,0x33); // mark
ID(ID=0x33)
eeprom_busy_wait();
EEPROM_write(0x01,timeL); // timeDefault low
data
eeprom_busy_wait();
EEPROM_write(0x02,timeH); // timeDefault high
data
eeprom_busy_wait();
EEPROM_write(0x03,tempDefault); // tempDefault data
putStringsLCD("EEPROM wrote !!");
writeFlug=1;
}
} while((PINC&0x02)==0);
if(writeFlug==0){
clearLCD();
putStringsLCD("stoped write");
}
waitMsecond(2000);
clearLCD();
}
//---------------------------------------------------------
//
void loadDefault()
{
int
tmp,timeL,timeH;
locateLCD(0,0);
putStringsLCD("EEPROM load
default"); waitMsecond(500);
eeprom_busy_wait(); //EEPROM rady
?
tmp = EEPROM_read(0x00); //ID check
if(tmp == 0x33){
eeprom_busy_wait();
timeL =
EEPROM_read(0x01);
eeprom_busy_wait();
timeH =
EEPROM_read(0x02);
timeDefault = timeH
* 256 + timeL;
eeprom_busy_wait();
tempDefault =
EEPROM_read(0x03);
}
else{
locateLCD(0,1);
putStringsLCD("Err.. did not read");
waitMsecond(2000);
}
}
//---------------------------------------------------------
//
int main(void)
{
char ch,buf[10],buf2[16];
ch='0'; //dummy
int LCDdisp = 10;
int tempOffset=0;
port_int();
initializeLCD();
//LCD
initialize
USART_Init(m8baud); //USART
initialize
loadDefault();
//if defalu data
exist
timer0_Init();
startLCD(); //disp
LCD
sei();
// enable
interrupt
while(1)
{
currentTemp =
ADCsub();
BinToAsciiZero(currentTemp,buf);
if(( unsignedchar)(currentTemp/100)>=(tempDefault-tempOffset)){
PORTB &=
0b11111110;
tempOffset = 2; //it hysteresis 2deg.
}
else{
PORTB |=
0b00000001;
tempOffset = 0;
}
if(RXdataCount != 0){
if(RXchar[0]=='T'||RXchar[0]=='S'){
addCRLF(buf,buf2,RXchar[0]);
sciTXsub(buf2);
RXdataCount=0;
}
else {
RXdataCount--;
if(RXdataCount<0) RXdataCount=0;
}
}
if((LCDdisp--)==10){ //LCD disp refresh is
about 0.1second
locateLCD(7,1); putStringsLCD(buf); putStringsLCD("'C");
}
elseif(LCDdisp<0) LCDdisp=10;
setTempMode=(PINC>>4)&1;
setTimeMode=(PINC>>5)&1;
if((setTempMode&setTimeMode )== 0){
clearLCD();
settingDataInput();
LCDdisp=10;
}
if((PINC&0x02)==0){
clearLCD();
setEEPROMdata();
startLCD();
LCDdisp=10;
}
}
cli();
return(0);
}
jamp to HOME
(c) 2009. Mi-Take/t.minobe