技術を間違った情熱に使いがちな人のページ

[AVRexample] UART

平たく言うとCOMポート使った通信の事。
RS232Cとか呼ばれる。

●簡単な送信(定数文字列)

Flashメモリ上に置かれた文字列定数データを送信。
AVRWiki「簡単な送信プログラム」のほぼそのまんまコピーです。
wiki執筆の方に大感謝です!

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>

// cbi()    addrのbit番目をLowに
// sbi()    addrのbit番目をHighに
#define cbi(addr,bit)     addr &= ~(1<<bit)
#define sbi(addr,bit)     addr |=  (1<<bit)

#define    UART_RX    0        //ATtiny2313 では PD0:RxD PD1:TxD
#define    UART_TX    1

const prog_char a[]  = "This is a test message";        //送信したい文字列

void uart_putchar(char c)
{
    loop_until_bit_is_set(UCSRA, UDRE); //UDREビットが1になるまで待つ
    UDR = c;
}
void uart_putstr_pgm(char *s)
{
    char c;
    while(1)
    {
        c = pgm_read_byte(s++);
        if (c==0) break;
        uart_putchar(c);
    }
    uart_putchar(10);        // 改行(LF)
}

int main(void)
{
    DDRA = ~0b11111111;        //portA all input    面倒なので一度全部適切な処理行う
    PORTA = 0b11111111;        //portA all pullup
    DDRB = ~0b11111111;        //portB all input
    PORTB = 0b11111111;        //portB all pullup
    DDRD = ~0b11111111;        //portD all input
    PORTD = 0b11111111;        //portD all pullup

    sbi(DDRD,UART_TX);        //UART関連だけのI/O方向処理
    cbi(DDRD,UART_RX);

    UCSRB = _BV(TXEN); //送信許可
    UBRRH = 0;
    UBRRL = 51;        // 8MHzで9600bps
    for(;;)
    {
        uart_putstr_pgm(a);
        _delay_ms(1000);        // 1秒待つ
    }
}

●簡単な送信(変数文字列)

定数文字列版のちょっと改造。
文字列変数をそのまま送信できる。

#include <avr/io.h>
#include <util/delay.h>

// cbi()    addrのbit番目をLowに
// sbi()    addrのbit番目をHighに
#define cbi(addr,bit)     addr &= ~(1<<bit)
#define sbi(addr,bit)     addr |=  (1<<bit)

#define    UART_RX    0        //ATtiny2313 では PD0:RxD PD1:TxD
#define    UART_TX    1

void uart_putchar(char c)
{
    loop_until_bit_is_set(UCSRA, UDRE); //UDREビットが1になるまで待つ
    UDR = c;
}
void uart_putstr(char *s)
{
    char c;
    while(1)
    {
        c = *s++;                // ポインタ s の指し示すアドレスの "データを" 読み出す
        if (c==0) break;
        uart_putchar(c);
    }
    uart_putchar(10);        // 改行(LF)
}

int main(void)
{
    DDRA = ~0b11111111;        //portA all input    面倒なので一度全部適切な処理行う
    PORTA = 0b11111111;        //portA all pullup
    DDRB = ~0b11111111;        //portB all input
    PORTB = 0b11111111;        //portB all pullup
    DDRD = ~0b11111111;        //portD all input
    PORTD = 0b11111111;        //portD all pullup

    sbi(DDRD,UART_TX);        //UART関連だけのI/O方向処理
    cbi(DDRD,UART_RX);

    UCSRB = _BV(TXEN); //送信許可
    UBRRH = 0;
    UBRRL = 51;        // 8MHzで9600bps
    for(;;)
    {
        uart_putstr("test mess");
        _delay_ms(1000);        // 1秒待つ
    }
}

●簡単な送信(数値=>文字列変換)

変数 num の値を送信。
ループ毎に num++ されるので。
123
124
125
:
とPCで受信できる。
Arduino では数値データの送信は文字列として行われる。
同じような感覚で行うためモノ。
上記「簡単な送信(変数文字列)」にの部分をいじっただけ
数値<=>文字列 相互変換について。

#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>

// cbi()    addrのbit番目をLowに
// sbi()    addrのbit番目をHighに
#define cbi(addr,bit)     addr &= ~(1<<bit)
#define sbi(addr,bit)     addr |=  (1<<bit)

#define    UART_RX    0        //ATtiny2313 では PD0:RxD PD1:TxD
#define    UART_TX    1

void uart_putchar(char c)
{
    loop_until_bit_is_set(UCSRA, UDRE); //UDREビットが1になるまで待つ
    UDR = c;
}
void uart_putstr(char *s)
{
    char c;
    while(1)
    {
        c = *s++;                // ポインタ s の指し示すアドレスの "データを" 読み出す
        if (c==0) break;
        uart_putchar(c);
    }
    uart_putchar(10);        // 改行(LF)
}

