温度計                              TOPページへもどる

 気温(室温)を記録できる温度計を作ろうと考えました。単純に温度を測るだけなら既成の温度計が安価に求められます。すこし工夫を加えて、1日の温度変化を EEPROMに記録して、PCのCOMポートから読みとれるものを作ってみようと思います。この項では完成してからのレポートでなく、作る過程を記録する事にします。
 構想は、温度センサLM35D(National Semiconductor社)の出力をAD変換して温度のディジタル値を得て、液晶に表示するとともに、10分毎にEEPOMに書き込む ことにします。MCUは手持ちのmega8を使います。温度センサは実験的に使ったことがあります。液晶表示も経験しました。EEPROMはまだ使ったことがありません。これから 勉強します。PCとのCOMポート経由の通信は実験したことがあります。できれば、未知のマイクロソフトエクセルに取り込みたいと思います。分からないことがいっぱい ですがぼちぼち手がけようと思います。ここしばらくは自由時間が少ないのでなかなかはかどらないでしょうがやってみましょう。

 液晶表示器は最近(2006.10)デジットで購入したやや大型(液晶面が93mm×22mm、16桁×2行、青色文字)のものを使います。¥350で売っていました。文字が大きい ので老眼鏡をかけまくても見えます。付属のコネクタを外して、いつものピンソケットに取り替えて周波数カウンタにつないだところ正常に表示しました。指向性がよく、 見やすい液晶です。文字のデザインはもう一つなのですが。

 いつもどおりスルーホールの両面基板(今回は秋月のもの)に、電源端子(単なる銅線)、プログラム用6Pと液晶用8PとCOM用4Pのピン(単に真鍮の針金)を立て、 真ん中にTQFPのmega8を置きました。0.1のパスコンとavccのフィルタに10uH+0.1uFを追加して、電源回路とプログラム回路を接続します。いつもどおり0.2mmのUEWを使い ます。今回は鏝先を細いもの(R0.2)から太いもの(R0.5)に変更したので作業が楽になりました。ここまでできたところでライタをつなぎ電源を入れて読み出してみ ます。デバグが楽なように(デバグ技術がない?)少し進んでは動作テストをしてバグを取り除くのが私の方法です。電源を入れるときにはアナログ電流計を見ながら スイッチを操作して、電流値が異常ならすぐに切ることにしています。今回もうまくいきました。


 クロックを水晶振動子にします。内部RCでも良いのですが、1日に14分狂うのはいやですし、COMポートの確実性のためにも8MHzの水晶にしました。秋月で5個100円 だったと思います。
 ヒューズビットの設定が必要です。データシートがわかりにくくていつも悩むのですが、その中から、
外部クリスタル試用の時は CKSEL3:0 1110〜1010
3〜8MHzのクリスタルでは CKSEL3:1 111 , CKOPT 1
外部クリスタルでBODリセット許可の時は SUT1:0 01  , CKSEL0 1
とありましたので、
low 00011111 (0=BODLVEL4.0v 0=BOD有効 01=SUT起動時間 1111=外部水晶3〜8MHz)としました。 highはデフォルト(11111001)のままです。

 液晶表示回路の接続は、周波数カウンタの時と同じく、DATA4〜7にportCの0〜3を、RSにPC4、ENにPC5を割り当てることにします。最近は、コントラスト調整 バリオームは液晶に抱かせ、R/Wはディレイ処理のためGNDに固定としています。したがってコネクタは8ピンで、
1GND 2Vcc 3RS 4EN 5D4 6D5 7D6 8D7 としています。

 温度センサLM35Dを取り付けました。後ほど延長も可能なようにピンソケットを使いました。
AD変換は2,3度しているのですが、やはり謎解きのようにデータシートを見ながらメモを取ります。(見苦しいメモですが)


 本来は割り込みで使うべきでしょうが、始まりと終わりがはっきりしない測定ですから、とりあえず読み込んでみました。今のWinAVRなら16ビットデータを 2バイトに分けなくても読めるだろう。1カウントが1/4℃だからディジタル値を4で割れば温度になります。測定時間間隔に余裕があることと雑音の影響を少なく するために、また整数計算となるように、25回の測定値を合計して100で割ることにしました。1回の測定では 0.0 0.2 0.5 0.7 となりますが、小数以下は 気にしないことにします。
 なんとなくプログラムを書いてみて、以外とうまくできたと思ったところで、用事ができて10数分のあいだ目を離したら、とんでもない表示に変わっていました。 念のためセンサの出力ピンを見ると2.4Vほどの電圧が出ています。こんなに高いはずがない。これだと240℃ということになってしまいます。センサを外してADC6ピン を見ると2.4Vほどになっています。1/2Vccが出ている感じです。理由が分からず、センサのポートをADC7に変更すると、正常に戻りました。mega8が壊れたのかもしれません。


 ハードウエアはこれでほぼ完成です。持ち運べるように電源を付けてまとめないといけませんが。

