![]() |
多重割り込みの許可 | |
![]() |
タイプによる割り込みベクタの違い | |
![]() |
ポートの入力と出力 | |
![]() |
ADDI命令 | |
![]() |
.DBで確保されるメモリ | |
![]() |
プログラムメモリのアクセス | |
![]() |
SRAMのオリジンアドレス | |
![]() |
タイマオーバーフロー割り込み使用時の設定値 | |
![]() |
ビット操作 | |
![]() |
内蔵RCオシレータの発振周波数 | |
![]() |
内蔵EEPROMのRead/Write |
![]() |
割り込み処理中は自動的に他の全ての割り込みが禁止状態になる。割り込み処理中に他の割り込みを許可したい場合は、割り込み処理中でSEI を実行する。CLI/SEI を内部で行っているサブルーチンを、割り込み処理中からCALLした場合、意図せずに多重割り込みを許可した事になってしまうので要注意。 |
![]() |
||||||||||||||||||||||||||||||||||||||||||||||||
同じAVRでも、割り込みベクタのアドレスはタイプ毎に異なる。 例えばAT90S1200とAT90S2313を比べた場合、ぞれぞれのベクタアドレスは以下のようになる。リセットとINT0割り込みのアドレスは同じだが、それ以降の割り込みはベクタアドレスがずれている。 |
||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
昔作ったソースファイルの一部をコピーして、新しいプログラムを作る場合、同一のAVRチップなら割り込みベクタ部分もコピーして問題ないが、それ以外の時は要注意。 |
![]() |
AVRは一つのポートが入力と出力に分かれている。出力ポートから入力することもできるが、この場合は出力した内容がそのまま読み出されてくるだけで、実際の入力は行われていない。 入出力を間違えても、一見するとプログラムは正常に動いているように見えてしまうため、要注意。 |
![]() |
AVRには何故かADDI(即値加算)命令が無い。 SUBI(即値減算)命令はあるので、 SUBI r16,-10 のように補数を即値減算する事でADDIの代わりにすることができる。しかし、この場合キャリーフラグが立たないため、複数バイト長の加算には使用できない。例外としてX,Y,Zの各レジスタペアに対しては ADIW 命令で即値加算を行うことができるが、加算できる値が0〜63の範囲内に限られる。 |
![]() |
AVRのプログラムメモリは必ずワード単位でアクセスされるので、.DBでプログラムメモリ上に定数を確保しようとしたときに、書き方によって確保されるワード数が異なる場合がある。 |
.DB "ABCDEFGHIJ" |
と書いた場合は |
|
のように5ワード確保されるが、これを |
|
と書いた場合は |
|
のように6ワード確保される。更に |
.DB "A" .DB "B" .DB "C" .DB "D" .DB "E" .DB "F" .DB "G" .DB "H" .DB "I" .DB "J" |
と書いた場合は |
|
となって10ワード確保される。文字列を.DBでプログラムメモリ上に確保する時に、途中で分けて宣言してしまうと、思わぬ結果を招く場合がある。 |
![]() |
||||||||||||||||||||||||||||||||||||||||||||||||
AVRのプログラムメモリはワード単位でアクセスされるが、レジスタは基本的に8ビットなので、ワード単位でデータを読むことができない。 そこで、プログラムメモリを読むときは必ずZレジスタペアによる間接アドレッシングを使い、ZLレジスタの下位1ビットでワードの上位8ビットと下位8ビットのどちらを読み込むのかを指定する。ちょっと分かりづらいが、要するにプログラムメモリのワードアドレスをZレジスタペアに1ビットシフトした状態で格納して、空いた1ビットでワードの上位(1)と下位(0)のどちらを読み込むのか指定すれば良いだけ。 |
||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
この場合ワードアドレスは15ビット(32Kワード)しか指定できないが、よく使われるAVRは1K〜4Kワードのプログラムメモリしか内蔵していないので、特に問題にはならない。 ちなみに32Kワード以上のプログラムメモリを内蔵するATmegaシリーズでは、拡張間接アドレッシング命令がサポートされている。 実際にプログラムメモリへアクセスする時のプログラムは、以下のようになる。 |
||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
Zレジスタペアに、プログラムメモリアドレスを2倍(1ビットシフト)した値を格納する事と、lpm 命令で読み出したデータは、常にR0に格納されるという点がポイント。ATmegaでは lpm 命令が拡張されて、読み出したデータを格納するレジスタや、ポストインクリメントの指定ができるようになっている。おまけ: レジスタペアにアドレスポインタを格納するときは、以下のようなマクロを定義して使うと便利。 |
||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
このマクロを使うと、上のプログラムは以下のようになる。 | ||||||||||||||||||||||||||||||||||||||||||||||||
|
![]() |
|||||||||||||||||||||||||||||||||||||||||||||
開始アドレスを指定しない場合の、プログラムメモリとEEPROMメモリのオリジンは$00からになるが、SRAMの場合は$60からになる。 これは何故かというと、下のようにSRAMアドレスの$00〜$1Fに汎用レジスタ、$20〜$5FにI/Oレジスタがマッピングされているため。 |
|||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||
SRAMのアドレス指定で、汎用レジスタ及びI/Oレジスタ領域を強制的に指定することもできる。アセンブルすると警告が出るが、エラーにはならない。 レジスタアドレスに重ねてメモリ領域を確保すると、その領域に対する読み書きは普通のレジスタアクセスと同じになる。 |
|||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||
このコードは | |||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||
と同じ結果になる。これを利用してX/Y/Zレジスタペアによる間接アドレッシングを、連続した汎用レジスタに対して行うことができる。 | |||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||
このコードを実行すると、R17〜R19にR16の内容が格納される。やや危険だが、使い方次第では便利な場合もある。 でもやらないほうが無難。 |
![]() |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
AVRの内蔵タイマは、システムクロックを設定値で割った時間毎にカウントアップされる。たとえばシステムクロックが4MHzで、分周比が1/256の時、4000000Hz/256->15625Hzなので、0.000064秒毎にカウントアップされることになる。 目的とする時間から分周比と、タイマの初期値を算出する場合。以下のようにして行う。 1).システムクロック値を目的の時間で割り、分周比を決める たとえば200mSecの場合、200mSecは5Hzだから、4000000Hz/5Hz=800000Hzとなる。この結果を設定可能な分周比(1/8/64/256/1024)で割り、8ビットまたは16ビットレジスタで設定可能な値を決める。2).分周後のクロック値を目的の時間で割り、カウンタ値を計算する 分周比が決まったら、分周クロック/目的時間を計算する。目的時間を200mSec、分周比を1/1024とした場合、4000000Hz/1024/5Hz=781.25となる。3).タイマレジスタに設定する値を計算する タイマはカウントアップタイマで、オーバーフロー時に割り込みが発生する。従って実際にタイマレジスタへ設定する値は、レジスタの最大値からカウンタ値を引いた値となる。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
おまけ:
|
![]() |
I/Oレジスタに対するビット操作命令と、汎用レジスタ、制御レジスタに対するビット操作命令は、オペランドの形式が異なる。I/Oレジスタのビット操作命令は、1ビットのみのON/OFFなのでビット位置を指定するが、汎用レジスタ、制御レジスタに対するビット操作命令は、ビットパターンを指定する。 たとえば5ビット目をONにしたい場合、対象がI/Oレジスタの場合は |
sbi PORTB,5 |
と指定するが、対象が汎用レジスタの場合は |
|
というふうに指定する。AVRアセンブラはオペランドの定数に数式やシフト演算子が使用できるので、汎用レジスタに対するビット操作命令は |
|
のように書くのが普通。 この命令は ori 命令(論理OR)と全く同じなのでは?と思った人は正解。AVRアセンブラでアセンブルするとsbr とori は全く同じバイナリが出力される。同様に汎用レジスタのビットクリアを行う cbr とandi (論理AND)も同じコードとしてアセンブルされるが |
|
は以下のようにオペランド部分のアセンブル結果が異なる。 |
|
cbr 命令の時は、AVRアセンブラがオペランドの定数をビット反転して、バイナリコードを出力するようになっている。つまり、cbr 命令は以下のマクロ定義と、全く同じと言うことになる。 |
|
ちなみにビット操作命令が使えるのは、PORTB/PORTD等が含まれるI/Oレジスタの前半(レジスタ番号$00〜$1F/アドレス$20〜$3F)のみで、後半のGIMSK/TIMSK等のレジスタに対して行うことはできない(アセンブルエラーになる)。 |
![]() |
AT90S1200の内蔵RCオシレータは1MHz固定と思われている事が多いが、これはVccとして+5Vを供給した時に限っての話。実際の発振周波数は、電源電圧によってかなり変動する。 3.3V動作時には、ほぼ半分の500KHz動作となってしまう。 ワンダースワンの拡張端子から供給される電圧は3.3Vなので、スワンとAVRを直接接続する時には注意が必要。外部クロックで動作させる時は問題ない。 AT90S1200はUARTを内蔵していないため、シリアル通信はソフトウェアUARTで行う事になる。内蔵RCオシレータ動作時にソフトウェアUARTを行う場合、電源電圧と温度によってクロックが無視できないほど変動するので、高いボーレートでは正しく通信が行えなくなる可能性が高い。 内蔵RCオシレータを使うのは、精度を必要としない用途のみと考えた方が良い。 |
![]() |
AVRの内蔵EEPROMへのアクセスは、通常のメモリアクセスとは異なり、制御レジスタを介して1バイトずつ読み書きする方式になっている。 読むときは簡単で、EEARレジスタに読みたいEEPROMのアドレスを入れ、コントロールレジスタEECRのEEREビット(EEPROM読み込み許可ビット)をオンにすると、内部でEEPROMリードストローブ信号が発生してデータがEEDRレジスタに読み出されてくる。 EEPROMを読むときのプログラムは、以下のようになる。 |
EEPROM_READ: sbic EECR,EEWE rjmp EEPROM_READ out EEAR,R16 sbi EECR,EERE in R17,EEDR ret |
最初に制御レジスタEECRのEEWEビットを監視しているのは、書き込み動作中はデータが正しく読み出せないため。このビットがゼロになっている時だけ、読み出しが行える。 R16にアドレスを入れてこのサブルーチンをCALLすると、R17にそのアドレスの内容が格納される。 EEPROMに書き込みを行うときも同じように、EEARレジスタにアドレス、EEDRレジスタにデータを格納するが、コントロールレジスタEECRの使い方がちょっとだけ異なる。 アドレスとデータをそれぞれのレジスタに入れたあと、EECRのEEMWEビット(マスタ書き込み許可ビット)をオン、EEWEビット(書き込み許可ビット)をオフに設定(同時に)し、そのすぐ後でEEWEビット(書き込み許可ビット)をオンすることで書き込み動作が行われる。 EEWEビットのオフとオンの間は4クロック以内と定められているため、この間で割り込みが発生しないようにする必要がある。 EEPROMに書き込むときのプログラムは、以下のようになる。 |
|
EERE、EEWE、EEMWEの各ビットは、処理終了後に自動的にゼロクリアされる。 |