PRS-DE07MS通信基礎実験・まとめ その2

公開日:  最終更新日:2014/06/05

すいません m(_ _)m、本記事はブログ引越時に書式が崩れました。順次修正中です。

ℹ️本記事にはPRが含まれています。

■通信実験プログラム
通信ができることを確認したかったので、とりあえず、割込み処理を使わない設計でプログラムを作成しました。久々のプログラム作成だったので、あれこれポカミスとかあってすんなりとは完成しなかったのですが、だんだん勘が戻ってきました。


ビルドオプションは今後のことを考えて、一気にオプティマイズレベル2で、拡張RAMありにしています。拡張RAMは、BTC068のジャンパをいじるのがめんどくさかったので、そのまま有効にして使っているだけで、たぶん、将来的には無効にすると思います。


■プログラム解説
プログラムの方ですが、今回は割込み無し、受信は簡単にループで時間を待つようにして一応タイムアウト処理もつけました。通信速度の定義は、333kbps~1Mbpsまで定義してありますが、333kbpsと400kbpsのみ実験しています(333kbpsは試してみたのですが通信できませんでした)。他の通信速度はこれから実験するつもりです。


なるべくコメントを多めにしたので、ソースコードを見てもらったほうが速いかと思いますが、一応、簡単に解説します。



  • init()…USART1初期化
    倍速許可、9ビットデータフレーム形式を使用するように初期化します。今回は、割込みなしで初期化しています。

  • _txM()…マルチプロセッサ1バイトID送信
    マルチプロセッサビット(9ビット目)をONにした状態で1バイトデータを送信します。ID部分の送信です。

  • _txD()…マルチプロセッサ1バイトデータ送信
    マルチプロセッサビット(9ビット目)をOFFにした状態で1バイトデータを送信します。データ部分の送信です。

  • _rxD()…1バイトデータ受信
    1バイトデータを受信します。手抜きですが、約0.1秒間、何も受信しない場合、受信エラーとして処理終了するようにしました。また、エラー発生時の情報はなるべく詳細に返すようにしています。

  • send()…データ送信
    PRS-DE07MSへデータを送信します。本来、この関数でチェックサム計算とチェックサムデータの付加をする方が綺麗なのですが、実験用の表示をmain()でやらせたかったので、この関数自身は要求されたデータを、「最初のデータはマルチプロセッサビットをマーク(ON)して送信、以降のデータはマルチプロセッサビットをスペース(OFF)して送信する、という機能のみになっています。

  • recv()…データ受信
    PRS-DE07MSよりデータを受信します。タイムアウトで終了したときに、データを受信していたかどうかをチェックし、もし、1バイトでもデータを受信した状態でタイムアウトした場合は「正常受信」、それ以外の場合は異常としています。

  • main()…メイン処理
    USART0(RS232Cでパソコンに接続されている方のポート)にて16進数で入力された数値を、チェックサム付きでPRS-DE07MSに送信します。キー入力処理が多くなってしまい、ちょっとソースコードが見辛くなってしまいましたが、やっていることは「入力を受け付けて、PRS-DE07MSと通信を行い、その状況を表示する」だけです。

■ソースコード


   1: //—————————————————————————————-
