AKI-H8(HitachiH8/3052)の使い方
マザーボードSWとLEDによるプログラミング

Copyright(C) 15Nov2004
Copyright(C) 15Dec2001


coskx

0. はじめに

0.1 この文書の構成
この文書はH8/3052のCプログラムをコンパイルする方法,AKI-H8/3052にフラッシュメモリ書き込み(転送)する方法を修得した学習者が,AKI-H8/3052のマザーボードを用いてLEDをつけたりスイッチを取り込んだりするプログラムを学習するための文書です。

0.2 AKI-H8(HitachiH8/3052)
 AKI-H8/3052(図1)は日立製作所の製品であるマイクロコンピュータH8製品群のH8/3052Fを用いて,秋月電子通商がCPUボード,マザーボードを製作販売している製品の商品名です。
購入して組み立てたばかりの状態では図の黄色部分のみでできています。
(LCD(液晶表示器)がついている場合もあります。)

マザーボード上には次の要素が搭載されています
(1)   フラッシュメモリ(ROM)書き込み回路
(2)   12V電源入力,5V出力3端子レギュレータ(12Vから安定した5Vを作るモジュール)
(3)   8ビットスイッチ
(4)   プッシュスイッチ
(5)   LED(発光ダイオード)

AKI-H8/3052でのプログラミングはパソコン上で次のように行ないます。
(1)   C言語またはアッセンブリ言語でプログラムを開発後
(2)   コンパイル・リンクを行ない実行プログラムファイルを作ります
(3)   ロードモジュールに変換します
(4)   RS232C通信でロードモジュールをH8に送信(フラッシュメモリに書き込む)
(5)   実行


H8-MB.JPG

図1 AKI-H8 マザーボード
(この写真はH8/3048のもの。H8/3052に差し替えても目立った変化はない)

1. LEDの点滅のプログラム

図2のLEDが対象となるLEDです。

H8-LED.JPG


H8-LEDD.JPG - 9,332BYTES

図2 2つのLED

1.1    LED点滅プログラム

マザーボード上の2つのLEDを点滅させるプログラムを作ります。
2つのLEDはH8/3052CPUのポート5の第0ビット,第1ビットの端子につけられています。
H8でポートというのは8ビットの出入り口のことです。ポート5には第0ビットから第7ビットまでの8ビットがあります。
ポートがCPUのどのピンに接続されているかはCPU設計者によって決められ,CPUのマニュアルに書いてあります。
またCPUのピンがCPUカードのどのピンに接続されているかは,CPUカードの設計者によって決められ,CPUカードのマニュアルに書いてあります。このWebページの「参考1」に接続一覧が書いてあります。

通常ポートは入出力兼用なので,この例のようにポート5の第0ビット,第1ビットの端子の先にLEDがついている場合は,CPUに対し,この2つのビットは出力に使用することを教えてあげなければなりません。(1回だけ設定しなければなりません。)

参考 電流制限

CPUの出力端子はレベルHの時5V,レベルLの時0Vであり,LED単体の電圧降下が1.5V程度であるため,保護抵抗1.5kΩには3.5Vがかかっていることになります。この抵抗に流れる電流は3.5[V]/1500[Ω] = 0.0023[A] = 2.3[mA]となります。LEDは10mA駆動が標準ですが,1mA駆動でも光らないないわけではありません。一方CPUの端子出力電流は最大2.0mAとされている(H8の仕様)ので,AKI-H8はわずかに仕様違反となっています。



1.2    LED点滅プログラムの考え方

(1)駆動の手順

(1) ポート5の下位2ビットを出力に設定(P5.DDRに設定する)
       0:入力  1:出力
       下位2ビット(第0ビットと第1ビット)を出力に設定するには
       2進数表現で00000011,10進数表現(16進表現でも同じ)で3を与えればよい。
(2) ポート5の下位2ビットに0または1を出力してLED点滅を行ないます。
       0:OFF  1:ON
(3) 時間調整して1秒ごとに2つのLEDが交互に点滅するようにします。

(2)具体的なプログラミングの考え方

ポート5の下位2ビットを出力に設定
以下を無限ループ
  ポート5の第0ビットに1を出力
  ポート5の第1ビットに0を出力
  1秒間時間待ち
  ポート5の第0ビットに0を出力
  ポート5の第1ビットに1を出力
  1秒間時間待ち

1.3 LED点滅プログラム


    /*P5の下位2ビットを出力に設定*/
    P5.DDR =  0x3;
    while(1) {/*これは無限ループ*/
        /*LED0をONにする*/
        P5.DR.BIT.B0=1;
        /*LED1をOFFにする*/
        P5.DR.BIT.B1=0;
        msecwait(1000);/*1000msecの間なにもしない*/
        /*LED0をOFFにする*/
        P5.DR.BIT.B0=0;
        /*LED1をONにする*/
        P5.DR.BIT.B1=1;
        msecwait(1000);
    }

参考 
(1)ポート5はP5という構造体(構造体学習前なら,家の名前と考えればよい)で表されていると考えられる。
(2)P5の各ビットを入出力のどちらに使うかの設定はP5.DDRという8ビットのレジスタ(P5家のDDR部屋と考えればよい)に設定する。ここでは下位2ビットのみを出力にするので2進数00000011に設定したいのでP5.DDRには3を設定する。もし,第2,第3ビットのみを出力にしたいのなら,2進数00001100を設定すればよいので,P5.DDRには16進数で0xc(10進数では8+4=12)を設定する。またもし第0ビットと第3ビットのみを出力にしたいのなら,2進数00001001を設定すればよいので,P5.DDRには9を設定する。別のポートも同様な記述を行なうことができる。例えばポート1の8ビットすべてを出力に設定したいのなら,2進数11111111に設定すればよいのでP1.DDR=0xffのように設定する。

