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