ルネサスの純正開発環境HEWを使って,秋月H8マイコン・マザーのLCDでprintf関数を使う方法
(秋月電子,AKI−H8/3048F−ONEマイコンボードを例にします。クロック25MHzです。)

2012/09/13 matsu 作成
<参考文献>
http://xythos.tokyo-ct.ac.jp/usr/kosaka/web/for_students/H8_3048fone_HEW/H8_3048fone_TNCT_HEW.html

1.開発環境のダウンロードとインストール

(1) ルネサスに登録
 http://japan.renesas.com/myrenesas/ に接続して,新規登録でメールアドレスを登録します。

(2) 開発環境ダウンロード
 http://japan.renesas.com/products/tools/evaluation_software/downloads.jsp で,「H8SX,H8S,H8コンパイラパッケージ」を探してダウンロードします。2012/09/13の時点で,【無償評価版】H8SX,H8S,H8ファミリ用C/C++コンパイラパッケージ V.7.00 Release 00 が最新版です。

(3) 開発環境インストール
 普通にインストールします。

2.プログラムをH8に転送するアプリ「H8ライター」のインストール

(1) H8ライターダウンロード
 yamasan氏のフリーソフトをダウンロードする。http://ym3.plala.jp/yamasan/ に接続して,H8ライター(書き込み制御プログラム含)H8W_*****.zip (*** KB)をダウンロード。2012/09/13の時点で,H8ライター(書き込み制御プログラム含)H8W_038b4.zip (229 KB) が最新版です。

(2) H8ライターインストール
 デスクトップ上で解凍しただけでもかまいませんが,適当な場所にインストールします。Windows 7 64bitの場合,C:\Program Files (x86) が適当と思われます。ダウンロードしたzipファイルを解凍してできたH8Wフォルダをそのまま,C:\Program Files (x86) に移動してください。さらに,スタートメニューに登録するとよいでしょう。C:\ProgramData\Microsoft\Windows\Start Menu\Programs\ を開いて,H8Wフォルダを作り,そこにH8Wフォルダのショートカットや,h8w.exeのショートカットを作っておきます。

(3) H8ライターを制御して一発で書き込む準備
 次の内容のファイルを作ります。拡張子は「.cmd」または「.bat」としてください。どちらでも差はありません。下の内容は,「H8/3048BF-ONEマイコン」の場合で記述しています。詳細は,C:\Program Files (x86)\H8W\CTRL_MOT にある,「添付書き込み制御ファイル.txt」を参照してください。たとえば,ファイル名を「H8-3048Fone.cmd」として,内容を次のようにします。

rem カレントドライブ・カレントディレクトリへ移動
%~d1
cd %~p1

rem ★フラッシュメモリ書き込みに使用するプログラム
set downloader="C:\Program Files (x86)\H8W\h8w.exe"
rem ★フラッシュメモリ書き込みのためのCOMポート番号を設定します
set ComPortNumber=1

echo [AutoPgm] >myAutoPgm.ini
echo AutoStart=1 >>myAutoPgm.ini
echo AutoExit=1 >>myAutoPgm.ini
rem ★マイコンのCPU指定,「添付書き込み制御ファイル.txt」を参照
echo CtrlProgam=3048B_F25M_P384.MOT >>myAutoPgm.ini
echo ComPortNo=%ComPortNumber% >>myAutoPgm.ini
echo UserMotPath=%1 >>myAutoPgm.ini
echo on
%downloader% -GO .\myAutoPgm.ini
@echo off
del myAutoPgm.ini


 ★の部分は,各自の環境に合わせてください。COMポートはデバイスマネージャを開き,使用しているシリアルポートが,COMの何番であるかを確認します。私の環境ではCOM1でしたので,「1」としています。
 やっていることは,h8w.exeを実行する条件をmyAutoPgm.iniに書き込んで,h8w.exeを実行後,myAutoPgm.iniを削除しています。この「goH8-3048Fone.cmd」をデスクトップにでもおいて,HEWで作成した「….mot」ファイルを「goH8-3048Fone.cmd」のアイコンにドラッグ&ドロップすると,マイコンに書き込んでくれます。もちろん,マイコンは書き込みモードにして電源を入れてください。書き込み後はいったん電源を落とし,実行モードにして電源を入れると動作します。

3.HEWによる開発

(1) HEWを起動します。
 新規を選択します。すでに作ってあるプロジェクトワークスペースでもかまいませんが,新規の方がわかりやすいでしょう。過去に作ったアプリと類似のものを作るなら,同じプロジェクトワークスペースの方がわかりやすいと思います。



(2) ワークスペース名とプロジェクト名の設定
 ワークスペース名は,作業する領域の名前です。どんな名前でもかまいません。プロジェクト名はこれから作成するアプリの名前を指定します。ディレクトリですが,デフォルトの「C:\WorkSpace」の配下だと,バックアップを忘れてしまうことも多いので,Windows 7のバックアップツールで標準的にバックアップしてくれる,マイドキュメント配下の方がよいでしょう。下の例では,マイドキュメントの下にHEWというフォルダを手動で作っておき,「参照」でそのフォルダを指定。ワークスペース名にWorkSpaceLCDを入力。プロジェクト名にはprintf1を指定しました。