(3)ポート5に出力する値はP5.DR(P5家のDR部屋)に出力する。P5.DRはさらに細かい小部屋に分かれており,P5.DR.BIT.B0はポート5の第0ビットを表す。同様にP5.DR.BIT.B1はポート5の第1ビットを,P5.DR.BIT.B2はポート5の第2ビットを,....のように使う。ポート5の第2ビットに0を出力したければ,P5.DR.BIT.B2=0,ポート5の第2ビットに1を出力したければ,P5.DR.BIT.B2=1のように使う。この表現は1ビットのみを表すため,代入できる値は0または1のみである。またP5.DR.BYTEの表現では8ビットまとめて出力が可能である。例えばポート5の第2ビットに1を,その他のビットには0を出力したければ,00000100を出力することになるので,P5.DR.BYTE=4のように表現できる。(ポート1の第0から第3ビットに1を,その他のビットには0を出力したければ,00001111を出力することになるので,P1.DR.BYTE=0xf)

P5はDDRとDRの2つの8ビットのレジスタで構成されている
さらにDRはBYTEとBITの2つの方法で書き込みが可能である。

参考図 レジスタP5の構造

1.4 実際のプログラム

led1st.c

/*  msecwait関数で1秒ごとのLEDのON-OFFを行う  */
#include <3052f.h>

void msecwait(int msec)
/*msec間なにもしない時間稼ぎ関数*/
{
    int i,j;
    for (i=0;i<msec;i++) {
        for (j=0;j<2481;j++);    /*2481は実測によって求めた値*/
    }
}

main()
{
    /*P5の下位2ビットを出力に設定*/
    /* P5のDDRの下位2ビットに1を与えるとこの設定になる*/
    /*DDRとはDataDirectionRegister(データ方向設定レジスタ)*/
    P5.DDR =  0x3;     /*0x3 = 00000011(二進数)*/
    while(1) {/*これは無限ループ*/
        /*LED0をONにする  P5のDRの第0ビットを1にする*/
        /*DRとはDataRegister(データレジスタ)*/
        P5.DR.BIT.B0=1;
        /*LED1をOFFにする  P5のDRの第1ビットを0にする*/
        P5.DR.BIT.B1=0;
        msecwait(1000);/*1000msecの間なにもしない*/
        /*LED0をOFFにする  P5のDRの第0ビットを0にする*/
        P5.DR.BIT.B0=0;
        /*LED1をONにする  P5のDRの第1ビットを1にする*/
        P5.DR.BIT.B1=1;
        msecwait(1000);
    }
}


1.5 実際のプログラム(「h8-3052.h」の利用)

実用プログラムでは,ポートの記述はできるだけ隠すようにしています。H8-1.hはマザーボード上のハードウェア操作のプログラミングを関数呼び出しで行なえるようにしたものです。関数呼び出しを利用すると,どこのポートのどのビットをどうするということを考えずに済み,専用コマンドを使うような感覚でプログラミングでき,便利です。
関数の定義はh8-3052.h中にあります。本Webページの末尾に「h8-3052.h」がありますが,その先頭部分には関数の説明があるので読んでください。

led2nd.c

#include "h8-3052.h"

void msecwait(int msec)
{
    int i,j;
    for (i=0;i<msec;i++) {
        for (j=0;j<2481;j++);    /*2481は実測によって求めた値*/
    }
}

main()
{
    initLed();  /*LED初期化*/
    while(1) {
        turnOnLed(0); /*LED0のON*/
        turnOffLed(1); /*LED1のOFF*/
        msecwait(1000);
        turnOffLed(0); /*LED0のOFF*/
        turnOnLed(1); /*LED1のON*/
        msecwait(1000);
    }
}

 

練習問題 led2nd.cを元にして次のプログラムを作りなさい。

(1)1秒周期で両方のLEDが同時に点滅するプログラム
(2)0.5秒周期で左右のLEDが交互に点滅するプログラム
(3)0.5秒ごとに2つのLEDが次のような4つの点滅パターンを繰り返すプログラム
   (○は消灯,●は点灯を示す)
   ○○,○●,●○,●●
(4)0.5秒ごとに「LED0を2回点滅の後LED1を2回点滅」を繰り返すプログラム
(5)0.5秒ごとに点灯状態が変化し,次の点滅パターンを繰り返すプログラム
  左側2回点滅→右側2回点滅→左側1回点滅→右側1回点滅
(6)10秒周期で両方のLEDが同時に点滅するプログラムをつくり動作させなさい。
  動作中にアナログテスタを使って,CN3の31,32の電圧を測定しなさい。

練習問題 次の作業を行ないなさい。

(1)h8-3052.h中にある関数initLed(),turnOnLed(),turnOffLed()について説明しなさい。
  なおH8/3052ハードウェアマニュアルの関連する説明を抜き出しなさい。(9.6 ポート5,モード7参照)
(2)次のような設計仕様の場合のLED初期化関数initLed4()とturnOnLed(),turnOffLed()を作りなさい。
  ポート5のbit0,bit1,bit2,bit3に制限抵抗付きのLEDが接続されているとします。
  void initLed4(void) LED初期化関数
  void turnOnLed(int number) LEDを点灯させる関数。
    ただし,引数は0,1,2,3を取り,LED0,1,2,3をそれぞれ個別に点灯させます。
  void turnOffLed(int number) LEDを消灯させる関数。
    ただし,引数は0,1,2,3を取り,LED0,1,2,3をそれぞれ個別に消灯させます。
