――晴子さんは、簡単に「printf関数を作って!」というけれど、実際、プログラムをROMに書き込んで実行・デバッグするのはとても手間が掛かります。そこで、C言語の利点を生かして、パソコンでデバッグしてはいかかでしょうか?
シリアル通信の応用として、オリジナルprintf関数を作ってみましょう。
いままでのプログラムでは、H8Tiny-USBにプログラムをダウンロードして、すなわち、実機で動作を確認してきました。しかし、そのやり方では手間が掛かりますし、マイコンのフラッシュメモリの寿命を浪費しかねません。
そこで今回は、パソコン上でプログラムを完成させ、最後にマイコンで動作を確認する方法を取ります。
今回、晴子さんは以下の「mprintf関数」を作りました(ソースコード2)。
/*============================================================================== + + 書式付きターミナル出力 + +============================================================================*/ #include <stdarg.h> /*#define H8TINY_USB*/ #ifdef H8TINY_USB # include "sci.h" # define output(ch) sci_putc(ch) #else # include <stdio.h> # define output(ch) putchar(ch) #endif #define C_MAX 12 /* ロングデータを8進数で表示するときの最大けた数 */ static void outs(char *, short); static void outc(char, short); static void outn(char, unsigned long, short); void mprintf(char *fmt, ...); /*------------------------------------------------------------------------------ + 書式付きターミナル出力 +----------------------------------------------------------------------------*/ void mprintf(char *fmt, ...) { va_list args; char *p; unsigned long v; short c; va_start(args, fmt); for (p = fmt; *p != '\0'; p++) { if (*p == '%') { p++; if ((*p >= '1') && (*p <= '9')) { c = *p++ - '0'; while ((*p >= '0') && (*p <= '9')) c = c * 10 + (*p++ - '0'); } else c = -1; v = (unsigned long)va_arg(args, long); switch (*p) { case 's': outs((char*)v, c); break; case 'c': outc((char)v, c); break; case 'd': case 'o': case 'x': outn(*p, v, c); } if (*p == '\0') goto fin; } else if (*p == '\n') { #ifdef H8TINY_USB output('\r'); #endif output('\n'); } else output(*p); } fin: va_end(args); } /*------------------------------------------------------------------------------ + 文字列を出力する +----------------------------------------------------------------------------*/ static void outs(char *s, short c) { char *p; for (p = s; *p != '\0'; p++) { if (c-- == 0) return; output(*p); } while (c-- > 0) output(' '); } /*------------------------------------------------------------------------------ + 文字を出力する +----------------------------------------------------------------------------*/ static void outc(char ch, short c) { output(ch); while (--c > 0) output(' '); } /*------------------------------------------------------------------------------ + 整数を出力する +----------------------------------------------------------------------------*/ static void outn(char fm, unsigned long v, short c) { char s[C_MAX], *p, z; unsigned short b; switch (fm) { case 'd': b = 10; z = ' '; break; case 'o': b = 8; z = '0'; break; case 'x': b = 16; z = '0'; break; default: return; } p = s; do { c--; *p++ = "0123456789abcdef"[v % b]; v /= b; } while (v != 0); for (; c > 0; c--) output(z); while (p > s) output(*--p); }
このモジュールをmain関数で呼び出すと、図9のようにパソコンのgccで動かすことができます(ここから「print.lzh」をダウンロード)。
パソコンでの動作が確認できたところで、今度はH8Tiny-USBで動作させます(ここから「hello2.lzh」をダウンロード)。
いかがでしょうか? C言語プログラムは機種に関係なく動作させることができるので、以上のようなデバッグの方法が可能です。
それでは、晴子さんオリジナルのprintfモジュールを詳しく調べてみましょう。
晴子さんのプログラムでは、機種依存となる1文字出力をうまく切り替えています。
/*#define H8TINY_USB*/ #ifdef H8TINY_USB # include "sci.h" # define output(ch) sci_putc(ch) #else # include <stdio.h> # define output(ch) putchar(ch) #endif
の記述がそれで、
/*#define H8TINY_USB*/
のコメントを消して、「H8TINY_USB」を定義すると、1文字出力関数にH8Tiny_USBのシリアルポートが使われます。
コメントアウトした状態では、標準入出力のputchar関数が使われるので、同じプログラムがパソコンで動きました。
すごーい。晴子さん!
さすが!!
C言語でプログラムを作っているんだから、それを生かさない手はないわね。
ところで晴子さん、卒業後はどうするんですか?
組み込みソフトウェア開発の企業から内定をもらったの。
ワタシ、忙しくなるからしばらく健一君にも会えないわね(涙)。
グスン……(涙)。
もう!! 健一君まで泣かないの!
健一君ももっとマイコン勉強して、ワタシを追いかけてきてね。
はい! もっと勉強して晴子さんに似合うオトコになります!
そ、そうすれば、デ、デートも……。
そうね。楽しみにしてるわ。
ウフフッ。
今回は、視点を変えてマイコンのソフトウェア開発環境について触れました。マイコンのソフトウェア開発の特徴的な点として“ROM化”があります。プログラムもシステムに組み込まなければなりません。ですから、ソフトウェア開発環境が何をしているのかを分かっていた方が、断然、有利なのです。
さて、ハードウェアの製作からプログラミングまでを一貫してお届けしてきた連載「イチから作って丸ごと学ぶ! H8マイコン道」もこれで終わりです。
健一君、そして、読者の皆さま、1年間お疲れさまでした。思い返すと、健一君はいつも晴子さんにやり込められてばかりでしたね。そして、健一君を指導してくれた二三夫さん、晴子さんも本当にありがとうございました。本連載が組み込み開発に携わる、そしてこれから組み込みの世界に飛び込もうとしている方々のお役に立てば幸いです。それでは皆さん、またどこかでお会いしましょう! さようなら。 (連載完)
Copyright © ITmedia, Inc. All Rights Reserved.