2: // PRS-DE07MS通信テストプログラム
3: // USART0に接続した端末から入力した16進数データをPRS-DE07MSへ送信し結果を表示します。
4: //
5: // 環境 BTC068(ATmega128)、GDL V2.0.0.0
6: // 説明 USART0に接続されたシリアル通信端末から入力した16進数データを、USART1に接続した
7: // PRS-DE07MSへ転送します。また、結果を受信したら端末に表示します。送信データが2
8: // バイト以下の場合はチェックサム無しで送信を行い、2バイトを超える場合はチェック
9: // サムを自動的に付加します。
10: // ビルドはPRS-DE07MS対応プログラム開発用に設定された環境(GDLの通信ライブラリから
11: // USART1用のプログラムを削除したライブラリ…AVR(ATmega128 ExtRAM NRS1))にて行い
12: // ます。また、最適化レベルは2でコンパイル確認しています。
13: // AUTHORED BY SISO JUNK STDUIO
14: //—————————————————————————————-
15: #include <avr/io.h>
16: #include <avr/interrupt.h>
17: #include <avr/pgmspace.h>
18:
19: #include <rs.h>
20:
21: //—————————————————————————————-
22: // 定数定義
23: //—————————————————————————————-
24: // 通信処理返値定義
25: #define _RECV_OK 0x00 // 正常完了(ACK応答を含みます)
26: #define _RECV_TIMEOUT 0x01 // 受信タイムアウト発生
27: #define _RECV_CSMERR 0x02 // Check Sum異常発生。
28: #define _RECV_RVFRER 0x03 // 受信フレーミングエラー発生
29: #define _RECV_RVDOER 0x04 // 受信データオーバーランエラー発生
30: #define _RECV_NACK 0x15 // NACK受信
31:
32: // 通信速度定義(初期化で使用)
33: typedef enum {
34: BR333K = 5,
35: BR400K = 4,
36: BR500K = 3,
37: BR667K = 2,
38: BR1M = 1,
39: } EbaudRate;
40:
41:
42: //—————————————————————————————-
43: // データ定義
44: //—————————————————————————————-
45: // USART0 送受信用バッファ
46: char GacTxb[100], GacRxb[100];
47:
48:
49: //—————————————————————————————-
50: // USART1(シリアルサーボ通信)ポートオープン
51: // 引数 EbaudRate 通信速度
52: // 戻値 void
53: //—————————————————————————————-
54: void init( EbaudRate br ){
55: // BaudRate設定
56: UCSR1B = _BV(UCSZ2)|_BV(RXEN)|_BV(TXEN); // 9ビット形式、受信許可、送信許可
57: UBRR1H = ( br >> 8 ) & 0xff; // ボーレート設定(上位バイト)
58: UBRR1L = br & 0xff; // ボーレート設定(下位バイト)
59: UCSR1A = _BV(U2X); // 倍速許可
60: }
61:
62:
63: //—————————————————————————————-
64: // USART1 マルチプロセッサID送信
65: // マルチプロセッサビットをONにした状態で、1バイトデータを送信します。前のデータが
66: // 送信中の場合は、送信完了するまで関数内で待機します。
67: // 引数 unsigned char 送信データ
68: // 戻値 void
69: //—————————————————————————————-
70: void _txM( unsigned char ucData ){
71: while(!( UCSR1A & _BV(UDRE))); // 送信バッファ空きチェック
72: UCSR1B |= _BV(TXB8); // 9ビット目ON
73: UDR1 = ucData; // データ送信開始
74: }
75:
76: //—————————————————————————————-
77: // USART1 マルチプロセッサデータ送信
78: // マルチプロセッサビットをOFFにした状態で、1バイトデータを送信します。前のデータが
79: // 送信中の場合は、送信完了するまで関数内で待機します。
80: // 引数 unsigned char 送信データ
81: // 戻値 void
82: //—————————————————————————————-
83: void _txD( unsigned char ucData ){
84: while(!( UCSR1A & _BV(UDRE))); // 送信バッファ空きチェック
85: UCSR1B &= ~_BV(TXB8); // 9ビット目OFF
86: UDR1 = ucData; // データ送信開始
87: }
88:
89: //—————————————————————————————-
90: // USART1 データ受信
91: // 1バイトデータを受信します。
92: // 引数 unsigned char* 受信データ
93: // 戻値 unsigned char 受信結果
94: //—————————————————————————————-
95: unsigned char _rxD( unsigned char* pucData ){
96: unsigned char ucStatus; // USART1状態レジスタ受け
97: volatile unsigned long ulTimer; // 手抜きタイマ用カウンタ
98:
99: // 受信完了待ちをしながら待ち時間検出
100: // (手抜き0.1secタイマ)
101: for( ulTimer = 0L;((( UCSR1A & _BV(RXC)) == 0 )&&( ulTimer < 41667L )); ulTimer++ );
102:
103: ucStatus = UCSR1A; // ステータスフラグ取得
104: UCSR1A &= ~(_BV(UPE)|_BV(DOR)|_BV(FE)); // クリアいるのか?これ。
105: *pucData = UDR1; // 受信データ取り出し
106:
107: if( ulTimer != 41667L ){ // タイムアップしていなければ受信処理
108: // エラーチェック
109: if( ucStatus & _BV(FE)) return _RECV_RVFRER;
110: if( ucStatus & _BV(DOR)) return _RECV_RVDOER;
111: return _RECV_OK; // 正常に受信完了
112: }
113: else return _RECV_TIMEOUT; // 一定時間経過しても受信なし
114: }
115:
116: //—————————————————————————————-
117: // PRS-DE07MSへのデータ送信
118: // PRS-DE07MSへのデータ送信を行います。割込みは使用しません。
119: // 引数 unsigned char* 送信データ
120: // unsigned char 送信データ長
121: // 戻値 void
122: //—————————————————————————————-
123: void send( unsigned char* pucData, unsigned char ucLen ){
124: unsigned char ucCnt;
125: _txM( pucData[0] );
126: for( ucCnt = 1; ucCnt < ucLen; ucCnt++ ) _txD( pucData[ucCnt] );
127: }
128:
129: //—————————————————————————————-
130: // PRS-DE07MSからデータ受信
131: // PRS-DE07MSからデータ受信を行います。割込みは使用しません。また、通信完了はデータ長
132: // に関係なく、タイムアウト(約1秒)により検出を行います。1バイトも受信せずにタイム
133: // アウト発生した場合はタイムアウトエラーとしますが、何かしらデータを受信していた場合
134: // は正常完了とします。そのため、正常にデータを受信しても最後はタイムアウト待ちとなり
135: // ます。
136: // 引数 unsigned char* 受信データ
137: // unsigned char* 受信データ長
138: // 戻値 unsigned char 受信結果
139: //—————————————————————————————-
140: unsigned char recv( unsigned char* pucData, unsigned char* pucLen ){
141: unsigned char ucLoop = 1;
142: unsigned char ucRecvRes;
143:
144: *pucLen = 0;
145: while( ucLoop ){
146: if(( ucRecvRes = _rxD( &pucData[*pucLen] )) != _RECV_OK ) ucLoop = 0;
147: else (*pucLen)++;
148: }
149: if(( ucRecvRes == _RECV_TIMEOUT )&&( *pucLen != 0 )) return _RECV_OK;
150: else return ucRecvRes;
151: }
152:
153: //—————————————————————————————-
154: // メイン
155: //
156: //
157: //—————————————————————————————-
158: void main(void)
159: {
160: char cRecv; // 入力文字データ
161: unsigned char aucInpBuff[10]; // 入力文字データ格納用バッファ
162: unsigned char ucBuffPos; // 入力文字データ格納用バッファ位置
163: unsigned char ucCnt; // forループ用カウンタ
164: unsigned char aucSendBuff[10]; // サーボ通信用バッファ
165: unsigned char aucRecvBuff[10]; // サーボ通信用バッファ
166: unsigned char ucLen; // サーボ受信データ長
167: unsigned char ucChkSum; // 送信チェックサムデータ
168: unsigned char ucRecvRes; // 受信結果
169: volatile unsigned long ulTimer; // 手抜きタイマ用カウンタ
170:
171: ucBuffPos = 0; // 入力文字バッファの書き込み位置を先頭
172:
173: // USART0通信ポートを初期化&割込み処理開始
174: rs0_init( br115200, GacTxb, sizeof(GacTxb), GacRxb, sizeof(GacRxb));
175: init( BR400K );
176:
177: sei();
178:
179: // 起動メッセージの表示
180: rs0_puts_P( PSTR(“PRS-DE07MS COMMUNICATION TEST PROGRAM\n”));
181: rs0_puts_P( PSTR(“PLEASE INPUT HEX DATA. [Enter]=EXECUTION, [ESC]=CANCEL INPUT\n”));
182: rs0_puts_P( PSTR(“INPUT DATA> “));
183:
184: // メインループ
185: while( 1 ){
186: switch( cRecv = rs0_getc()){ // 1文字受信(入力があるまで待つ)
187: case ‘\x0d’: // ENTER入力時は処理実行
188: if( ucBuffPos >= 4 ){
189: // データ送信
190: // 入力されたデータをバイナリデータに変換し、データが2バイトを超える
191: // 場合はチェックサムを付加して送信
192: rs0_puts_P( PSTR(“\n…SEND [“));
193: // 送信データの準備をする。
194: ucChkSum = 0;
195: for( ucCnt = 0; ucCnt < ucBuffPos/2; ucCnt++ ){
196: aucSendBuff[ucCnt] = (unsigned char)(aucInpBuff[ucCnt*2]<<4) + (unsigned char)aucInpBuff[ucCnt*2+1];
197: rs0_printf_P( PSTR(“%02X”), aucSendBuff[ucCnt] );
198: ucChkSum += aucSendBuff[ucCnt];
199: }
200: // 2バイトを超えるデータの場合はチェックサムも追加する。
201: // 本当は、送信関数に入れたほうがいいのだが、デバッグのための表示処理を
202: // main()に入れているため、表示のためにmain()に入れてある。
203: if( ucCnt > 2 ){
204: aucSendBuff[ucCnt] = ucChkSum;
205: rs0_printf_P( PSTR(“/%02X”), aucSendBuff[ucCnt] );
206: ucCnt++;
207: }
208: // PRSからの応答が速いと、USART0(パソコン側)に文字列を送っている
209: // 間にバッファオーバーランが発生することがあるので、PRSに送る前に
210: // パソコンへの文字列送信をやりきってしまう。
211: rs0_puts_P( PSTR(“]…RECV [“));
212:
213: // 本当はここでrs0_tx_buff()を使いたいのだが、なんとなく動きが微妙だった
214: // ので、かわりに手抜き0.1secタイマで送信完了しただろう時間待つ。
215: for( ulTimer = 0L; ulTimer < 41667L ; ulTimer++ );
216:
217: // コマンドの送信
218: send( aucSendBuff, ucCnt );
219:
220: // データ受信
221: // データ受信を実行し、受信結果が問題なければそのまま受信データを
222: // 表示し、異常の場合は異常値を表示する。
223: ucRecvRes = recv( aucRecvBuff, &ucLen );
224: for( ucCnt = 0; ucCnt < ucLen; ucCnt++ ) rs0_printf_P( PSTR(“%02X”), aucRecvBuff[ucCnt] );
225: rs0_puts_P( PSTR(“]\n”));
226: if( ucRecvRes != _RECV_OK ) rs0_printf_P( PSTR(“RECV ERROR %02X\n”), ucRecvRes );
227: }
228: else rs0_puts_P( PSTR(“…DATA IS NOT ENOUGH.\n”));
229: ucBuffPos = 0;
230: rs0_puts_P( PSTR(“INPUT DATA> “));
231: break;
232: case ‘\x1b’: // ESC入力時は入力キャンセル
233: rs0_puts_P( PSTR(“…CANCELED\nINPUT DATA> “));
234: ucBuffPos = 0;
235: break;
236: default:
237: if( ucBuffPos < 10 ){ // 入力文字列最大長チェック
238: // aucInpBuffに、1バイトあたり16進数一桁として入力文字をセットしていく。
239: if(( cRecv >= ‘0’ )&&( cRecv <= ‘9’ )) aucInpBuff[ucBuffPos++] = cRecv – ‘0’;
240: if(( cRecv >= ‘a’ )&&( cRecv <= ‘f’ )) aucInpBuff[ucBuffPos++] = cRecv – ‘a’ + 0x0a;
241: if(( cRecv >= ‘A’ )&&( cRecv <= ‘F’ )) aucInpBuff[ucBuffPos++] = cRecv – ‘A’ + 0x0a;
242: rs0_putc( cRecv );
243: }
244: else{ // 最大を超えたら入力処理をリセット
245: rs0_puts_P( PSTR(“…DATA LENGTH OVER\nINPUT DATA> “));
246: ucBuffPos = 0;
247: }
248: }
249: }
250: }

