★H8に関して
処理系によると思いますが、gcc-2.95.2では0b101010のような2進数表記ができません。もともとANSIにはないと思うので仕方がないのですが、どうしてもビット操作が多くなりがちな組み込み用途では不便です。そこで、0bXXXXXXを扱えるようにするパッチを作りました。でも、ソース配布時に問題あるかも・・・
% cd gcc-2.95.2
% cat ../gcc-2.95.2-20010926.diff | patch -p1
patching file `gcc/c-lex.c'
後はコンパイル・インストールすればOKです。
% cd build
% su
% make LANGUAGES="c"
% make LANGUAGES="c" install
ためしにプログラムを入力してみます。
% cat > bin.cエラーが出なければOKです。生成されたbin.sを開いて確認してみてください。main()
{
int a = 0b1010110;
}
CTRL+D
% h8300-hms-gcc -mh -mint32 -S bin.c
H8マイコンはCCRというレジスタにグローバルな割り込み許可・禁止のフラグを持っています。割り込みを発生させるには割り込みコントローラの割り込み許可フラグを立てるほかに、このCCRレジスタの変更が必要です。割り込みコントローラはメモリマップドI/OなのでC言語で直接アクセスすることができますが、CCRレジスタにはC言語で
直接アクセスすることはできません。そこアセンブラの力を借ります。1つの関数にしてもいいのですが、関数のコールのオーバーヘッドが大きいのでインラインアセンブラを使います。ヘッダファイルに記述しておくといいでしょう。H8/300Hシリーズ共通です。
次のように使います。
#define STI() asm volatile ("andc.b #0x7f,ccr")
#define CLI() asm volatile ("orc.b #0x80,ccr")
main()
{
<初期化処理>STI(); // 割り込み許可
<割り込みが発生します。>
CTI(); // 割り込み禁止
<割り込みが発生しません。>
}
gccでは割り込み処理ルーチンもC言語で作成できます。割り込みハンドラ関数の定義の前に次のような宣言をすればOKです。
"#pragma interrupt"がその宣言です。割り込みハンドラは当然ですが引数なしで、戻り型はvoidでなければなりません。
#pragma interrupt
void int_handler(void)
{
<割り込み処理ルーチン>
}
printfに代表されるような変数を可変長にすることができる関数があります。このような関数をH8で利用する場合、必ずプロトタイプ宣言が必要です。printfについてはstdio.hをインクルードするだけで済みますので乱暴に作らなければ大丈夫ですが、ユーザが可変長引数の関数を作成する場合は注意が必要です。例えば、
のようなプログラムを作成しておいて、他の別のソースファイルから呼び出した場合、
#include <stdarg.h> int debug(char *fmt, ...)
{
va_list arg;va_start(arg, fmt);
<省略>
va_end(arg);}
上記の例では正しく動作しますが、赤字の部分"extern int debug(char *fmt, ...);"がないと正しく動作しません。これは、コンパイラの引数渡しの方法に原因があります。
extern int debug(char *fmt, ...);main()
{
debug("%s:%d\n", filename, line);
}
ここでは可変引数の関数についてだけ説明していますが、それ以外のタイプの引数についても、プロトタイプ宣言がないとトラブルが発生する可能性がありますので、必ずやっておいた方がいいでしょう。戻り値がintだから宣言しなくても動くというふうに思わないように!!
int xx = 5;
int yy = 0; main()
yy = 9;
|
注意しないといけないのは上記でyy=0と記述しても、同じ現象が発生します。
RAMに割り当てるには初期化をしてはいけません。
int start;
main()
#pragma interrupt
|
上記のようなプログラムの場合、intという関数が割り込みハンドラとして定義されており、割り込みが発生すると変数start
が加算されます。そうすると、main関数では変数startが0以外になるのでdo_job関数が実行されるように見えますが、
実際は実行されません。これはmain関数で変数startを変更している箇所がないため、while(start)の評価を1度しか
行わないためです。上記のint startをvolatile
int startに変えると思い通りの動作になります。
組み込み系システムではvolatileは重要です!
#define DUMP(var) printf(#var "=%d\n", var) main()
x = 12345;
|
上記のプログラムを入力、実行してみてください。ANSI準拠のコンパイラならできるはずです。すると
x=12345 *y=12345 |
のように表示されます。DUMP(*y)とやっただけで、自動的に
"*y="を付けてくれるのです。
もちろん DUMP(ptr[2]->array[i]->member)
のように複雑なものでも、ちゃんと表示します。DUMP(x+100) とかやってもちゃんと、"x+100=12445"
とでます。
printf("x=%d\n", x); printf("*y=%d\n", *y); |
となどとやってもいいのですが、普通コピー&ペーストでプログラム組みますから、絶対に変数と文字列の修正を忘れます。10行以上ならかなりの率です。
コピペに頼るのはよくないです。それで、さっきの方法が有効となってきます。
#define DUMP(var) printf(#var "=%d\n", var) |
このマクロの説明をするとい、まずvarが引数になりますが、ここでDUMP(counter)というマクロの展開を考えます。スタートは
DUMP(counter) |
です。次にvarがcounterに置き換わりますから、
printf(#counter, "=%d\n", counter) |
と等価になります。それで#counterをみて?と思うかもしれません。そうです、#という演算子はC言語にありません。でも#演算子はプリプロセッサ命令として存在するのです。#はプリプロセッサ命令についています。#includeにも頭についてるでしょ。
#counterはどう解釈されるかというと、文字列として扱われるようになります。つまり、変数あるいはラベルとしてのcounterではなく、文字列
"counter"となるのです。
それを踏まえると、次のようになります。
printf("counter" "=%d\n", counter) |
"AAAAA" "BBBBB"のように文字列を並べて書くとコンパイラがその文字列を連結しますので、
printf("counter=%d\n", counter) |
となり、うまいことcounter=12345のように表示できるようになります。これで、知らない人に教えてあげよう!
あと ## という演算子もあります。どういうものか調べてみよう!