AKI-H8(HitachiH8/3664f)の使い方
LED,SCI,PWM,ADCによるプログラミング
Copyright(C) 21Nov2003
Copyright(C) 7Nov2002
coskx
1. はじめに
1.1 この文書の構成
この文書はH8/3664fのCプログラムをコンパイルする方法,AKI-H8/3664fにフラッシュメモリ書き込み(転送)する方法を修得した学習者が,AKI-H8/3664fのマザーボードを用いてLEDをつけたりSCIでホストPCと通信するプログラムを学習するための文書です。
1.2
AKI-H8(HitachiH8/3364f)
AKI-H8/3664f(図1.1参照)は日立製作所の製品であるマイクロコンピュータH8製品群のH8/3664fを用いて,秋月電子通商がCPUボード,ベースボードを製作販売している製品の商品名です。購入したキットの説明書通り製作しても何も出来ない上,9V電池駆動なので不便です。そこで,LEDを付加し,電源もACアダプタが使えるようにしました。ACアダプタが供給する電圧範囲は7Vから12V程度がよいでしょう。
図1.1 AKI-H8/3664f 電源部,LED部は独自仕様 |
図1.2 AKI-H8/3664f 電源部,LED部は独自仕様 |
図1.3 ベースボード電源部 |
図1.4 LED拡張部 |
図1.5 ベースボードシリアル通信DSUB9コネクタ部 |
AKI-H8/3664fでのプログラミングはパソコン上で次のように行ないます。
(1)
C言語またはアッセンブリ言語でプログラムを開発後
(2)
コンパイル・リンクを行ない実行プログラムファイルを作ります
(3)
ロードモジュールに変換します
(4)
RS232C通信でロードモジュールをH8/3664fに送信(フラッシュメモリに書き込む)
(5) 実行
1.3 以下で扱うプログラムのダウンロード
ダウンロードはここです |
2.LEDの点灯
H8_3664.hで定義された関数を用いてLEDの点滅を行なうプログラム。
ledtest.c |
/*LED点灯プログラム*/ void msecwait(int
msec) main() |
3.シリアル通信でホストPCと通信
H8_3664.hで定義された関数を用いてシリアル通信でホストと交信する。 scitest.c /*シリアル通信でホストと交信する*/ main()
ホストPC(Windowsマシン)では,ハイパーターミナルなどのターミナルソフトを起動しておく。
#include
"H8_3664.h"
{
int
ch;
initSCI();
/*シリアル通信インタフェイスの初期化
38400baud, Async, 8bit , NoParity, stop1*/
SCI_printf("****** SCI test ******\n");
SCI_printf("Hit any character key\n");
while (1)
{
ch=getCharSCI();
/*1文字取得*/
putCharSCI(ch+1);
/*1文字送信*/
SCI_printf("
test %d %d
%x\n",1234,9876,ch);
SCI_printf(" %c %s
%lx\n",'#',"hello",0x80804040L);
SCI_printf(" %s %c
%lx\n","hello",'#',0x80804040L);
}
}
4.タイマー割り込みでLED点灯制御
通常の関数は,関数がプログラム中の他の関数から呼び出されたときに作業を行ないます。これに対して,割り込み関数は何らかの割り込み要因によって呼び出される関数です。
タイマ割り込み関数は,タイマ割り込み初期設定によって設定された時間間隔で起動する割り込み関数です。ここのプログラムでは,約33msのタイマ割り込み初期設定が行なわれ,CPUの割り込み許可がなされ,タイマがスタートした後,プログラムの流れは
while(1);
となり,無限ループに突入します。しかし,33ms(0.033秒)ごとにタイマ割り込み関数「interrupt_cfunc()」が起動し,cntの値が0から29まで増加しては0に戻るという動作が繰り返され,LEDのON−OFFが継続して行なわれます。変数cntはvolatile修飾されているので,変数が呼び出されたときに,必ずメモリから呼び出されます。(コンパイラにより最適化がなされると,一度メモリからレジスタに呼び出された変数は,メモリを参照されなくなる可能性があり,volatile修飾子をつけておくとこの現象を回避できます。)
ロボットの制御には一定時間ごとに起動する定時間割り込み(タイマー割り込み)が良く用いられます。またPWMの生成にもこの定時間割り込みが用いられる場合があります。
小坂のシステムを用いる限り,タイマ割り込み関数「interrupt_cfunc()」の名前を変更してはいけません。関数の内容は変更してもOKです。
H8_3664.hで定義された関数を用いてタイマー割り込みを起動し,LEDの点滅制御を行なうプログラム。
intledtest.c |
/*タイマー割り込みを起動し,LEDの点滅制御を行なう*/ volatile int cnt=0; main() /*割り込み関数 関数名は変更してはならない*/ |
H8_3664.hで定義された関数を用いてタイマー割り込みを起動し,LEDの点滅制御を行なうプログラム。
点滅動作はPWM駆動されている。
PWMintledtest.c |
/*タイマー割り込みを起動し,LEDの点滅制御を行なう*/ volatile int cnt=0; void msecwait(int
msec) main() /*割り込み関数 関数名は変更してはならない*/ |
5.タイマーWユニットを用いて2系統PWM出力生成
タイマーWユニットを用いると3系統のPWM信号出力を行なうことができるが,このプログラムでは2系統のみ出力する。
initTimerWPWM(1000)では,システムクロック1000カウントを1周期とするPWM信号を出力するようにTimerWを初期化する。
setPWMValueB(700)では,FTIOB端子にデューティ比700/1000のPWM信号を出すように設定する。
setPWMValueC(400)では,FTIOC端子にデューティ比400/1000のPWM信号を出すように設定する。
pwmtest.c /*「TimerW」を用いた2系統PWM出力*/ void msecwait(int
msec) main()
#include
"H8_3664.h"
/*msec間なにもしない時間稼ぎ関数*/
{
int
i,j;
for (i=0;i<msec;i++)
{
for
(j=0;j<1588;j++);
/*1588は実測によって求めた値*/
}
}
{
int
ch;
initSCI();
initTimerWPWM(1000); /*TimerWの2系統PWM出力の初期化*/
/*約16kHzの周期のPWM信号が発生される16MHz÷1000*/
while (1)
{
setPWMValueB(1000);
/*B系統に1000/1000*/
setPWMValueC(1000);
/*C系統に1000/1000*/
putStringSCI("PWM
1000/1000\n");
msecwait(3000);
setPWMValueB(700);
/*B系統に700/1000*/
setPWMValueC(700);
/*C系統に700/1000*/
putStringSCI("PWM
700/1000\n");
msecwait(3000);
setPWMValueB(400);
/*B系統に400/1000*/
setPWMValueC(400);
/*C系統に400/1000*/
putStringSCI("PWM
400/1000\n");
msecwait(3000);
}
}
6.AD変換
6.1 シングルモードAD変換
シングルモードAD変換を行なう。シングルモードAD変換ではADCの初期化はその都度行なわれるので。プログラム中に初期化関数は存在しない。
ADCsingletest.c /*シングルモードでADコンバータから信号を得る*/ void msecwait(int
msec) main()
/*シングルモードでは初期化は不要*/
#include
"H8_3664.h"
/*msec間なにもしない時間稼ぎ関数*/
{
int
i,j;
for (i=0;i<msec;i++)
{
for
(j=0;j<1588;j++);
/*1588は実測によって求めた値*/
}
}
{
unsigned int v0,v1,v2,v3;
int
i;
initPCR();
initSCI();
putStringSCI("ADC single
mode\n");
while (1)
{
v0=getADCValue(0);
/*ADCch0から入力*/
v1=getADCValue(1);
/*ADCch1から入力*/
v2=getADCValue(2);
/*ADCch2から入力*/
v3=getADCValue(3);
/*ADCch3から入力*/
SCI_printf("ch0,1,2,3=");
SCI_printf(" %4x",v0);
SCI_printf(" %4x",v1);
SCI_printf(" %4x",v2);
SCI_printf(" %4x",v3);
SCI_printf("\n");
msecwait(1000);
}
}
6.2 スキャンモードAD変換
スキャンモードAD変換では。一度どこまでのチャンネルまでを動作させるか初期化で指示すれば,その後は連続変換を続ける。
初期化の後は,変換結果を読み出せば,最新の変換結果が得られる。
ADCscantest.c /*スキャンモードによるAD変換*/ void msecwait(int
msec) main()
#include
"H8_3664.h"
/*msec間なにもしない時間稼ぎ関数*/
{
int
i,j;
for (i=0;i<msec;i++)
{
for
(j=0;j<1588;j++);
/*1588は実測によって求めた値*/
}
}
{
unsigned int v0,v1,v2,v3;
int
i;
initSCI();
putStringSCI("ADC scan mode\n");
initScanADC(3);
/*ch0からch3までを連続変換する初期化*/
while (1)
{
v0=getADCValue0();
/*ch0のAD変換結果の取得*/
v1=getADCValue1();
/*ch1のAD変換結果の取得*/
v2=getADCValue2();
/*ch2のAD変換結果の取得*/
v3=getADCValue3();
/*ch3のAD変換結果の取得*/
SCI_printf("ch0,1,2,3=%8u %8u %8u
%8u\n",v0,v1,v2,v3);
msecwait(1000);
}
}
7.2 参考 AKI-H8/3664fピン配置
CN1 3664f ピン番号 名称・機能 CN2 3664f ピン番号 名称・機能 1 9 Vss(GND) 26 9 Vss(GND) 2 9 Vss(GND) 25 - TXD(RS232Cレベル) 3 55 PB4/AN4 24 - RXD(RS232Cレベル) 4 56 PB5/AN5 23 54 P17/IOQ3/TRGV 5 57 PB6/AN6 22 53 P16/IOQ2 6 58 PB7/AN7 21 52 P15/IOQ1 7 59 PB3/AN3 20 51 P14/IOQ0 8 60 PB2/AN2 19 46 P22/TXD 9 61 PB1/AN1 18 45 P21/RXD 10 62 PB0/AN0 17 44 P20/SCK3 11 6 Vc1 16 43 P87 12 7 RES 15 42 P86 13 8 TEST 14 41 P85(JP2) 14 13 P50/WKP0 13 40 P84/FTIOD 15 14 P51/WKP1 12 39 P83/FTIOC 16 19 P52/WKP2 11 38 P82/FTIOB 17 20 P53/WKP3 10 37 P81/FTIOA 18 21 P54/WKP4 9 36 P80/FTCI 19 22 P55/WKP5/ADTRG 8 35 NMI(JP3) 20 23 P10/TMOW 7 30 P76/TMOV 21 24 P11 6 29 P75/TMCIV 22 25 P12 5 28 P74/TMRIV 23 12 Vcc 4 27 P57/SCL 24 - PS-IN(電源) 3 26 P56/SDA 25 9 Vss(GND) 2 9 Vss(GND) 26 9 Vss(GND) 1 9 Vss(GND)