モータ制御評価装置による
AKI-H8(HitachiH8/3048)プログラミング
(cygwin+GCC)
Copyright(C) 3Oct2005
8Nov2004
15Oct2003
coskx
1. はじめに
1.1 この文書の構成
この文書はH8/3048のCプログラムをコンパイルする方法,AKI-H8/3048にフラッシュメモリ書き込み(転送)する方法を修得した学習者が,モータ制御評価装置(図1)で入出力装置操作プログラミングを行なうことを解説したものである。
cygwin+GCCがインストールしてある環境での使用を前提にしている。
サンプルプログラムのダウンロード
DownLoad |
図1 モータ制御評価装置 |
1.2
AKI-H8(HitachiH8/3048)
AKI-H8/3048(図2)は日立製作所の製品であるマイクロコンピュータH8製品群のH8/3048Fを用いて,秋月電子通商がCPUボード,マザーボードを製作販売している製品の商品名です。
マザーボード上には次の要素が搭載されています
(1)
フラッシュメモリ(ROM)書き込み回路
(2)
12V電源入力,5V出力3端子レギュレータ(12Vから安定した5Vを作るモジュール)
(3)
8ビットスイッチ
(4) プッシュスイッチ
(5) LED(発光ダイオード)
AKI-H8/3048でのプログラミングはパソコン上で次のように行ないます。
(1)
C言語またはアッセンブリ言語でプログラムを開発後
(2)
コンパイル・リンクを行ない実行プログラムファイルを作ります
(3)
ロードモジュールに変換します
(4)
RS232C通信でロードモジュールをH8に送信(フラッシュメモリに書き込む)
(5) 実行
|
図2 AKI-H8 マザーボード |
1.3 モータ制御評価装置
モータ制御評価装置では,マザーボードを拡張し,図3のように入出力装置を使用できるようになっている。
図3 モータ制御評価装置の各部紹介 |
2.CPUから接続された入出力装置とIOポート割り当て
入出力装置の回路図とポート割り当てを図4と表1に示します。
図4 モータ制御評価装置の各部の回路 図で「P4-2」というのは「ポート4の第2ビット(Port4 Bit2)」の意味であり, |
表1 ポート・ビットの割り当て
ポート・ビット | 用途 | 入出力 |
Port2 Bit0 |
8bitDIPスイッチ | 入力 |
Port2 Bit1 |
8bitDIPスイッチ | 入力 |
Port2 Bit2 |
8bitDIPスイッチ | 入力 |
Port2 Bit3 |
8bitDIPスイッチ | 入力 |
Port2 Bit4 |
8bitDIPスイッチ | 入力 |
Port2 Bit5 |
8bitDIPスイッチ | 入力 |
Port2 Bit6 |
8bitDIPスイッチ | 入力 |
Port2 Bit7 |
8bitDIPスイッチ | 入力 |
Port4 Bit0 |
モータ回転方向制御 | 出力 |
Port4 Bit1 |
モータ回転方向制御 | 出力 |
Port4 Bit2 |
リミットスイッチ | 入力 |
Port4 Bit4 |
プッシュスイッチ | 入力 |
Port4 Bit5 |
プッシュスイッチ | 入力 |
Port4 Bit6 |
プッシュスイッチ | 入力 |
Port4 Bit7 |
プッシュスイッチ | 入力 |
Port5 Bit0 |
LED | 出力 |
Port5 Bit1 |
LED | 出力 |
Port5 Bit2 |
電球 | 出力 |
3.サンプルプログラムのダウンロード
ここからサンプルプログラムをダウンロードできます。
DownLoad |
4.サンプルプログラム
このサンプルプログラムはコンパイラシステムが供給している「3048f.h」と小坂研究室で開発した「h8_3048.h」を利用することを前提としている。
4.1 シリアル通信
プログラム書き込み用通信回線はそのままプログラム実行時にも使えます。
実行時にはハイパーターミナルを起動しておいて下さい。
実行時にはハイパーターミナルを起動しておいて下さい。
サンプルフォルダ中の次に示すアイコンで起動すると,設定済みのハイパーターミナルが起動します。
Async, 8bit, NoParity, stop1, 38400baud,
(Backspace:Ctrl+H, Space, Ctrl+H)で設定されています。
ハイパーターミナルを利用した,ビットスイッチやプッシュスイッチのチェックおよびキーボードとの通信プログラムです。
ビットスイッチやプッシュスイッチのチェックの時はそれぞれのスイッチを動かしてみてください。
パソコン画面への出力(WindowsのHyperTerminal使用)
パソコン(キーボード)からの入力(WindowsのHyperTerminal使用)
リスト 1.1 |
なにかのキーが押されると「Hello
world!」を表示する。 通信作業の時は必ず,関数initSCI1()を呼び出して,SCI1の初期化が必要である。 while(1)というのは無限ループの記述方法 ●SCIというのはシリアルコミュニケーションインタフェイスNo1のことで,H8/3048に 内蔵されている通信機能のことである。この機能を用いている関数には「SCI1」がつ いている。 |
/**************************************** ◎getCharSCI1() #include "3048f.h" { int ch; initSCI1();/*SCI1初期化*/ SCI1_printf(" ** Serial Communication Interface **\n"); while (1) { SCI1_printf("Key in any key.\n"); ch=getCharSCI1(); SCI1_printf(" Hello world! \n"); } } |
実行例(ハイパーターミナル画面) |
** Serial
Communication Interface ** Key in any key. a Hello world! Key in any key. b Hello world! Key in any key. c Hello world! Key in any key. |
リスト 1.2 |
2数の和と差の計算 |
/**************************************** myint=getIntSCI1("honya
honya=>"); #include "3048f.h" { int x,y,add,diff; initSCI1();/*SCI1初期化*/ SCI1_printf(" ** Serial Communication Interface **\n"); while (1) {/*無限ループ*/ x=getIntSCI1("Key in an integer number x=>"); y=getIntSCI1("Key in an integer number y=>"); add=x+y; diff=x-y; SCI1_printf("x=%d y=%d x+y=%d\n",x,y,add); SCI1_printf("x=%d y=%d x-y=%d\n",x,y,diff); } } |
実行例(ハイパーターミナル画面) |
** Serial
Communication Interface ** Key in an integer number x=>26 Key in an integer number y=>31 x=26 y=31 x+y=57 x=26 y=31 x-y=-5 Key in an integer number x=>100 Key in an integer number y=>-20 x=100 y=-20 x+y=80 x=100 y=-20 x-y=120 Key in an integer number x=> |
リスト 1.3 |
スペースキーが押されると「SCI1_printf」のデモを行なう。 どのような動作になるか,プログラムを読みながら,確認してください。 |
/**************************************** 1)getCharSCI1() 2)chkgetCharSCI1() #include
"3048f.h" /*何もしないで指定された時間[msec]たつと戻る関数*/ main() |
練習問題1A 次の作業を行いなさい。 (1)リスト1.1を参考に,次のプログラムを作りなさい。 (2)リスト1.2を参考に,2つの整数値をキーボードから受け取り,積を表示するプログラムを作 (4)アドレス0x0000から0x03FFまでのメモリを十六進ダンプするプログラムを作りなさい。 |
練習問題1B 次の作業を行ないなさい。 (1)指定したアドレスから0x100byteをメモリダンプするプログラムを作りなさい。ただし指定アドレスは十六進の1の位は0とする。 (2)指定したアドレスから0x100byteをメモリダンプするプログラムを作りなさい。ただし指定アドレスは十六進の下位2桁は0とし, 実行例 |
4.2 LED駆動
リスト 2.1 |
無駄ループによるウエイト関数を用いたLEDの点滅駆動 LEDを操作する時には,LED関係の初期化関数initLed()を1回だけ最初に呼び出さなければならない。 |
/**************************************** |
図5のLEDが対象となるLEDです。
図5 2つのLED |
リスト 2.2 |
無駄ループによるウエイト関数を用いたLEDの点滅駆動 |
/**************************************** |
練習問題2A 次のプログラムを作りなさい。 |
練習問題2B 次の作業を行ないなさい。 |
4.3 タイマ割り込みLED点滅プログラム
リスト 3.1 |
通常の関数は,関数がプログラム中の他の関数から呼び出されたときに作業を行ないます。これに対して,割り込み関数は何らかの割り込み要因によって呼び出される関数です。 最適化コンパイルされた実行モジュールにおいては,volatile修飾子がないグローバル変数を割り込み関数と通常関数で共有すると動作が異常になることがある。最適化コンパイルされた実行モジュールではメモリ上の変数を一度レジスタに読み込むとその値をそのまま使い続けることがある。割り込み関数によってその変数の値が変化していることに気づくことが出来ない。volatile修飾子をつけると,その変数の値を使う時には必ずメモリから再読み込みする実行モジュールが出来る。「volatile」とは「変化しやすい」の意味。 |
/**************************************** |
●修飾子「volatile」について
英語の意味は「変化しやすい」の意味である。
割り込み関数と,通常の(mainを含む)関数の間で共有する変数につける。
初級・中級向け(初心者は読み飛ばしてよい)説明
本当のことをいうと,コンパイラに対する指示である。コンパイラは機械語コードを最適化する。
グローバル変数はメモリ上に置かれるが,最適化された機械語コードでは,その変数の値が変更されない限り
メモリからCPUのレジスタに読み込まれた値を保持していて,アクセスごとに毎回メモリを読みに行くわけではない。
そのため,その変数を割り込み関数が変更した(割り込み関数は値を変更しているので,メモリを書き換える)とし
ても,気づかずに,レジスタに読み込まれた値を使い続けてしまう。
「volatile」は,このような最適化をしてはいけないという意味で,その変数の値を使う時は,毎回メモリ上の値を使
いなさいという意味になる
リスト 3.2 |
タイマ割り込みを用いたLEDの点滅駆動 タイマ割り込みのON-OFF スペースキーを押すと動作のスタートストップが出来る。 |
/**************************************** |
リスト 3.3 |
タイマ割り込みを用いたLEDの点滅駆動 タイマ割り込みの間引き動作 |
/**************************************** |
リスト 3.4 |
タイマ割り込みを用いたLEDの光度制御駆動 |
/**************************************** |
リスト 3.5 |
タイマ割り込みを用いた電源ONからの時間の測定 |
/**************************************** #include "3048f.h" main() /*タイマ割り込み関数*/ |
実行の様子 |
** Running Time ** 4.17.7 |
練習問題3 次のプログラムを作りなさい。 |
4.4 8ビットDIPスイッチプログラム
リスト 4.1 |
8ビットDIPスイッチプログラム |
/**************************************** |
図6 8ビットDIPスイッチ |
練習問題4A 次のプログラムを作りなさい。 |
練習問題4B |
4.5 プッシュスイッチプログラム
リスト 5.1 |
プッシュスイッチプログラム |
/**************************************** |
リスト 5.2 |
プッシュスイッチ指令でPWM駆動によるLEDの光度制御 |
/**************************************** |
図7 プッシュスイッチ |
練習問題5 次のプログラムを作りなさい。 |
4.6 リミットスイッチプログラム
リスト 6.1 |
リミットスイッチプログラム |
/**************************************** void
initLimitSW(void) |
図8 リミットスイッチ |
練習問題6 次のプログラムを作りなさい。 |
4.7 電球点滅プログラム
リスト 7.1 |
電球点滅プログラム 色の薄い部分のプログラムは関数の機能だけ理解すればよい。 |
/**************************************** void
turnOffMOSFET(void) |
リスト 7.2 |
プッシュスイッチ指令,タイマ割り込みによる電球のPWM光度制御 色の薄い部分のプログラムは関数の機能だけ理解すればよい。 |
/**************************************** |
練習問題7 次のプログラムを作りなさい。 |
4.8 DAコンバータプログラム
DAコンバータ(Digital Analogue
Converter)とはコンピュータ内部の数値(ディジタル量)をコンピュータ外部に電圧(アナログ量)として出力する機能である。H8/3048には2チャンネルのDAコンバータがある。装置ではADコンバータチャンネル0に出力している。(図3参照)
以下のプログラムではシリアルインタフェイスに接続されたPCのターミナルソフトでキー入力を行ない,0から255までの値を入力すると「DAC
out」(図9.2参照)に約0Vから約5Vまでが電圧として出力される。これはH8/3048のDAコンバータが8ビット構成であることに起因している。
図9.1 DAコンバータ |
図9.2 DAコンバータの出口 |
リスト 8.1 |
DAコンバータプログラム 色の薄い部分のプログラムは関数の機能だけ理解すればよい。 |
/**************************************** |
練習問題8 |
4.9 ADコンバータプログラム
ADコンバータ(Analogue Digital
Converter)とはDAコンバータとは逆に,与えられた電圧(アナログ量)をコンピュータ内部の数値(ディジタル量)をとして入力する機能である。H8/304は8チャンネルのADコンバータが備わっている。各ADコンバータの分解能は10ビットであり,入力電圧が0Vから5Vまで変化すると取り込まれた値は0から1023まで変化する。
なお次のプログラムは,DAコンバータチャンネル0から電圧出力しながら,ADコンバータチャンネル0が入力するので,図10のようにこの2つを直結すると,DAコンバータへの出力値とADコンバータ入力値がターミナル上に表示される。
図10.1 DAコンバータ出力をADコンバータで読み込む |
図10.2 DAコンバータの出口とADコンバータの入り口 |
リスト 9.1 |
ADコンバータプログラム 色の薄い部分のプログラムは関数の機能だけ理解すればよい。 |
/**************************************** unsigned int
getADC(unsigned char ch) void
initADC0(void) unsigned int
getADC0(void) void
initADC1(void) unsigned int
getADC1(void) |
練習問題9
|
4.10 位相カウンタによるインクリメンタル型ロータリエンコーダのパルス計測
軸の回転角度を測定するセンサに,光学式ロータリエンコーダがある。これは回転軸に,スリットのある円板を取り付け,発光器と光センサ間にこの円板を置き,軸が回転するとセンサへの光が透過・遮断を繰り返すようにする。その結果光センサ出力は1−0を繰返し,1−0の繰返し数をカウントすると軸の回転角が読み取れるようになっている。この構造をもつロータリエンコーダはインクリメンタル型ロータリエンコーダと呼ばれる。さらに,位相の異なる位置にもう1つの発光器と光センサをつけることにより,2相の光センサ出力が得られ。回転方向もわかるようになっている。
H8/3048には2相のセンサ出力で,自動的にアップカウントダウンカウントを行なうカウンタがあり,これは位相カウンタと呼ばれている。このカウンタにインクリメンタル型ロータリエンコーダの2相出力信号を取り込むことによって,回転軸の角度を検出できる。
装置には,1回転すると200カウントするロータリエンコーダが付属しており,内部で4倍カウントするので,軸の1回転を800カウントとして読み込む。
次のプログラム(リスト10.1)を起動し,ロータリエンコーダを手で回転させると,角度変位が読み取れる。ただし1パルスは1/800回転である。
|
図11 インクリメンタル型ロータリエンコーダ |
リスト 10.1 |
位相カウンタによるインクリメンタル型ロータリエンコーダのパルス計測 色の薄い部分のプログラムは関数の機能だけ理解すればよい。 |
/**************************************** |
タイマ割り込みにより,一定間隔でインクリメンタル型ロータリエンコーダの角度を読み取っていくと,前回の角度との差を計算することが出来る。この差は「差分」といって,回転速度を意味する。例えばリスト10.2では1/100秒間の角度変化を読み取っている。
リスト 10.2 |
位相カウンタによるインクリメンタル型ロータリエンコーダのパルス計測とカウント差分算出 色の薄い部分のプログラムは関数の機能だけ理解すればよい。 |
/**************************************** |
練習問題10 |
4.11 モータ駆動プログラム
モータを駆動するため,PWM信号をITUチャンネル3を用いて発生させ,ポート4のビット0,1で回転方向を決めている。使用しているモータドライバはTA8429である。
PWMとはパルス幅変調のことで,リスト2.2に説明がある。人間の感覚ではわからないくらいの高速なモータON−OFF動作を行ない,見かけ上モータへ与える電圧を変化させているようにしている。1回のON−OFF動作にかかる時間がPWM周期であり,周期中のONになっている時間の比がデューティ比である。リスト11.1のプログラムではPWM周期が1/16000秒(0.0000625秒)でデューティ比は「「キーボード入力したPWMValue」÷1000」で設定される。適当なPWM値を与えて,モータを駆動している時に,CN1-16のピンをオシロスコープで観察するとPWM信号が観察できる。
| ||||||||||||||||||||
| ||||||||||||||||||||
図12 モータ駆動とモータドライバIC「TA8429」 | ||||||||||||||||||||
ITU内部カウンタは16MHzのCPUクロックをカウントしている。 CPUクロック周波数=16MHzなのでクロック周期は0.0625μsである。 | ||||||||||||||||||||
図12-B PWM信号の発生メカニズム |
リスト 11.1 |
モータ駆動プログラム 色の薄い部分のプログラムは関数の機能だけ理解すればよい。 |
/**************************************** /*ITU3の初期化*/ |
次のプログラムはPWMでモータを駆動し,一定時間ごとの角度を表示するプログラムである。
一定時間を確実にするためにタイマ割り込みを利用している。
タイマ割り込み関数内で角度を読み取り,メイン側にデータ表示要求を出している。
メイン側は,割り込み関数が表示要求を出していることがわかったら,表示するようになっている。
なお,msec単位の時刻もわかるような変数timecountを持っている。10msecごとのタイマ割り込みなので
タイマ割り込み関数内でtimecountは10ずつ増加している。
リスト 11.2 |
モータ駆動および定期角度センサ取り込み表示プログラム 色の薄い部分のプログラムは関数の機能だけ理解すればよい。 |
/**************************************** #include "3048f.h" void driveMotor(int
pwm) void
brakeMotor(void) void init_pwm3(int pwmMax) /*ITU3の初期化*/ void driveMotor(int
pwm) void
brakeMotor(void) /*************************************** int
getPhaseCounter(void) void
clearPhaseCounter(void) ****************************************/ void initPhaseCounter(void) /* void clearPhaseCounter(void) #define PWM_MAX 1000 volatile int
pulsecount;
/*割り込み時位置*/ main() /*タイマ割り込み関数*/ |
実行例 |
PWM
value(-1000..1000) =1000 time[msec] position[pulse] 0 0 10 4 20 26 30 59 40 103 50 153 60 206 70 263 80 322 90 384 100 446 110 510 120 573 130 637 このあと省略 |
リスト11.2では,モータ指令値の変更(ブレーキも同様)は非割り込み関数側で処理していた。
リスト11.3のように,非割り込み関数側は,表示に専念し,モータへの指令を割り込み関数内でのみ行うようにすると,これ以降のプログラミングの役に立つようになる。リスト11.3はリスト11.2の後ろの部分である。
リスト11.3 |
---|
#define PWM_MAX 1000 volatile int pulsecount; /*割り込み時位置*/ volatile int requestDisplaydata; /*表示リクエスト*/ volatile int timecount; /*時刻を表す変数 単位msec*/ volatile int pwmvalue; /*PWM指令値*/ main() { int max=PWM_MAX; initSCI1(); initPhaseCounter(); /*Rotaryencoder counter ITUch2初期化*/ init_pwm3(max); initTimer1Int(10000); /* 10msecごとの割り込み関数起動を設定*/ E_INT(); /*CPU割り込み許可*/ SCI1_printf(" ** Motor Drive with PWM **\n"); SCI1_printf("PWM value should be in the range of -%d .. %d.\n",max,max); while (1) { SCI1_printf("PWM value(-%d..%d) =",max,max); pwmvalue=getIntSCI1(""); timecount=-10; requestDisplaydata=0; clearPhaseCounter(); SCI1_printf("time[msec] position[pulse]\n"); startTimer1(); /*時間割り込みタイマスタート ch1*/ while (timecount<=1010) { if (requestDisplaydata) { SCI1_printf("%10d %10d\n",timecount,pulsecount); requestDisplaydata=0; } } stopTimer1(); } } /*タイマ割り込み関数*/ /*この関数名は変更できない。プログラム中で1つしか使えない。*/ void interrupt_cfunc() { timecount+=10; pulsecount=getPhaseCounter(); if (timecount==0) { driveMotor(pwmvalue); } else if (timecount==1000) { brakeMotor(); } requestDisplaydata=1; ITU1.TSR.BIT.IMFA=0; /*Clear IMFA これは自分の責任で行なう*/ } |
練習問題11A |
練習問題11B |
練習問題11C 実行結果例(ヒントもあり) (2)次の仕様のプログラムを作りなさい。 |
練習問題11D (1)次の仕様のプログラムを作りなさい。 (2)次の仕様のプログラムを作りなさい。 (3)次の仕様のプログラムを作りなさい。 実行例(ヒントもあり) |
4.12 PSDプログラム
PSD素子の上方20cm程度の位置に手をかざすと距離計が反応する。
図13 赤外線距離計PSD(SHARP GP2D12) |
リスト 12.1 |
赤外線距離計PSD(Position Sensitive Detector)プログラム |
/**************************************** unsigned int getADC(unsigned char
ch) void
initADC0(void) unsigned int getADC0(void) void
initADC1(void) unsigned int getADC1(void) |
AKI-H8付属のコネクタ番号表 |
参考2 h8_3048.h
h8_3048.h
/****************************************************************
h8_3048.h
Copyright (c) Kosaka Lab CS TNCTこのインクルードファイルは小坂研究室の代々の研究生が開発した
有用な関数群を改良して小坂がまとめたものである。
28 Jun 2006 h8-3048.h 小坂 chkgetSCI1のタイミング修正
4 Dec 2003 h8-3048.h 小坂 printf更新,initLed更新,initDDR削除
08 Oct 2003 h8-3048.h 小坂 stopTimer追加,getIntSCI1でBS使用可
6 Jan 2003 h8_3048.h 小坂 getIntSCIバックスペイスに対応。
17 Apr 2002 h8-01.h 小坂 %uの使い方をansiにあわせた。
14 Dec 2001 h8-01.h 小坂,越智
15 Jly 2000 h8-00.h 小坂,藤原
22 Dec 1999 h8-99.h 小坂,高沢
29 Oct 1999 h8-99.h 小坂
05 Feb 1999 lib.h 笠井【1】ポートの入出力管理
void initDDR(void)
write only register DDR設定用変数の初期化【2】SCI ch1 関係
void initSCI1()
SCI-ch1の初期化 38400baud, Async, 8bit , NoParity, stop1short int getCharSCI1()
SCI-ch1から1byte入力コード。エラーがあると-2が戻る。
short int chkgetCharSCI1()
SCI-ch1を検査し,受信データがあれば1byte入力コード。なければ-1が,失敗すると-2が戻る。
short int getIntSCI1(char prompt[])
SCI-ch1からプロンプト付で,short intの値を受け取る。
正負の10進数または16進数を受け付ける。16進数は0xで始まるvoid putCharSCI1(char c)
SCI-ch1に1バイト出力する。
void putStringSCI1(char *str)
SCI-ch1に文字列を出力する。
void SCI1_printf(char *format,...)
関数printfのSCI版
軽量化のためエラー処理はないので桁数指定の場合は注意
対応書式
%d : [int] integer with sign. '%d','%4d','%-4d', and '%04d' are available
%ld : explicit [long int] '%ld','%9ld','%-9ld', and '%09ld' are available
%u : [unsigbed int] unsigned integer.
'%u','%4u','%-4u', and '%04u' are available
%lu : explicit [unsigned long int]
'%lu','%9lu','%-9lu', and '%09lu' are available
%x : [unsigned int] in Hex '%x','%4x','%-4x', and '%04x' are available
%lx : explicit [unsigned long int] in Hex
'%lx','%8lx','%-8lx', and '%08lx' are available
%o : [unsigned int] in Oct '%o','%4o','%-4o', and '%04o' are available
%lo : explicit [unsigned long int] in Oct
'%lo','%8lo','%-8lo', and '%08lo' are available
%b : [unsigned int] in Bin '%b','%8b','%-8b', and '%08b' are available
%lb : explicit [unsigned long int] in Bin
'%lb','%8lb','%-8lb', and '%08lb' are available
%c : char
%s : string %20s %-20s are available【3】AKI-H8マザーボード関係
void initLed()
LEDの初期化
void turnOnLed(short int number)
LEDの点灯 numberはLED番号で0または1を指定する
void turnOffLed(short int number)
LEDの消灯 numberはLED番号で0または1を指定するvoid initPushSW(void)
押しボタンスイッチの初期化
short int getPushSW(void)
押しボタンスイッチの取得 ただしポートを読み込み,ビット反転のみ。
押しボタンスイッチの状況は第4-第7ビットに現れる。
これはマクロ定義で実現されている
short int checkPushSW(short int number)
push sw 0,1,2,3の状態を調べる number:0,1,2,or 3
押されていたら1、そうでなかったら0を返すvoid init8BitSW(void)
8ビットスイッチの初期化
short int get8BitSW(void)
8ビットスイッチの取得 ただしポートを読み込み,ビット反転のみ。
8ビットスイッチの状況は第0-第7ビットに現れる。
これはマクロ定義で実現されている
short int check8BitSW(short int number)
8bitsw 0,1,2,3,4,5,6,7の状態を調べる number:0,1,2,3,4,5,6,or 7
ONなら1、そうでなかったら0を返す【4】タイミング割り込み
void initTimer1Int(unsigned short int period)
ITU1による割り込みタイマーの設定
割り込み間隔は引数peiodで単位はμsecである
値は32767以下でなければならない。32.767msecまで設定可能
void startTimer1(void)
Timer CH1 スタート
これはマクロ定義で実現されているvoid initTimer01Int(unsigned short int period)
ITU0とITU1による割り込みタイマーの設定
割り込み間隔は引数peiodで単位はmsecである
値は65535以下でなければならない。65.535secまで設定可能
ただしポートPAの第3ビットが使用できなくなるので注意
void startTimer01(void)
Timer CH0 CH1 同時スタート
これはマクロ定義で実現されている****************************************************************/
#include<stdarg.h>
unsigned char P1DDR=0,P2DDR=0,P3DDR=0,P4DDR=0,P5DDR=0;
unsigned char P6DDR=0,P7DDR=0,P8DDR=0,P9DDR=0,PADDR=0,PBDDR=0;extern void E_INT();
extern void D_INT();/*void initDDR(void)
{
P1DDR=P2DDR=P3DDR=P4DDR=P5DDR=P6DDR=P7DDR=P8DDR=P9DDR=PADDR=PBDDR=0;
}
*/
/*以前のバージョンとの互換性のため*/
#define initDDR()/*SCI関係の基本部分は笠井君(1998年度)藤原君(2000)の開発です*/
/* ------------------------------------------------- */
/* SCI1 INITIALIZATION fixed baud at 38400 */
/* ------------------------------------------------- */
void initSCI1()
{
short int i;
/*unsigned char dummy;*/
SCI1.SCR.BYTE = 0; /* clear all flags */
/* 2400-38400baud are available at n=0(cks1=0,cks2=0) */
SCI1.SMR.BYTE = 0; /* Async, 8bit , NoParity, stop1, 1/1 */
SCI1.BRR = 12; /* 38400baud (CPU=16MHz) */
for(i=0;i<1000;i++); /* wait more than 1bit time */
SCI1.SCR.BYTE = 0x30; /* scr = 0011 0000 (TE=1,RE=1) */
/*dummy = SCI1.SSR.BYTE;*/ /* read dummy ????*/
/*SCI1.SSR.BYTE = 0x80;*/ /* clear error flag (TDRE = 1) ????*/
return;
}/* ------------------------------------------------- */
/* GET BYTE FROM SCI1 */
/* ------------------------------------------------- */
short int getCharSCI1()
/* return value 0x00-0xFF:received data */
/* -2(0xFFFE):error */
{
short int flags,recdata;
do {
flags = SCI1.SSR.BYTE;
if (flags&0x38) {/* error */
SCI1.SSR.BIT.RDRF = 0;
SCI1.SSR.BIT.ORER = 0;
SCI1.SSR.BIT.FER = 0;
SCI1.SSR.BIT.PER = 0;
return -2;
}
if (flags&0x40) {/* normally received one data */
SCI1.SSR.BIT.RDRF = 0;
recdata=SCI1.RDR;
return recdata;
}
} while (1);
}/* ------------------------------------------------- */
/* CHECK SCI BUFFER AND GET DATA */
/* ------------------------------------------------- */
short int chkgetCharSCI1()
/* return value -1(0xFFFF):no received data */
/* 0x00-0xFF:received data */
/* -2(0xFFFE):error */
{
short int flags,recdata;
flags = SCI1.SSR.BYTE;
if (flags&0x38) {/* error */
SCI1.SSR.BIT.RDRF = 0;
SCI1.SSR.BIT.ORER = 0;
SCI1.SSR.BIT.FER = 0;
SCI1.SSR.BIT.PER = 0;
return -2;
}
if (flags&0x40) {/* normally received one data */
recdata=SCI1.RDR;
SCI1.SSR.BIT.RDRF = 0;
return recdata;
} else {
return -1;
}
}void putStringSCI1(char *str);
/*SCI1より文字列入力[return]が終端だが,'\n'は取得されない*/
/*^Hでバックスペイス*/
int getStringSCI1(char *buff,int max)
{
int i,ch;
for (i=0;i<max-1;i++) {
ch=getCharSCI1(); /*1文字取得*/
*buff=(char)ch; /*1文字取得*/
if (*buff=='\r'||ch<0) {
*buff=0;
return i+1;
}
if (*buff==0x8) {
buff-=2;
i-=2;
}
if (*buff!='\n') buff++;
else i--;
}
*buff=0;
return i+1;
}/*SCI1へプロンプトを表示して,SCI1より整数値を入力*/
short int getIntSCI1(char prompt[])
/*getting integer from serial port*/
/* format 123[ret] */
/* -123[ret] */
/* 0x1a[ret] */
/* -0x100[ret] */
{
short int x=0,y,m=0,n=0,v=0,i=0;
char buff[16];
putStringSCI1(prompt);
getStringSCI1(buff,16);
y=buff[i];
while(y!=0){
if(y=='-') m=1;
if('a'<=y&&y<='z') y=y-'a'+'A';
if(y=='0') n=1;if(v==1){
if('0'<=y&&y<='9'){
y=y-'0';
}
else if('A'<=y&&y<='F'){
y=y-'A'+10;
}
x=16*x+y;
}if(n==1&&y=='X'){
v=1;
}
if(v==0&&'0'<=y&&y<='9'){
y=y-'0';
x=10*x+y;
}y=buff[++i];
}
if(m==1) x=-x;
return x;
}/* ------------------------------------------------- */
/* PUT BYTE TO SCI1 */
/* ------------------------------------------------- */
void putCharSCI1(char c)
{
unsigned char tmp;
if (c=='\n') putCharSCI1('\r');
do{
tmp = SCI1.SSR.BYTE;
} while((tmp & 0x80)==0);
SCI1.TDR = c;
SCI1.SSR.BIT.TDRE = 0;
return;
}void putStringSCI1(char *str)
{
while(*str){
putCharSCI1(*str);
str++;
}
}const char hexstring[]="0123456789abcdef0123456789ABCDEF";
#define MAXDIGIT 34
void SCI1_printf(char *format,...)
{
va_list arg_ptr;
char buf[MAXDIGIT];
unsigned char flag=0; /*%d:bit2 l:bit1 %:bit0 */
unsigned char digit=0; /* 桁数 */
unsigned char minus=0;
char fill=' ',format1=' ';
unsigned char radix=10; /*N進基数*/
char sign=' ';
char *ptr=buf; /*出力文字ポインタ*/
unsigned char cntr=0; /*出力文字数カウンタ*/
unsigned char shift=0; /*16進シフト 0 or 6*/
unsigned char i;
unsigned long int value=0;
va_start(arg_ptr,format);
while (*format) {
format1=*format;
if (flag==0) {
if (format1=='%') {
flag=1;
digit=0;
fill=' ';
minus=0;
radix=0;
ptr=&buf[MAXDIGIT-1];
*ptr--='\0';
cntr=0;
shift=0;
sign='+';
} else {
putCharSCI1(format1);
}
} else {
if (format1=='l') {
flag|=2;
} else if ('0'<=(format1)&&(format1)<='9') {
if (digit==0 && format1=='0') {
fill='0';
} else {
digit=digit*10+((format1)-'0');
if (MAXDIGIT-2<digit) digit=MAXDIGIT-2;
}
} else if (format1=='-') {
minus=1;
} else if (format1=='d') {
flag|=4;
radix=10;
} else if (format1=='u') {
radix=10;
} else if (format1=='x') {
radix=16;
} else if (format1=='X') {
radix=16;shift=16;
} else if (format1=='o') {
radix=8;
} else if (format1=='b') {
radix=2;
} else if (format1=='p') {
radix=16;shift=16;digit=8;fill='0';flag|=2;
} else if (format1=='c') {
putCharSCI1((unsigned char)(va_arg(arg_ptr,int)));
flag=0;
} else if (format1=='s') {
if (digit) {
cntr=0;ptr=va_arg(arg_ptr,char *);
while (ptr[cntr]) cntr++; /*cntrは文字数*/
if (!minus) for (i=cntr;i<digit;i++) putCharSCI1(' ');
putStringSCI1(ptr);
if (minus) for (i=cntr;i<digit;i++) putCharSCI1(' ');
} else {
putStringSCI1(va_arg(arg_ptr,char *));
}
flag=0;
} else {
putCharSCI1(format1);
flag=0;
}
if (radix) {
switch (flag&6) {
case 0: /* unsig int */
value=(unsigned int)va_arg(arg_ptr,int);
break;
case 2: /* unsig long int */
value=va_arg(arg_ptr,long int);
break;
case 4: /* sig int */
value=(long int)va_arg(arg_ptr,int);
if ((long int)value<0) {
value=-(long int)value;
sign='-';
}
break;
case 6: /* sig long int */
value=va_arg(arg_ptr,long int);
if ((long int)value<0) {
value=-(long int)value;
sign='-';
}
break;
default:
break;
}
while (value) {
*ptr--=hexstring[value%radix+shift];
cntr++;
value/=radix;
}
if (cntr==0) {
*ptr--='0';
cntr++;
}
if (fill==' ') {
if (sign=='-') {
*ptr--='-';
cntr++;
}
if (!minus) for (i=cntr;i<digit;i++) putCharSCI1(' ');
putStringSCI1(++ptr);
if (minus) for (i=cntr;i<digit;i++) putCharSCI1(' ');
} else {
for (;cntr<digit-1;cntr++) *ptr--='0';
if (sign!='-'&&cntr<digit) *ptr--='0';
else if (sign=='-') *ptr--='-';
putStringSCI1(++ptr);
}
flag=0;
}
}
format++;
}
}/* ------------------------------------------------- */
/* LED INITIALIZATION */
/* ------------------------------------------------- */
/**********************************************************
LED 0:P5-0
LED 1:P5-1
**********************************************************/
void initLed()
{
P5DDR |= 0x3;
P5.DDR = P5DDR;
}/* ------------------------------------------------- */
/* LET LED ON */
/* ------------------------------------------------- */
/*numberは0または1*/
void turnOnLed(short int number)
{
static unsigned char mask[]={1,2};
P5.DR.BYTE |=mask[number];
}/* ------------------------------------------------- */
/* LET LED OFF */
/* ------------------------------------------------- */
/*numberは0または1*/
void turnOffLed(short int number)
{
static const unsigned char mask[]={0xfe,0xfd};
P5.DR.BYTE &=mask[number];
}/* ------------------------------------------------- */
/* PUSH SW INITIALIZATION */
/* ------------------------------------------------- */
/**********************************************************
押しボタンスイッチS0:P4-4
押しボタンスイッチS1:P4-5
押しボタンスイッチS2:P4-6
押しボタンスイッチS3:P4-7
**********************************************************/
void initPushSW(void)
{
P4DDR &= 0xf; /*P4-4,5,6,7は入力*/
P4.DDR=P4DDR;
P4.PCR.BYTE|=0xf0; /*P4-4,5,6,7はプルアップ */
}/* ------------------------------------------------- */
/* GET PUSH SW */
/* ------------------------------------------------- */
/*push swの状態をそのまま返す
short int getPushSW(void)
{
return (((unsigned char)(~P4.DR.BYTE))&0xf0);
}
*/
#define getPushSW() (((unsigned char)(~P4.DR.BYTE))&0xf0)short int checkPushSW(short int number)
/*push sw 0,1,2,3の状態を調べる number:0,1,2,or 3*/
/*押されていたら1、そうでなかったら0を返す*/
{
short int ret;
static const unsigned char mask[]={0x10,0x20,0x40,0x80};
if (P4.DR.BYTE&mask[number]) ret=0;
else ret=1;
return ret;
}/* ------------------------------------------------- */
/* PUSH 8 BIT SW INITIALIZATION */
/* ------------------------------------------------- */
void init8BitSW(void)
{
P2DDR &= 0x00;/*8bitSWのポートを入力に設定*/
P2.DDR = P2DDR;
P2.PCR.BYTE = 0xff;/*8bitSWのプルアップ設定*/
}/*8bitswの状態をそのまま返す
short int get8BitSW(void)
{
return (unsigned char)(~P2.DR.BYTE);
}
*/
#define get8BitSW() (unsigned char)(~P2.DR.BYTE)short int check8BitSW(short int number)
/*8bitsw 0,1,2,3,4,5,6,7の状態を調べる number:0,1,2,3,4,5,6,or 7*/
/*ONなら1、そうでなかったら0を返す*/
{
short int ret;
static const unsigned char mask[]={1,2,4,8,0x10,0x20,0x40,0x80};
if (P2.DR.BYTE&mask[number]) ret=0;
else ret=1;
return ret;
}/*タイマ割り込みは笠井君(1998),越智君(2001)による開発です*/
/* ------------------------------------------------- */
/* TIMER INITIALIZATION */
/* ------------------------------------------------- */
void initTimer1Int(unsigned short int period)
/*ITU1による割り込みタイマーの設定(越智君2001による)*/
/*割り込み間隔は引数peiodで単位はμsecである*/
/*値は32767以下でなければならない*/
/*32.767msecまで*/
{
ITU1.TCR.BIT.CCLR=1; /*GRAのコンペアマッチでTCNTをクリア*/
ITU1.TCR.BIT.CKEG=0; /*立ち上がりエッジでカウント*/
ITU1.TCR.BIT.TPSC=3; /*内部クロックφ/8でカウント*/
ITU1.GRA=2*period-1; /*割り込みの周期をperiod[μs]に指定*/
ITU1.TIER.BIT.IMIEA=1; /*TCNT=GRAとなったときの割り込み要求を許可*/
ITU1.TIER.BIT.OVIE=0; /*オーバー・アンダーフロー発生時の割り込みを禁止*/
ITU1.TIER.BIT.IMIEB=0; /*TCNT=GRBとなったときの割り込みを禁止*/
}void initTimer01Int(unsigned short int period)
/*ITU0とITU1による割り込みタイマーの設定(笠井君(1998)による)*/
/*割り込み間隔は引数peiodで単位はmsecである*/
/*値は65535以下でなければならない*/
/*65.535secまで*/
/*ただしポートPAの第3ビットが使用できなくなるので注意*/
{
ITU0.TCR.BYTE = 0xc3; /* タイマー CH0 GRBでクリア、内部1/8クロック */
ITU0.TIOR.BYTE = 0xb8; /* タイマー CH0 GRBのコンペアマッチでトグル出力 */
ITU0.GRB = 2000-1; /* タイマー CH0 ((16/8)MHz)/1000Hz=2000 */
ITU1.TCR.BYTE = 0xb7; /* タイマー CH1 GRAでクリア、TCLKDをカウントする */
ITU1.TIOR.BYTE = 0x8a; /* タイマー CH1 GRAのコンペアマッチ出力 */
ITU1.GRA = period-1; /* タイマー CH1 1000 = 1SEC */
ITU1.TIER.BYTE = 0xf9; /* タイマー CH1 GRAで割り込みする */
}/* ------------------------------------------------- */
/* TIMER START */
/* ------------------------------------------------- */
/*
Timer CH0 CH1 同時スタート
void startTimer01(void)
{
ITU.TSTR.BYTE |= 0x03;
}
Timer CH1 スタート
void startTimer1(void)
{
ITU.TSTR.BYTE |= 0x02;
}Timer CH0 CH1 同時ストップ
void stopTimer01(void)
{
ITU.TSTR.BYTE &= ~0x03;
}
Timer CH1 ストップ
void stopTimer1(void)
{
ITU.TSTR.BYTE &= ~0x02;
}
*/
#define startTimer01() (ITU.TSTR.BYTE |= 0x03) /* Timer CH0 CH1 同時スタート */
#define startTimer1() (ITU.TSTR.BYTE |= 0x02) /* Timer CH1 スタート */
#define stopTimer01() (ITU.TSTR.BYTE &= ~0x03) /* Timer CH0 CH1 同時ストップ */
#define stopTimer1() (ITU.TSTR.BYTE &= ~0x02) /* Timer CH1 ストップ */