第11回

シリアル通信


通信について

複数の機器間で情報のやり取りする時の通信として、パラレル通信シリアル通信があります。
  • パラレル通信
パラレル通信では、通信する機器同士の出力と入力を繋げます。そうすると、0か1の情報をやり取りすることが出来ます。ただ、この通信では1bitの情報しかやり取りできません。なので、それ以上の情報量のものをやり取りするとなると、それに合わせて信号線を増やす必要があります。例えば、8bitの情報をやり取りする時は、8本の信号線が必要になります。さらに、この場合だと単一方向にしか通信できないので、双方向の通信を行う場合には受信用の信号線と送信用の信号線を用意する必要があり、双方向で8bitの情報をやり取りするなら16本の信号線が必要になります。
  • シリアル通信
シリアル通信で使われる信号線は、やり取りする情報量によらず、送受信それぞれ1本ずつだけでオッケーです。じゃあどうやって2bit以上の情報をやり取りするのでしょうか。答えは情報を1bitずつ順番にやり取りするのです。具体的にはどうやるかというと、一定時間ごとに送信側は信号線のHi、Lowを切り替え、受信側はそのHi、Lowを読み取るのです。
例えば、01011110という情報をやり取りしたい時は、送信側は一定時間ごとに Low、Hi、Low、Hi、Hi、Hi、Hi、Low と切り替え、受信側はそれを読み取ればいいわけです。
ただ、シリアル通信では送信側と受信側でタイミングを揃える必要があります。そこで、切り替えの間隔と読み込みの間隔を揃えなくてはいけませんので、通信速度を予め決めておく必要があります。また、スタートビットストップビットというものを設け、通信開始と通信終了の合図を出します。

通信速度…1秒間に何bit送るかを表しています。単位はbps(bit per second)です。

上図はマイコンでのシリアル通信を模式的に表したものです。
①は通信を行っていない状態で、この時信号線の電位はHiに引き上げられています。
②はスタートビットの事で、Lowに電位を引き下げます。これが通信開始の合図です。
③はやり取りする情報です。
④はストップビットの事で、Hiに電位を引き上げます。これが通信終了の合図です。
つまり、8bitの情報をシリアル通信でやり取りする時はスタートビット、ストップビットを合わせて10bitの情報をやり取り必要があり、この10bitのセットをフレームといいます。
つまり、上図での①~④を合わせて1フレームとなり、この例だと通信速度は9600bpsですね。


シリアル通信に使うレジスタ

実際に通信を行う時に、パラレル通信ならプログラムでなんとかなりそうな気がしますが、シリアル通信をプログラムを書いてやろうとすると大変そうですよね。
そこで、今回はAVRに内蔵されているUARTという非同期シリアル通信回路を使おうと思います。
では、UARTを使う際に必要なレジスタを紹介します。
UARTに使うレジスタは、UCSRnAUCSRnBUCSRnCUBRRnUDRnです。
注)実際プログラムを書く際、nには使うシリアル通信回路の番号を入れます。今回使うマイコンのATmega88Vには、シリアル通信回路は1つしか入っていなく、その番号は0なので、今回は0を入れます。
以下は各レジスタの各bitにおける設定の内容を説明します。(データシートのP121~P125も合わせて見てください)
  • UCSRnA
7bit目、6bit目:これらのbitはそれぞれ受信、送信が完了したことを表すbitなので、書き換える必要はないので、0にしときましょう。
5bit目:このbitは送信バッファが空かどうかを表すbitなので、このbitも0にしときましょう。
4bit目、3bit目、2bit目:これらのbitは異常が起こった時にそれを表すbitなので、これらも0にしといてください。
1bit目:このbitでは倍速許可をするかどうか選択します。ここに1を書くと、通信速度は倍になります。今回は倍速許可してみましょう。
0bit目:このbitでは複数の機器との通信動作を許可するかどうか選択しますが、今回は1対1の通信なので、0にしてください。

  • UCSRnB
