ATmega328でUART通信

提供:MochiuWiki - SUSE, Electronic Circuit, PCB
2021年11月15日 (月) 01:08時点におけるWiki (トーク | 投稿記録)による版 (文字列「</source>」を「</syntaxhighlight>」に置換)
ナビゲーションに移動 検索に移動

概要

ATmega328に用意されているUSART機能を使用してシリアル通信を行う。
USARTはUniversal Synchronous Asynchronous Receiver Transmitterの略で、
非同期通信のUARTだけでなく、同期通信も可能とした機能のことである。

今回は、非同期通信のUARTについてのみ記述する。

AVRのマイコンでUARTを使うには、以下の3つの設定を行う必要がある。

  1. ボーレートの設定
  2. レシーバとトランスミッタの有効化
  3. フレームフォーマットの設定



ボーレートの設定

設定したいボーレート(通信速度)に合わせて通信用の内部クロックを生成するため、下表の式を元にUBRRレジスタの値を算出する。

ATmega328 UART 1.jpg

BAUD : ボーレート
Fosc : ATmega328のクロック周波数

<source lang="c++">
// Set baudrate parameter
// RoundOff
UBRR0 =  (U16)(((F32)F_CPU / (F32)BAUDRATE / 16.0) - 1.0 + 0.5);
</syntaxhighlight>


表と式が異なるが、そのまま計算すると整数切り捨てのための誤差が大きくなるため、四捨五入で誤差を小さくしている。
誤差が大きくなると文字化けするので、適宜試しながら正しく通信できる速度を探らなければならない。

UBRRレジスタのサンプル値もデータシートに記載されているので、そちらを参照して定数で指定してもよい。
例えば、ATmega328のクロック周波数が8[MHz]のとき、ボーレート19.2[kbps]に設定したければUBRRレジスタの値は25になる。

ATmega328 UART 2.jpg



レシーバとトランスミッタの有効化

レシーバとトランスミッタの有効化は、USARTのコントロールレジスタを設定する。

<source lang="c++">
// Enable receiver and transmitter
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
</syntaxhighlight>



フレームフォーマットの設定

シリアル通信では1本の信号線で時系列に0または1を送信することで通信を行う。
そのため、予めどのようなフォーマットでデータを送信するかを定義する必要がある。

シリアル通信のフレームフォーマットは以下の要素で構成されます。

名称 ビット数 説明
スタートビット 1 フレームの先頭であることを示すビット
データビット 5 - 9 送信するデータ
5 - 9[bit]の範囲で自由に設定できる
パリティビット 0 or 1 ビットの誤りをチェックするビット
設定しなくともよい
ストップビット 1 or 2 フレームの終わりであることを示すビット


上表において、スタートビットは常に1[bit]なので、残りの3項目のビット数を設定する。

<source lang="c++">
// Set frame format: 8data, 1stop bit : 8N1
UCSR0C = (0 << USBS0) | (3 << UCSZ00);
</syntaxhighlight>

一般的には、データビット8[bit]、パリティビット無し、ストップビット1[bit]の通称8N1という形式が多い。
ここでも、8N1形式で送受信を行う。


サンプルコード

送信と受信ともにUDR0レジスタを用いて1[byte]データを操作する。
1度の操作で1[byte]しか扱えないため、数byteを送受信するときは単純に同じ操作を繰り返す。

送信方法

送信バッファが空になるまで待機し、UDR0レジスタに1[Byte]分のデータを書き込む。

<source lang="c++">
void Transmit1Byte(char data)
{
   // Wait for empty transmit buffer
   while(!(UCSR0A & (1 << UDRE0)));
   // Put data into buffer, sends the data
   UDR0 = data;
}
</syntaxhighlight>


受信方法

1[Byte]分のデータを受信するまで待機(ポーリング)し、UDR0レジスタを読み取る。

<source lang="c++">
char Receive1Byte(void)
{
   // Wait for data to be received
   while(!(UCSR0A & (1 << RXC0)));
   // Get and return received data from buffer
   return UDR0;
}
</syntaxhighlight>