先週マルツで買ったATmega168というAtmel社のAVRマイコンを、動作チェックした。
ここね。秋月の通り。棚に在庫無かったので、言ったら他店舗から取り寄せてくれた。
■ATmega8→ATmega168
ATmega168はATmega8系統のピンコンパチ(28pin)の上位版。ATmega8->ATmega48->ATmega88->ATmega168という順列。
HERO’S Downloadのデータシート翻訳版をざっと見た違いは以下の通り。
・Flashメモリの容量が2倍
・全てのピンに外部入力割り込みが付いた
・PWMが6つある
・いくつかのレジスタの名前が変わった
28ピンというサイズとその機能が俺らの用途に絶妙なので、AT90S4433の頃からずっと使っている。最近のArduinoもATmega168用のブートローダがある。
「全てのピンに外部入力割り込みが付いた」は、ピンへの電気の入力ON/OFFをイベントで通知してくれるという事。ATmega8までは基本的には(INT0, INT1以外のピンは)ループの中で監視するしかなく、重たい他の処理中は信号を見ることができなかった。PCの様な高機能なマルチスレッドが無いマイコンで複雑な事をするにはとても重要な機能だ。
■動作チェック
今までATmega8を動かしていた回路にそのまま入れ替えてみた。
そしてELMのchanさんの所のAVRライターで読み込みテスト
avrsp -r
上はATmega8、下はATmega168のchip info
■動かす
適当にプログラムを書いて動かす事にする。
参考:s.h.log: WinAVR(AVRGCC)の使い方
WinAVRと一緒にインストールされるMFileというツールで、Makefileを作る
MCU typeでATmega168を選択
Main file nameで main と入力
そしてソースコードと同じフォルダに保存する。
PB0のLEDを点滅させるプログラムを書いた。
→ SourceCode, MakeFile, Hex (AVR-GCC3.4.6)
コンパイルして、avrspで書き込む
cdC:¥src¥avr¥MEGA168¥061213_led
make
avrspmain.hex
書き込んでからマイコンリセットをオフにすると動き出す
なんとなく外付け16MHzにしては点滅動作が遅い気がする。
/***
PB0のLEDを点滅させる
CPU:ATMEGA1681MHz(内蔵)
Compiler:WinAVR20060421(AVR-GCC3.4.6)
Date:2006/12/13
Author:ShoHashimoto
WebSite:http://shokai.org
***/
#include<avr/io.h>
#include<avr/interrupt.h>
#include<avr/signal.h>
#defineTRUE1
#defineFALSE0
#defineNULL'¥0'
#definesbi(BYTE,BIT)BYTE|=_BV(BIT)//BYTEの指定BITに1をセット
#definecbi(BYTE,BIT)BYTE&=~_BV(BIT)//BYTEの指定BITをクリア
#defineLED_SET()sbi(PORTB,PB0)//動作確認LED
#defineLED_CLR()cbi(PORTB,PB0)
/*NoOperation*/
voidnop(intcount){
inti;
for(i=0;i<count*100;i++){
}
}
/*PORT設定*/
voidport_init(void){
sbi(DDRB,PB0);//PB0出力設定
}
intmain(void){
port_init();//PORT設定
for(;;){
LED_SET();//LED点滅
nop(300);
nop(300);
nop(300);
LED_CLR();
nop(300);
nop(300);
nop(300);
}
}
■シリアル通信で動作クロックを調べる
点滅動作が遅い気がしたので、出荷時は内蔵クロックで動作している様だ。
なので詳しく調べる。ちなみにその辺はデータシート見てもしょうがない(ロットによって違う可能性もあるので)自分でヒューズビットをいじりましょう。
まず現在のクロックが知りたいので、USARTでPCと通信するプログラムを書いた。
→ SourceCode, MakeFile, Hex (AVR-GCC3.4.6)
そして書き込んで動作させて、Acknowrichでボーレートを調べる。
16MHz動作なら9600bpsで送信するはずのプログラムを書いたのに、600bpsで受信していた。
なので今は1MHzで動いている事がわかった。全然実用的な速度じゃないので後でヒューズビットいじってクロック上げる予定。
シリアル通信しているところ
シリアル通信のプログラム暫定版。データシートろくに見ずに適当に書いたので間違っているかも。でも動いてる。
USART関係のレジスタの名前(UDR、UCSRA, UCSRBなど、大体全部)がUDR0, UCSRA0, UCSRB0になっていた。でも1は無い。将来的に2つになるんだろうか?
/***
USARTでwを送信し続ける
CPU:ATMEGA1681MHz(内蔵)
Compiler:WinAVR20060421(AVR-GCC3.4.6)
Date:2006/12/13
Author:ShoHashimoto
WebSite:http://shokai.org
***/
#include<avr/io.h>
#include<avr/interrupt.h>
#include<avr/signal.h>
#defineTRUE1
#defineFALSE0
#defineNULL'¥0'
#definesbi(BYTE,BIT)BYTE|=_BV(BIT)//BYTEの指定BITに1をセット
#definecbi(BYTE,BIT)BYTE&=~_BV(BIT)//BYTEの指定BITをクリア
/**動作設定**/
#defineFOSC16000000//16MHz
/**UART設定**/
#defineBAUD9600//9600bps
#defineMYUBRRFOSC/16/BAUD-1//UART分周率
//#defineUCSRA_U2X1//倍速フラグ等速ならコメントアウト
#ifdefUCSRA_U2X//倍速が定義されているならば
#defineMYUBRRFOSC/16/(BAUD/2)-1//UART分周率(倍速)
#endif
#defineLED_SET()sbi(PORTB,PB0)//基盤上の動作確認LED
#defineLED_CLR()cbi(PORTB,PB0)
volatilecharusart_recvData;
/*NoOperation*/
voidnop(intcount){
inti;
for(i=0;i<count*100;i++){
}
}
/*PORT設定*/
voidport_init(void){
sbi(DDRB,PB0);
}
/*USART設定*/
voidusart_init(unsignedintubrr){
UBRR0H=(unsignedchar)(ubrr>>8);//ボーレート上位8bit
UBRR0L=(unsignedchar)ubrr;//ボーレート下位8bit
UCSR0B=(1<<RXEN0)|(1<<TXEN0);//送受信許可
UCSR0C=(1<<USBS0)|(3<<UCSZ00);
}
intmain(void){
port_init();//PORT設定
usart_init(MYUBRR);//USART設定
LED_SET();//起動確認LED点滅
nop(300);
nop(300);
nop(300);
LED_CLR();
nop(300);
nop(300);
nop(300);
LED_SET();
for(;;){
UDR0='w';//USART送信
nop(300);
}
}
次はヒューズビット変更、USART受信割り込み、ADC、外部割り込みをやる予定。