(3) CPUのシリーズとタイプの設定
 CPUのシリーズとタイプを指定します。「300H」「3048F」です。これはCPUにより異なりますので,シリーズやタイプは各マイコンボードのCPUの種類により変更します。
(300H:AKI-H8/3048,AKI-H8/3052,AKI-H8/3069など,300:AKI-H8/3664など)
(3048f:AKI-H8/3048,AKI-H8/3048f-oneなど)



(4) 動作モードとアドレス空間の設定
 アドレス空間のみ1M byteに変更します。これは,メモリを増設しないモード7でCPUを使用するためです。ライブラリ作成方針は,「コードサイズ優先」でかまいませんが,「スピード優先」にすれば,コードは多少大きくなりますが,速く動作するようになります。



(5) I/Oライブラリ,ヒープメモリ,main()関数生成,等の設定
 標準入出力ライブラリは使わないので,「I/Oライブラリ使用」のチェックを外します。プログラム実行中の動的なメモリ確保(mallocやcalloc)も使用しないので,「ヒープメモリ使用」のチェックも外します。なおH'420は1056バイトです。もともとRAMは4kバイトしかありませんので,ヒープメモリを使う場合は注意してください。
 開発したプログラムは,C言語で開発するので,「C source file」を選択します。「I/Oレジスタ定義ファイル」は使用したいので,チェックを入れておきます。「ハードウェアセットアップ関数生成」は,I/Oの初期化をする関数を自動で作っておきますか? という意味ですが,便利なので作って置きましょう。「C/C++ source file」を選択します。「次へ」。




(6) ライブラリの選択
 デフォルトで「runtime」, 「new」にチェックが入っていますが,加えて,最低限「string.h」はチェックを入れてください。「ctype.h」,「stdarg.h」,はチェックしなくても,これから紹介するLcdLibは動作してしまいますが,LcdLibのソース中で使っていますのでチェックしておいた方が無難です。なおこれらはあとから,ビルド,Toolchain,標準ライブラリ,カテゴリ:標準ライブラリ,で選択し直すことができます。
 これで設定終了です。「完了」します。




(7) 概要表示
 そのまま,okしてください。


(7) HEWでの設定
 HEWで生成するコードにデバック情報を含むかどうかですが,含むとサイズが大きくなったりします。今回はデバッグ情報は使わないので,「Release」に変更してください。



(7) ハードウェアセットアップ関数生成を選択した人へのTips
 hwsetup.cとresetprg.cを開くとわかるのですが,電源オンで最初に実行されるのがresetprg.cなのですが,main()関数に飛び込む前に,hwsetup.cのHardwareSetup()関数を呼び出してくれています。resetprg.cのリマーク文等を取り除いたプログラムを示します。

 set_imask_ccr((_UBYTE)1);
 _INITSCT();
 HardwareSetup();    // Use Hardware Setup
 set_imask_ccr((_UBYTE)0);
 main();
割り込み禁止
初期化済み変数をROMからRAMにコピー
ハードウェアセットアップ関数の呼び出し
割り込み許可
main()関数へジャンプ 

 main()関数は,作成した「プロジェクト名.c」,今回はprintf1.cにあります。

(8) 割り込み関数の実装に関するTips
 割り込み処理関数のスケルトンが,自動生成されています。ファイル名はintprg.cになります。これをダブルクリックして開くとわかるのですが,ありがたいことに,すべての割り込みベクターが用意されています。たとえば,タイマー0の割り込みであれば,
  __interrupt(vect=24) void INT_IMIA0(void) {/* sleep(); */}
の{内}に割り込みルーチンを書くことになります。
 ここまではいいのですが,上の方を見ると,
  #pragma section IntPRG
があります。これは割り込みプログラムは,メモリのPIntPRGセクションに配置し,変数等のデータはDIntPRGセクションに配置することを意味します。しかし困ったことに,HEWでは,PIntPRGセクションはデフォルトで用意してくれていますが,DIntPRGセクションは用意されていません。自分でビルドメニューにある,Toolchain設定をいじってセクションをセットする必要があります。どうもHEWは割り込みプログラムとその変数を特別なセクションに置きたがっているような感じですが,通常のプログラムと変数等のデータを配置する場所である,PセクションとDセクションを使っても何も問題はありませんので,そうしてしまいましょう。やり方は簡単です。コメントアウトします。
//#pragma section IntPRG
 これだけでもよいのですが,デフォルトで用意されているPIntPRGが使われてないというWarningエラーが出ます。無視してもかまいませんが,気になる場合は,ビルド,Toolchain,最適化リンカ,カテゴリ:セクション,編集,と進んで,PIntPRGを選択して削除します。これで,大手を振って,intprg.c内に割り込みプログラムを書くことができます。下の図は,PIntPRGを消した後の様子です。
 なお,intprg.cを無視して,別のファイルに割り込みプログラムを書く場合は,intprg.c内の当該ベクターの行をコメントアウトします。そうしないと二重定義になってしまい,エラーとなります。