(3)「(2)」で作成した関数を使って,ポート5のbit0,bit1,bit2,bit3にLEDがついていると仮定して,
  10秒周期で4つのLEDが同時に点滅するプログラムをつくり動作させなさい。
  動作中にアナログテスタを使って,このプログラムが4つのビットを駆動していることを検証しなさい。
  (ヒントCN3のどこか)

 

1.6  LEDのPWM駆動

LEDを高速にON-OFFを繰返し,ONになっている時間と周期との比(デューティ比)を変化させると,人間の目には点滅は見えず,デューティ比に応じて明るさが変化しているように見えます。
このような高速ON-OFFスイッチングで出力を制御する方法は「パルス幅変調(PWM)」「Pulse Width Modulation」と呼ばれます。
次のプログラムはLED0を点灯状態に保ち,LED1をPWM駆動します。3秒ごとに,デューティ比を90%,50%,10%と変化させています。

ledpwm.c

/**********************************************************
LEDのPWM(PulseWidthModulation)駆動
**********************************************************/
#include "h8-3052.h"

void msecwait(int msec)
/*msec間なにもしない時間稼ぎ関数*/
{
    int i,j;
    for (i=0;i<msec;i++) {
        for (j=0;j<2481;j++);    /*2481は実測によって求めた値*/
    }
}

main()
{
    int i;
    initLed();  /*LED初期化*/
    turnOnLed(0); /*LED0のON*/
    while(1) {
        for (i=0;i<300;i++) { /*ループ3秒間ループ デューティ比90%*/
            turnOnLed(1); /*LED1のON*/
            msecwait(9);
            turnOffLed(1); /*LED1のOFF*/
            msecwait(1);
        }
        for (i=0;i<300;i++) { /*ループ3秒間ループ デューティ比50%*/
            turnOnLed(1); /*LED1のON*/
            msecwait(5);
            turnOffLed(1); /*LED1のOFF*/
            msecwait(5);
        }
        for (i=0;i<300;i++) { /*ループ3秒間ループ デューティ比10%*/
            turnOnLed(1); /*LED1のON*/
            msecwait(1);
            turnOffLed(1); /*LED1のOFF*/
            msecwait(9);
        }
    }
}

 

次のプログラムは約1秒間隔でLED2が徐々に明るくなる動作を繰り返すプログラムです。
pは0から999まで変化するが,各pの値に対してiの値が0から999まで変化します。
pが10の時は,iが0から9の時LED1はONで10から999まではOFFとなります。すなわちpが10の時LED1がONになっている時間割合は1%程度です。
pが100の時は,iが0から99の時LED1はONで100から999まではOFFとなります。すなわちpが100の時LED1がONになっている時間割合は10%程度です。
pが900の時は,iが0から899の時LED1はONで900から999まではOFFとなります。すなわちpが900の時LED1がONになっている時間割合は90%程度です。
このように時間経過を考えると,LED1がONになっている時間とOFFになっている時間比が変化しています。しかし大変高速にLED1が点滅しているため,人間の目にはLED1の明るさが変化しているように見えます。

ledpwm1.c

/**********************************************************
LEDのPWM(PulseWidthModulation)駆動
**********************************************************/
#include "h8-3052.h"

main()
{
    int p,i;
    initLed();  /*LED初期化*/
    turnOnLed(0); /*LED0のON*/
    while(1) {
        for (p=0;p<1000;p++) {
            for (i=0;i<1000;i++) {
                if (i<p) turnOnLed(1); /*LED1のON*/
                else turnOffLed(1); /*LED1のOFF*/
            }
        }
    }
}


2. 8ビットスイッチ

図3の8ビットスイッチの読み取りを行い,LEDを制御します。
8ビットスイッチのSW1がONならLED1をON。SW2がONならLED2をON,SW3がONならLED1・LED2ともにON,それ以外は2つのLEDはOFFにします。
8ビットスイッチはP2の8つのビットすべてにつながっています。

H8-8BITSW.JPG - 46,974BYTES
H8-8BITSWD.JPG - 12,938BYTES

図3 8ビットスイッチ

参考
通常用いられるのは,図3.1の回路である。スイッチがOFFの時CPUの入力ピンには5Vが与えられ,スイッチがONの時CPUの入力ピンには0Vが与えられる。この用途で用いられている抵抗のことをプルアップ抵抗と呼んでいる。通常この抵抗値は10kΩから100kΩが用いられる。図3.2左はスイッチがOFFであるため,電流は流れず,抵抗で電圧降下が起こらないため,5Vが出力されているところを示している。図3.2右はスイッチがONであるため,電流が流れ,抵抗で電圧降下が起こり,0Vが出力されているところを示している。
H8CPUのポート2,4,5では,スイッチのON-OFF状態の取得等に都合の良い仕掛けがある。図3.3に示すように,図3.1のプルアップ抵抗をCPUユニットが内蔵しており,プルアップ抵抗を有効にするかどうかをソフトウェアで決めることができるようになっている。このプルアップ抵抗の有効無効を設定するのが,プルアップコントロールレジスタ(PCR)である。
AKI-H8のマザーボードでは,ディップスイッチ(8ビットスイッチ)がポート2の8つのビットに,プッシュスイッチ(4つ)がポート4の上位4ビットにつながっており,P2.PCRとP4.PCRの対応するビットに1を書き込むことで,プルアップ抵抗を有効にして使用することができる。そのため,マザーボード上のこれらのスイッチにはプルアップ抵抗がついていない。
図3.1 スイッチ状態のCPUへの入力 図3.2 プルアップ抵抗の役割 図3.3 H8のプルアップコントロール

 

2.1 8ビットSWでLED駆動

8ビットスイッチのON-OFFの状態によってLEDのON-OFFを制御するプログラムを作成します。
LED駆動部のみh8-3052.hを用いてプログラムを作ります。
8ビットスイッチの各端子はH8内部でプルアップされる設定なので,スイッチがONになるとポート2の対応するビットは0になります。OFFになると1になります。通常の感覚と逆なので注意しなければなりません。

