[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進)
Comments are currently closed.