4.タイマー割り込みプログラムを動かす

(1) タイマーの初期化
 hwsetup.cを開いて,次の内容にします。これでITU0を使って100Hzで割り込みがかかります。タイマーをスタート,ストップする関数も追加しています。

#include "iodefine.h"


void initLedP5(void)
{
    P5.DDR=0xff;/*P5-0,1 = LED  High=on*/
}

void initTimer(void) /*タイマーの初期化*/
{
/*100Hzカウントアップ用*/
    unsigned gra=31250;
    ITU0.TCR.BIT.TPSC=3;  /*p358 内部クロック1/8clock でカウント*/
    ITU0.TCR.BIT.CKEG=0;  /*p358 立ち上がりエッジでカウント*/
    ITU0.TCR.BIT.CCLR=1;  /*p358 GRAでTCNTをクリア*/
    ITU0.GRA = gra-1;     /*p356 Timer ch0 25MHz/8/(gra)=100Hz */
    ITU0.TIER.BIT.IMIEA=1;/*p367 GRA割込許可*/
    ITU0.TIOR.BYTE=0x88;  /*p361 端子出力禁止*/
    ITU.TMDR.BYTE =0x80;  /* ch0,1,2,3,4=通常動作*/
}

void timerStart(unsigned num)/*  num= 0-4 */
{
    unsigned char tstr;
    tstr=ITU.TSTR.BYTE;
    tstr|=(0x01<<num);
    ITU.TSTR.BYTE=tstr;
}
void timerStop(unsigned num)/* num= 0-4 */
{
    unsigned char tstr;
    tstr=ITU.TSTR.BYTE;
    tstr&=(~(0x01<<num));
    ITU.TSTR.BYTE=tstr;
}

void HardwareSetup(void)
{
 initTimer();
 initLedP5();

}

コメントは筆者手持ちのハードウェアマニュアルの
ページ番号です。無視してください。 

(2) ヘッダーファイルの追加
 上のhwsetup.cでも動作しますが,mainでtimerStart等を呼び出すと,プロトタイプ宣言がないと怒られます(C0200 (I) No prototype function)。ヘッダファイルを作ってしまいましょう。C:\Users\matsu\Documents\HEW\WorkSpaceLCD\printf1フォルダに,次の内容でhwsetup.hを作ってください。

void initLedP5(void);//LEDのポート5の初期化
void initTimer(void); /*タイマーの初期化*/
void timerStart(unsigned num);//タイマースタート num= 0-4
void timerStop(unsigned num);//タイマーストップ num= 0-4
void HardwareSetup(void);//ポート等の初期化関数
プロトタイプ宣言の集まり。
必要に応じて追加していきます。 

 HEWの左側のペインで,printf1を右クリックし,hwsetup.hを追加します。




(2) 割り込み関数
 割り込みがあった場合に実行するプログラムを書きます。intprg.cを開いて,先頭行に,#include "iodefine.h"を必ず入れてください。ITU0.TSR.BIT.IMFAなどの便利な定義が使えるようになります。この定義はCPUメーカー社員が作った秀逸なヘッダファイルです。
 修正は,タイマー0のGRAコンペアマッチでかかる割り込み,IMIA0,ベクター番号24の部分のみ書き換えます。

#include "iodefine.h"

#include    <machine.h>
//#pragma section IntPRG   //PIntPRGもToolchainから削除
//  vector 1 Reserved

//  vector 2 Reserved

途中略

//  vector 24 IMIA0
extern unsigned count;
__interrupt(vect=24) void INT_IMIA0(void)
{
    count++;
    if(count==100) count=0;
    ITU0.TSR.BIT.IMFA=0;
}
//  vector 25 IMIB0
__interrupt(vect=25) void INT_IMIB0(void) {/* sleep(); */}

途中略

←これを忘れないこと









←vector 24の部分だけ書き換える
←printf1.cで定義したグローバル変数を使う宣言
{/* sleep(); */}となっていた部分を書き換える。








 



(3) main関数
 printf1.cを開いて,次の内容にします。2行目でhwsetup.hを取り込んでいますが,これはtimerStart関数の使い方を示すプロトタイプ宣言を取り込んで正しく使われているか,コンパイラにチェックさせるためです。この行がない場合はチェックできないので「C0200 (I) No prototype function」という警告エラーが出ます。

#include "iodefine.h"
#include "hwsetup.h"

volatile unsigned count=0;/*割り込み関数でカウントアップ*/

void main(void);

void main(void)
{
   
    timerStart(0);
    while(1){
        if(count<50) P5.DR.BIT.B0=1;//led on
        else P5.DR.BIT.B0=0;    //led off

    }


}

←忘れないこと。
←作ったhwsetup.hをインクルード

