オルタナティブ・ブログ > mtaneda ブログ >

中小企業の開発者は会社で何をしているのか

AVR ATmega128 でシリアル通信

»

最近はAVRをいじっています。(adruinoではないです)

なかなかATmega128について書いているサイトさんが少なくて、シリアル通信まで試行錯誤しましたが、
慣れないので1日かかってしまいましたが、
きちんとデータシートを読めばそんなに難しいことではありませんでした・・・

AVRのlibcは、このあたりがちょっと面白いですね。

FILE console=FDEV_SETUP_STREAM(USART0Putchar,USART0Getchar,_FDEV_SETUP_RW);
stderr=stdout=stdin=&console;

これのおかげで、パソコンのC言語みたいに扱えるのが良いです。

せっかくなので試行錯誤したときのサンプルコードを載せておきます。
非常に怪しい場所もあるので、あくまで実験用と割り切ってください。

もしATmega128でシリアル通信をしてみようと思っている方のお役に立てれば幸いです。

 

#define F_CPU 16000000UL	//16MHzの外部水晶を使っているため

#include <stdio.h>

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

struct RingBuffer{
	unsigned char rbuf[BUFFER_SIZE];
	unsigned char rbuf_front;
	unsigned char rbuf_last;

	unsigned char sbuf[BUFFER_SIZE];
	unsigned char sbuf_front;
	unsigned char sbuf_last;
}USART0;

void
USART0Init(unsigned int ubrr)
{
	//転送レート設定
	UBRR0H=(unsigned char)(ubrr>>8);
	UBRR0L=(unsigned char)ubrr;
	
	//RX/TX/RXINTを有効にする
	UCSR0B=(1<<RXCIE0)|(1<<RXEN0)|(1<< TXEN0);

	USART0.rbuf_front=0;
	USART0.rbuf_last=0;
}

void
USART0DataReadyHandler(void)
{
	unsigned char c;

	if(USART0.sbuf_front!=
	   USART0.sbuf_last){
	
		c=USART0.sbuf[USART0.sbuf_front];
		USART0.sbuf_front=(USART0.sbuf_front+1)%BUFFER_SIZE;

		UDR0=c;	//送信
	}
	else{
		//リングバッファが空になったら割り込みレベル解除
		UCSR0B&=~(1<< UDRIE0);
	}
}

void
USART0RXIntHandler(void)
{
	USART0.rbuf[USART0.rbuf_last]=UDR0;
	USART0.rbuf_last=(USART0.rbuf_last+1)%BUFFER_SIZE;
}

void
USART0Putchar(char data)
{
	cli();

	//リングバッファが空ということは、これからはじめてデータを送信するということ
	//そのため、sei()されたらUSART0_UDRE_vectの割り込みが発生するように、
	//ここで仕掛けておく
	if(USART0.sbuf_front==
	   USART0.sbuf_last){
		UCSR0B|=(1<< UDRIE0);
	}

	USART0.sbuf[USART0.sbuf_last]=data;
	USART0.sbuf_last=(USART0.sbuf_last+1)%BUFFER_SIZE;

	sei();
}

char
USART0Getchar(void)
{
	unsigned char c;
	
	while(USART0.rbuf_front==USART0.rbuf_last)
		;//ここは最適化しないで欲しいな

	c=USART0.rbuf[USART0.rbuf_front];
	USART0.rbuf_front=(USART0.rbuf_front+1)%BUFFER_SIZE;
	
	return(c);
}


FILE console=FDEV_SETUP_STREAM(USART1Putchar,USART1Getchar,_FDEV_SETUP_RW);

ISR(USART0_UDRE_vect)
{
	USART0DataReadyHandler();
}

ISR(USART0_RX_vect)
{
	USART0RXIntHandler();
}

int
main(void)
{
	char buf[16];

	USART0Init(F_CPU/16/38400-1);

	stderr=stdout=stdin=&console;
	
	printf("Hello, world!\n");

	while(1){
		fgets(buf,16,stdin);
		printf("buf=%s\n",buf);
	}

	return(0);
}
Comment(0)