技術ネタそのニ 『PSoCでRXとかTXとか』
どもーRamencozoです。
前回に引き続き、卒研で扱った技術ネタの投下です。
今回はPSoCマイコン。そしてその中でもなんかあんまり話されてない感がある、『RX8モジュール』と『TX8モジュール』について。
まず各モジュールの説明から。
RX8:ボーレート(今だとビットレートですか)に準じた8bitシリアルデータの受信を行う。デリミタやバッファ等の設定も可。
TX8:ボーレート(今だt(ry)に準じた8bitシリアルデータの受信を行う。
まぁ名前の通り。ちなみにこれらをひとつのモジュールにまとめた「UARTモジュール」も存在します。これらはPSoC Designerの「User Modules」→「Digital Comm」にあります。
そっちを使わない理由としてはまぁのちほど。
RX8を使う際、下記のように設定します。
・Clock - クロック → 後述
・Input - 入力信号線 → 基本的には「GlobalInxxx」の任意のピンに接続
・ClockSync - 動作の同期(?) → Sync to SysClk でおk
・RxCmdBuffer - 受信バッファ → Enable でおk
・RxBufferSize - バッファサイズ → デフォ(16bytes)でもおk
・CommandTerminatior - 終端文字(?) → デフォ(13)でおk
・Param_Delimiter - 区切り文字 → デフォ(32、「 」(スペース))でおk
・IgnoreCharsBelow - 無視する文字の範囲 → デフォ(32、0x00〜0x10)でおk
・RXOutput - 受信出力 → なし(空欄 or none)でおk
・DataClockOut - 受信割込みパルス(?) → なしでおk
・InvertedInput - 入力論理 → Normalでおk
だいたいデフォ設定でおkなものです。基本「クロック」「入力ピン」ぐらいが任意となります。(もちろん必要に応じてバッファの拡張や論理の反転もするかもです)
クロックについては、これが直接のボーレートとなりますので2種類クロックの生成法を紹介します。
1.VC1,VC2,VC3を駆使してクロックを生成する
2.PWM8モジュールを用いてクロックを生成する
まず1.のシステムクロックのN分周を行うVC1,VC2,VC3でのクロック生成法から。
要は割り算の計算だけです。仮に下記の設定だとします。
・SysClk = 24MHz
・9600bps を生成したい
・最終生成はVC2で行う
ここでRX8(TX8も同じく)の仕様があります。
・入力されたクロックの1/8をボーレートとする
要は計算に÷8を盛りこんでおいてください、ということです。
上記の設定でいくと、計算は例ですが
9600 = (24×10^6)/8(RX8の固定分周)/13(VC1)/24(VC2)
として生成できます。(VC1は適当に決めて、VC2を方程式で逆算してます)
ただしこの方法は、他のモジュールに対してもVC1・VC2の値が影響してきますので、オペアンプ等のモジュールと同時に使用する際等に難しい、という可能性があります。
そこで2.のPWMモジュールをクロック源としてボーレートを指定する方法です。
PWM8モジュールを配置して、下記設定とします。
・VC1からPWMモジュールへクロックを供給
・9600bps を生成したい
・PWMモジュールは PulseWidth = (Period - 1) / 2 とする。
※Periodが奇数だったらどっちかに寄ってもいいです
9600 = (24*10^6)/8(RX固定分周)/13(VC1)/24(PWMのPeriod-1)
※2011/05/06追記:18→24(Period-1) 単純に計算間違ってましたスイマセン
として生成します。これもPeriodを前の値から逆算します。
こうするとVC2とVC3をどうしても必要とするモジュールに対して分けてあげることが可能です。
お次、TX8です。下記の設定があります。
・Clock - クロック → RX8と同じ。(上記)
・Output - 出力信号線 → Row_n_OutputからGlobalOutの任意のピンへ
・TXInterruptMode - 送信割込み → なし(空欄)
・ClockSync - 動作の同期 → Sync to SysClk でおk
・DataClockOut - 送信割込みパルス(?) → None でおk
こっちは設定少ない+クロックはRXと同じでおkなのでまぁいいでしょ。
さて、さらにコードの方の説明に入ります。まずRXから。
自分は高度APIでの実装しかしたことないので、そっちの説明オンリーになります。(自分で受信完了フラグとか見るやり方わかんないれす(^q^))
RX8は下図のようなフローでデータ受信を行います。(データシート抜粋)
まずプログラム開始時に、モジュールの起動と割込み許可、状態の初期化を行います。
パリティなしの起動の例です。
※このとき、PWMタイプのクロック生成法を使用している方はPWMモジュールの方を先に起動しておくことをオススメします。
RX_1_CmdReset();
RX8_1_Start(RX8_1_PARITY_NONE);
RX8_1_EnableInt();
そののち、main内で無限ループを構築し、受信のチェックとその後の処理を行います。
(一見すると常時状態チェックなやり方に見えるんですが…割込みらしいです)
こんな感じで、szGetParamなる関数で文字を受信→コマンドとかデータ仕分けとかの条件分岐に使用 という流れらしいです。
main(void){char *cmdPtr;
while(1){
if(RX8_1_bCmdCheck()){ //受信あり?
if(cmdPtr = RX8_1_szGetParam()){ //何か受信した?
while(cmdPtr = RX8_1_szGetParam()){ //受信データ全部拾った?
//何らかの処理、データ全部拾うまで
}
}
RX8_1_CmdReset(); //バッファ初期化、再度割込み待ちへ
}
}
//他の処理
}
※日本語データシートありましたので→こちら
RXは以上です。次、TX。こっちはかなりシンプルなもので、起動と割込みとデータの送信だけです。
文字列だけでなく、数値を文字列に変換して送信してくれる関数やchar *str なものを送信する関数などがあります。これらはTX8のデータシートに全部書かれていますので、そちらをご参照ください。(各モジュールを右クリック→「Show PDF」)
main(void){TX8_1_Start(L_Hand_PARITY_NONE); //パリティなし
TX8_1_EnableInt(); //割込み許可while(1){
TX8_1_CPutString("Hello, RX!"); //文字列送信
TX8_1_PutCRLF(); //改行文字送信
}}
まとめて送受信を行ないたい場合はUARTモジュールを使用するといいのですが、受信と送信で数が違ったりするときはこの2つのモジュールを別々で使います。
あと、「RX・TXはデジタルブロックの右側タテ2列にしかおけない」ので、設計時はお気をつけください。(置くにおけないことがしばしばあります)
ホントはこのあと赤外線LEDを38kHz+シリアルデータ乗せて送信なネタを書こうと思ったのですが、予想以上に長くなったので、今回はここまで。
ではまたー(´ω`)ノシ
P.S.
参考さいとー BluefishさんのPSoCのUARTを使ってみる