←割り込み関数でカウントアップしてもらう変数

←main関数のプロトタイプ宣言。消さない

←main関数の始まり 


←タイマーの初期化,割り込み速度のセット等
←無限ループ
←LEDを1秒周期で点滅






(4) ビルドしてマイコンに書き込み
 さて,ここまできて,やっとマイコンが動作します。ビルド,すべてをビルド,してください。編集中のファイル以外変更がない場合は,F7キーを押すだけでもOKです。エラーがなければ,C:\Users\matsu\Documents\HEW\WorkSpaceLCD\printf1\Releaseフォルダに,printf1.motができているはずです。そのmotファイルを「goH8-3048Fone.cmd」にドラッグ&ドロップすると,マイコンにプログラムが書き込まれますが,その前に,マイコンを書き込みモードにして,電源を入れるのを忘れないでください。無事書き込みが終わったら,マイコンの電源を落とし,実行モードにして電源を入れます。LEDが点滅するはずです。


<例題>
 割り込みを1ms周期に変更し,さらに,LED点滅周期は1秒のままとせよ。


5.printf等を使う

 前置きが長くなってしまいました。printf関数を使ってみましょう。割り込みプログラムはもちろんなくても動作します。

(1) 必要なファイルの取り込み
 添付のLcdLib.hとLcdLib.cをプロジェクトのフォルダにコピーします。HEWの左側のペインで,printf1を右クリックし,「ファイルの追加」から,LcdLib.hとLcdLib.cを取り込んでください。 



(2) mainの書き換え
 printf1.cを次のように書き換えます。LcdLibを使うことで便利な関数が使えるようになります。ビルドしてmotファイルを書き込むとLCDの1行目にHelloと表示され,2行目には,World!と表示されます。

#include "iodefine.h"
#include "hwsetup.h"
#include "LcdLib.h"
                 
volatile unsigned count=0;/*割り込み関数でカウントアップ*/

void main(void);

void main(void)
{
   
    initMotherSystem();
    clrscr();
    gotoxy(0,0);
    printf("Hello");
    gotoxy(0,1);
    printf("World!");
   
    timerStart(0);
    while(1){
        if(count<50) turnOnLed(RIGHT);//led on
        else turnOffLed(RIGHT);    //led off

    }


}



←忘れないこと。



←main関数のプロトタイプ宣言。消さない

←main関数の始まり 


←マザーを使うための全初期化
←LCD画面クリア
←1行目の先頭にカーソル移動
←Helloを表示
←2行目の先頭にカーソル移動
←World!を表示



←右側LEDを点灯
←右側LEDを消灯






(3) 使うマザーやマイコンによりLcdLib.hの一部書き換え
 LcdLib.hの先頭が次のようになっています。使用する,マザーおよびマイコンについて,それぞれどれか一つをリマークを外し,有効にしてください。このサンプルでは,東京高専製のマザーMD_M52F_48F1と ,マイコンH8_3048FONEが有効になっています。

//マザーの種類により次のどれか一つを有効にすること
#define MD_M52F_48F1   //東京高専製マザー,AE_H8MBと完全互換で二つのLEDの左右が逆
// #define AE_H8MB     //秋月電子製
// #define AKI_H8_USB  //秋月電子製

//マイコンの種類により次のどれか一つを有効にすること
#define H8_3048FONE   //25MHz
//#define H8_3048F16  //16MHz
//#define H8_3052F25  //25MHz

←マザーを選択




←マイコンを選択



(4) Tera Termの設定
 Windows 7ではシリアル通信を手動でテストできるターミナルソフトHyper Terminalが付属しなくなってしまいました。しかたないので,有名なTera Termを使ってみます。Tera Termは2012/10/22の時点で,4.75が最新です。http://www.vector.co.jp/soft/dl/win95/net/se320973.htmlからダウンしてください。リンク切れの場合は,Tera Termで検索してください。
 ダウンロードして,デスクトップにでも保存して,ダブルクリックすればインストールできます。起動すると,次のウィンドゥが出てきます。



 今回,シリアル通信を使って,パソコン側にprintfで表示するので,次のように変更します。COMポートは各自の環境に合わせてください。私の場合は,COM1を選択しました。OKをクリックします。



 設定,シリアルポート,を選択して,シリアルポートの設定を次のように修正してください。ボーレートを38400に,フロー制御をhardwareにして,OKをクリックします。



 設定,設定の保存,をしておくとよいです。ファイル名はデフォルトのTERATERM.INIのまま,上書きでかまいません。これで設定はおしまいです。一旦,ファイル,接続断,をしておいてください。再接続は,ファイル,新しい接続,です。あるいはTera Termを終了しておいてください。再度起動させると,自動的に保存した条件で接続されます。

(5) Tera Termにprintfで表示
 printf1.cを次のように書き換えます。

#include "iodefine.h"
#include "hwsetup.h"
#include "LcdLib.h"
                 
volatile unsigned count=0;/*割り込み関数でカウントアップ*/