7bit目、6bit目、5bit:これらのbitは割り込みを行う時に使うのですが、説明は省略します。0にしてください。
4bit目、3bit目:これらのbitはそれぞれ受信、送信を行うかどうか選択します。これらのbitに1を書くと2番ピン、3番ピンが汎用I/Oポートからそれぞれ受信、送信用ピンに切り替わります。
2bit目:後で出てくるUCSRnCの2bit目、1bit目と合わせてやり取りする情報のbit数を選択します。p123の表20-7を見てください。今回は8bitの情報をやり取りするので、このbitは0にしてください。
1bit目、0bit目:後で説明しますが、どちらも0にしといてください。

  • UCSRnC
7bit目、6bit目:これらのbitではシリアル通信回路の動作を選択します。今回はUART(非同期シリアル通信回路)なので、どちらのbitも0にしてください。
5bit目、4bit目:これらのbitではパリティチェックという通信エラーの検出を行うかどうか選択します。今回は使わないので、どちらのbitも0にしてください。
3bit目:このbitではストップビットのbit数を選択します。今回はストップビットは1bitにするので、このbitは0にしてください。
2bit目、1bit目:さっき出てきたUCSRnBの2bit目の続きです。今回はどちらのbitも1にしてください。
0bit目:このbitは同期動作の時に使いますが、今回は非同期動作なので、0にしてください。

  • UBRRn
このレジスタでは、通信のボーレートを設定します。

ボーレート…情報の通信速度を表す指標の1つですが、今回の場合は通信速度と同義です。単位はbpsです。

 UBRRn = fosc / (16 * BAUD) -1
  fosc…システムクロック周波数。今回、マイコンのシステムクロック周波数は1MHzです。
  BAUD…ボーレート(bps)。
  注)これはUCSRnAの1bit目で倍速許可をしていない時の計算式です。
上記のような計算式からUBRRnの値を決めるのですが、計算するのめんどいですよね。
そこで、p124の表を見てください。ここにボーレートの設定例があります。今回、システムクロック周波数は1MHzなので、1MHzの爛を見てください。そしたら、U2X = 0 と U2X = 1 の欄があると思います。これはUSCRnAの1bit目に0と1どちらを書いたか、つまり倍速許可をしたかどうかで見る欄が変わるということです。今回は倍速許可したので、 U2X = 1 の欄を見てみましょう。次はその中からボーレートが大きいのを選ぼうと思うのですが、黒字のもの選んでください。赤字は誤差率が大きいため、お勧めしません。なので、今回、ボーレートは9600bpsにします。この時、UBRRnの値は12ですね。

  • UDRn
このレジスタには送受信したデータが格納されます。このレジスタは8bitの容量しかないので、9bitの通信を行う場合、1bitあぶれてしまいます。この時、あぶれた1bitの情報は受信、送信それぞれUCSRnBの1bit目、0bit目を使います。まぁ今回は8bitの通信なので気にしなくてオッケーです。
実際使う時は、送信したい情報をUDRnに書き込めばその情報を送信してくれ、受信した情報はUDRnに格納されるのでそれを読み込めばいいのです。


さて、長い長い説明はこの辺にして実際にマイコンを使っていきましょうか。
まず、マイコンを2つ(送信用と受信用)用意してください。
片方(受信用)には以下のプログラムを書きこんでみましょう。
 #define F_CPU 1000000
 #include<avr/io.h>
 int main(void)
 {
  
        DDRB = 0xff;//PBピン全てを出力設定に
        PORTB = 0x00;//PBピン全ての電位をLowに
  
        UBRR0 = 12 ;//1MHz4800bps.倍速で9600bps
        UCSR0A = 0b00000010;//倍速モード許可 1対1通信 Aは基本的に読み出しにしか使わない。
        //UCSR0A = 1<<U2X0;
        UCSR0B = 0b00011000;//割り込み無効、送受信機起動許可
        //UCSR0B = (1<<RXEN0) | (1<<TXEN0);
        UCSR0C = 0b00000110;//非同期動作、パリティなし、ストップ1ビット、データ8ビット
        //UCSR0Cは初期値のままであるため書かないほうがベター(フラッシュ領域の節約)
     
        while(1)
        {
             while( !(UCSR0A & 0b10000000 ) );//受信完了まで待機
             //while(!(UCSR0A&(1<<RXC0)));
             PORTB = UDR0;//受け取ったデータに応じてPBピンの電位を操作		    
        }
 }

