リスト1 内蔵フラッシュ・メモリの読み書き #include "mbed.h" // localファイル・システムへアクセスするためのpathをlocalに設定している。 // 標準ライブラリを使用するので、ライブラリを追加する操作は必要はない。 LocalFileSystem local("local"); int main() { // DIR構造体のポインタ宣言 // ディレクトリ(フォルダ)の情報にアクセスするためのポインタ DIR *d; // dirent構造体のポインタ宣言 // この構造体にファイル名が格納されている struct dirent *p; FILE *fp; // <-----(1) 変数(ファイル・ポインタ)の宣言 int i=1; // 取得したファイル名一覧を書き込むためのファイルを開く // 最初の引数はファイル名、2番目の引数は読み書きなどファイルにアクセスするモードを指定する fp = fopen("/local/filelist.txt","w"); // <-----(2) ファイルを開く // 正常にファイルが開けないときはNULLを返す // エラー処理は必ずすること if(fp== NULL) { printf("File /local/filelist.txt could not be opened!\r\n"); exit(1); } // localディレクトリ(フォルダ)をオープンする // 正常に開けないときはNULLを返す d = opendir("/local"); if (d != NULL) { // ディレクトリ(フォルダ)にアクセスし、ディレクトリ内にあるdirentのポインタを返す while ((p = readdir(d)) != NULL) { // dirent構造体からファイル名を取得しファイルに書き込む fprintf(fp,"[%2d] - %s\r\n",i,p->d_name); // <-----(3) ファイルの読み込/書き込 i++; } } else { // ディレクトリを開けないときの処理 printf("Could not open directory!\r\n"); exit(1); } // 開いたディレクトリを閉じる closedir(d); fclose(fp); // <-----(4) ファイルを閉じる } --- list3-2 E 4 E E 4 E F 4 E G 4 Q F 4 E E 4 E D 4 E D 4 E D 4 E E 4 E F 4 Q R 4 Q E 4 E E 4 E E 4 E F 4 E G 4 E F 4 E F 4 Q E 4 Q D 4 E D 4 E C 4 Q R 4 Q E 4 E E 4 E F 4 E G 4 Q F 4 E E 4 E D 4 E D 4 E D 4 E E 4 E F 4 Q R 4 Q E 4 E E 4 E E 4 E F 4 E G 4 E F 4 E F 4 Q E 4 E E 4 E D 4 E D 4 E C 4 q R 4 Q A 5 E A 5 E A 5 E B 5 E C 5 Q B 5 E A 5 E B 5 E G 4 E R 5 Q G 4 E A 5 E F 4 E R 4 D G 4 E G 4 E G 4 E G 4 E G 4 S G 4 S G 4 S F 4 E E 4 E F 4 Q F 4 E E 4 E D 4 E E 4 E F 4 Q R 4 Q E 4 E E 4 E E 4 E F 4 E G 4 Q F 4 E E 4 E D 4 E D 4 E D 4 E E 4 E F 4 q R 4 Q E 4 E E 4 E E 4 E G 4 E B 5 E A 5 E A 5 Q A 4 Q B 4 E D 4 E C 4 D R 4 Q --- リスト3 ヘッダ・ファイルMySound.h // --- MySound.h --- // 以下の2行と最後の行は多重定義を防止するため #ifndef MBED_MY_SOUND_H #define MBED_MY_SOUND_H #include "mbed.h" class MySound { public : // MySoundクラスのコンストラクタ 初期化関数 MySound(PinName out); // 楽譜データを引数として与えるとそれに応じた方形波を出力する関数 void play(char,int,char); protected: // 方形波を出力するためのメンバ変数 PwmOut _out; // Timerオブジェクトで音を出力する時間を調整するためのメンバ変数 Timer t; }; #endif --- リスト4  MySound.cpp // --- MySound.cpp --- // MySound.hをinclude(インクルード)する。これをincludeしないとエラーになる。 #include "MySound.h" // MySoundクラスのコンストラクタ(初期化関数) // クラスのメンバ変数である_outを初期化するには初期化リストを使用します。 // 初期化リストの記述方法は、コンストラクタ名(引数):メンバ変数(引数),… // 初期化リスト _out(out) は メンバ変数 _outに引数outの値を代入するということ MySound::MySound(PinName out) : _out(out){ } // play関数の処理を記述する。 // プログラムは少し長いが、処理内容はとても簡単。 // ファイルから読み取った記号データを数値などに変換するために、switch文によって処理を // 分けているだけ。 void MySound::play(char pn,int s, char l) { // play関数内で使用するローカル変数の宣言 double freq,f; float length ; int scale ; int begin; // ここでは、音長データの記号を数値に変換している // 例えば lの値が'W'だったら、lengthに4が代入される。 // 4分音符(Q)の長さが基準になっていて0.5[S]にしています。 // この値にlengthの値を乗算したものが音符の長さになります。 switch(l){ case 'W': length = 4 ; break ; case 't': length = 3; break ; case 'D': length = 2 ; break; case 'Q': length = 1; break; case 'q': length = 1.5; break; case 'E': length = 0.5; break; case 'S': length = 0.25; break; case 'T': length = 0.125; break; default: length = 1; } // 音名データの記号を周波数(freq)に変換する。 switch(pn){ case 'a': // G#/ Ab ソ# / ラb freq = 415.30469 ; break; case 'A': // A ラ freq = 440.0; break ; case 'b': // A#/Bb ラ# / シb freq = 466.16876; break; case 'B': // B シ freq = 493.88330; break ; case 'C': // C ド freq = 261.62556; break ; case 'd': // C#/Db ド# / レb freq = 277.18263; break ; case 'D': //D レ freq = 293.66476; break; case 'e': // D#/Eb レ# / ミb freq = 311.12698; break ; case 'E': // E ミ freq = 329.62755; break ; case 'F': //F ファ freq = 349.22823; break; case 'g': // F#/Gb ファ# / ソb freq = 369.99442; break ; case 'G': // G ソ freq = 391.99543; break ; case 'R': // REST 休符 freq = 0.0; break ; default: freq = 440; } // 音高データの数値が一つ上がるごとに周波数が倍になり、一つ下がるごとに 1/2 倍になる。 // 基準の音高データは 4 になっている。 switch ( s ){ case 6: f = freq * 4 ; break; case 5: f = freq * 2 ; break; case 4: f = freq; break; case 3: f = freq / 2 ; break; case 2: f = freq / 4; break; default: f = freq ; break ; } // 周期は波一つの時間で、周波数は1秒間に繰り返す波の数 // 周波数と周期には 周波数 = 1/周期という関係が成り立つ // period_us()関数の引数に周期をマイクロ秒の単位で指定すると、その周期の方形波が出力される。 scale = (int)((1.0/f)*1e6) ; _out.period_us(scale); // 波形を出力する時間はタイマ関数で測定している。 // (1)whileに入る前の時間を取得する // (2)経過時間と音長データを比べて、音長データが大きい間はループ内を // 実行し波形を出力する。このときに、ループを1回処理するごとに // 時間を取得し経過時間を更新する // (3)経過時間が音長データより大きくなったらループを抜ける // 4分音符の時間を0.5秒としていて、0.5に音長記号で変換した係数を乗算することで // 波形を出力する時間を決めている。 t.start(); begin = t.read_ms() ; if ( pn != 'R' ){ while(t.read_ms()-begin < (int)(500 * length) ){ // デューティ・サイクルを0.5(OnとOffの時間が半分ずつ)にしている。 _out.write(0.5f); } }else{ while(t.read_ms()-begin < (int)(500 * length) ){ // 休符の場合はONの割合を0[%]にして出力する。 _out.write(0.0f); } } t.stop(); t.reset(); } --- リスト5 main関数 // --- main関数 --- #include "mbed.h" //LCDとマイクロSDを使うので、ヘッダ・ファイルをincludeする #include "TextLCD.h" #include "SDFileSystem.h" // 自作のMySound.hもincludeしておく #include "MySound.h" // コンストラクタの呼び出し TextLCD lcd(p24, p26, p27, p28, p29, p30); SDFileSystem sd(p5, p6, p7, p8, "sd") ; MySound music(p21) ; int main() { char pitch , ln; int scale; // ファイルを操作するので、ファイル・ポインタの宣言をする。 FILE *fp; int n; // ファイルを開く処理 // fopen("ファイル名","MODE") // ファイルが何らかの原因で開けない場合は、fopen関数はNULLを返すので、 // プログラムが終了する。 // fopenを使う場合は必ずエラー処理を設ける。 // 正常にファイルが開けたら、fopen関数はファイル・ポインタを返すので、 // ファイル・ポインタを使ってファイル操作が可能になる。 if ( (fp = fopen("/sd/music.txt","r")) == NULL ) { lcd.printf("Open Failed. ") ; return -1; } // キャラクタLCDに曲名(ナツノオモイデ)を表示する lcd.locate(2,0); lcd.putc(0xC5); lcd.putc(0xC2); lcd.putc(0xC9); lcd.putc(0xB5); lcd.putc(0xD3); lcd.putc(0xB2); lcd.putc(0xC3); lcd.putc(0xDE); // fscanf内の""(ダブル・コーテーション)に記述されているスペースの数は重要。 // 空白や改行文字を読み飛ばすためにも使用している。 // fscanfは正しく読み込めた文字数を値として返します。したがって、この場合は引数が三つあるので // すべての文字数が正しく読み込めるとnの値は3になる。 while( (n = fscanf(fp,"%c %d %c ",&pitch,&scale,&ln)) != EOF ){ // デバッグ用関数 printf("%d %c %d %c\n",n,pitch,scale,ln); // MySoundライブラリのplay関数を呼び出し、1行(音符)ごとのデータを渡し音を鳴らす。 music.play(pitch, scale, ln) ; } // ファイル操作が終了したらプログラムが終了する前に必ずファイルを閉じる処理をする。 fclose(fp) ; } --- リスト6 温度と湿度データをマイクロSDに記録するプログラム // 追加したライブライのヘッダ・ファイルをincludeする。 #include "mbed.h" #include "TextLCD.h" #include "SDFileSystem.h" /* ----- 設定ファイルから時刻設定する ----- */ #include "ConfigFile.h" /* ----- NTPを使って時刻設定する -----*/ #include "NTPClient.h" #include "EthernetNetIf.h" // 液晶とマイクロSD、ローカル・ファイル・システムの変数(オブジェクト)を初期化する。 TextLCD lcd(p24, p26, p27, p28, p29, p30); SDFileSystem sd(p5, p6, p7, p8, "sd1") ; LocalFileSystem local("local"); ConfigFile cfg; // 温度センサの読み取りにはmbedのp20端子を使用。 AnalogIn temp_in(p20); // 湿度センサの読み取りにはmbedのp19端子を使用。 AnalogIn humid_in(p19); // 指定した時間が経過すると関数を呼び出す処理をするための変数(オブジェクト) Ticker in, write; // 日付時刻の文字列データを格納する変数 char strTimeMsg[16]; // センサから取得したデータを格納する変数 float r_temp, r_humid; // NTP変数(オブジェクト) NTPClient ntp; // ファイルにデータを書き込むための関数 /* ----- Write File -----*/ void dataWriting() { // ファイル・ポインタの宣言 FILE *fp; // ファイル(env.txt)を追加書き込みモード("a")で開く if ( (fp = fopen("/sd1/env.txt","a")) == NULL ) { printf("Open Failed. \n") ; exit(0); } // ファイルにデータを書き込む fprintf(fp,"%s,%5.3f,%5.3f\r\n",strTimeMsg,r_temp, r_humid); // デバッグ用 ファイルに書き込むデータと同じ形式でターミナルにも表示する printf("%s,%6.2f,%6.2f\r\n",strTimeMsg,r_temp, r_humid); // ファイルを閉じる fclose(fp); } // センサからデータを取得し液晶にデータを表示する。 // この部分は「キャラクタLCDを極める」の製作事例とほとんど変更なし /* ----- Update LCD ----- */ void UpdateLCD(){ float temp,humid; time_t ctTime; temp = temp_in; humid = humid_in; // r_temp = temp * 3.3 * 100 ; // ---- (1) r_temp = temp * 55.0 ; // ---- (2) r_humid = humid * 3.3 * 100 ; lcd.cls(); lcd.locate(1,1); lcd.printf("%5.1f",r_temp); lcd.locate(6,1); lcd.putc(0xDf); lcd.putc(0x43); lcd.locate(9,1); lcd.printf("%5.1f%%",r_humid); // 時間はUTCなので日本時間に修正する。(JST = UTC + 9 hour (32400 = 60 * 60 * 9 )) ctTime = time(NULL)+32400; // 時刻データを文字列に整形する strftime(strTimeMsg,16,"%y/%m/%d %H:%M",localtime(&ctTime)); lcd.locate(0,0); lcd.printf("%s",strTimeMsg); } // 設定ファイルから時刻をセットする // mbedのConfigFileライブラリを使用する /* ----- Set RTC by ConfigFile -----*/ void setRTC_ConfFile() { char *strData = "DATE"; char dvalue[16]; char *strTime = "TIME"; char tvalue[16]; int year, month; struct tm ltime; // mbed内蔵フラッシュ・メモリ領域から時刻設定ファイルを読み込む if (!cfg.read("/local/datetime.cfg")) { error("Failure to read a configuration file.\n"); } // 日付データを取得する 取得したデータはdvalueの配列に格納される cfg.getValue(strData, &dvalue[0], sizeof(dvalue)); // 時刻データを取得する 取得したデータはtvalueの配列に格納される cfg.getValue(strTime, &tvalue[0], sizeof(tvalue)); // 取得した日付・時刻データから年、月、日、時、分のデータを抜きだす。 // 抜き出したデータは、日付や時刻を管理する構造体(struct tm)に代入する sscanf(dvalue,"%d/%d/%d",&year,&month,<ime.tm_mday); sscanf(tvalue,"%d:%d",<ime.tm_hour,<ime.tm_min); // 年は1900年が0なので、現在の年から1900を引いた値を代入する ltime.tm_year = year - 1900; // 月の値は0から11までで、実際の月から1引いた数を代入する ltime.tm_mon = month -1 ; ltime.tm_sec = 0; // 日付時間をRTCにセットする。 // このときRTCをUTCでセットする。(※NTPはUTCでセットするので設定ファイルから読み込む // 時刻合わせもUTCに合わせている。だから、JST- 9hour) set_time(mktime(<ime)-32400) ; printf("[able to read a datetime.cfg]\r\n"); } // NTPを使って時刻を合わせる /* ----- Set RTC by NTP ----- */ void setRTC_NTP() { char strNtpErrMsg[32] ; EthernetErr ethErr; // DHCPを使ってネットワークの設定をする。こちらのほうが簡単でお勧め /* DHCP */ EthernetNetIf eth; // (1) // ネットワーク環境でDHCPが使用できない場合は、以下のコメント部分を外し // 手動でネットワークを設定する。このときは(1)の部分をコメントにする。 /* static ip EthernetNetIf eth( // (2) -- static IP address IpAddr(192,168,0,20), // IP Address IpAddr(255,255,255,0), // Subnet Mask IpAddr(192,168,0,1), // Default Gateway IpAddr(192,168,0,1) // DNS Server ) ; */ lcd.cls(); lcd.locate(0,0); lcd.printf("Please wait..."); // NICをアクティブにする ethErr = eth.setup() ; // ネットワークの接続状態の確認 // 正しくネットワークに接続できない場合は、キャラクタLCDに状況を表示してプログラムを終了する。 // ネットワークへに接続できない場合は、ターミナルにもエラーが表示される if( ethErr != ETH_OK ) { printf("Error %d in setup.\r\n", ethErr); lcd.locate(0,1); lcd.printf("NW Setup Error."); exit(1); } // NTPサーバ(ntp.nict.jp)の情報が入ったhost変数(オブジェクト)を作成 // NTPサーバはIPアドレスで設定しない。 Host ntpsrv(IpAddr(), 123, "ntp.nict.jp") ; // NTPサーバから時刻データを取得し設定する NTPResult ntpResult = ntp.setTime(ntpsrv) ; // NTPサーバとの接続状態の確認 // 今回のプログラムは何らかの原因でNTPサーバに接続できなくても終了せずに処理を継続する。 // ただし、その場合時刻合わせができないので、正しい時刻でデータが記録されない。 // NTPサーバとの接続の状態は、ターミナルに表示される if( ntpResult == NTP_OK ){ sprintf(strNtpErrMsg,"NTP Connect OK!"); }else if ( ntpResult == NTP_PRTCL ){ sprintf(strNtpErrMsg,"NTP Protocol error.") ; }else if ( ntpResult == NTP_TIMEOUT ){ sprintf(strNtpErrMsg,"Connection timeout."); }else if ( ntpResult == NTP_DNS ){ sprintf(strNtpErrMsg,"Could not resolve DNS hostname.") ; }else if ( ntpResult == NTP_PROCESSING ){ sprintf(strNtpErrMsg,"Processing."); }else{ sprintf(strNtpErrMsg,"NTP Error."); } printf("[%s]\r\n",strNtpErrMsg); } /* ----- main関数 ----- */ int main() { // 設定ファイル(datetime.cfg)を読み込んで時刻設定を行う //setRTC_ConfFile() ; // NTP(ネットワーク)で時刻設定を行う setRTC_NTP(); // 起動時はセンサの値が安定しないので、最初の10[秒]は値を表示しない lcd.cls(); lcd.locate(0,0); lcd.printf("Please wait..."); // 10秒ごとにセンサからデータを読み込みキャラクタLCDの表示を更新する in.attach(&UpdateLCD,10); // 5分ごとにデータをマイクロSDに書き込む write.attach(&dataWriting,300); // 無限ループ while(1){ } }