はじめに
A33Fに搭載されているマイコンdsPIC33FJ256710にはシリアル通信機能UARTが2つ付いています。1つはUSBシリアル変換ICを経由してPCなどと接続できるようになっており、もう一つはマイコンからの端子がそのまま出ています。ここではUARTの使い方について説明します。尚、USBシリアルのドライバについてはUSBドライバのインストールのページ、PCへのモニタ表示についてはモニタ表示のページを参照願います。
※このページで紹介する内容はあくまでも一例です。個別の作成のご相談ご質問はお答えできませんのでご了承下さい。このページと同じ内容についてのご質問についてはロボット掲示板にてお願いいたします。
※以下の情報は2007年11月現在のものです。ご注意ください。
シリアル通信とパラレル通信
コンピュータ同士でデータをやりとりするのに、大きく分けて2つの方法があります。
パラレル通信は複数の信号線をつなぎ、一度に数ビットづつ送信する方法です。身近な例ではPCとプリンタの接続があります。(最近はUSBも多いかも、USBはシリアルです。)
シリアル通信は1本の線をつなぎ、一度に1ビットづつ送信する方法です。受け取る方は1ビットづつをシフトレジスタというものに順番に入れてゆき、必要なビット数に達したらバッファに書き込みます。
これは、8ビット通信の場合の例です。GNDは両方のコンピュータのGNDを共通化させ、信号線の基準電圧を作るのに接続する必要があります。制御線は場合によっては無い場合もあります。また、この図は一方から一方に送る場合ですので注意して下さい。シリアル通信の場合は双方向だと信号線が2本になる場合が普通です。
たとえば、上の例でコンピュータの動作クロックが1クロックで1ビット送信できるとしましょう。パラレル通信は8ビット送るのに1クロックしかかかりませんが、シリアル通信は8ビット送信するのに8クロックかかることになります。
しかし、パラレル通信は信号線の数が多いというデメリットがあります。線数が多くなると装置の大きさも大きくなるので、通常はコンピュータ間の通信にはシリアル通信が使われます。
尚余談ですが、以前まではシリアル通信よりもパラレル通信の方が速いというのが常識でしたが、最近では、通信速度が速くなりすぎて、複数の線を束ねるとお互いに干渉しあうので、場合によってはシリアル通信の方がデータを速く送れたりします。ホビーのマイコン程度のシステムではそこまで速くは通信しません。
どちらにしても、ロボットという狭いスペースで多数のサーボ線などがある状態で、線数を増やすのは得策ではありませんし、メンテナンス性も悪いので、コンピュータ同士のインターフェイスは極力シリアル通信が良いということになります。
同期シリアル通信と非同期シリアル通信
シリアル通信には大きく分けて「同期シリアル通信」と「非同期シリアル通信」があります。同期シリアルはコンピュータ同士で通信のタイミングを同期させるクロック線があります。非同期シリアルは、コンピュータ同士であらかじめ通信速度を決めておき、受信側ではスタートのタイミングから自分のコンピュータ内のクロックで受信タイミングを決める方式です。
非同期通信の方が線数が少なくなるので良いのですが、クロック線があると通信のタイミングが間違いなく行われるというメリットもあります。非同期シリアルは同期していないので、場合によっては送信と受信のタイミングがズレで、データが変わってしまうという可能性があります。(速度を上げなければ、マイコンシステム程度ではあまり問題にならないですが)
シリアル通信の種類
シリアル通信はその送受信方式でいろいろな種類があります。
<通常のシリアル通信(EIA232)>
通常、マイコンなどでシリアル通信といえばEIA232になります。これは送信線と受信線があり、送信は送信専用、受信は受信専用になっています。2つのコンピュータをつなぐ場合は片方の送信をもう片方の受信へつなぎます。送信側がHIGHになったときに受信側を読めばHIGHが認識されます(単純に)。A33Fのシリアル通信機能のUARTもこのタイプです。基本的にはコンピュータ1つに対して1つのコンピュータをつなぐ1対1通信になります。また、PCのRS232Cも、マイコンのUARTと電圧が違いますが同じタイプです。これについては以降の節で詳しく説明します。
通信速度は2400pbs〜115kbpsが一般的です。pbsはビットパーセックで、一秒間に何ビット送れるかを表す単位です。
<RS422>
1本の信号線で1つのデータを送る場合、両方のコンピュータにつながれたGNDが基準電圧となりますが、ケーブル経路の途中でノイズが入った場合はGNDの電圧は変わりづらいのですが信号線の方はノイズを沢山拾ってしまい、データが変わってしまう場合があるのでケーブル長をあまり長くできません。RS422はRS232を改良したもので、1つの信号を送るのに2つの線を使って、その電圧差でHIGH/LOWを判断します。ケーブルの一ヶ所にノイズが入ると、2本の線どちらにも同じノイズが入りますので、最終的な電圧差は変わりません。これにより通信ケーブル長を長くできます。また、通信速度もRS232(又はEIA232)よりもかなり速くできます。
このように2本の線の電圧間で通信する方式を差動伝送と言います。
<RS485>
RS422をさらに改良したもので、1つの経路に複数のコンピュータをつなぐことができます。最近のロボットサーボではこのRS485でサーボ位置を指定するものもあります。モータなどは大きいノイズ源になりますので、ノイズによる誤動作が少ない方式で、かつサーボのように複数をつなぎたい場合に有効です。
<SPI>
SPIは同期シリアル通信の一種で、送信線、受信線、クロック線の3本から構成されます。マスタとスレーブの1対1通信で、数Mbpsで通信できます。マイコンとメモリデバイスをシリアルで高速にデータのやりとりをする場合によく使われます。SPIについては、後のページでmicroSDカードと通信するところで詳しく説明します。
<I2C>
I2Cは同期シリアル通信の1種で、1つのクロック線と1つのデータ線で、1つのマスタに対して8個までのスレーブを接続できるものです。通信速度は100kbpsか400kpbsで通信されます。データ線は1つしかありませんが双方向で通信できます(タイミングにより送信になったり受信になったりする)。マイコンとその他のICを通信するのによく使われます。I2Cについては後のページでdsPICと音声ICを通信するところで詳しく説明します。
<USB>
差動伝送方式の一種で、非常に速く(現時点で480Mbps)通信できます。最近のPCにはほとんど付いており、5Vの電源を外部に供給できます。A33FとはUSBシリアル変換回路を経由して、仮想シリアルポートとしてPCと接続します。
<LVDS>
差動伝送方式の一種で、非常に速く(現時点で655Mbps)、低消費電流の通信方式です。液晶テレビのシステムなどに使われています。
PCのシリアル通信とマイコンのシリアル通信
通常のシリアル通信(EIA232)は非同期です。非同期シリアル通信の場合、お互いのコンピュータで通信速度をあらかじめ決めておきます。通信していない時は論理1の状態が続いています(下の絵のマイコンの部分を参照してください)。通信は待機状態から論理0になった瞬間から開始されます。受信側は通信開始の瞬間から時間を計測し、決めておいた通信速度で、ちょうど信号の中間に来るタイミングでHIGH/LOWを読み取ります。
PCとマイコンの非同期シリアル通信の電圧は下の絵のように異なりますし、極性も逆になります。PCの方は電圧がマイナスになったりします。ということでPCとマイコンを直接接続することはできません。
※下の絵は他のページの流用なのでマイコンのHIGHが5Vになってますが、dsPIC33FのUARTの出力は3.3Vです。
|
論理0
|
論理1
|
名称
|
PC |
+3V〜+12V
|
−3V〜−12V
|
RS232C電圧レベル
|
マイコン |
0V
|
5V
|
TTL電圧レベル
|
PCのRS232CポートはCOMポートと呼ばれます。しかし、最近のPCではCOMポートが無いものもありますので注意して下さい。
COMポートとマイコンの接続は電圧差があるので直接は接続できませんが、電圧変換ICを使って接続することができます。これについてはC#のシリアル通信機能を使ってみる、のページ(の最後の方)に書いてあります。また、PCのCOMポートについてもこのページで詳しく説明しています。
非同期シリアル通信の信号線
非同期シリアル通信には、次の端子があります。
TX : 信号を送信する線
RX : 信号を受信する線
RTS: 送信要求
CTS: 送信可
信号GND
初期の非同期シリアル通信は主にコンピュータとモデムを使って行われていました。昔の機器は速度が遅かったので、たとえばコンピュータがデータを送信しようとしてもモデムがまだ何かを送信中で準備ができていないということもあったので、送信が可能かどうかの制御としてRTSとCTSがあります。
コンピュータはまず、送信をしたい場合はRTSをHIGHにします。モデムが準備OKの状態になったらモデム側でCTSをHIGHにします。コンピュータはCTSがHIGHになったのを確認してTXからデータを送信し始めます。受信RXは常に受信待ち(又は受信)なので特に制御は入りません。このように送信が可能かどうかを信号線を使って制御する方法を「フロー制御」と言います。
本来、このような使い方が前提なのですが、単にコンピュータ同士を近距離で通信させる場合はモデムは使わないのでRTSとCTSは不要です。
マイコンの場合、モデムは使わないのでなぜRTSとCTSが必要か疑問に思うかも知れませんが、マイコンの接続先によってはまだこのようなフロー制御が必要な機械もあります。特に、無線機器はフロー制御が必要なものが多いです。
UART1部分の接続図
dsPIC33Fには非同期シリアル通信を行うUARTという機能が2つあります。A33FではUART1はUSBシリアル変換ICであるFT232RとdsPICが下のように接続されています。PCの方にVCPというFT232用のバーチャルCOMポートドライバをインストールすると、PCのUSBと仮想シリアル通信で接続されます。VCPのインストールはこちら、実際のPCとの通信はこちらを参照してください。
USB mini-Bコネクタに接続されたUSBはFT232Rを経由してdsPICのUART1に接続されています。U1はUART1を表します。TXは送信、RXは受信を表します。TXとRXはそれぞれクロスして結線されています。
USBの「VBUS」は電源ラインです。USBは5V、数百mAまでの電力を子機に供給することができます。A33Fの場合はノイズカット回路を経由してVCC(電源の意味)につながっています。VCCは別の場所で3.3V電源を生成する回路につながっており、このVSUBをつなげばUSBからの5VでA33Fを駆動する3.3V電源も生成されます。つまり、バッテリなどをつながなくても、USBポートをPCに接続すればA33Fに電源が供給されます。
FT232RはUSBシリアル変換以外にもいろいろなことができますが、A33Fではそれらの機能は使いません(その他多数の端子は未接続なので、使おうと思っても使えない。)。
UART1は仮想でPCとシリアル通信を行うので、RTSもCTSもありません。(物理的な通信はUSBの規格で行っている)
UART2の接続部分
UART2の方は自由に使えるように、dsPICからの配線がそのまま端子として出ています。ピン間隔は2mmピッチです。電圧は3.3Vですので注意して下さい。
ここには発売予定のブルートゥース無線又は他のマイコンとの接続を想定しています。
dsPIC33FのUARTの使い方
dsPIC33Fには2つのUARTがあります。UART1のSFRをU1xxx、UART2のSFRをU2xxxと表します。以下、UART1の例を挙げますがUART2でも同じです。
UARTを使う場合は以下のレジスタを操作します。
U1MODE : UART1の設定を行います。
U1BRG : UART1の通信速度を設定します。
U1STA : UART1の状態を表します。
U1TXREG : UART1で送信する場合、このレジスタに値をセットします。
U1RXREG : UART1でデータを受信した場合、このレジスタに値が入ります。
<U1MODE>
ここはUARTのモード設定を行います。一般的な非同期シリアル通信の設定は「データ8ビット、ストップビット1、パリティなし、フロー制御なし」なのですが、初期設定でそのような設定になっていますので特に操作する必要は無いでしょう。
1つだけ、UART1の機能をONにする場合はU1MODEのUARTENビットを1にする必要があります。
<U1BRG>
通信速度を設定します。通信速度の計算についてはこのページ最後の節で説明しています。よく使われる通信速度での設定は(クロックが36.85MHzの場合)
9600bps : 239
115200bps : 19
が設定値となります。
<U1STA>
UART1の状態を設定したり、確認するレジスタです。
以下、重要な部分を説明します。
UTXEN:送信を許可します。U1MODEのUARTENを1にしただけでは送信は許可されませんので注意して下さい。
UTXBF:送信が可能かを確認するビットです。送信をする前に、ここが1の場合は送信できません。
PERR、RERR、OERR:通信エラーが起きた場合にここが1になります。
URXDA:なにか受信されているかを確認します。
<U1TXREG>
このレジスタに値をセットすると、自動的にTX端子から送信されます。
<U1RXREG>
受信された場合にこのレジスタに値が入ります。受信がいつされたかを調べるには、受信割り込みを使うか、U1STAのURXDAを調べます。
キャラクタデータとバイナリデータ
今まで何回かprintf関数を使ってPCに文字を送りました。シリアル通信は1データが8ビットになりますので、送信できるデータは0〜255の256個の数値になります。この数値データをバイナリデータと言います。バイナリデータとは2進数のデータという意味で、コンピュータは基本的には0か1の2値しか判断できません。
printf文では文字を送りましたが、実際のところ、通信している途中の段階では単なる8ビットの数値を送っています。それを、送る側と受け取る側が文字として扱っているだけです。何の数値がなんの文字かはASCIIコードで決められています。
よくある間違いに、printf文でPCにデータを送ったが数値が受け取れない、というものがあります。printf文はASCII文字コードに対応した数値を送っているので、実際に送ろうとしたデータと違う値になってしますということです。
逆に言うと、printf文を使わないで、ASCIIコードの”数値”をハイパーターミナルに送ると、該当する数値が出るというとこです。
UARTを使ってみる
では実際にUARTを使って数値データを送信してみましょう。数値データを送信しても確認する手段が無いのですが、前の節で説明した通り、ハイパーターミナルに数値を送ると、該当するASCIIコードが表示されるはずですのでそれで確認してみます。サンプルで作ったプログラムが下になります。(右クリックで対象を保存)
UART.c
まず、ヘッダファイルですが、今回はC30のライブラリで用意されているprintf関数は使いませんので、uart.hもstdio.hも不要です。heapの設定も入りません。
メイン部です。UARTはそんなに設定するところが無いのでメイン内で設定しました。まず、行56に送信するデータを入れる配列を宣言しています。非同期シリアル通信は8ビット単位なのでデータ型はchar型(C30では8ビット、intは16ビットになる)で宣言してます。
行67〜69はUART1の設定です。UARTを有効にして、送信を許可し、通信速度をセットしています。その他は初期値で「データ8ビット、ストップビット1、パリティなし、フロー制御なし」に設定されています。
実際に送信する数値データは行76〜83でセットしてます。文字をセットするのではなく、数値をセットしています。この数値はシリアル通信でPCへそのまま数値で送られます。
UARTはU1TXREGに値をセットすると自動的にTX端子から送信されます。セットされた文字は4るあるバッファを経由して送信装置(シフトレジスタ)に送られます。ということで4文字までは連続してU1TXREGにセットできますが、それ以上はバッファが空かないと、U1TXREGに値を入れても送信されません。今回は8個データがあります。よって、行88でバッファの状態を確認しながら送信を行っています。バッファは4つともフルでこれ以上データを受けられない状態の場合はU1STAレジスタのUTXBFが1になります。データが1つでも受けられる状態になるとUTXBFが0に戻ります。
実行の結果はこのようになりました。
数値65はACKIIコードで’A’になります。数値83は’S’、75は’K’...32は空白にあたります。ということで数値データが数値としてPC(正確にはWindows)まで送信されたということになります。ハイパーターミナルは数値を勝手に文字に直して表示しているだけです。
<受信の場合>
受信の場合は、PCから数値データを送信する必要があるのですぐには実験できません。ここでは説明だけ。
dsPICが何かを受信すると、U1STAのURXDAが1になります。ということで、方法の1つとしては何か受信されるタイミングで
while(U1STAbits.URXDA==0);
で受信されるのを待ちます。なにか受信されると処理が次の行へ移るというわけです。
もう一つの方法は受信割り込みを使うという方法です。
割り込み
割り込みについての説明はRCサーボを動かすページで詳しく説明しています。そこではタイマー割り込みを使っていますが、UARTの割り込みも同じよにできます。
受信割り込みをするルーチンはこのように宣言した関数内に記述します。
void __attribute__((interrupt, no_auto_psv)) _U1RXInterrupt(void)
{
IFS0bits.U1RXIF = 0;
//以降、割り込み処理のプログラム
}
割り込み許可はmain内で
IEC0bits.U1RXIE=1;
とします。 割り込み条件はU1MODEで設定したとおりの条件で発生します。初期値では1文字受信すると割り込みが発生します。
PCからの受信や、受信割り込みについては、PC側のソフトウェアも作成する必要があるのでここでは説明しませんが、機会があれば事例を紹介するかもしれません。
最高スピードを調べてみる
非同期シリアル通信は、その物理的仕様からあまり高速には通信できません。しかしUSBはもっとずっと高速に通信することができます。A33FとPC間の物理的接続はUSBなので、どのぐらいまでの速度で通信できるかを実験してみます。
dsPICのUARTの通信速度設定はBRGxで行います。UART1の設定はBRG1で行います。計算式はデータシートを見ると次の通りとなっています。
今回の構成では、ハイパーターミナルの通信速度を115200bps(ビット/Sec:一秒間に何ビット送れるか)に設定しました。A33FのFCY(動作クロック、のようなもの。)は36.85MHzです。これは前のページで説明していると思いますが、行19〜25のヒューズ設定(ハード的にチップ内部のクロック源を設定)と、行82〜85のPLL設定(クロックを数倍に上げるもの)で36.85MHzに設定しています。この速度は内部クロックを使った場合のほぼ最高速です。
このFCYを上の式に代入しますと、
BRG1=((36.85x1000x1000) / ( 16x115200)) - 1 = 19.9924 - 1 = 約19
となります。よって、ソースプログラムでは
U1BRG = 19;
となっています。
非同期シリアル通信はだいたい、300を2倍づつにした値で設定されます。これは、初期のシリアル通信が300bpsだったことによるものです。
300x2 = 600
600x2 = 1200
1200x2 = 2400
2400x2 = 4800
4800x2 = 9600
9600x2 = 19200
19200x2 = 38400
となりますが、ここで次は
19200x3 = 57600
が使われます。
57600x2 = 115200
115200x2 = 230400
230400x2 = 460800
460600x2 = 921600
・・・
という設定が一般的であり、PCのCOMポートでも設定できる、つまりハイパーターミナルでも設定できる数値になります。それでは、どれだけ高速に通信できるか実験してみます。
115200は通信できましたので次の230400の設定を考えます。
BRG1=((36.85x1000x1000) / ( 16x230400)) - 1 = 9.9962 - 1 = 約9
U1BRG = 9;
にしてハイパーターミナルの設定を230400にしてみます。そして適当な文字を送信したところ
無事、送信されました。
次は460800です。
BRG1=((36.85x1000x1000) / ( 16x460800)) - 1 = 4.9981- 1 = 約4
ということで
U1BRG = 4;
にしてハイパーターミナルの設定を460800bpsにしてみます。そして適当な文字を送信したところ
まだいけました。
次の921600bpsはハイパーターミナルで設定できる最高値です。ちなみに、遅いPCだともっと低いと思います。
BRG1=((36.85x1000x1000) / ( 16x921600)) - 1 = 2.499 - 1 = 約1.5
1.5という小数点の設定はできませんのでおそらく無理っぽいですが、一応、BRG1を1又は2に設定して実験してみましたところ、
無理でした。データは送信しているようですので、受け側の速度を調整できるようであれば受信は可能と思われます。
ということで一般的にPCと通信する場合は460,800bpsが通信速度の限界と思われます。
おわりに
このようにしてPCと高速に通信することができるようになります。使い方はアイデア次第。PCでロボットのモーションを作成して転送したり、センサーからのログをとったり、ということが可能かと思います。
2007年11月8日
|