アーカイブ
ATmega168を動かしてみた
先週マルツで買った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を動かしていた回路にそのまま入れ替えてみた。
AVR – ATMega8でUSARTエコー
UART(USART)の回路がちゃんとできているかチェックする時に使ってるプログラム。
UARTでマイコンが文字列を受け取る。そして受け取った文字をそのままUARTで送り返す。
Arduino+ATMega8で作ったら15行で書けるけど、avr-gcc+ATMega8だと58行必要になる。
同じ動作をするプログラムなのに。
そういえばWinAVR060421が出ているのにまだ移行していなかった。あとでやる。
3軸加速度センサ ACA302を使って傾斜を測定
加速度センサーで、重力加速度つまり地球が引っ張るアレをセンシングできます。これで傾斜とか、向きがわかります。
これで俺もMacSaberできる!(やりません)
論文2つsubmitして6時間寝たら明け方目が覚めて、朝9時から授業のグルワでその後研究室で昼寝。
その後ふらふらになりながら、なんとなく1年以上前に買った加速度センサーに挑戦してみた。
マイコンさわるの1ヶ月半ぶりだけど1時間ぐらいであっさり動いた。慣れたもんだ…
→ SourceCode(avr-gcc)&Video
使ったのは、秋葉原のツクモロボット館などで売ってるスター精密のACA302。価格は2000円ぐらい。
普通加速度センサーは1万円とかのが色々あるんだけど、手が届かないのでコレで。アンプ内蔵型なのでコレ単体でAVR atmega8のADコンバータにぶち込めば動くお手軽感がいい。実にPhysical Computing向け。
とりあえず、傾斜を検出する分には問題ない。
AVR – ATMEGA8のA/Dコンバータ
ついでに。atmega8というよく使うマイコンでのa/d converterのコードを張っておく。avr-gcc用。でもそろそろmega88に移行かな
sbi()cbi()マクロ使ってます。
この関数2つを適当にコピペして
/* ADコンバータ設定 */
void adc_init(void){
ADCSR =_BV(ADEN)|_BV(ADSC)|(0<<ADPS2)|(0<<ADPS1)|(0<<ADPS0)|(0<<ADFR);
// A/D変換許可、1回目変換開始(調整)、分周率2、連続変換しない
}
/* ピンを指定してAD変換 return 0-1023 */
int adc_convert(char pin){
int ad;
ADMUX = pin; // AD変換入力ピン
cbi(ADCSR,ADIF);
sbi(ADCSR,ADSC);
loop_until_bit_is_set(ADCSR,ADIF);
ad = ADCL;
return ad += (ADCH<<8); // 上位2bit取得
}
main()ではこんな感じで。
int main(void){
adc_init();
int ad;
ad = adc_convert(0); // ADC0でAD変換
}
ちなみに、adc_init()でAD変換の速度を最速にしてます。ADPS2,1,0のa/d変換分周率指定で変えれる。分周率が大きいほど遅い。
HERO’S Download データシートより

AVR – mega8でロータリーエンコーダを回す
2週間ぐらい前の事なので曖昧だが、ATmega8のタイマ/カウンタ1で秋月で100円のインクリメンタル型ロータリーエンコーダーを使ってみた。
![]()
写真下のマイコンは関係無い。
既にTiny26Lでやっている人がいたので参考にしながらさくっと書いた。
→ソースコード(AVR-GCC)
んで数日後に書き直した。
→ソースコード(AVR-GCC)、動画
なんで書き直したかは記憶が定かではないのだが、とりあえず大した違いは無いしどちらも動く。昨日も古い方でデモしてきたばかりだし。
動作設定としてはこんな感じで
/** 動作設定 **/
#define FOSC 8000000 // 8MHz
#define BAUD 9600 // 9600bps
#define MYUBRR FOSC/16/BAUD-1 // UART分周率
volatile char uart_recv_data; // UART受信データ
/** ロータリーエンコーダ設定 **/
volatile char rot_state;
#define ROT_TCNT1 65536-32+1 // 8MHz 1024分周で1ms(1000Hz)
タイマ/カウンタ1を初期化する。main()から1回だけ呼び出す必要がある。
/* タイマ/カウンタ1オーバーフロー割り込み設定 */
void overflow1_init(void){
TCCR1B = (1<<CS12)|(0<<CS11)|(0<<CS10); // 256分周
sbi(TIMSK,TOIE1); // タイマ/カウンタ1オーバーフロー割り込み許可
TCNT1 = ROT_TCNT1; // 1ms毎に割り込み設定(ロータリーエンコーダー用)
}
ロータリーエンコーダー監視スレッド。割り込みなので書いておけば一定時間毎に実行される。
/* タイマ/カウンタ1オーバーフロー割り込み
ロータリーエンコーダー監視用 */
SIGNAL(SIG_OVERFLOW1){
TCNT1 = ROT_TCNT1; // タイマ/カウンタ初期化 1ms毎に割り込み設定
char past_state; // 1回前の状態
past_state = rot_state;
if(bit_is_set(PIND,PD3)){
if(bit_is_set(PIND,PD4)) // HH
rot_state = 1;
else // HL
rot_state = 0;
}
else{
if(bit_is_set(PIND,PD4)) // LH
rot_state = 2;
else // LL
rot_state = 3;
}
if((rot_state+3+1)%3 == past_state){ // 右回り
uart_send_str(&qute;R&qute;);
}
else if((rot_state+3-1)%3 == past_state){ // 左回り
uart_send_str(&qute;L&qute;);
}
}
書いてて10ms毎じゃない気がしてきたが、速い分には問題ないし、他にもタイマを回しているのだったら色々タイミングもずれてくると思うので適宜対処して下さい。
ロータリーエンコーダーの真ん中の足をGNDに接続し、左右の足をそれぞれマイコンのピンに接続。また、左右の足とマイコンのピンの間で、10kΩの抵抗を使ってプルアップする(VCCに接続する)
まあ写真の通り。
インクリメンタル型ロータリーエンコーダーは2本の線で4種類の回転状態を出力する。1クリック回す(カチッと言う)と、4種類の状態が一回りする。
とりあえず状態に0,1,2,3と名前をつけて、10ms毎ぐらいに状態を見に行くと、状態が1増えていたら右に回転、減っていたら左に回転みたいな感じでわかる。
■参考サイト
・113.ロータリーエンコーダを使う
・2343e-conv
・AVR試用記-ロータリーエンコーダ
・ELM – 接点入力と処理のコツ – ロータリーエンコーダの使い方
ところでタイマ/カウンタ、以前書いた時はイマイチわかってなかったのだが、タイマ割り込みが発生するのはTCCNxが8bitなら256、16bitなら65536になった時起こるとの事。つまりタイマ/カウンタオーバーフロー割り込みとはそういう事。
TCCNxが増えるタイミングは分周率(TCCRx)で決まる。64分周だったら、64クロック毎に1増える。分周なし、8、64、256、1024分周まで5段階あるのでそれでタイミングを調節できる。
また、TCCNxに直接書き込み、カウンタの初期値を設定する事もできる。これは割り込みが起こった瞬間に次の割り込みに備えて代入しなおす必要がある。
この2種類の方法で割り込みタイミングを操作する。



最近のコメント