int main(void)
{
    int num;
    char strg[7];

    DDRA = ~0b11111111;        //portA all input    面倒なので一度全部適切な処理行う
    PORTA = 0b11111111;        //portA all pullup
    DDRB = ~0b11111111;        //portB all input
    PORTB = 0b11111111;        //portB all pullup
    DDRD = ~0b11111111;        //portD all input
    PORTD = 0b11111111;        //portD all pullup

    sbi(DDRD,UART_TX);        //UART関連だけのI/O方向処理
    cbi(DDRD,UART_RX);

    UCSRB = _BV(TXEN); //送信許可
    UBRRH = 0;
    UBRRL = 51;        // 8MHzで9600bps
    num=123;
    for(;;)
    {
        utoa(num,strg,10);            //符号無し int を10進数文字列に変換
        uart_putstr(strg);
        _delay_ms(1000);        // 1秒待つ
        num++;
    }
}

 

●簡単な受信

ポーリング(待ち処理)にて受信。
受信した文字が1byteごとにPORTBに表示される。
AVRWiki のほぼそのまんまコピーです。
wiki執筆の方に大感謝です!

#include <avr/io.h>

#define cbi(addr,bit)     addr &= ~(1<<bit)
#define sbi(addr,bit)     addr |=  (1<<bit)
#define    UART_RX    0        //ATtiny2313 では PD0:RxD PD1:TxD
#define    UART_TX    1

int main(void)
{
    DDRA = ~0b11111111;        //portA all input    面倒なので一度全部適切な処理行う
    PORTA = 0b11111111;        //portA all pullup
    DDRB = ~0b11111111;        //portB all input
    PORTB = 0b11111111;        //portB all pullup
    DDRD = ~0b11111111;        //portD all input
    PORTD = 0b11111111;        //portD all pullup
    sbi(DDRD,UART_TX);        //UART関連だけのI/O方向処理
    cbi(DDRD,UART_RX);

    DDRB = ~0b00000000;        //portB all output
    PORTB = 0x00;

    UCSRB = _BV(RXEN);    // 受信有効
    UBRRH = 0;
    UBRRL = 51;        //9600bps in MCU clock 8MHz
    for(;;)
    {
        if (bit_is_set(UCSRA,RXC))
        {
            PORTB = UDR;
        }
         // 他の処理
    }
}

●割り込みで受信

受信した文字が1byteごとにPORTBに表示される。
AVRWiki のほぼそのまんまコピーです。
wiki執筆の方に大感謝です!

#include <avr/io.h>
#include <avr/interrupt.h>

#define cbi(addr,bit)     addr &= ~(1<<bit)
#define sbi(addr,bit)     addr |=  (1<<bit)
#define    UART_RX    0        //ATtiny2313 では PD0:RxD PD1:TxD
#define    UART_TX    1

ISR(USART_RX_vect)
{
    PORTB = UDR;
}
int main(void)
{
    DDRA = ~0b11111111;        //portA all input    面倒なので一度全部適切な処理行う
    PORTA = 0b11111111;        //portA all pullup
    DDRB = ~0b11111111;        //portB all input
    PORTB = 0b11111111;        //portB all pullup
    DDRD = ~0b11111111;        //portD all input
    PORTD = 0b11111111;        //portD all pullup
    sbi(DDRD,UART_TX);        //UART関連だけのI/O方向処理
    cbi(DDRD,UART_RX);

    DDRB = ~0b00000000;        //portB all output
    PORTB = 0x00;

    UCSRB = _BV(RXCIE)|_BV(RXEN);    // 受信・受信割り込み有効
    UBRRH = 0;
    UBRRL = 51;    //8MHz で9600bps
    sei();        //全割り込み許可
for(;;){}
}

 

●ArduinoIDEのシリアルモニタを活用

送受信のテストはArduinoIDEのシリアルモニタを使うのがお手軽。
フリーソフトもいっぱいあるけどね。

●注意

●I/O方向設定はした方が良い

ネットや書籍の例文を見るとDDRBなどのI/O方向設定を指定していない。
実際指定してなくても動いてしまう。
だが、他ピンのLow/Highの影響を受けて変動してしまう事があり誤動作する。
(特に、受け側が高インピーダンスの場合。)
よって下記のように適切な定義はした方が良い。

    DDRA = ~0b11111111;        //portA all input    面倒なので一度全部適切な処理行う
    PORTA = 0b11111111;        //portA all pullup
    DDRB = ~0b11111111;        //portB all input
    PORTB = 0b11111111;        //portB all pullup
    DDRD = ~0b11111111;        //portD all input
    PORTD = 0b11111111;        //portD all pullup
    sbi(DDRD,UART_TX);        //UART関連だけのI/O方向処理
    cbi(DDRD,UART_RX);

●参考リンク

Getting Started Notes – UART – AVRWiki

非常に有用な資料です!
割り込み方式がちょっと古いけどね。

ASCIIコード表

改行コードの確認に。
LF : 10 (10進)
CR :13 (10進)

Posted in AVR, 電子

Comments are currently closed.