IC周りの半田付けです。数をこなすと少しはきれいになってきた....と自分では思っています。


ついでに、机上のディジタル温度計(上にセンサが見えるもの)とは1.5℃ほど違います。自作のものが高く出ます。手元の水銀温度計と比べると 自作のものが近い表示です。温度計を買いに行くと、同じものなのに表示がばらばらですからどれにしようか迷います。


なお、ここまで半田付けが終わってもまだ回路図は作っていません。

 あと、一定時間間隔でデータを取り出すこと、EEPROMに書くこと、EEPROMから読み出して通信でPCへ送ること、AD変換を割り込み処理すること、など 多くの勉強が待っています。

 まず、PCとの通信の実験です。今回ターミナルソフトは TeraTerm を使うことにしました。単にハイパーターミナルは良くない、と読んだことが あるためですが。インストールの後に日本語用に上書きしました。PCとの接続ハードはCOMポートがプログラムライタでふさがっていますので、USBからCP2102で変換して TXDとRXDを取り出したものを使います。以前に作ったものを今日取り出すと、0.5mmピッチの端子から1本半田付けが離れていました。ルーペの下で付け直しです。 O.5Rの鏝先は大きいのですがうまくつきました。細かい部分のベタ付けは時間が経つと以外と離れるようです。実用品を作るならしっかり半田を盛って置かなくては いけないようです。TQFPやMFLでは苦しいところです。  TXDとRXDはクロス接続となりますので、CP2102のTXDはmega8のRXDに接続しています。

 TeraTermのデフォルトは、ボーレート9600 データ8ビット パリティなし 1ストップビット フロー制御なし ですからこれに合わせることにします。mega8が 1文字の信号を受け取ったら、LCDにその文字を表示し、PCに「a」を返すプログラムを考えました。受信割り込みでこの処理を考えます。
ISR(USART_RXC_vect){
  char data;
  data=UDR;              //PCからのdataを読み込む
  if(data>0x1f && data<0x80){ //アスキーコードだったら。 ノイズ対策
    lcd_gotopos(0,1); lcd_putch(data); lcd_putstrp("               ");
    while ( !(UCSRA & (1<<UDRE)) );   /* 送信バッファ空き待機*/
    data='a';
    UDR =data;   // データ送信(送信開始)
  }
}
メインルーチンで通信条件を設定します。
  UBRRH = 0;   /* ボーレート設定(上位バイト) */
  UBRRL = 51;   /* ボーレート設定(下位バイト) 8MHzで9600bps*/
  UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);   /* 送受信許可割込許可*/
  UCSRC = (1<<URSEL)|(0<<USBS)|(3<<UCSZ0);   /* フレーム形式設定(8ビット,1ストップビット) */

  sei();
これで予想していたとおりの結果が得られました。実際には、PCからの読み出し要求に応じてEEPROMから読み出した文字列をPCへ送ることになります。

 EEPROMへ記録するための時間を作ります。16ビットのタイマ/カウンタ2を使って、前置分周器で1024分周すると7812.5Hzができますから2倍の15625カウントで割り込み が発生するようにしますと2秒のタイマができます。この2秒タイマを16ビット変数で数えると300カウントで10分間隔の信号ができます。このタイミングで10分に1回の 割合でEEPROMに書くことにします。テスト中は長い時間を待てないので300カウントを5カウントに変更すると10秒ごとの操作ができます。IO端子が十分あるので2秒のタイマ を確認する緑LED(portD6)と10分を知らせる赤LED(portD7)を取り付けてHで点灯することにします。

 16ビットタイマカウンタ1の設定は、標準動作(IOに影響されない・影響しない)でオーバーフローの割り込みだけ設定します。