eightsw.c

/**********************************************************
8ビットスイッチによってLEDのON-OFFを行う
**********************************************************/
#include "h8-3052.h"

main()
{
    initLed();
    P2.DDR = 0x00;/*8bitSWのポートを入力に設定*/
    P2.PCR.BYTE = 0xff;/*8bitSWのプルアップ設定*/
    while(1) {
        if (P2.DR.BIT.B0==0) { /*8bitSWの1がONの時*/
            turnOnLed(0);
            turnOnLed(1);
        } else if (P2.DR.BIT.B1==0) { /*8bitSWの2がONの時*/
            turnOnLed(0);
            turnOffLed(1);
        } else if (P2.DR.BIT.B2==0) { /*8bitSWの3がONの時*/
            turnOffLed(0);
            turnOnLed(1);
        } else {
            turnOffLed(0);
            turnOffLed(1);
        }
    }
}

参考 「P2.DDR」は「P2のDDR」,「P2.PCR.BYTE」は「P2のPCRをバイト単位で見た時のバイトデータ」,「P2.DR.BIT.B0」は「P2のDRをビットごと指定した時の第0ビット」と読めばよい。「P2.DDR」に指定できる値は0から255(0xff),「P2.PCR.BYTE」に指定できる値は0から255(0xff),「P2.DR.BIT.B0」に指定できる値は0または1である。
この例ではでてこないが,P2.PCR.BIT.B0」は「P2のPCRをビットごと指定した時の第0ビット」と読み,この場合は指定できる値は0または1となる。



2.2  8ビットSWでLED駆動(「h8-3052.h」の利用)
 
8ビットSWの操作も「h8-3052.h」を利用します。2.1のようなプログラムは行なわず,ここにあるようなプログラムにするのがよいでしょう。
プログラム中でcheck8BitSWは
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を関数の戻り値として返します。この関数のおかげで,「0:OFF,1:ON」という普通の感覚でプログラミングできます。

eightswh.c

/**********************************************************
8ビットスイッチによってLEDのON-OFFを行う
**********************************************************/
#include "h8-3052.h"

main()
{
    initLed();
    init8BitSW();/*8bitSWの初期化*/
    while(1) {
        if (check8BitSW(0)) { /*8bitSWの1がONの時*/
            turnOnLed(0);
            turnOnLed(1);
        } else if (check8BitSW(1)) { /*8bitSWの2がONの時*/
            turnOnLed(0);
            turnOffLed(1);
        } else if (check8BitSW(2)) { /*8bitSWの3がONの時*/
            turnOffLed(0);
            turnOnLed(1);
        } else {
            turnOffLed(0);
            turnOffLed(1);
        }
    }
}

練習問題 eightsw.cを元にして次のプログラムを作りなさい。

(1)8bitSWの1がOFFの時,0.5秒周期で2つのLEDを同時点滅,
  8bitSWの1がONの時,1秒周期で2つのLEDを同時点滅
(2)8bitSWのすべてのビットがOFFの時,0.5秒周期で2つのLEDを同時点滅,
  8bitSWの1がONの時,1秒周期で2つのLEDを同時点滅,
  8bitSWの2がONの時,2秒周期で2つのLEDを同時点滅

練習問題

(1)8bitスイッチの回路図を見ると,CPUの端子からスイッチを経てGNDに接続されているだけである。
通常はこの回路ではスイッチの状態を読み取ることができない。
スイッチを読み取るプログラムの初期化部分の意味(8bitSWのプルアップ設定)とあわせてどうして可能なのか検討し,説明しなさい。
なおH8/3052ハードウェアマニュアルの関連する説明を抜き出しなさい。(9.3 ポート2参照)
また小坂のweb文書「h8CPU_Input.html」も参考にしなさい。
(2)8bitスイッチで,4つのスイッチをON,残りの4つのスイッチをOFFにしなさい。
8bitスイッチの初期化をともなうプログラム(例えば「eightswh.c」)を動作させ,アナログテスタを使って,
8ビットスイッチのON-OFFの状態が電圧として見えていることを検証しなさい。(ヒントCN3のどこか)
「H8-MB-Pro.html」の「参考1 H8ピン配置」を参照しなさい。
どのように検証したか(テスタの赤黒を何処に触れたのかを含む),どのような結果が得られたか報告しなさい。
(3)次のポートのビットがCN1,CN2,CN3のどこのピンに見えるのかを答えなさい。
「H8-MB-Pro.html」の「参考1 H8ピン配置」を参照しなさい。
1)ポート5のbit0からbit3
2)ポート2のbit0からbit7
3)ポート1のbit0からbit7
3)ポート3のbit0からbit7
3)ポートAのbit0からbit7
3)ポートBのbit0からbit7

3. プッシュスイッチ

図4のプッシュスイッチの読み取りを行い,LEDを制御します。
プッシュスイッチ1を押すとLED1が点灯し,プッシュスイッチ2を押すとLED2が点灯するプログラムとします。
プッシュスイッチはポート4の第4ビットから第7ビットにつながっています。

H8-PUSHSW.JPG - 31,142BYTES
H8-PUSHSWD.JPG - 14,425BYTES

図4 プッシュスイッチ

3.1  PushSWでLED駆動(「h8-3052.h」の利用)

pushsw.c

/**********************************************************
プッシュスイッチによってLEDのON-OFFを行う
**********************************************************/
#include "h8-3052.h"

