昨日、ごださんから「受信したデータをLCDに表示するような動作はできていますか?」というコメントをいただきました。なるほど、学習コースとしては、LEDチカチカ → LCD出力 → シリアル入出力ときて、シリアル+LCDというのは今までの総仕上げとしてはなかなかよさそうです。
あいかわらずブレッドボードです。配線が多くなってきて面倒なので、このくらいまでくると母艦がほしくなってきます。
appliletが生成するファイルは後で生成しなおしたときに上書きされるので、あまり手を入れたくないのですが、今回は割り込み処理ルーチンを書き換えます。
受信割り込みをキューで受けるようにします。serial.cの一部です。受信キューはq[ ]という配列にしています。
キューのラウンドアップ処理を速くするためにキューのサイズを2べきにしてアンドでラウンドアップしています。キューのサイズは16でQMASKは15にしています。エラーが起きたりキューが足りなくなったときはLEDを点灯します。まずないとは思いますが、受信データが壊れないように最初に変数で受けています。
メインはこんな感じです。キューが空でないときは1文字取り出してLCDとシリアルに出力する無限ループです。LCDへの出力はスクロールすると重そうなので一番下まできたら上に戻るようにしています。
キューからの取り出しはこんなかんじです。q_ctr--;の前後を__DI()と__EI()で囲った方がいいかもしれません。アトミックな処理でなかったときはカウンターの値が壊れてしまいます。
さて動かしてみた結果です。データの送信にはTera Termを使いました。Tera Termはalt+vでクリップボードの中身を一気に送信してくれるます。115200bpsだとデータの取りこぼしがかなりありました。処理が追いついていないせいだと思います。9600bpsまで送信速度を落としてやると、取りこぼしもなくなりました。送ったデータは数kバイト程度あるテキストです。
処理が間に合わないときはフロー制御を使って送信を待ってもらうのが筋のような気もしますが、やり方がよく分かりません。配線がないのでハード制御はできないので自然とXON/XOFF制御ということになると思いますが、XONとかXOFFのデータそのものを送るときはどうするんでしょうね?そもそも送ってはいけないのかな。おいおい調べてみることにします。
組み込み系っていうのかな。こういうプログラムはあまり書いたことがないので変なことをしているかもしれません。とりあえず思ったことは、必ず変数に一旦コピーしてから使うということです。割り込みとか色々な原因で勝手に書き換わってしまうかもしれないからです。
あいかわらずブレッドボードです。配線が多くなってきて面倒なので、このくらいまでくると母艦がほしくなってきます。
appliletが生成するファイルは後で生成しなおしたときに上書きされるので、あまり手を入れたくないのですが、今回は割り込み処理ルーチンを書き換えます。
受信割り込みをキューで受けるようにします。serial.cの一部です。受信キューはq[ ]という配列にしています。
int q_putp = 0; __interrupt void MD_INTUA2R( void ) { unsigned char err = UA2STR; unsigned char c = UA2RX; if((err & 0x07) != 0 || q_ctr == QSIZE){ PCT.6 = 0; // LED点灯 } else { q[q_putp] = c; // キューに書き込む q_putp = (q_putp + 1) & QMASK; // ポインタを進める q_ctr++; // キューの中身が1つ増えた } }
キューのラウンドアップ処理を速くするためにキューのサイズを2べきにしてアンドでラウンドアップしています。キューのサイズは16でQMASKは15にしています。エラーが起きたりキューが足りなくなったときはLEDを点灯します。まずないとは思いますが、受信データが壊れないように最初に変数で受けています。
メインはこんな感じです。キューが空でないときは1文字取り出してLCDとシリアルに出力する無限ループです。LCDへの出力はスクロールすると重そうなので一番下まできたら上に戻るようにしています。
void main(void) { unsigned char c; lcd_init(); // LCD初期化 while(1){ if(!empty()){ // キューが空でないときは c = q_get(); // キューから取り出す UART2_SendData(&c, 1); // エコーバック lcd_putc(c); // LCDに1文字出力 } } }
キューからの取り出しはこんなかんじです。q_ctr--;の前後を__DI()と__EI()で囲った方がいいかもしれません。アトミックな処理でなかったときはカウンターの値が壊れてしまいます。
unsigned char q_get() { unsigned char c; if(q_ctr == 0){ // アンダーフロー PCT.6 = 0; // LED点灯 c = 0; } else { c = q[q_getp]; // 1文字取り出す q_getp = (q_getp + 1) & QMASK; // ポインターを進める q_ctr--; // キューの中身が1つ減った } return c; }
さて動かしてみた結果です。データの送信にはTera Termを使いました。Tera Termはalt+vでクリップボードの中身を一気に送信してくれるます。115200bpsだとデータの取りこぼしがかなりありました。処理が追いついていないせいだと思います。9600bpsまで送信速度を落としてやると、取りこぼしもなくなりました。送ったデータは数kバイト程度あるテキストです。
処理が間に合わないときはフロー制御を使って送信を待ってもらうのが筋のような気もしますが、やり方がよく分かりません。配線がないのでハード制御はできないので自然とXON/XOFF制御ということになると思いますが、XONとかXOFFのデータそのものを送るときはどうするんでしょうね?そもそも送ってはいけないのかな。おいおい調べてみることにします。
組み込み系っていうのかな。こういうプログラムはあまり書いたことがないので変なことをしているかもしれません。とりあえず思ったことは、必ず変数に一旦コピーしてから使うということです。割り込みとか色々な原因で勝手に書き換わってしまうかもしれないからです。