もう片方(送信用)には以下のプログラムを書きこんでみましょう。
 #define F_CPU 1000000
 #include<avr/io.h>
 int main(void)
 {
  
        DDRB = 0x00;//PBピン全てを入力設定に
        PORTB = 0xff;//PBピン全ての内部プルアップを有効に
  
        UBRR0 = 12 ;//1MHz4800bps.倍速で9600bps
        UCSR0A = 0b00000010;//倍速モード許可 1対1通信 Aは基本的に読み出しにしか使わない。
        //UCSR0A = 1<<U2X0;
        UCSR0B = 0b00011000;//割り込み無効、送受信機起動許可
        //UCSR0B = (1<<RXEN0) | (1<<TXEN0);
        UCSR0C = 0b00000110;//非同期動作、パリティなし、ストップ1ビット、データ8ビット
        //UCSR0Cは初期値のままであるため書かないほうがベター(フラッシュ領域の節約)
     
        while(1)
        {
             while( !(UCSR0A & 0b00100000 ) );//送信準備完了まで待機
             //while(!(UCSR0A&(1<<UDRE0)));
             UDR0 = PINB;//PBピンの電位状態を送信	    
        }
 }

さて書き込み終わったら、2つのマイコンのRXDとTXDを繋ぎ、受信用マイコンのPBピンにはLEDを繋いでください。
そしたら、送信用マイコンのどれでもいいのでPBピンの電位をHiにしてみてください。
そうすると、Hiにしたピンに対応する受信用マイコンのピンのLEDが光ると思います。
ここで、プログラムの説明を

 while( !(UCSR0A & 0b10000000 ) );//受信完了まで待機
 //while(!(UCSR0A&(1<<RXC0)));
こんなコードが受信用のプログラムにあったと思います。
これは、UCSR0Aの7bit目が1になる、つまり受信が完了するまで無限ループをするという意味です。
その後のプログラムを読むと、UDR0の値をPORTBに代入していますよね。
つまり、受信が完了したら受信データはUDR0の中に入っているので、そのデータを読み込んだって事です。

次は送信用のプログラムです。
 while( !(UCSR0A & 0b00100000 ) );//送信準備完了まで待機
 //while(!(UCSR0A&(1<<UDRE0)));
このコードが意味しているのは、UCSR0Aの5bit目が1になる、つまり送信バッファが空になるまで無限ループをするということです。
その後はUDR0にPINBの値を代入してますね。
これは、送信の準備が完了したら送信したいデータをUDR0に代入し、データを送信したって事です。


以下にシリアル通信の初期設定、送信、受信をする関数をあげておきます。
 void serial_init()//シリアル通信の設定関数
 {
  UBRR0 = 12 ;//1MHz4800bps.倍速で9600bps
  UCSR0A = 0b00000010;//倍速モード許可 1対1通信 Aは基本的に読み出しにしか使わない。
  //UCSR0A = 1<<U2X0;
  UCSR0B = 0b00011000;//割り込み無効、送受信機起動許可
  //UCSR0B = (1<<RXEN0) | (1<<TXEN0);
  UCSR0C = 0b00000110;//非同期動作、パリティなし、ストップ1ビット、データ8ビット
  //UCSR0Cは初期値のままであるため書かないほうがベター(フラッシュ領域の節約)
 } 

 void trans_char(char data)//シリアル通信での1文字送信関数
 {
  while( !(UCSR0A & 0b00100000 ) );//送信準備完了まで待機
  //while(!(UCSR0A&(1<<UDRE0)));
  UDR0 = data;
 }

 char receive_char()//シリアル通信での1文字受信関数
 {
  while( !(UCSR0A & 0b10000000 ) );//受信完了まで待機
  //while(!(UCSR0A&(1<<RXC0)));
  return UDR0;
 }