main()
{
    initLed();
    initPushSW();/*PushSWの初期化*/
    while(1) {
        if (checkPushSW(0)==1) { /*PushSWの1がONの時*/
            turnOnLed(0);
            turnOffLed(1);
        } else if (checkPushSW(1)==1) { /*PushSWの2がONの時*/
            turnOffLed(0);
            turnOnLed(1);
        } else {
            turnOffLed(0);
            turnOffLed(1);
        }
    }
}

 

練習問題 pushsw.cを元にして次のプログラムを作りなさい。

(1)すべてのプッシュスイッチがOFFの時,0.5秒周期で2つのLEDを同時点滅,
プッシュスイッチの1がONの時,1秒周期で2つのLEDを交互点滅,
プッシュスイッチの2がONの時,2秒周期で2つのLEDを交互点滅
(2)プッシュスイッチの状態によって2つのLEDの同時PWM駆動を行なう。
すべてのプッシュスイッチがOFFの時,なにもしない。
プッシュスイッチの1がONの時,デューティー比100%で点灯,
プッシュスイッチの2がONの時,デューティー比50%で点灯,
プッシュスイッチの3がONの時,デューティー比25%で点灯
(ここではまだ割り込みを用いてはならない)


4. 割り込み

通常の関数は,関数がプログラム中の他の関数から呼び出されたときに作業を行ないます。これに対して,割り込み関数は何らかの割り込み要因によって呼び出される関数です。
タイマ割り込み関数は,タイマ割り込み初期設定によって設定された時間間隔で起動する割り込み関数です。「4.1」のプログラムでは,500msのタイマ割り込み初期設定が行なわれ,CPUの割り込み許可がなされ,タイマがスタートした後,プログラムの流れは
while(1);
となり,何もしない無限ループに突入します。しかし,500ms(0.5秒)ごとにタイマ割り込み関数「interrupt_cfunc()」が起動し,LEDのON−OFFが継続して行なわれます。変数tickはstatic修飾されているので,関数が呼び出されたときに,前回呼び出しの時の値が残っています。かつ0が代入されるのははじめの1回だけです。tick=1-tickの演算により,tickの値は0,1を繰り返します。
ロボットの制御には一定時間ごとに起動する定時間割り込み(タイマー割り込み)が良く用いられます。またPWMの生成にもこの定時間割り込みが用いられる場合があります。
小坂のシステムを用いる限り,タイマ割り込み関数「interrupt_cfunc()」の名前を変更してはいけません。関数の内容は変更してもOKです。

4.1  割り込みでLED駆動

プログラム中main()側で500msec(0.5秒)間隔でタイマ割り込みを設定します。
main()関数内でなにもしないループ動作をしている最中に,割り込み関数interrupt_cfunc()は0.5秒ごとに起動し,LEDのON-OFFを行ないます。
このタイマ割り込みはITUのch0,ch1が使われています。

 

int1st.c

/**********************************************************
時間割り込みによってLEDのON-OFFを行う
**********************************************************/
#include "h8-3052.h"

main()
{
    initLed();
    initTimer01Int(500); /*時間割り込み500msec ch0,ch1使用*/
    E_INT();        /*CPU割り込み許可*/
    startTimer01();  /*時間割り込みタイマスタートch0,ch1*/
    while(1);       /*なにもしないループ*/
}

void interrupt_cfunc() /*この名前は固定*/
{
    static int tick=0;
    if (tick==1) {
        turnOnLed(0);  turnOffLed(1);
    } else {
        turnOffLed(0);  turnOnLed(1);
    }
    tick=1-tick;
}

練習問題 int1st.cを元にして次のプログラムを作りなさい。

(1)割り込み周期を1秒ごとにする。
(2)initTimer1Int()を用いて1秒周期のLED点滅を行なう。(引数がマイクロ秒であること,引数にはshort int型が用いられていることに注意)

 

4.2  割り込みでLED駆動

割り込みを用いたPWM駆動でLEDの制御を行ないます。
このプログラムではITUのch1のみを用います。
PushSW 1 → LED 0 明るく点灯(10/10)
PushSW 2 → LED 0 暗く点灯(1/10)
PushSW 3 → LED 1 明るく点灯(10/10)
PushSW 4 → LED 1 暗く点灯(1/10)

volatile修飾子は,割り込み関数と通常の関数とで同じグローバル変数を用いるときに使います。
コンパイラは通常コードの最適化を行ないます。例えば,変数は通常はメモリ上にあります。ある変数を一度レジスタに読み込んで,その変数の値を変化させていない場合は,次にその変数の値が必要になったときには,メモリをもう一度読みに行くようなことはせず,レジスタの値を用います。しかし,その間に割り込み関数がその変数の値を変化させることもあります。そこでvolatile修飾子をつけた変数にしておくと必ずメモリにある変数を使うコードになります。この例の場合は,特に必要がありませんが,おまじないとしてつけておくようにしましょう。

このプログラムではLEDの暗い点灯時では1/10の時間割合で点灯している。LEDの暗い点灯時に5/10の時間割合で点灯するように変更しなさい。この点灯時間の割合は「デューティ比」と呼ばれる。

int2nd.c

/**********************************************************
プッシュスイッチと時間割り込みによってLEDのPWM制御を行う
**********************************************************/
#include "h8-3052.h"

volatile int led0,led1;
const int period=10; /*周期10msec*/
const int low=1;

main()
{
    led0=led1=0;
    initLed();
    initPushSW();
    initTimer1Int(1000); /*タイマ割り込み1msec */
                         /*単位はμsec ITUch1のみ使用*/
    E_INT();        /*CPU割り込み許可*/
    startTimer1();  /*時間割り込みタイマスタート*/
    while(1){
        if (checkPushSW(0)==1) { /*PushSWの1がONの時*/
            led0=period;
        } else if (checkPushSW(1)==1) { /*PushSWの2がONの時*/
            led0=low;
        } else {
            led0=0;
        }
        if (checkPushSW(2)==1) { /*PushSWの3がONの時*/
            led1=period;
        } else if (checkPushSW(3)==1) { /*PushSWの4がONの時*/
            led1=low;
        } else {
            led1=0;
        }
    }
}

