AKI-H8のCクロスコンパイラ環境でのプログラミング
シリアルコミュニケーションインタフェイスCH1でリングバッファ+割り込みの実装
自分でスタートアップおよび割り込みベクタテーブルを管理する中級者向け
簡単コマンドh8ccBasic.cmd利用版
Copyright(C)26Jan2004
Copyright(C)18Sep2002
coskx
TNCT
28May2003 updated
1.はじめに
この文書は,Windows2000パソコンにAKI-H8のC言語クロスコンパイル環境での,シリアルコミュニケーションインタフェイスCH1でリングバッファ+割り込みの実装サンプルを記述しています。C言語クロスコンパイラ環境で,C言語によるH8プログラミングを学ぼうとする方が,自分でスタートアップルーチンおよび割り込みベクタテーブルを管理し,プログラミングを行なう良い例題です。
なお割り込みベクタテーブルの管理はアセンブリ言語ファイルで行ない,割り込みルーチンはpragma命令でC言語で書くことにします。
秋月から購入したCコンパイラ環境では出来ませんが,VER2の環境では割り込みベクタテーブルの管理はCのソースファイルでできるようになっていますが,本解説では触れません。
ファイルのダウンロード
プログラムのダウンロード (5.プログラム(テキストデータ用)) |
| |
バイナリデータ受信テストプログラムのダウンロード (6.バイナリデータ受信テストプログラム) |
|
本文書で記述してある作業の特徴
Cプログラムソースファイルが出来上がったら,スタートアップルーチン(アセンブリ言語)と必要なら割り込みベクトルテーブルファイル(アセンブリ言語)をまとめてドラッグアンドドロップを1回行なうだけです。他に何もすることはありません。簡単コマンドを用いるので,作業が効率的です。
前提
(1)秋月から購入したCコンパイラ関係ファイルおよびインクルードファイル,ライブラリファイルはすべて「C:\Program
Files\h8\C」に入っているものとします。
(2)転送ソフト「n-h8w.exe」を利用します。これも「C:\Program
Files\h8\C」に入っているものとします。
h8w.exeはシェアウェアですが10kバイトまではライセンスキー不要で書き込める転送ソフトです。
h8w.exeは,ライセンス登録作業を行なうと,標準でn-h8w.exeに名前が変わり,10kバイトの制限が外れます。この文書では名前が変わった場合の記述をしておりますが,ライセンス取得前の「h8w.exe」でも作業することが出来ます。その場合はh8cc.cmd中の次の個所を変更してください。
なお,この書き込みソフトは(本校)情報工学科の前任助教授の前田先生が作成したものです。前田先生には大変お世話になっております。前田先生は別の名前をつけて使うように勧めていますが,作者に敬意をはらいまして,あえて標準のままにしておきした。
変更前 rem フラッシュメモリ書き込みに使用するプログラムを指定します。
set downloader=n-h8w.exe変更後 rem フラッシュメモリ書き込みに使用するプログラムを指定します。
set downloader=h8w.exe
「h8w.exe」の取得はhttp://www.vector.co.jp/soft/win95/prog/se232247.htmlになります。
注意
2.プログラムの実行
プログラムのコンパイルリンク,H8へのフラッシュメモリ書き込み,実行は次の手順で行なってください。
(1)AKIH8:プログラム受信可にして,電源ONにする。
(2)「SCI1withringbuff_main.c」「IntTbl.src」の3つのファイルをまとめて「h8ccBasic.cmd」上にドラッグ&ドロップする。
(3)プログラムの送信まで無事終了したら,「to_H8.ht」をダブルクリックして「ハイパーターミナル」を立ち上げる。
(4)AKIH8を実行モードで起動する。
(5)最初の文字列が表示された後,ハイパーターミナルからのキーボード受け付け&エコーバックが始まる。
(6)キーボードからスペースが入力されると最初の文字列が表示される。
実行結果(ハイパーターミナル画面)
ABSCI
This is SCI Test with the ring buffer and interrupt.
This is SCI Test with the ring buffer and interrupt.
qqoowwiieemmxxnnzzllzz::112244This is SCI Test with the ring buffer and interrupt.
3.シリアル通信における割り込み
シリアル通信のようにCPUの処理速度に対して遅い作業をプログラム中から行なうと,ほとんどが待ち時間になってしまいます。
そこで,送信時には送信したいデータをバッファにためておき,1byte送信が終わるたびに,送信用割り込み関数を起動し,バッファ内にあるデータを1byte送信する作業を,バッファが空になるまで行なわせれば,プログラムの流れは別な作業ができるようになります。
逆に受信時には1byte受信するたびに受信用割り込み関数を起動させ,受け取ったデータをバッファに格納し,後から別な処理がバッファ内を読み出せば,受信中には,プログラムの流れは別な作業を行なうことが出来ます。
このような作業で用いられるバッファはリングバッファといって,バッファの最後と最初を連結したバッファが用いられます。書き込み場所を示す書き込みポインタと読み出し場所を示す読み出しポインタの2つのポインタがあり,読み出しポインタは書き込みポインタを追いかけながら作業を進めます。ただし,リング状の格納域ですから,お互いに追い越さないように作業します。書き込みポインタが読み出しポインタを追い越すようなら,バッファサイズが小さ過ぎることになります。
なおシリアル通信中のエラー発生時にもエラー発生割り込み関数が起動します。
リングバッファを用いたシリアル通信受信に関して
(1)リングバッファ
リングバッファといえども,バッファはただのメモリの領域(C言語からはunsigned char の配列に見える)です。このバッファに関連したポインタが2つあります。1つは現在バッファ中のどこに書き込んでいるかを示すポインタ[書き込みポインタ](本物のポインタ変数を用いるか,配列要素番号を格納したint型変数を用いる2つの方法があります。実用では本物のポインタ変数を使うのですが,学習のためならint型変数にポインタの役割を負わせ,配列要素番号で指すことにするのがよいでしょう)もう1つは現在バッファ中のどこを読み出しているのかを示すポインタ[読み出しポインタ]です。
正確に言うと[書き込みポインタ]は,次のデータを格納する場所を指しており,[読み出しポインタ]は次にデータを取り出す場所を指しています。
そして,初期状態では,2つのポインタは配列の先頭を指しています。(2)受信割り込み関数
受信バッファフルを割り込み要因とした受信割り込み関数は次のような動作をします。(ただし,割り込み作業に関すること(レジスタの退避など)にはここでは触れません)
1)シリアル通信機能から受信データをもらい,[書き込みポインタ]の場所に格納します。
2)[書き込みポインタ]を1増加させ,次の受信に備えます。ただし,あらかじめ用意されたバッファ領域から外れた場合は先頭に戻し,次の受信に備えます。
3)シリアル通信機能に対し,受信データ貰い受け後に行なうべき処理をします。(3)1文字受信関数
ユーザプログラムから呼び出される,1文字受信関数は次のようになっています。
ユーザプログラムにどのように受信データを渡し,受信データがない時にどうするかはいろいろ方法があるところですが,ANSIのgetchar()を真似すると次のような関数仕様になります。すなわち,受信データが存在するときは受信データを返す。このデータの値の範囲は0〜0xff(0〜255)です。受信データがないときは0xffff(-1)を返すようにします。
実際の作業は
1)[書き込みポインタ]と[読み出しポインタ]が同じ値の時は,受信データが存在しないと考えて-1を返すため,[返す値変数]に-1を格納します。。
2)そうでない時は[読み出しポインタ]の位置にあるデータを返すことにして,[返す値変数]にこのデータを保存します。そして[読み出しポインタ]を1増加させ,次の読み出しに備えます。ただし,あらかじめ用意されたバッファ領域から外れた場合は先頭に戻し,次の読み出しに備えます。
3)[返す値変数]を呼び出し側に返しながらこの関数は終ります。(4)受信バッファオーバーフロー
[読み出しポインタ]は[書き込みポインタ]を追い越すことはないのですが,ユーザプログラムが他の仕事で忙しくてなかなか1文字受信関数を呼び出して受信データを読み出してくれない場合には,[書き込みポインタ]が[読み出しポインタ]を追い越してしまう現象が起こります。(あるいはプログラムを追い越し禁止にしておいて,オーバーフローエラーフラッグを立てることもあります。)
このような場合には受信バッファサイズを大きくしてあげることが必要になります。または,追い越しそうになったらシリアル通信のフロー制御で,相手に待ってもらうことも考えられます。
4.割り込みベクタテーブル
CPUマニュアルによれば,SCI1関係の割り込みベクタテーブルは次のようになっています。「IntTbl.src」の内容で確認してください。
割り込み ベクタ番号 |
割り込み ベクタアドレス |
割り込み 要因の名前 |
割り込み要因 |
56 |
H'00e0 |
ERI1 |
SCI1でオーバーランエラー,パリティエラー,フレーミングエラ−発生 |
57 |
H'00e4 |
RXI1 |
受信バッファフル(受信バッファにデータを受信した) |
58 |
H'00e8 |
TXI1 |
送信バッファエンプティ(送信バッファから送信を完了したので次のデータを要求) |
59 |
H'00ec |
TEI1 |
送信完了(このプログラムでは使用していない) |
5.プログラム(テキストデータ用)
プログラムはヘッダファイルで提供されています。実用時にはCソースファイル+ヘッダファイルの形にしてください。
「StartupBasic.src」は他と共通です。
SCI1withringbuff.h |
/***************************************************************** Interrupt
Vectors extern void E_INT(); /*defined in
"StartupBasic.src"*/ #define RECEIVERINGBUFFSIZE 256 static volatile int receiveptr_in; /*input
pointer for receive*/ /* ---------------------------------- */ /*
------------------------------------------------------------- */ /* ------------------------------------- */ /* ------------------------------------- */ /* ----------------------------------------
*/ /* ------------------------------------- */ |
SCI1withringbuff_main.c |
#include <3048f.h> void putsSCI1_RB(char
*str) main() |
IntTbl.src |
;************************************************************************ .ORG H'0000e0
;ERI1 |
6.バイナリデータ受信テストプログラム
「5.」のプログラム中,関数main()のファイルのみ書き換えてテストします。
SCI1withringbuff_main.c バイナリデータ受信テスト |
#include <3048f.h> |
テストの結果
テキストデータ送信テストの後,「@」を送信することでバイナリ受信テストモードになるため,ホストPC側が00-FFのデータを送信すると,H8側がhex形式で返信してきたところ。最後に「@」を5回送信してテストから抜け出している。
このテストはteratermにて行なわれ,ホストPCの1バイト送信に対して,H8は3バイト返信するため,H8の受信バッファがあふれてしまう。
そこでteraterm側で1バイト送信するごとにwaitを入れてテストしている。
バイナリデータ受信テストの結果 |
@ |