void main(void);

void main(void)
{
    unsigned i;
    initMotherSystem();
    clrscr();
    gotoxy(0,0);
    printf("Hello");
    gotoxy(0,1);
    printf("World!");
    seldevice(SCI_1);
    printf("Hello World!\n");
    for(i=0;i<10;i++){
        printf("i=%2u\n",i);
    }
    seldevice(LCD);

    timerStart(0);
    while(1){
        if(count<50) turnOnLed(RIGHT);//led on
        else turnOffLed(RIGHT);    //led off

    }


}



←忘れないこと。



←main関数のプロトタイプ宣言

←main関数の始まり 


←マザーを使うための全初期化
←LCD画面クリア
←1行目の先頭にカーソル移動
←Helloを表示
←2行目の先頭にカーソル移動
←World!を表示
←printf出力先をデフォルトのLCDからSCI_1に変更
←Hyper Terminalに表示
←Hyper Terminalに1-10を表示


←printf出力先をLCDに戻す



←右側LEDを点灯
←右側LEDを消灯





 このプログラムをビルドしてmotファイルを書き込んで実行すると,Tera Termに次のように表示されます。




6.printfリファレンスマニュアル

(1) 全システムの初期化
void init_mother_system(void);          /*マザーボードシステムの初期化*/
void initMotherS
ystem(void);          /*マクロ,init_mother_systemと同じ*/

 サンプルプログラムtest.cでも実行していますが,必ずmain関数の始めにこの関数を実行してください。この関数により,LCD,SCI1その他のデバイスが初期化されます。各ポートは次のように初期化されます。これらのポートのうち特に,AE-H8MBの場合P3.DDR,AKI-H8-USBの場合PB.DDRについては,各ユーザープログラム上で設定変更しないでください。変更すると本ライブラリは動作しません。AE-H8MBの場合で,タクトスイッチがつながっているP4は,プルアップ設定にしないと正しくスイッチの状態が読み込めませんので,そのようになっています。

<AE_H8MB,MD_M52F_48F1の場合>
{
    P2.DDR=0x00;/*P2-0-7 = ディップSW LOW=on*/
    P2.PCR.BYTE=0xff;/*P2-0-7 Pull Up 設定*/
    P3.DDR=0xff;/*port3(lcd) = all output*/
                /*NC,NC,E,RS,D7,D6,D5,D4*/
    P4.DDR=0x00;/*P4-4-7 = タクトSW LOW=on*/
    P4.PCR.BYTE=0xff;/*P4-4-7 Pull Up 設定*/
    P5.DDR=0xff;/*P5-0,1 = LED  High=on*/
}
<AKI_H8_USBの場合>
{
    PA.DDR=0x00;/*PA-0-3 = ディップSW LOW=on*/
    PB.DDR=0xff;/*port3(lcd)= all output*/
                /*E,NC,NC,RS,D7,D6,D5,D4*/
}

 シリアルコミュニケーションインターフェース1は,次のように初期化されています。これを設定変更すると,Hyper Terminalへの出力ができなくなりますので,SCI1を他の用途に使う場合以外はユーザープログラムで変更しないでください。

<H8_3048F16の場合>
{
    unsigned char dummy;
    SCI1.SCR.BYTE=0x00; /*P497 割り込み・送受信禁止*/
    SCI1.SMR.BYTE=0x00; /*P491 調歩同期 データ長8bit NoParity StopBit 1*/
    SCI1.BRR=12;        /*P504 ビットレートレジスタの設定38400bps CPU=16MHz*/
    waitus(50);         /*1/38400s待つ*/
    SCI1.SCR.BYTE=0x30; /*P495送受信動作を許可*/
    dummy=SCI0.SSR.BYTE;/*p499ダミーリード*/
    SCI1.SSR.BYTE=0x80; /*P497 エラーフラグをクリア1000 0000*/
}

<H8_3052F25,H8_3048FONEの場合>
{
    unsigned char dummy;
    SCI1.SCR.BYTE=0x00; /*P497 割り込み・送受信禁止*/
    SCI1.SMR.BYTE=0x00; /*P491 調歩同期 データ長8bit NoParity StopBit 1*/
    SCI1.BRR=19;        /*P504 38400bps CPU=16MHz:12, 25MHz:19 3052f*/
    waitus(50);         /*1/38400s待つ*/
    SCI1.SCR.BYTE=0x30; /*P495送受信動作を許可*/
    dummy=SCI0.SSR.BYTE;/*p499ダミーリード*/
    SCI1.SSR.BYTE=0x80; /*P497 エラーフラグをクリア1000 0000*/
}

(2) LED関連
typedef enum{RIGHT,LEFT,ALL} led_type;/*←マザーにより内容は異なります*/
void ledon(led_type sel);               /*LED ON*/
void ledoff(led_type sel);              /*LED OFF*/

 LEDを点灯・消灯させます。AE-H8MBは2個,AKI-H8-USBは4個のLEDが搭載されています。引数にはright, left, allの他,各LEDに対応するビットを1にした16進数を指定することもできます。
