pp.361ff.
今度はテキストを参考にメニューを追加するなどしてもっとちゃんとしたデータロガーにしてみる。これでChapter 17 I2Cはおおむね終わりである。
一度中断してもまたデータロギングが再開できるよう下のようにしておく。
- EEPROMの0~1H番地に、次に書き込むべきアドレスを記録しておく。
- EEPROMの2~3H番地に、前回までのデータ取得間隔(秒数)を記録しておく。
メインファイル:
#include <avr/io.h> #include <inttypes.h> #include <util/delay.h> #include "USART.h" #include "myI2Cv2.h" #include "LM75v2.h" #include "mySPIv2.h" #include "EEPROM25_256v2.h" #define CURRENT_LOCATION_POINTER 0 // 次に書き込むべきEEPROMアドレスをEEPROMの0-1h番地に記録しておく。 #define SECONDS_POINTER 2 // 前回までのデータの取得間隔 をEEPROMの2-3h番地に記録しておく。 #define MEMORY_START 4 // したがってデータはEEPROMの4h番地以降に記録することにする。 #define MENU_DELAY 5 // 何も操作しないで何秒経過したらメニューから抜けるかを決めておく。 #define DEFAULT_DELAY 30 // データ取得間隔のデフォルト秒数。 #define DEFAULT_DELAY_MIN 5 // データ取得間隔の最短デフォルト秒数。 #define DEFAULT_DELAY_MAX 600 // データ取得間隔の最長デフォルト秒数。 int main(){ initUSART(); LM75v2 tempSensor(3); // ユーザー定義アドレス3 (0~7)のスレーブ(LM75)を実体化する。 myI2Cv2.enable(80); // システムクロックの80分周をI2CクロックとしてAVRのI2Cモジュールを有効化する。 EEPROM25_256v2 rom('B', 2); // PB2を!SS端子とするスレーブ(EEPROM)を実体化する。PB3~PB5は!SS端子に指定してはならない。 mySPI.enable(128, 0, 'M'); // (システムクロックの分周比, モード0, MSBファースト)でSPIモジュールを有効化する。 uint16_t currentMemoryLocation = rom.readWord(CURRENT_LOCATION_POINTER); // 次に記録すべきEEPROMアドレスをEEPROMから取り込む。 uint16_t secondsDelay = rom.readWord(SECONDS_POINTER); // 前回までの読み取り間隔(秒数)をEEPROMから取り込む。 uint8_t enterMenu; // メニューへの出入りを決めるためのフラグ。 // メニューを表示する。 printString("Push any key within "); printNibble(MENU_DELAY); printString(" seconds to enter the menu,\n"); printString("Or measurement will start.\n\n"); _delay_ms(1000 * MENU_DELAY); // 指定秒数以内に (bit_is_set(UCSR0A, RXC0) && (UDR0)) ? enterMenu = 1 : enterMenu = 0; // 何かキーが押されたらメニューに入る。 while(enterMenu){ // 現在EEPROMに何バイト記録してあるかを表示する。 if(currentMemoryLocation < MEMORY_START){currentMemoryLocation = MEMORY_START;} printWord(currentMemoryLocation - MEMORY_START); printString(" byte(s) in the log.\n"); // 現在設定してある読み取り間隔(秒数)を表示する。 printWord(secondsDelay); printString(" seconds between readings.\n\n"); printString("Push [<] to decrease the measurement interval.\n"); printString("Push [>] to increase the measurement interval.\n"); printString("Push [?] to reset the measurement interval to "); printWord(DEFAULT_DELAY); printString(" sec.\n"); printString("Push [f] to print out the log (float values) over USART.\n"); printString("Push [w] to print out the log (word values) over USART.\n"); printString("Push [e] to erase the EEPROM.\n"); printString("Push [s] to start logging.\n\n"); switch(receiveByte()){ case ',': // +Shift = '<' if(secondsDelay > DEFAULT_DELAY_MIN){ rom.writeWord(SECONDS_POINTER, secondsDelay -= 5); } break; case '.': // +Shift = '>' if(secondsDelay < DEFAULT_DELAY_MAX){ rom.writeWord(SECONDS_POINTER, secondsDelay += 5); } break; case '/': // +Shift = '?' rom.writeWord(SECONDS_POINTER, secondsDelay = DEFAULT_DELAY); break; case 'f': printString("TEMPERATURE (float values) DUMPED:\n"); for(uint16_t i=MEMORY_START; i<currentMemoryLocation; i+=2){ // 温度データが2バイトなのでアドレスは2ずつインクリメントする。 printFloat(rom.readWord(i) / 256.0); printString("\n"); } break; case 'w': printString("TEMPERATURE (word values) DUMPED:\n"); for(uint16_t i=MEMORY_START; i<currentMemoryLocation; i+=2){ // 温度データが2バイトなのでアドレスは2ずつインクリメントする。 printWord(rom.readWord(i)); printString("\n"); } break; case 'e': printString("CAUTION!! [e] will erase all of the data on your EEPROM.\n"); printString("Push [y] to continue.\n"); printString("Push any other key to cancel.\n\n"); if(receiveByte()=='y'){ printString("Deleting... (taking a little time)\n"); rom.clearAll(); // データが全部消えてしまうので、 currentMemoryLocation = MEMORY_START; // 次に書き込むべきEEPROMアドレスを再セットし、 rom.writeWord(CURRENT_LOCATION_POINTER, MEMORY_START); rom.writeWord(SECONDS_POINTER, secondsDelay); // 取得間隔(秒数)も再セットしておく。 }else{ printString("Deletion cancelled.\n"); } break; case 's': enterMenu = 0; // switch()からbreakしたあとwhile()の条件が偽になるのでメニューから抜ける。 break; default: printString("Push a correct key.\n"); break; } } // ロギングを始める。 int16_t temperature; printString("OK, let's start logging...\n"); printString("To stop measuring, push the reset button on your AVR.\n\n"); printString("CURRENT TEMPERATURES:\n"); while(1){ temperature = tempSensor.getTempRaw(); // 温度データ(2バイト)を取得して、 rom.writeWord(currentMemoryLocation, temperature); // その2バイトをEEPROMに書き込んで printFloat(tempSensor.raw2float(temperature)); // 確認のためターミナルに表示する。 printString("\n"); if(currentMemoryLocation < BYTES_MAX-2){ // EEPROMが満杯でなければ、 rom.writeWord(CURRENT_LOCATION_POINTER, currentMemoryLocation += 2); // 次に書き込むべきアドレスに更新するが、 }else{ // EEPROMが満杯なら、 printString("Your EEPROM is full, and the measurement loop will exit.\n"); break; // プログラムを停止する。 } for(int i=0; i<secondsDelay; i++) _delay_ms(1000); } mySPI.disable(); myI2Cv2.disable(); return 0; }