void interrupt_cfunc() /*この名前は固定*/
{
    static int tick=0;
    if (tick<led0) {
        turnOnLed(0);
    } else {
        turnOffLed(0);
    }
    if (tick<led1) {
        turnOnLed(1);
    } else {
        turnOffLed(1);
    }
    tick++;
    if (tick==period) tick=0;
}

5. パソコンとのシリアル通信

プログラム書き込み用通信回線はそのままプログラム実行時にも使えます。
実行時にはハイパーターミナルを起動しておいて下さい。
サンプルフォルダ中の次に示すアイコンで起動すると,設定済みのハイパーターミナルが起動します。

Async, 8bit, NoParity, stop1 ,38400baud, (Backspace:Ctrl+H, Space, Ctrl+H)で設定されています。

ハイパーターミナルを利用した,ビットスイッチやプッシュスイッチのチェックおよびキーボードとの通信プログラムです。
ビットスイッチやプッシュスイッチのチェックの時はそれぞれのスイッチを動かしてみてください。


パソコン画面への出力(WindowsのHyperTerminal使用)
パソコン(キーボード)からの入力(WindowsのHyperTerminal使用)

sciout.c

/**********************************************************
SCI1へ出力,WINDOWSのHyperTerminalなどで受信できる。
ただし,設定は 38400baud, Async, 8bit , NoParity, stop1
**********************************************************/
#include "h8-3052.h"

void func1(void)
{
    unsigned char sw,previous;
    SCI1_printf("Printing 8-bitSW status...\n");
    SCI1_printf("Change 8-bitSW and new status will appear.\n");
    SCI1_printf("If any key on the keyboard, this test will quit.\n");
    previous=sw=get8BitSW();
    SCI1_printf("8-bitSW status= %2x[%08b]\n",sw,sw);
    do {
        sw=get8BitSW();
        if (sw!=previous) {
            SCI1_printf("8bitSW status= %2x[%08b]\n",sw,sw);
            previous=sw;
        }
    } while (chkgetCharSCI1()<0);
}

void func2(void)
{
    unsigned char sw,previous;
    SCI1_printf("Printing PushSW status...\n");
    SCI1_printf("Change PushSW and new status will appear.\n");
    SCI1_printf("If any key on the keyboard, this test will quit.\n");
    previous=sw=getPushSW();
    SCI1_printf("PushSW status= %2x[%08b]\n",sw,sw);
    do {
        sw=getPushSW();
        if (sw!=previous) {
            SCI1_printf("PushSW status= %2x[%08b]\n",sw,sw);
            previous=sw;
        }
    } while (chkgetCharSCI1()<0);
}

void func3(void)
{
    int x;
    x=getIntSCI1("Key in a decimal number >>>");
    SCI1_printf("The number you keyed in is %d %x\n",x,x);
    x=getIntSCI1("Key in a hexdecimal number (ex. 0x23ff) >>>");
    SCI1_printf("The number you keyed in is %d %x\n",x,x);
}

main()
{
    int menu;
    initSCI1(); /*SCI-ch1の初期化*/
    initPushSW(); /*押しボタンスイッチの初期化*/
    init8BitSW(); /*8ビットスイッチの初期化*/
    SCI1_printf("Hello. How are you?\n");
    while (1) {
        SCI1_printf("***************menu**********\n");
        SCI1_printf("1:   get 8-bit SW and print \n");
        SCI1_printf("2:   get Push SW and print \n");
        SCI1_printf("3:   get integer from SCI1 and print \n");
        do {
            menu=getCharSCI1(); /*menuには'1','2','3'が入るはず*/
        } while (menu<'1'||'3'<menu);
        SCI1_printf("\n");
        switch (menu) {
        case '1':
            func1();
            break;
        case '2':
            func2();
            break;
        case '3':
            func3();
            break;
        default:
            break;
        }
    }
}

  ●画面への表示をそのままファイル化する方法

練習問題 次のプログラムを作りなさい。

(1)マイコンのプログラム実行開始後,4つのプッシュスイッチがそれぞれ何回押されたかを表示するプログラムを作成しなさい。
このプログラムは電源がOFFされるまでカウントを続け,絶えず最新のカウントを表示し続けるものとします。

(2)アドレス0x0000から0x01FFまでのメモリを十六進ダンプするプログラムを作りなさい。
ヒント int型変数ptrに0x1200が入っている時,アドレス0x1200の内容を表示するには
次のように書くと良い。
SCI1_printf(" %02x",*(unsigned char *)ptr);

実行例
memory dump 0x0000-0x01ff
     +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
0000 00 00 01 00 ff ff ff ff ff ff ff ff ff ff ff ff
0010 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0020 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0030 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0040 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0050 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0060 00 00 0a 24 ff ff ff ff ff ff ff ff ff ff ff ff
0070 00 00 0a 24 ff ff ff ff ff ff ff ff ff ff ff ff
0080 00 00 0a 24 ff ff ff ff ff ff ff ff ff ff ff ff
0090 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00a0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00b0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00c0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00d0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00e0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00f0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0100 7a 07 00 0f ff 10 01 00 6b 20 00 00 0b 8c 01 00
0110 6b 21 00 00 0b 90 01 00 6b 22 00 00 0b 94 01 f0
0120 64 22 5a 00 01 2e 6c 03 68 93 0b 01 1b 72 46 f6
0130 01 00 6b 21 00 00 0b 98 01 00 6b 22 00 00 0b 9c
0140 f3 00 01 f0 64 22 5a 00 01 50 68 93 0b 01 1b 72
0150 46 f8 5e 00 09 90 40 fe ff ff ff ff ff ff ff ff
0160 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0170 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0180 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0190 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
01a0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
01b0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
01c0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
01d0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
01e0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
01f0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff


(3)指定したアドレスから0x100byteをメモリダンプするプログラムを作りなさい。
ただし指定アドレスは十六進の1の位は0とする。

実行例
start address (0xnnnn) =0x400
memory dump 0400-04ff
     +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
0400 18 88 6e f8 00 32 7a 06 00 00 00 50 0a f6 0b 96
0410 73 0e 47 0e 7a 00 00 00 00 50 0a f0 0b 90 0b 70
0420 40 0a 7a 00 00 00 00 50 0a f0 0b 90 0f 86 7a 00
0430 00 00 00 25 0a f0 01 00 6f f0 00 2a 5a 00 08 64
0440 01 00 6f 70 00 50 68 0c 0c 44 46 44 ac 25 46 36
0450 f4 01 18 55 f8 20 6e f8 00 2f 18 88 6e f8 00 32
0460 6e f8 00 33 01 00 6f 70 00 2a 1b 70 0f 82 0b 70
0470 18 99 68 89 18 dd 18 88 6e f8 00 30 f8 2b 6e f8
0480 00 31 5a 00 08 56 0c c8 5c 00 ff 32 5a 00 08 56
0490 ac 6c 46 06 70 14 5a 00 06 54 ac 30 4d 2c ac 39
04a0 4e 28 0c 55 46 0e ac 30 46 0a f8 30 6e f8 00 2f
04b0 5a 00 06 54 f8 0a 50 50 08 c8 88 d0 0c 85 a8 20
04c0 58 30 01 90 f5 20 5a 00 06 54 ac 2d 46 0a f8 01
04d0 6e f8 00 32 5a 00 06 54 ac 64 46 0c 70 24 f8 0a
04e0 6e f8 00 33 5a 00 06 54 ac 75 46 0a f8 0a 6e f8
04f0 00 33 5a 00 06 54 ac 78 46 0a f8 10 6e f8 00 33
start address (0xnnnn) =0x500
memory dump 0500-05ff
     +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
0500 5a 00 06 54 ac 58 46 0e f8 10 6e f8 00 33 6e f8
0510 00 30 5a 00 06 54 ac 6f 46 0a f8 08 6e f8 00 33
0520 5a 00 06 54 ac 62 46 0a f8 02 6e f8 00 33 5a 00
0530 06 54 ac 70 46 18 f8 10 6e f8 00 33 6e f8 00 30
0540 f5 08 f8 30 6e f8 00 2f 70 14 5a 00 06 54 ac 63
0550 46 3c 0f e4 0b f4 73 0c 47 06 0f c0 0b 70 40 02
0560 0f c0 0f 86 1b f0 01 00 6f f0 00 26 73 08 47 0a
0570 01 00 6f 71 00 26 1b 71 40 06 01 00 6f 71 00 26
0580 6e 18 00 01 5c 00 fe 36 18 44 5a 00 06 54 ac 73
0590 58 60 00 b8 0c 55 47 7c 18 dd 0f e0 0b 90 01 00
05a0 6f f0 00 26 73 08 47 0a 01 00 6f 70 00 26 0b 70
05b0 40 06 01 00 6f 70 00 26 0f 86 1b 90 0f 84 73 08
05c0 47 06 0f c0 1b 70 40 02 0f c0 01 00 69 02 40 02
05d0 0a 0d 0c d8 17 50 17 70 0f a1 0a 81 68 18 46 f0
05e0 6e 78 00 32 46 10 0c dc 40 08 f8 20 5c 00 fd ce
05f0 0a 0c 1c 5c 45 f4 0f a0 5c 00 fd de 6e 78 00 32
start address (0xnnnn) =


5. 「パソコンとのシリアル通信」,「タイマー割り込み」を用いた時計

「パソコンとのシリアル通信」,「タイマー割り込み」を用いた時計を作ります。

timer.c

/**********************************************************
割り込みを用いた時計 起動時からの経過時間[秒]を
SCI1へ出力,WINDOWSのHyperTerminalなどで受信できる。
ただし,設定は
38400baud, Async, 8bit , NoParity, stop1
**********************************************************/
#include "h8-3052.h"

volatile unsigned int counter;

main()
{
    unsigned int counter1;
    unsigned int t1,t2;
    initSCI1(); /*SCI-ch1の初期化*/
    initTimer01Int(100); /*時間割り込み100msec ch0,ch1使用*/
    E_INT();        /*CPU割り込み許可*/
    startTimer01();  /*時間割り込みタイマスタートch0,ch1*/
    counter=0;
    while(1) {
        counter1=counter;
        t1=counter1/10;
        t2=counter1%10;
        SCI1_printf("%10u.%1u\r",t1,t2);
    }
}

void interrupt_cfunc() /*割り込みルーチン この名前は固定*/
{
    counter++;
}

練習問題 int2nd.c,sciout.c,timer.cを元にして次のプログラムを作りなさい。

(1)100msecごとの割り込みを用いて,ストップウォッチを作成せよ。スタート・ストップはキーボードのキーに割り当てても良いし,あるいはマザーボード上のプッシュスイッチを用いても良い。また割り込み関数内で表示を行なってはいけない。グローバル変数のカウンタを用いればよいだろう。
(2)キーボードから0から10までの整数をint型変数ratioに受け取り,「4.2 int2nd.c」のプログラムで,点灯時間をratio/10のデューティ比になるようにしなさい。またデューティ比の変更は何回でもできるようにしなさい。



 参考1 H8ピン配置

