続いて、UART の送受信を行うプログラムを書きます。以下に公開するコードはエコーバックをするものです。ボーレートは 9600bps でご設定を。
コード
.include "../m328pdef.inc"
.device atmega328p
.def tmp = r16
.def data = r17
.cseg
.org 0x0000
rjmp main
uart_init:
ldi tmp, 0
sts UBRR0H, tmp
ldi tmp, 51
sts UBRR0L, tmp ; set baud rate to 9600 bps
ldi tmp, (1<<RXEN0) + (1<<TXEN0)
sts UCSR0B, tmp ; enable tx and rx
ldi tmp, (0b11<<UCSZ00)
sts UCSR0C, tmp ; Set frame format: 8data, 1stop bit
ret
USART_Transmit:
; Wait for empty transmit buffer
lds tmp, UCSR0A
sbrs tmp, UDRE0
rjmp USART_Transmit
; Put data into buffer, sends the data
sts UDR0, data
ret
USART_Receive:
lds tmp, UCSR0A
sbrs tmp, RXC0
rjmp USART_Receive
lds data, UDR0
ret
main:
rcall uart_init
loop:
rcall USART_Receive
rcall USART_Transmit
rjmp loop
...ところどころ UART なのか USART なのか表記ゆれがありますが、ご了承を。
UARTの設定
それではいつものようにデータシートを見ながら説明していきます。
ボーレートの設定
この部分です。なお、クロックは 内蔵の RCクロック(8MHz) です。
uart_init:
ldi tmp, 0
sts UBRR0H, tmp
ldi tmp, 51
sts UBRR0L, tmp ; set baud rate to 9600 bps
よって UBRR0
の値は、8e6 / 16 / 9600 - 1 = 51 と決まりました。この値は 8bit に十分収まるので、High の部分は単にゼロとしています。
送受信有効化
UCSRnB
を見てみましょう。
この下部の説明を読むと、送受信を有効化するには TXEN
と RXEN
のビットを立てればいいと分かります。
ldi tmp, (1<<RXEN0) + (1<<TXEN0)
sts UCSR0B, tmp ; enable tx and rx
送受信ビット数の決定
続いて、UCSRnC
の UCSZ
ビット(2ビット)を見ると、以下のようにしてビット数を決定するようです。
今回は通常の8bit通信なので、0b11
とします。
ldi tmp, (0b11<<UCSZ00)
sts UCSR0C, tmp ; Set frame format: 8data, 1stop bit
ret
送受信部の実装
基本的には UCSRxA
をポーリングして、その結果として UDRx
を利用します。具体的にはこのようなコードです。
USART_Transmit:
; Wait for empty transmit buffer
lds tmp, UCSR0A
sbrs tmp, UDRE0
rjmp USART_Transmit
; Put data into buffer, sends the data
sts UDR0, data
ret
USART_Receive:
lds tmp, UCSR0A
sbrs tmp, RXC0
rjmp USART_Receive
lds data, UDR0
ret
送受信どちらとも、UCSR0A
を tmp
にロードしています。この lds
という命令は、メモリの指定番地アドレスの内容を汎用レジスタにロードするという命令です。
ここで条件分岐に sbrs
という命令を使っています。通常条件分岐だとラベルを張って、予めコンペアした結果に則ってその場所にジャンプさせる等々の処理が必要なのですが、AVR では 値に応じて命令を飛ばす ということができます。
この sbrs
命令は、指定ビットがセットされていたら次の命令を飛ばすというものです。これで書き方が簡単なポーリングを実装しているのです。一方で sbrc
命令は逆に指定ビットがセットされていなかったら次の命令を飛ばすというものになります。
動作
PC 上でシリアルモニタを起動し、適当な文字を打ち込むとマイコンから値がそのまま帰ってきます(エコーバック)。