4. プログラミング小ネタ集

にけがものづくりをしてきたなかで悩んだことをまとめてみました。

AVRは優れたマイコンですが、プログラムを作るにあたっていくつかの制約があり、ついそこでつまづいてしまいます。

これからAVRアセンブラでプログラムを作ろうとした際のお役に少しでもたってくれるととうれしいです。

 

インクルードファイル

I/Oレジスタ関連

ビット操作関連

汎用レジスタ関連

ポート関連

微少時間の挿入

 

 

<インクルードファイル>

プログラムの最初に. include "m88def.inc" というような記述をしています。
これによって、マイコン別に用意されたインクルードファイルがアセンブラ時にプログラムに展開されて実行ファイルが生成されます。

 

<I/Oレジスタ関連>

ビットセット/クリア命令 SBI/CBIでアクセスできるI/Oアドレスは$00~$1Fまでです。
$20以降のI/Oレジスタのビットセット/クリアをするには、I/Oレジスタの内容を汎用レジスタ(R0~R31)に読込(IN)後、指定ビットをセット/クリア(SBR/CBR)し、I/Oレジスタに書き戻し(OUT)ます。
マイコンATtiny45でタイマ0を割込可に設定する例を記述します。
I/Oレジスタ$39 TIMSKのTOIE0ビットをセットします。

** ATtiny45 でタイマ0を割込可に設定する **

IN	R16,TIMSK
SBR R16,(1<<TOIE0)
OUT TIMSK,R16

注意しないといけないのは、IN/OUT命令が使えるI/Oアドレスは$00~$3Fまでです。

I/Oアドレスがこの範囲内の場合と範囲外の場合でのプログラミングの違いについて説明します。
マイコンが異なると、同じ設定を行う場合でも操作するI/Oレジスタのアドレスが違う場合があります。

ATtiny45は、I/Oレジスタ$39 TIMSKのTOIE0ビットをセットします。
ATmega88は、I/Oレジスタ$6E TIMSK0のTOIE0ビットをセットします。
そのため、マイコンATmega88でタイマ0を割込可に設定する場合は下記のように記述します。

** ATmega88 でタイマ0を割込可に設定する **

LDS	R16,TIMSK0
SBR R16,(1<<TOIE0)
STS TIMSK0,R16
<ビット操作関連>

I/Oアドレス$00~$1Fはビットセット/クリア命令 SBI/CBIが使えること、それ以外のアドレスでビット操作を行うにはSBR/CBR命令を使うことは既に述べました。

実はAtmel社のデータシートでは、SBR/CBR命令は算術論理演算命令に含まれています。
例えば下記のように記述したとします。(R16の初期値は0x00とします)

SBR R16,5

一見レジスタR16のビット5がセットされたように感じますが実は中身は0x05となっています。
つまり0b00000101です。ビット2と0がセットされてしまいました。

指定ビットをセットするには下記のようにします。

SBR R16,(1<<TOIE0)

指定ビットのクリアは下記となります。

CBR R16,(1<<TOIE0)

 

<汎用レジスタ関連>

SRAMメモリのアドレス$0000~$001FはR0~R31と表記され汎用レジスタと呼ばれますが、命令によってはアクセスできるアドレスが制限されます。
例えばSBR/CBR/LDIは、R16~R31に対して使用可能です。

プログラミングの際はR0~R15は使用せず、R16~R31だけを使用するほうがこの制限を意識せずに済みます。
もしプログラムの規模が大きくなって R0~R15を使いたい場合は、アドレス制限の無いLDSやMOV命令を使うような目的に使用するとよいでしょう。

<ポート関連>

プログラム中、I/Oポートの出力はPORTxと記述します。
I/Oポートの入力はPINxと記述します。

<微少時間の挿入>

完璧に思えるプログラムが実際に動作させるとおかしな動作をする場合があり、原因として処理に必要な時間が足りない場合があります。そういう場合は1秒未満の微少時間を挿入すると解決する場合があります。
一例として、

・スイッチ入力で誤判定する→スイッチ特性であるチャタリングの問題であり、判定後時間を置いて再度判定する。
・他デバイスとデータ転送がうまくいかない→他デバイスの処理が完了しない間に次のデータを送っているので、データを送った後少し待ってから次のデータを送る。

などがあります。