■実行結果
実行結果もついでにアップしておきます。起動するとメッセージが表示され、16進数で送信データを入力します。チェックサムはプログラムの方で自動的に判別して付加しますので入力不要です。わりとまったりめに動いている感じがしますが、通信完了はタイムアウトで検出しているためであり、PRS-DE07MSの応答が遅いわけではありません。


PRS-DE07MS COMMUNICATION TEST PROGRAM
PLEASE INPUT HEX DATA. [Enter]=EXECUTION, [ESC]=CANCEL INPUT
INPUT DATA> 0103
…SEND [0103]…RECV [01030004]
INPUT DATA> 0104
…SEND [0104]…RECV [0104A0A5]
INPUT DATA> 0105
…SEND [0105]…RECV [01051016]
INPUT DATA> 0141
…SEND [0141]…RECV [01410143]
INPUT DATA> 0142
…SEND [0142]…RECV [01424F92]
INPUT DATA> 014f
…SEND [014F]…RECV [014F0656]
INPUT DATA> 0150
…SEND [0150]…RECV [015096E7]
INPUT DATA> 0151
…SEND [0151]…RECV [01510052]
INPUT DATA> 0152
…SEND [0152]…RECV [0152388B]
INPUT DATA> 0155
…SEND [0155]…RECV [01550360B9]
INPUT DATA> 0156
…SEND [0156]…RECV [015606D936]
INPUT DATA> 0161
…SEND [0161]…RECV [0161000264]
INPUT DATA> 0162
…SEND [0162]…RECV [0162000063]
INPUT DATA> 0163
…SEND [0163]…RECV [0163FFFF62]
INPUT DATA>

  • このエントリーをはてなブックマークに追加
  • Pocket

関連前後記事

Your Message

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

*

PAGE TOP ↑