秋月オシロスコープキットの波形イメージをPCに取り込みできるようにする
元々PCへ波形イメージをシリアルで転送する機能があるがI/FがUSARTなのでPCと通信するにはRS232CかUSBレベルに変換する必要がある
いずれにしても転送する際にPCと接続しないとならないのと受信ソフトの操作が必要で面倒だなってことで、いっそSDカードに格納してしまおうかってことを考えていた(SDにしてもPCにもっていく作業はあるが・・・)
といっても、オシロスコープにSDカードスロットを追加することはハード、ソフト的にも困難なのでUSARTの出力をAVRで受けてSDカードに格納することにした
ざーと思い立った仕様は
- 3.3V版のATmega328Pを使用しArduinoで開発後ユニバーサル基盤に実装して組み込む
- SDカードスロットとの接続は先日確認した物を使う
- イメージの転送が行われてない時はスリープ状態で省電力化(自動的に転送を開始したいが可能かどうか現状は不明)
- SDカードに格納される波形イメージファイルは連番のファイル名で被らないようにする
当初、作成しないとならないと思っていたXmodemプロトコルはArduino用のxmodemライブラリがあったので利用させてもらった
しかもXmodemで受けてSDカードに保存してくれる仕様だったのでありがたい
ライブラリはダウンロードし、IDEの libraries\xmodem 配下(xmodem フォルダー作成)に展開して、xmodem.h はそのまま、xmodem.c は xmodem.cpp と変更して置いた
さくっと以下(コメントなどは適当な部分があるので注意)を作成してTera Termを相手にテスト
/* Oscilloscope kit for micro SD card
*
* SD card attached to SPI bus as follows:
* MOSI - pin 11
* MISO - pin 12
* CLK - pin 13
* CS - pin 4
*/
#include <avr/sleep.h> // スリープモード
#include <EEPROM.h>
#include <SD.h>
#include <xmodem.h>
#define PROM_CPUID_ADDR (0) //byte data address
#define PROM_FILENUM_ADDR (2) //short data address
#define CABLESELECTPIN (4)
#define STATLEDPIN (8)
char cpuID;
int fileNum;
void setup()
{
// Open serial communications and wait for port to open:
//Serial.begin(38400);
Serial.begin(9600);
// wait for serial port to connect. Needed for Leonardo only
while (!Serial);
Serial.print("Initializing SD card...");
// On the Ethernet Shield, CS is pin 4. It's set as an output by default.
// Note that even if it's not used as the CS pin, the hardware SS pin
// (10 on most Arduino boards, 53 on the Mega) must be left as an output
// or the SD library functions will not work.
pinMode(10, OUTPUT);
if(!SD.begin(CABLESELECTPIN)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");
//LEDステータス
pinMode(STATLEDPIN, OUTPUT);
//スリープモード設定(アイドル)
set_sleep_mode(SLEEP_MODE_IDLE);
//格納ファイル名データ(EEPROM保持)
cpuID = EEPROM.read(PROM_CPUID_ADDR);
fileNum = (EEPROM.read(PROM_FILENUM_ADDR)<<8) + EEPROM.read(PROM_FILENUM_ADDR + 1);
}
void loop()
{
char fileName[13];
//シリアル入出力バッファ初期化
Serial.flush();
//アイドルモードで転送待ち(シリアルデータ受信でウェイクアップ)
while(!Serial.available()) {
cli(); //割り込み禁止
sleep_enable(); //スリープ許可
sei(); //割り込み許可
sleep_cpu(); //割り込みで抜ける
sleep_disable(); //スリープ禁止
}
//receive file to SD write
digitalWrite(STATLEDPIN, HIGH);
sprintf(fileName, "OSK%c%04d.BMP", cpuID, fileNum);
Serial.println(fileName);
short res = XReceive(&SD, &Serial, fileName);
Serial.print("XReceive result : ");
Serial.println(res);
if(res < 0) {
//error
for(;;) {
digitalWrite(STATLEDPIN, HIGH);
delay(500);
digitalWrite(STATLEDPIN, LOW);
delay(500);
}
}
//complite
fileNum++;
EEPROM.write(PROM_FILENUM_ADDR, (fileNum>>8)&0xff);
EEPROM.write(PROM_FILENUM_ADDR + 1, fileNum&0xff);
digitalWrite(STATLEDPIN, LOW);
}
(処理概要)リセット後アイドルモードでスリープしシリアルの割り込みでウェイクアップしたらXmodemでデータ受信してSDカードに記録する
ところが、このプログラムは失敗
なぜかというと、Xmodemは受信側が転送プロトコルのトリガーになっており(つまり受信側が受信しますというデータを送信しないと送信側は待ち状態で送信しない)このプログラムでは送信側のTera Termで送信手順を行っても動作しない
とりあえずはTera Termで1文字入力したらXmodemによる通信が開始されSDカードに記録されたのでXmodemライブラリの動作確認はとれた
仕様変更で以下を追加
・SDカード格納時リセットボタンを押す
起動ボタン操作でも可能なのだがハングアップやエラー状態からの復帰方法を考慮した結果リセットボタンにすることにした
(オシロキットから転送開始が受けれれば自動にもできるが信号があるかどうか不明)
改良仕様版は以下のとおり(同じくコメントなどいいかげんな部分もあるので注意)
/* Oscilloscope kit for micro SD card
*
* SD card attached to SPI bus as follows:
* MOSI - pin 11
* MISO - pin 12
* CLK - pin 13
* CS - pin 4
*/
#include <avr/sleep.h> // スリープモード
#include <EEPROM.h>
#include <SD.h>
#include <xmodem.h>
#define PROM_CPUID_ADDR (0) //byte data address
#define PROM_FILENUM_ADDR (2) //short data address
#define CABLESELECTPIN (4)
#define STATLEDPIN (8)
void setup()
{
char fileName[13];
//パワーON・外部リセット判定
char regMCUSR = (MCUSR&0x0f);
MCUSR = 0;
//LEDステータス
pinMode(STATLEDPIN, OUTPUT);
//パワーオン・リセットとブラウン・アウト・リセットの場合はスリープする
if(regMCUSR&(0x01|0x04)) {
sleep();
return;
}
//外部リセットとウォッチドッグ・システム・リセットの場合はデータ受信後スリープ
// Open serial communications and wait for port to open:
Serial.begin(38400);
//Serial.begin(9600);
// wait for serial port to connect. Needed for Leonardo only
while (!Serial);
// Serial.print("Initializing SD card...");
// On the Ethernet Shield, CS is pin 4. It's set as an output by default.
// Note that even if it's not used as the CS pin, the hardware SS pin
// (10 on most Arduino boards, 53 on the Mega) must be left as an output
// or the SD library functions will not work.
pinMode(10, OUTPUT);
if(!SD.begin(CABLESELECTPIN)) {
// Serial.println("initialization failed!");
return;
}
// Serial.println("initialization done.");
//格納ファイル名データ(EEPROM保持)
char cpuID = EEPROM.read(PROM_CPUID_ADDR);
int fileNum = (EEPROM.read(PROM_FILENUM_ADDR)<<8) + EEPROM.read(PROM_FILENUM_ADDR + 1);
//シリアル入出力バッファ初期化
Serial.flush();
//receive file to SD write
digitalWrite(STATLEDPIN, HIGH);
sprintf(fileName, "OSK%c%04d.BMP", cpuID, fileNum);
// Serial.println(fileName);
short xresult = XReceive(&SD, &Serial, fileName);
// Serial.print("XReceive result : ");
// Serial.println(xresult);
//エラーの場合はloop()へ
if(xresult < 0) return;
//正常終了でファイルNoをカウントアップして格納
fileNum++;
EEPROM.write(PROM_FILENUM_ADDR, (fileNum>>8)&0xff);
EEPROM.write(PROM_FILENUM_ADDR + 1, fileNum&0xff);
digitalWrite(STATLEDPIN, LOW);
sleep();
}
void sleep()
{
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
cli(); //割り込み禁止
sleep_enable(); //スリープ許可
sei(); //割り込み許可
sleep_cpu();
}
void loop()
{
//エラー時の点滅処理
digitalWrite(STATLEDPIN, HIGH);
delay(500);
digitalWrite(STATLEDPIN, LOW);
delay(500);
}
(処理概要)電源ON時は何もしないでパワーダウンスリープ、リセットボタンでXmodeによる通信を行いSDカードに記録し正常終了でパワーダウンスリープする
アイドルスリープからパワーダウンスリープになったので未処理中は更に省電力になった
ボタンを押すという操作が増えてしまったのは残念(改良したい課題となった)
尚、プログラムサイズは以下のとおり
(追加)
状態を知るためLEDを使っている
消灯:スリープ中
点灯:通信処理中(通信しているとは限らない)
点滅:エラー時(SDカード無し、書込みエラーなど)