アーカイブ
ATmega168でピン変化割り込み
ATmega88以降は全てのI/Oピンに「外部入力割り込み」が付いている。これは、それぞれのピンに電流がONになったり、OFFになったりするとイベントが起こるという事だ。
今まではmain()の中のループで各ピンをずっと監視し続けなければならなかったが、この外部入力ピンを使うと完全にイベントドリブンでプログラムを書ける様になる。ちなみにArduinoからは使えない機能です。


■作った
PB1につながったスイッチを押した時に割り込み(SIG_PIN_CHANGE0)が発生し、UARTでPCに通知する。PB0のLEDも光らせる。スイッチを離すとLEDを消し、UARTで通知する。
SourceCode, hex, Makefile(avr-gcc 3.4.6)
■外部入力割り込みの仕組み
2箇所設定する必要がある。
1.「ピン変化割り込みレジスタ」でピン変化割り込みを許可する
2.入力割り込みを受け取るピンを「ピン変化割り込みマスクレジスタ」で指定する
ピン変化割り込み0,1,2(PCIE0,1,2)の3つがあり、それぞれPORTB,PORTC,PORTDに対応している。
つまり、割り込み1つで7~8個のピンを受け持つという所がINT0,INT1の外部入力割り込みと違う。
ATmega88のデータシートの41ページを見るとPCICRというレジスタのPCIE0ビットに1をセットしてやるとピン変化割り込み0が許可される事がわかる。
sbi(PCICR,PCIE0); // ピン変化割り込み0
ATmega168でAD変換
ATmega168でADコンバータも試した。
CdS(光量センサ)と10kΩの抵抗を使った。

ADC0でAD変換した値を文字列に変換して、UARTでPCに送る
ADC0の値が700以上の時、LEDを点灯させる。700以下だったら消灯する。
動いているところ
■コード
SourceCode, hex, Makefile(avr-gcc 3.4.6)
AD変換の準備のadc_init()、実際にAD変換を行ない値(int)を取るadc_convert(int pin)、USARTで文字列を送る関数 usart_sendStr()、intをStringに変換するintToStr(int, buf)を作った。
s.h.log: Arduino – UART、LED、AD変換を試したでも書いたが
シリアル通信で送信できるのは8bitまで。AD値は10bit。
なので、そのままSerial.print()してしまうと上位2bitが飛んで変な値になる。こういう時は
・上位2bit/下位8bitを2回に分けて送信し、PC側で連結する
・マイコン側で、AD値が0~50の時は’a'を送る/51~100の時は’b'を送るの様に、プロトコルを決める
・Stringにして送信して、PC側で数値に直す
・4で割ると、10bitの最大値1023が8bitの最大値255に納まる。ただし精度は4分の1になる
のどれかで対処する。
なので今回は文字列に変換して送ってみた。これが無いとデバッグとかやってられない。
ATmega168でUSART受信割り込み、シリアルエコー
mega168でUART受信割り込みできた。
回路はmega8の時と同じ。
さっきできなかった理由は割り込みベクタ名が間違ってた為だった。
コンパイル結果をよく見ると SIGNAL(SIG_UART_RECV)の所でwarningが出ていたので、avr-gccのフォルダの中のコードをよく読んだらSIG_USART_RECVになっていた。
コンパイラのバージョンというわけではなく、ATmega8のコードではSIG_UART_RECVで通るのでATmega168以降はSIG_USART_RECVに変わったみたいだ。
あとavr/signal.hは廃止されてavr/interrupt.hに統合される模様。
■関連記事
s.h.log: AVR – MEGA8のUART送受信
s.h.log: AVR – ATMega8でUSARTエコー
ATmega168でシリアルエコー
8MHz駆動になったmega168で、UARTエコー。
シリアルコンソールで送信した値がそのまま帰ってくる。
ATMega8の時とは違って、受信割り込みに反応して返すのではなくmain()の中のループで受け取って返している。というか受信割り込みから復帰できないので。
今晩中に解決できるといいな…



最近のコメント