TCCR1A タイマカウンタ1制御レジスタA bit5,4=00 で標準動作。他はデフォルトの0。
TTCR1B タイマカウンタ1制御レジスタB bit4,3=00 で標準動作。 bit2,1,0=101 でクロック1024分周。
TIMSK  タイマ割り込みマスクレジスタ bit2(TOIE1)=1 でタイマ1オーバーフロー割り込み許可。
TCNT1  初期値設定。タイマクロックでインクリメントし、ffffから0000に戻るとき割り込みが発生します。

 mainルーチンで、TCNT1 を設定して、オーバーフロー割り込みを待ちます。オーバーフローの割り込みがかかると、割り込みルーチン内でTCNT1を再設定し、16ビットの グローバル変数をインクリメントして2秒の回数を数えます。この変数が300になると10分経過していますから、変数をクリアすると同時に温度データをEEPROMに記録 します。

 EEPROMの書き込み方法を調べて、臨時の書き込みテストをします。EEPROMを使うのは今回が初めてですからデータシート(日本語)から関係するレジスタを眺めま す。
@ EEPROMアドレスレジスタ(EEPROM Address Register) EEARH,EEARL (EEAR)
A EEPROMデータレジスタ(EEPROM Data Register) EEDR
B EEPROM制御レジスタ(EEPROM Control Register) EECR
この3つのレジスタが関係しているようです。@でEEPROMのアドレスを設定して、今のWinAVRなら16ビットで一度に設定できるだろうと思いながら、Aで書き込むデータを 用意して、Bの書き込みビットを設定すると書き込みされる−−ようです。

読み進むと具体的に書いてくれてありました。
@ EEPROM書き込み許可(EEWE)ビットが0になるまで待ちます。
A SPM制御レジスタ(SPMCR)のSPM操作許可(SPMEN)ビットが0になるまで待ちます。<ブートローダを使わないときは不要>
B 今回のEEPROMアドレスをEEPROMアドレスレジスタ(EEAR)に書きます。
C 今回のEEPROMデータをEEPROMデータレジスタ(EEDR)に書きます。
D EEPROM制御レジスタ(EECR)のEEPROMマスタ書き込み許可(EEMWE)ビットに1を、EEPROM書き込み許可(EEWE)ビットに0を同時に書きます。
E EEMWEビット設定後4クロックサイクル内にEEPROM書き込み許可(EEWE)ビットへ論理1を書きます。

さらに読み進むと、Cのコード例がありました。
C言語プログラム例(注意:html用に一部の文字コードが変わっています &と<)
void EEPROM_write(unsigned int uiAddress, unsigned char ucData)
{
	 while(EECR & (1<<EEWE));	 /* 以前のEEPROM書き込み完了まで待機*/
	 EEAR = uiAddress;	 /* EEPROMアドレス設定*/
	 EEDR = ucData;	 /* EEPROM書き込み値を設定*/
	 EECR |= (1<<EEMWE);	 /* EEPROMマスタ書き込み許可*/
	 EECR |= (1<<EEWE);	 /* EEPROM書き込み開始*/
}
これをそのまま使ってみました。
int main (void) {
  uint8_t  ep,ead,edt; //書き込みカウンタ、書き込みデータ、書き込みアドレス(今は8ビットだけ)

  ep=ead=0;
  edt=10;
  sei();
  
  for( ; ; ) {                                 /* 無限ループ */
    if(ep<200){
      cli();
      EEPROM_write(ead,edt);
      ep++; ead++; edt++;
      sei();
    }
  }
}
無事コンパイルが終了し、実行しました。書き込みの確認は avrsp -re でEEPROMを読み出して行いました。期待通りの結果が得られましたので次に進むことができます。 なお、書き込み時間は、動作クロックに関係なく内蔵1MHzのクロックで行われ、8448サイクル、8.5msかかるようです。遅いとは聞いていましたが想像以上でした。

つぎは、読み出しです。これも下のようにありますから、そのまま使うことにします。
unsigned char EEPROM_read(unsigned int uiAddress){
  while(EECR & (1<<EEWE));     /* 以前のEEPROM書き込み完了まで待機*/
  EEAR = uiAddress;            /* EEPROMアドレス設定*/
  EECR |= (1<<EERE);           /* EEPROM読み出し開始*/
  return EEDR;                 /* EEPROM読み出し値を取得,復帰*/
}
mainルーチンからは、次のように呼び出して、USARTに渡しています。
  for(j=0;j<512;j++){
    t_byte= EEPROM_read(j);
    while ( !(UCSRA & (1<<UDRE)) );   /* 送信バッファ空き待機*/
    UDR =t_byte;                      /* データ送信(送信開始) */
  }