使用例:
ledon(ALL);・・・すべてのLEDを点灯します(AE_H8MB, MD_M52F_48F1, AKI_H8_USB)。
ledon(0x3);・・・すべてのLEDを点灯します(AE_H8MB, MD_M52F_48F1)。右側二つのLEDを点灯します(AKI_H8_USB)。
ledon(0xf);・・・すべてのLEDを点灯します。(AKI_H8_USB)
ledon(RIGHT);・・・一番右側のLEDを点灯します。(AE_H8MB, MD_M52F_48F1, AKI_H8_USB)
ledon(LEFT);・・・一番左側のLEDを点灯します。(AE_H8MB, MD_M52F_48F1, AKI_H8_USB)
ledon(0x1);・・・一番右側(AKI_H8_USB, MD_M52F_48F1),左側(AE_H8MB)のLEDを点灯します。
ledon(0x7);・・・右側3つのLEDを点灯します。(AKI_H8_USB)
ledoff(0x1);・・・一番右側(AKI_H8_USB, MD_M52F_48F1),左側(AE_H8MB)のLEDを消灯します。

(3) 待ちループ
void waitms(unsigned ms);               /*msec待ちループ*/
void waitus(unsigned us);               /*μsec*/

 LCDやSCI1の初期化のために用意した待ちループです。もちろん汎用に使えます。ms, usの値は65535まででmsまたはμs単位でwaitします。割り込みがない場合の実測値は,次の通りです。

<3048F16の場合>
waitms(1000);  1.02s
waitms(100);   100.00ms
waitms(10);    10.20ms
waitms(1);     1.00ms
waitms(0);     2.88us
-
waitus(10000);   10ms
waitus(1000);  1000us
waitus(100); 104.00us
waitus(10);   13.20us
waitus(5);     8.40us
waitus(1);     4.50us
waitus(0);     3.50us

<3052F25の場合>
waitms(100); 100.00ms
waitms(10);    10.00ms
waitms(1);       1.00ms
waitms(0);       1.76us
-
waitus(1000); 960.00us
waitus(100);   96.00us
waitus(10);    12.40us
waitus(1);       3.60us
waitus(0);       2.80us


使用例:LCDを左右交互に点滅させます。
#include "iodefine.h"
#include "hwsetup.h"
#include "LcdLib.h"
void main(void);
void main(void)
{
    init_mother_system();
    while(1){
        ledon(RIGHT); ledoff(LEFT);
        waitms(500);
        ledon(LEFT); ledoff(RIGHT);
        waitms(500);
    }
}

(4) 出力デバイス設定関数
typedef enum{ LCD, SCI_1 } devType;
void seldevice(devType device);         /*出力先の選択*/
typedef enum{ C16L2, C20L4 } sizeType;
void lcdsize(sizeType size);    /*出力先の選択*/

 後述のprintf関数の出力先(LCDユニット:LCD,Hyper Terminal:SCI_1)を設定します。またLCDのサイズ(16桁2行:C16L2,20桁4行:C20L4)を設定します。上述のinit_mother_system();ではデフォルトで次のように設定されます。必要に応じて変更してください。
    seldevice(LCD); /*デフォルト*/
    lcdsize(C16L2); /*デフォルト*/

使用例:Hyper Terminalに"Hello World"を出力します。
#include "iodefine.h"
#include "hwsetup.h"
#include "LcdLib.h"
void main(void);
void main(void)
{
    init_mother_system();
    seldevice(SCI_1);
    printf("Hello World");
    while(1);
}

使用例:16桁2行のLCDに"Hello World"を出力します。
#include "iodefine.h"
#include "hwsetup.h"
#include "LcdLib.h"
void main(void);
void main(void)
{
    init_mother_system();
    seldevice(LCD);
    lcdsize(C16L2);
    clrscr();
    printf("Hello World");
    while(1);
}

(5) LCD専用関数
void clrscr(void);                      /*LCD画面クリア*/
void gotoxy(unsigned x,unsigned y);     /*LCDカーソル移動*/

次の6つの関数はVer2.2との互換のために定義したマクロです
void lcdprintc(char c);                 /*LCD表示,1文字*/
void lcdprints(char *data);             /*LCD表示,文字列*/
void lcdprintx(unsigned char data);     /*LCD表示,小文字16進*/
void lcdprintX(unsigned char data);     /*LCD表示,大文字16進*/
void lcdprintb(unsigned char data);     /*LCD表示,2進*/
void lcdprintub(unsigned char data);    /*LCD表示,2進上位4ビット*/
void lcdprintlb(unsigned char data);    /*LCD表示,2進下位4ビット*/