このように関数にしておくと、プログラムを書くときに楽になります。(シリアル通信の設定なんてそんなしょっちゅう変えるものでもないですしね。)


ここで、用語の説明を
  1. シリアル通信モジュール…みなさんがパソコンと通信する時に使ったケーブルのことです。これは、何をするためのものかというと、マイコンはCMOSレベルという5~3.3V系で動かしていて、信号のHiは5Vor3.3VでLowは0Vなのですが、PCはRS232Cレベルというもので動かしていて、信号のHiは15VでLowは-15Vなのです。つまり、電位のレベルを変換しなくてはいけない、それをしてくれるのがシリアル通信モジュールなのです。
  2. ターミナルエミュレータ…PC側にターミナルエミュレータというソフトを入れる必要があります。これは、マイコンから送られてきた文字がターミナルエミュレータに表示され、ターミナルエミュレータに入力された文字がマイコン側に送られる、といったような、通信の中継を担うソフトです。みなさんが使っているTera Termがそうですね。
  3. 外部発振子…UARTでは送信側と受信型のタイミングを合わせることが重要になります。そのため、クロック周波数を正確にする必要があり、マイコン外部に水晶発振子をつけることがあります。しかし、なくても大抵の場合問題なく動くので、今回はマイコン内部の発振子に頼ることにしました。高速通信を行うなら、つけておいた方が良いようです。
(ちなみに、シリアル通信の中にはタイミング同期を行うことで正確に通信を行う同期式シリアル通信:USARTというものもあったりします。AVRにも備わっています。)


無線化について

無線化って難しそうですよね。でも、今回のシリアル通信が出来れば簡単です。
イメージとしては、今回のシリアル通信の信号線をぶち切って、その切れ端それぞれに無線化のデバイスをつけた感じです。
無線化のデバイスとしては、BluetoothモジュールとXBeeモジュールがCRSでは主流です。
PC-マイコン間ではBluetooth、マイコン間ではXBeeを使うのがいいかと思います。(もちろんどっちのデバイスも両方の通信で使えるので、買うならどっちか片方でいいと思います。)
  • Bluetoothモジュール
    • メリット
      • PC-マイコン間通信が簡単(Bluetoothに対応したPCが必要)
      • 海外通販なら安い(bluetoothによるシリアル通信モジュールの販売には電波法が関わってきて、ライセンス料が高いので、海外通販でライセンスの通ってないのを探せば安い)
    • デメリット
      • bluetoothには電波の強さでclass1(通信距離100m)とclass2(通信距離10m)がある。ロボコン当日など人通りの激しいときは影響を受けやすく,通信がうまくいかないこともしばしば。
      • 海外通販経由となるため、購入に時間がかかる。
      • マイコン-マイコン間通信をやろうとするととても面倒。

  • XBeeモジュール
    • メリット
      • 電波強度が(bluetoothClass2よりは)強い(ZigBee規格だったりそうじゃなかったりしますが、結構強めの電波)
      • ライセンス通っているので安心
      • マイコンーマイコン間通信が簡単
      • 通信以外にもいろいろできる(AD変換とか)
    • デメリット
      • 高い。基本的に2つ必要になるので4000円~
      • PC-マイコン間通信にひと手間かかる

まぁどちらにせよ無線化をしたい人がいれば、先輩に相談してみてください。力になります。

XBeeの詳しい使い方が零電に載っているので参考にしてください。
http://www.nicovideo.jp/watch/sm19427346

任意課題

  • PC-マイコン間でシリアル通信を行い、PCのキーボードで数字を打ったらLEDが点灯し、それ以外の場合はLEDを消灯。また、打った数字によってLEDの明るさを変更

  • PC-マイコン間通信で、PCの画面上に4桁の数字を表示(ヒント:シリアル通信では1文字づつしか送信できません。また、表示っていうのはそう見えればいいんです)

以下はポインタなどの知識が必要になるので、C言語の勉強や先輩に教えてもらうなどしてやってみてください
  • PC-マイコン間通信で、PCの画面上に文字列を表示(注意:1文字送信ではありません)
最終更新:2016年09月12日 17:15