モードの設定:温度計測run:r と EEPROM読みだしsend:s と EEPROMクリアclear:c の3つのモードを作りました。ターミナルから、r,s,cを送ります。
温度計測run:r 測定を始めます。EEPROMの記録アドレスを 0番地に戻します。
EEPROM読みだしsend:s ターミナルにデータを送ります。1バイトデータ(0〜255)は温度を4倍した値です。512バイト送り出します。EEPROMアドレスはリセットされ、 次のモード設定まで停止します。したがって同じデータを何度でも読みとれます。
EEPROMクリアclear:c EEPROMを0xffでクリアします。アドレスはリセットされます。次の設定まで停止します。


これで10分おきの温度(室温)を測って記録することができるようになりました。でも問題はまだ残っています。
@ tera termで読み出せるが、バイトの生データなので読んでも分からない。数表またはグラフにしたいので、できればエクセルのVBAで操作したい。(要勉強!)
A 測定途中にリセットがかかるとEEPROMの記録アドレスがリセットされてしまってわからなくなる。瞬間停電やノイズでリセットされないようにはどうすればいいので しょうか。専用ボタンだけリセットできて、その他のリセット時はEEPROMに書かれているアドレスを使うといいかな、とも思いますが、手間と寿命はどんなものでしょうか。 使ってみて考えましょう。

今回も回路図を書かずに作ってしまいました。接続端子は文の中にメモしたと思いますので後でも書けるだろうと思います。あと、机上の実験用電源では異動できないので、 電池電源に換えて、持ち運びができるようにケースと言わないまでもボード上にまとめるつもりです。

 プログラム thermo.c lcd.c lcd.h(サーバの関係でlcd.txtになっています。 使うなら.hに戻してください)   回路図を書きました。

2006.11.28 通信の形態を変えました。温度の4倍値を3桁のキャラクタ(アスキーコード)に変換してCRLFを付加して送ることにしました。これでTeraTermで受けても 意味のわかる形になります。またコピー&ペーストでエクセルの表に貼り付け、グラフを書くこともできます。

2006.12.02 右のグラフは室温を48時間記録したものです。途中で暖房が入ったことがよくわかります。excelで手動でグラフを作りました。









2006.12.03 測定間隔を2秒に設定して、温度変化にどのように追従するかを調べてみました。
室温に放置した温度計のセンサを指でつまんで(A点)暖めて、次に指をはなします(B点)。次第に温度表示は室温に戻りますが、最後はなかなか室温に なりません。グラフから、5℃の差から温度平衡に達するまでには2分14秒ほどかかっています。室温のこれほど急な変化を測定することはないと思いますので 実害はないでしょう。プラスチックパッケージですから熱伝導は悪いとは感じていましたがこれでおよその時間がわかりました。



書きながら作ったのは初めてのことです。うだうだと長い文に付き合っていただいて、ここまでお読みいただいた方にはお礼を申し上げます。
ありがとうございました。 なお、ご感想などありましたらどうぞ寄せてください。


2009.11.27 EEPROM記録の工夫と記録の読み出し
EEPROMのデータを利用した後、次のデータを記録するためには前回のデータを消去する必要がありますが、一度に消去すると誤って操作したときにすべてのデータを失うことになります。しかし、消さないことには次のデータが書けません。
そこで、データは一括して消去せず1記録毎に前回の1記録を消すことを考えました。記録時に 今回のデータ を書いた後に次のデータアドレスに通常は現れないデータ、たとえば 254 を書きます。次の記録ではこの254にデータを上書きして次のアドレスに254を書きます。その結果EEPROMデータを順に見て254が現れるまでが今回のデータであり、以降は前回のデータであることがわかります。1測定毎に前回の1測定データが消えますから、間違って操作しても少しのデータ喪失で済みます。単純にリセットで全データをクリアすると電源の一時断で長時間のデータがなくなります。(データ処理時に区切り値に注意します)
電源断のアクシデントについては再起動時にリセットがかかるので継続測定はできませんが、リセットののち開始ボタンで記録をはじめるようにすれば今回の方法により測定済みのデータが消えることはありません。

EEPROMデータの取り出しについては温度計自身にUART通信プログラムを組み込んでPCと通信してデータを取りだしていましたが、専用のルーチンとPCにUART端子が必要になります。どのPCにも接続しやすいプログラマHIDaspxがある場合には他のソフトやAVR内のプログラム無しでEEPROMを .eepファイル(hexファイル) として簡単に取り出せますから、このファイルを10進のテキストファイルに変換すれば後にExcelなどで処理が簡単にできます。そのためにドラッグアンドドロップだけで同じフォルダに同名の .txt ファイルを作るソフトを作りました。eep2txt.exeがそのプログラムです。







TOPページへもどる


inserted by FC2 system