SNSへはこちら

AVRでアセンブリ(4) – UART

続いて、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 を見てみましょう。

この下部の説明を読むと、送受信を有効化するには TXENRXEN のビットを立てればいいと分かります。

    ldi tmp, (1<<RXEN0) + (1<<TXEN0)
    sts UCSR0B, tmp ; enable tx and rx

送受信ビット数の決定

続いて、UCSRnCUCSZ ビット(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

送受信どちらとも、UCSR0Atmp にロードしています。この lds という命令は、メモリの指定番地アドレスの内容を汎用レジスタにロードするという命令です。
ここで条件分岐に sbrs という命令を使っています。通常条件分岐だとラベルを張って、予めコンペアした結果に則ってその場所にジャンプさせる等々の処理が必要なのですが、AVR では 値に応じて命令を飛ばす ということができます。
この sbrs 命令は、指定ビットがセットされていたら次の命令を飛ばすというものです。これで書き方が簡単なポーリングを実装しているのです。一方で sbrc 命令は逆に指定ビットがセットされていなかったら次の命令を飛ばすというものになります。

動作

PC 上でシリアルモニタを起動し、適当な文字を打ち込むとマイコンから値がそのまま帰ってきます(エコーバック)。