マイコンの開発をしている際に,「今この変数はどんな値になっているのか」等を知りたくなる時が多々あるかと思います.AtmelStudioでは,PC上でAVRの動作をシミュレートし,プログラムを一行ずつ進めた際にどのような動作をするかを確認する機能があります.このシミュレータを使った確認作業をデバッグといいます.
試しに次のようなプログラムを作成して,デバッグを行ってみましょう.
#include<avr/io.h>
int main(void)
{
DDRD=0b00000001;
PORTD=0b00000000;
for(char i=0;i<255;i++)
{
PORTD=i;
}
}
シミュレータの設定
初めに,AVRシミュレータをプログラムの実行環境として設定します.Solutioin Explorerのプロジェクトの部分を右クリックして,Propertiesを選択します(画面上部にあるツールバーの「NO TOOLS」から直接開くこともできます).ProperyウィンドウのToolsタブの「Selected debugger/programmer」の項目のダイアログから,simulatorを選択します.
ブレークポイントの設定
プログラムは1行目から順に進んでいくわけですが,変数の値などを確認する場合にはプログラムを一時停止させる必要があります.この停止させるポイントをブレークポイントといいます.プログラムエディタの停止させたい行にカーソルを合わせて,F9キーを押すと行頭に赤い丸印が付き,ブレークポイントが設定されます(もう一度押すと解除されます).赤い丸印の部分をクリックすることでも切り替えが可能です.
デバッグの開始
デバッグはF5キーで開始し,ブレークポイントがあるところまで進みます.しかし,VisualStudioのバグなのか,main関数の1行目のブレークポイントを無視することがありますので,最初の1行目から進めたい場合はF11キーでデバッグを開始しましょう.
今回はF11キーでデバッグを開始します.初めに記号の羅列が出てくることがありますが,これはコンパイルによって生成された機械語となります.アセンブリを勉強すると読めるようになりますが,今は使わないので閉じておきます.
1行目に黄色い矢印が出ていると思います.この矢印は次に実行する行を表しており,これを進めながら確認作業を行っていきます.
レジスタの値の確認
レジスタの値は「I/O View」というウィンドウに表示されます.画面上に「I/O View」が見当たらない場合は,画面上部の「Debug」→「Windows」から「I/O View」を選択してください.このウィンドウではAVRの全レジスタがジャンルごとにまとめられており,選択すると各レジスタの詳細が表示されます.ここではPORTDを選択しましょう.F11キーを押してステップを進めてみると,bitの変化が確認できます.見方は次のようになります.
imageプラグインエラー : ご指定のファイルが見つかりません。ファイル名を確認して、再度指定してください。 (値の変化.png)
Valueを書き換えたり,Bitの部分をクリックすることで値を変更させたりすることもできます.入力ポートの動作などはここを書き換えながら進めることで確認できます.
変数の観測
for文の中に入ると変数が出てきますが,この変数の値は画面左下の「ローカルウィンドウ」や「自動変数ウィンドウ」で確認できます.レジスタと同様にValueを直接書き換えることができます.グローバル変数などのここに表示されない変数は「Watchウィンドウ」に追加することで確認することができます.
ステップの進め方
ここまで,ステップを進める方法としてF11キーを押してきましたが,これを「ステップイン」といいます.ステップの進め方には他に「ステップオーバー」と「ステップアウト」があります.これらは画面上部の次のボタンに対応しています.
imageプラグインエラー : ご指定のファイルが見つかりません。ファイル名を確認して、再度指定してください。 (デバッグツールバー.png)
ステップを1行進めます.関数の呼び出しの行では関数の内部に飛びます.
imageプラグインエラー : ご指定のファイルが見つかりません。ファイル名を確認して、再度指定してください。 (ステップイン.png)
ステップを1行進めます.関数の呼び出しの行ではそれ自体を1行と考え,次の行に進みます.
imageプラグインエラー : ご指定のファイルが見つかりません。ファイル名を確認して、再度指定してください。 (ステップオーバー.png)
ステップインなどで関数内に入っていた場合,それを抜けて呼び出し元の次の行に進みます.
これらの操作がデバッグの基本となります.うまく活用して,効率よくデバッグを行いましょう.
ヒント集
delay関数は呼び出す際には1行ですが,内部的には莫大な数のループが含まれています.シミュレータの速度はそこまで早くありませんので,delay関数を抜けるためにはそこそこ時間がかかります.10ms程度なら気になりませんが,Lチカのように1000ms待つような場所では結構シャレになりません.この待ち時間が気になるときは,次のようにプリプロセッサを使ってデバッグのときだけdelay関数をnop命令に置き換えるのが有効です.
#define debug//デバッグ時以外はこの行をコメントアウト
#ifdef debug
#define _delay_ms(x) asm("nop")
#define _delay_us(x) asm("nop")
#endif
デバッグ中の確認用として一時的な変数を置きたくなる時がありますが,プログラムと関係のない変数はコンパイラによって消されてしまうことがあります.例えば現在のループの回数を知りたいときに,次のような変数を置いたとします.
int count=0;
while(1)
{
//countとは関係のない処理
//・・・
count++;
}
このとき,countという変数はプログラム本筋に無関係であるため,コンパイラの最適化によって消されてしまいます.これを避ける方法は2種類あります.一つはプロジェクトの「properties」→「Toolchain」→「AVR/GNU C Compiler」→「Optimization」の「Optimization Level」を「None」に設定することです.こうすることで,コンパイルが最適化を行わないようになります.もう一つは変数宣言の際に「volatile」修飾子をつけることで,その変数に関する最適化を抑制することです.変数に関してはvolatile修飾子で対応することができるので,それ以外で最適化の弊害が現れた場合などにコンパイル設定の変更をするといいでしょう.
AVRシミュレータでは実際の処理にかかるクロック数を確認することができます.高速な割り込み処理などでは,一回の割り込みにかかるクロック数を把握する必要があります.その時は,「Processer Status」ウィンドウの「Cycle Counter」で確認できます(画面上に出ていなければ,デバッグ中に「Debug」→「Windows」から開けます).また,「Frequency」を書き換えることで実際にかかる秒数を確認することもできます.
ブレークポイントの赤丸を右クリックして「Conditions」を選択すると,ブレークポイントに条件を付けることができます.「○回目にヒットしたとき」や,「ある変数の値が○○のとき」など,割と柔軟な条件を付けることができるので,うまく活用するとデバッグ効率がぐっと上がります.
最終更新:2016年01月18日 02:55