clrscr・・・LCD画面をクリアします。
gotoxy・・・LCD上でカーソル移動します。なおカーソルは見えません。
lcdprintc・・・LCDに1文字表示します。
lcdprints・・・LCDに文字列を表示します。文字列中に\nがあっても対応します。
lcdprintx・・・dataを16進数二桁小文字表示します。
lcdprintX・・・dataを16進数二桁大文字表示します。
lcdprintb・・・dataを2進数8桁表示します。
lcdprintub・・・dataの上位4ビットをを2進数4桁表示します。
lcdprintlb・・・dataの下位4ビットをを2進数4桁表示します。

使用例:
#include "iodefine.h"
#include "hwsetup.h"
#include "LcdLib.h"
void main(void);
void main(void)
{
    init_mother_system();
    seldevice(LCD);
    lcdsize(C16L2);
    clrscr();
    gotoxy(0,0); lcdprints("Hello");
    gotoxy(6,0); lcdprints("World");
    gotoxy(0,1); lcdprints("LCD");
    gotoxy(4,1); lcdprints("Library");
    while(1);
}

(6) printf,sprintf, devprintf関数
void printf(const char *format,...);    /*書式付き出力*/
void sprintf(char *buffer, const char *format,...);
typedef enum{ LCD, SCI_1 } devType;
void devprintf(devType device,const char *format,...);/*出力先の選択付きprintf*/

 通常のC言語のprintf, sprintf関数と同じ動作をします。但し,値は返しません。devprintf関数は,一時的に出力デバイスを指定のものに変更して出力します。
 なお,char又はunsigned char型データの2進数表示に関して,%bが拡張されています。指定された印字幅を超える桁数となった場合,通常は印字幅は無視されますが,%bに関しては下位ビットから指定された幅数(桁数)のみの表示となります。下にサンプルをたくさん用意しましたので,確認してください。

   書式指定   %[flags][width][.prec][prefix]type

 書式指定については,変換指定文字typeに対して,8進数(o),浮動小数点数(f,e,E,g,G),ポインタ(n,p)以外すべてに対応しています。また2進数(b)が拡張されています。精度指定子[.prec]は対応していません。印字幅指定子[width]とフラグ文字[flags]には完全対応しています。エスケープシーケンスは,\\, \n, \r に対応しています。

使用例:添付のサンプルプログラムtest.c。実行結果は6(7)参照。

#include "iodefine.h"
#include "hwsetup.h"
#include "LcdLib.h"
void main(void);
void main(void)
{
    unsigned i;
    char s[17];
    init_mother_system();
    seldevice(LCD); lcdsize(C16L2);
    clrscr();
    gotoxy(0,0); printf("Hello!");
    for(i=0;i<20;i++) devprintf(SCI_1,"%5u %04x %016b\n",i,i,i);
    gotoxy(0,1); sprintf(s,"%d year",2002); printf("%s",s);

    while(1){
        ledon(RIGHT);ledoff(LEFT);waitms(250);
        ledon(LEFT);ledoff(RIGHT);waitms(250);
    }
}

 以下,サンプルです。

<サンプル(Turbo C Ver5.01J と同じ結果になることを確認済)>

プログラム 実行結果
printf("test%s","str"); [teststr]
printf("test%5s","str4567890"); [teststr4567890]
printf("test%-5s@","str"); [teststr  @]
printf("test%5s","str"); [test  str]
printf("test%c",'c'); [testc]
printf("test%-5c@",'c'); [testc    @]
printf("test%5c",'c'); [test    c]
printf("test%X",(unsigned)35243); [test89AB]
printf("test%-#8X@",0x89ab); [test0X89AB  @]
printf("test%5X",0x89ab); [test 89AB]
printf("%lx",4294967295); [ffffffff]
printf("%-#14lX@",16777215); [0XFFFFFF      @]
printf("%#12lx",16777215); [    0xffffff]
printf("%#012lx",0x12341234); [0x0012341234]
printf("%u",(unsigned)0xffff); [65535]
printf("%-8u@",(unsigned)65535); [65535   @]
printf("%8u",(unsigned)65535); [   65535]
printf("%d",32767); [32767]
printf("% 8ld@",-32769); [  -32769@]
printf("%- 8ld@",32768); [ 32768  @]
printf("%-+8ld@",32769); [+32769  @]
printf("% -8ld@",32768); [ 32768  @]
printf("%+-8ld@",32769); [+32769  @]

<サンプル 2進数に関してオリジナル拡張,8bit型(char, unsigned char)のみ>

プログラム 実行結果
printf("%08b",0x5c); [01011100]
printf("%8b",0x5c); [ 1011100]
printf("%4b",0x5c); [1100]
printf("%3b",0x5c); [100]

 

(7) puts,purchar関数
void puts(char *s);
void putchar(char c);

 通常のC言語のputs関数,putchar関数と同じ動作をします。マクロです。値は返しません。どちらの関数も,上述のseldevice関数で指定されたデバイスに出力します。putsでは改行文字が出力されます。

(8) putc関数
typedef enum{ LCD, SCI_1 } devType;
void putc(char c,devtype dev);

 通常のC言語のputc関数と同様の動作をします。指定したデバイスに1文字出力します。マクロです。値は返しません。