コネクタ1(CN1)ピン割り当て

コネクタ2(CN2)ピン割り当て

コネクタ3(CN3)ピン割り当て

コネクタ4(CN4)ピン割り当て

コネクタ5(CN5)ピン割り当て

CN1 pin H8 pin name
1 GND GND
2 GND GND
3 87 P8-0
4 88 P8-1
5 89 P8-2
6 90 P8-3
7 91 P8-4
8 93 PA-0
9 94 PA-1
10 95 PA-2
11 96 PA-3
12 97 PA-4
13 98 PA-5
14 99 PA-6
15 100 PA-7
16 2 PB-0
17 3 PB-1
18 4 PB-2
19 5 PB-3
20 6 PB-4
21 7 PB-5
22 8 PB-6
23 9 PB-7
24 10 FWE
25 12 P9-0
26 13 P9-1
27 14 P9-2
28 15 P9-3
29 16 P9-4
30 17 P9-5
31 18 P4-0
32 19 P4-1
33 20 P4-2
34 21 P4-3
35 5V 5V
36 5V 5V
37 GND GND
38 GND GND
39 POWER POWER
40 POWER POWER
CN2 pin H8 pin name
1 GND GND
2 GND GND
3 62 STBY
4 63 RES
5 64 NMI
6 69 P6-3
7 70 P6-4
8 71 P6-5
9 72 P6-6
10 76 AVCC
11 77 AREF
12 78 P7-0
13 79 P7-1
14 80 P7-2
15 81 P7-3
16 82 P7-4
17 83 P7-5
18 84 P7-6
19 85 P7-7
20 86 AVSS
CN3 pin H8 pin name
1 GND GND
2 GND GND
3 23 P4-4
4 24 P4-5
5 25 P4-6
6 26 P4-7
7 27 P3-0
8 28 P3-1
9 29 P3-2
10 30 P3-3
11 31 P3-4
12 32 P3-5
13 33 P3-6
14 34 P3-7
15 36 P1-0
16 37 P1-1
17 38 P1-2
18 39 P1-3
19 40 P1-4
20 41 P1-5
21 42 P1-6
22 43 P1-7
23 45 P2-0
24 46 P2-1
25 47 P2-2
26 48 P2-3
27 49 P2-4
28 50 P2-5
29 51 P2-6
30 52 P2-7
31 53 P5-0
32 54 P5-1
33 55 P5-2
34 56 P5-3
35 58 P6-0
36 59 P6-1
37 60 P6-2
38 61 CK
39 GND GND
40 GND GND
CN4 pin H8 pin name
1 POWER POWER
2 GND GND
3 5V 5V
4 U2-8 RXD1
5 U2-13 RXD0
6 U2-7 TXD1
7 U2-14 TXD0
8 10 FWE
9 75 MD2
10 63 RES
CN5 pin H8 pin name
1 GND GND
2 73 MD-0
3 GND GND
4 74 MD-1
5 GND GND
6 75 MD-2

 


参考2 h8-3052.h

h8-3052.h

/****************************************************************
h8-3052.h
Copyright (c) Kosaka Lab CS TNCT

このインクルードファイルは小坂研究室の代々の研究生が開発した
有用な関数群を改良して小坂がまとめたものである。
28 Jun 2006 h8-3052.h  小坂 chkgetSCI1のタイミング修正
11 Nov 2004 h8-3052.h  小坂,西 3052用にクロック関係部分を変更16MHz→25MHz
 4 Dec 2003 h8-01.h  小坂 printf更新,initLed更新,initDDR削除
08 Oct 2003 h8-01.h  小坂 stopTimer追加,getIntSCI1でBS使用可
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】SCI ch1 関係
void initSCI1()
 SCI-ch1の初期化 38400baud, Async, 8bit , NoParity, stop1

short 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

【2】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を返す

【3】タイミング割り込み
void initTimer1Int(unsigned short int period)
 ITU1による割り込みタイマーの設定
 割り込み間隔は引数peiodで単位はμsecである
 値は20971以下でなければならない。20.971msecまで設定可能

void startTimer1(void)
 Timer CH1 スタート
 これはマクロ定義で実現されている
void stopTimer1(void)
 Timer CH1 ストップ
 これはマクロ定義で実現されている

void initTimer01Int(unsigned short int period)
 ITU0とITU1による割り込みタイマーの設定
 割り込み間隔は引数peiodで単位はmsecである
 値は65535以下でなければならない。65.535secまで設定可能
 ただしポートPAの第3ビットが使用できなくなるので注意
void startTimer01(void)
 Timer CH0 CH1 同時スタート
 これはマクロ定義で実現されている
void stopTimer01(void)
 Timer CH0 CH1 同時ストップ
 これはマクロ定義で実現されている

****************************************************************/

#include<stdarg.h>
#include<3052f.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 = 19;          /* 38400baud (CPU=25MHz) */
    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より整数値を入力*/
int getIntSCI1(char prompt[])
/*getting integer from serial port*/
/* format 123[ret] */
/*        -123[ret] */
/*        0x1a[ret] */
/*        -0x100[ret] */
{
    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である*/
/*値は20971以下でなければならない*/
/*20.971msecまで*/
{
    unsigned int period25=(unsigned int)((25*(long int)period+4)>>3);
    ITU1.TCR.BIT.CCLR=1;  /*GRAのコンペアマッチでTCNTをクリア*/
    ITU1.TCR.BIT.CKEG=0;  /*立ち上がりエッジでカウント*/
    ITU1.TCR.BIT.TPSC=3;  /*内部クロックφ/8でカウント*/
    ITU1.GRA=period25-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 = 3125-1;        /* タイマー CH0 ((25/8)MHz)/1000Hz=3125 */
   
    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 ストップ */