AVRシリアル通信のコード

2013年8月17日 by admin | Filed under 未分類.

AVRでシリアル通信をするときのサンプルコードです。
このコードは昔ATMEGA324Pのボードを作って、ソフトも作ったときに書いたものです。受信・送信とも割り込み処理で行っています。ATMEGAのいろいろなCPUで動作すると思います。

受信は1バイト取り込むごとに割り込みがかかりますので、これをFIFOにコピーしてバッファリングしています。行での取り込み(ASCIIっぽい通信)がしやすいようにしてあります。

送信側は、最初の1バイトのみ、送信プログラムそのもので送って、あとは送信バッファが空になった割り込みで送るべきものがあれば送信するという形になっています。このため、1行送信の関数から帰ってきたからといって全ての送信が完了しているわけではありません。

#define RXBUF	256		// 受信バッファサイズ
#define TXBUF	256		// 送信バッファサイズ


//
//	内部変数
//
volatile BYTE	rxbuf[RXBUF];	// 受信バッファ実体
volatile BYTE	txbuf[TXBUF];	// 送信バッファ実体
volatile int 	rxip;			// 受信取り込みポインタ
volatile int 	rxop;			// 受信吐き出しポインタ
volatile int	rxln;		// 受信バッファ有効データサイズ
volatile int	txip;			// 送信取り込みポインタ
volatile int	txop;			// 送信吐き出しポインタ
volatile int	txln;		// 送信バッファ有効データサイズ


//
//	API:シリアルOPEN
//
void usr_open(void )
	{
	PRR &= ~PRUSART0;		// CPUシリアルCH0電源on
	UBRR0H = 0;
	UBRR0L = 29;			// 18.432/2MHz水晶での38400ボー U2X=1
	UCSR0C = 0x06;			// パリティなし、1ストップビット、8ビット
	UCSR0B = 0xb8;			// 送受信許可(送受信割り込み)
	UCSR0A = 0x02;			// 倍速動作

	// 送受信バッファポインタのクリア
	rxip = rxop = rxln = 0;
	txip = txop = txln = 0;

	return ;
	}


//
//	API:シリアルクローズ
//
void usr_close(void )
	{
	PRR |= PRUSART0;		// CPUシリアルCH0電源off

	return ;
	}


//
//	内部:1バイト受信
//
static void usr_rx1(void )
	{
	if (UCSR0A & 0x80)	// 受信データが存在するのでデータ取得
		{
		rxbuf[rxip] = UDR0;
		rxip++; if (rxip >= RXBUF) rxip = 0;
		rxln++;

		// 0x0d 0x0a の場合カウンタを更新しておく
		if (rxbuf[rxip] == 0x0d || rxbuf[rxip] == 0x0a) usr_line++;
		}
	return ;
	}


//
//	内部:受信割り込みエントリー
//
ISR(USART0_RX_vect)
	{
	usr_rx1();
	return ;
	}


//
//	API:受信文字数を返す
//
int usr_rlen(void )
	{
	return rxln;
	}


//
//	API:1文字返す
//
BYTE usr_getc(void)
	{
	BYTE dat;

	// 受信バッファにデータがたまるまで待機する
	while(rxln == 0) ;

	disable();
	dat = rxbuf[rxop];	// 受信データセット
	rxop++; if (rxop >= RXBUF) rxop = 0;
	rxln--;
	enable();

	return dat;
	}


//
//	API:1行データがある場合にコピーする
//
BYTE usr_getline(BYTE* buf,int len)
	{
	int i,j;

	i = rxop;
	for (j = 0;j < rxln;j++)
		{
		if (rxbuf[i] == 0x0d || rxbuf[i] == 0x0a) break;
		i++; if (i >= RXBUF) i = 0;
		}
	if (j >= rxln) return 0;		// 行データなし

	for (i = 0;i < len;i++)
		{
		buf[i] = usr_getc();
		if (buf[i] == 0x0d || buf[i] == 0x0a)
			{
			buf[i] = 0x00;	// 文字列終端に変換
			break;
			}
		}
	return 1;	// データあり
	}


//
//	内部1バイト送信
//
static void usr_tx1(void )
	{
	// 送信バッファに空きがあり、送信データがある(=ただちに送信できる)
	if ((UCSR0A & 0x20) && (txln != 0))
		{
		UDR0 = txbuf[txop];		// データ送信
		txop++; if (txop >= TXBUF) txop = 0;
		txln--;
		}
	return ;
	}


//
//	送信バッファ空き割り込みエントリー
//
ISR(USART0_UDRE_vect)
	{
	usr_tx1();
	return ;
	}


//
//	API:1バイトデータ送信
//
void usr_putc(BYTE dat)
	{
	// 送信バッファに空きができるまで待機
	while(txln >= TXBUF) ;

	// 送信バッファにデータをセットする
	disable();
	txbuf[txip] = dat;
	txip++; if (txip >= TXBUF) txip = 0;
	txln++;

	usr_tx1();		// 送信できるならただちに送る
	enable();

	return ;
	}


//
//	1文字データ送信(FILE STREAM対応)
//
int usr_putchar(char c,FILE* fp)
	{
	if (c == '\n') usr_putc('\r');
	usr_putc((BYTE)c);
	return 0;
	}
← Previous