使用例:1行目に"Start",2行目に"End"を表示。
#include "iodefine.h"
#include "hwsetup.h"
#include "LcdLib.h"
void main(void);
void main(void)
{
    init_mother_system();
    seldevice(LCD);
    lcdsize(C16L2);
    clrscr();
    puts("Start");
    putchar('E');
    putc('n',LCD);
    putc('d',LCD);
    while(1);
}

(9) 整数→文字列変換関数
char *ctoa(char value, char *string, int radix);          /*stringはmax9byte*/
char *uctoa(unsigned char value, char *string, int radix);/*stringはmax9byte*/
char *itoa(short int value, char *string, int radix);     /*stringはmax17byte*/
char *uitoa(unsigned short value, char *string, int radix);/*stringはmax17byte*/
char *ltoa(long value, char *string, int radix);          /*stringはmax33byte*/
char *ultoa(unsigned long value, char *string, int radix);/*stringはmax33byte*/

 valueをヌル('\0')で終わる文字列に変換して,結果をstring内に格納します。valueはすべて整数型です。radixは,valueを変換する基数を示します。radixは,2以上の値を指定します。valueが負でradixが10であれば,stringの最初の文字はマイナス符号になります。各関数ともstringを指すポインタを返します。

ctoa・・・char型のvalueを基数radixで文字列に変換し,stringに格納します。
uctoa・・・unsigned char型のvalueを基数radixで文字列に変換し,stringに格納します。
itoa・・・short int型のvalueを基数radixで文字列に変換し,stringに格納します。
uitoa・・・unsigned int型のvalueを基数radixで文字列に変換し,stringに格納します。
ltoa・・・long int型のvalueを基数radixで文字列に変換し,stringに格納します。
ultoa・・・unsigned long int型のvalueを基数radixで文字列に変換し,stringに格納します。

 なお,stringに割り当てられる領域は,最後のヌル('\0')も含めて,返される文字列を格納するのに十分な大きさ(radixが2の時必要となる大きさ)がなければなりません。
ctoa・・・stringの大きさは,最大9バイト必要
uctoa・・・stringの大きさは,最大9バイト必要
itoa・・・stringの大きさは,最大17バイト必要
uitoa・・・stringの大きさは,最大17バイト必要
ltoa・・・stringの大きさは,最大33バイト必要
ultoa・・・stringの大きさは,最大33バイト必要

使用例:unsigned int型のデータを2進数に変換

#include "iodefine.h"
#include "hwsetup.h"
#include "LcdLib.h"
void main(void);
void main(void)
{
    unsigned num=12345;
    char s[17];
    init_mother_system();
    seldevice(LCD);
    lcdsize(C16L2);
    clrscr();
    gotoxy(0,0); printf("%16s",uitoa(num,s,2));
    gotoxy(0,1); printf("%08b%08b",(char)(num>>8),(char)num);
    while(1);
}

.謝辞
 本ライブラリの開発にあたり,kosaka氏にたくさんアドバイスを頂きました。感謝いたします。

8.バージョンアップ履歴
3.8->4.0
 ・HEW開発環境に対応,ソースリストの完全公開
3.7->3.8
 ・AE_H8M8使用時,Port Bに不正アクセスする場合があったバグをフィクス

3.6->3.7  2002/10/20
 ・AKI-H8-USB/LANマザー,H8/3052Fに対応。
3.5->3.6  2002/06/23
 ・sprintfのバグのフィクス(よけいな文字が後ろに出力されることがあった)。
 ・lcd関係の若干の改良。
3.4->3.5  2002/05/15
 ・ライブラリの小型化(ルーチンの改良,7160バイト→6282バイト)。
 ・sprintfの実装。
 ・マニュアルの訂正。
3.3->3.4  2002/04/18
 ・マニュアルの訂正。
3.0->3.3  2002/04/18
 ・printf("%%%3d%%",100);で,[%%100%]と表示されてしまうバグをフィクス。正解は[%100%]。
 ・電源投入時にマイコンが動作しない可能性があるバグをフィクス。(変数の初期化ミス。)
2.2->3.0  2002/04/01
 ・20桁×4行のLCDに対応。
 ・wait関数の改良。
 ・ANSI準拠のprintf関数を実装。
 ・LCDユニットだけでなくWindowsのHyper Terminalへもprintf関数で出力を可能にした。
2.1->2.2 1998/12/27
 ・小坂氏のレポートを追加。
2.0->2.1 1998/12/25
 ・リンカの設定ファイル内のSTART設定の解説を追加(readme2.txt)。
1.4->2.0 1998/12/22
 ・clrscr(); 実行直後,gotoxy関数を実行すると表示が不正になるバグをフィクス。
 ・タクトスイッチがつながっているポート(P4 7/4)の読みとり値が不正になるバグをフィクス。

9.感想・質問・ご要望など問い合わせ先
 以下まで必ずメールにてご連絡ください。
 松林: matsu@tokyo-ct.ac.jp