H8サンプルプログラム-その2
CPUボード:RY3048Fone を使って、
制御対象回路として「ものづくり kumamoto Ver.01」を制御するサンプルプログラムを作ります。
7セグメントLED(LED1、LED2)の点灯、スイッチ入力を制御します。小さなテーマの集まりですが、対象としているハードウェアの接続(ケーブル、回路内のすべて)を確認しながら進めてください。その一つひとつがプログラムの力になります。
■テーマ概要
・制御のヒント
PA.DR.BYTE → 0xff or ~0x00 = a~gの点灯
PA.DR.BIT.B0 → a = 0:点灯、1:消灯
PA.DR.BIT.B1 → b = 0:点灯、1:消灯
PA.DR.BIT.B2 → c = 0:点灯、1:消灯
PA.DR.BIT.B3 → d = 0:点灯、1:消灯
PA.DR.BIT.B4 → e = 0:点灯、1:消灯
PA.DR.BIT.B5 → f = 0:点灯、1:消灯
PA.DR.BIT.B6 → g = 0:点灯、1:消灯
PA.DR.BIT.B7 → n/a(接続なし)
SW1(トグルスイッチ)の状態により、点灯するLEDを切り替える。
SW1がオンの時は、LED1が点灯+LED2が消灯し、
SW1がオフの時は、LED1が消灯+LED2が点灯する。
・テーマは、次の通りです。
1)LED1とLED2の全セグメントを点灯する。
2)LED1とLED2の全セグメントを消灯する。
3)LED1とLED2のセグメント「a」だけを点灯する。
4)LED1とLED2のセグメント「b」だけを点灯する。
5)LED1とLED2のセグメント「c」だけを点灯する。
6)LED1とLED2のセグメント「d」だけを点灯する。
7)LED1とLED2のセグメント「e」だけを点灯する。
8)LED1とLED2のセグメント「f」だけを点灯する。
9)LED1とLED2のセグメント「g」だけを点灯する。
10)SW2(プッシュスイッチ)でセグメントの点灯をシフトする。
11)SW3(透過センサー)でセグメントの点灯をシフトする。
12)SW2(プッシュスイッチ)でカウント表示(1桁)する。
13)SW3(透過センサー)でカウント表示(1桁)する。
注:この時、LED3~LED10は全消灯とする。
■接続
制御対象回路 CPUボード:RY3048Fone
CN1 → J2
CN2 → J3
J1 → トグルスイッチ、プッシュスイッチ、透過センサー
■開発環境
ルネサスエレクトロニクス社 High-performance Embedded Workshop を使います。
最新版をルネサスエレクトロニクス社のホームページよりダウンロードしてセットアップしてください。
注:このプロジェクトでは、「H8S,H8/300 Standard Toolchain...」(「ビルド」メニューから起動)の設定を変更している。「標準ライブラリ」の「モード」をデフォルト設定の「ライブラリファイル指定なし」から、「ライブラリファイル作成(常に)」に設定した。そうしないと下記リンクエラーが発生する。
L2310 (E) Undefined external symbol "$sp_regsv$3" referenced in "C:\sakaki\・・\demo02.obj"
L2310 (E) Undefined external symbol "$spregld2$3" referenced in "C:\sakaki\・・\demo03.obj"
Optimizing Linkage Editor Abort
→この対応で一度、ライブラリファイルが作成されると、その後、以前の「ライブラリファイル指定なし」に戻してもリンクエラーは発生しなくなった。理由は、不明。しかし、今後の事が心配である為、「ライブラリファイル指定なし」には戻さない。
■準備-その1
ヘッダファイルを用意します。
ファイル名:ry3048fone.h
フォルダー:自分の開発環境に合わせる。
ヘッダファイルの内容は、次の通り。
---この次から---
void InitializeIO(void);
int GetSW1(void);
int GetSW2(void);
int GetSW3(void);
#define LED_AL_OFF 0xff
#define LED_AL_ON 0x00
#define OE_ENABLE 0
#define OE_DISABLE 1
#define FET_ENABLE 1
#define FET_DISABLE 0
#define LED7SEG_ALL PA.DR.BYTE
#define OE_7SEG PB.DR.BIT.B7
#define OE_LED PB.DR.BIT.B6
#define A 0x01
#define B 0x02
#define C 0x04
#define D 0x08
#define E 0x10
#define F 0x20
#define G 0x40
#define SW1 P7.DR.BIT.B1
#define SW2 P7.DR.BIT.B3
#define SW3 P7.DR.BIT.B5
#define SW_ON 0
#define SW_OFF 1
#define True 1
#define False 0
const char LEDSegData[10] = {
~(A+B+C+D+E+F),
~(B+C),
~(A+B+G+E+D),
~(A+B+G+C+D),
~(F+G+B+C),
~(A+F+G+C+D),
~(A+F+G+C+D+E),
~(A+B+C),
~(A+B+C+D+E+F+G),
~(A+B+C+D+F+G) };
void InitializeIO(void)
{
/* 入出力端子の定義 */
PA.DR.BYTE = 0;
PA.DDR = 0xff;
PA.DR.BYTE = LED_AL_OFF;
PB.DR.BYTE = 0;
PB.DDR = 0xff;
}
int GetSW1(void)
{
return( SW1 );
}
int GetSW2(void)
{
return( SW2 );
}
int GetSW3(void)
{
return( SW3 );
}
---この前まで---
■準備-その2
サンプル用のスタータプログラム(アセンブラ)を用意します。
ファイル名:demo02start.src
フォルダー:プロジェクト指定のフォルダー
---この次から---
.CPU 300HA:20
STACK_BASE: .EQU H'FFFF10 ; スタック基底アドレス(モード7)
.IMPORT _main ; 外部参照(main関数)
.SECTION V ; H'000000
.DATA.L RESET_START
.SECTION P ; H'000100
RESET_START:
MOV.L #STACK_BASE,ER7 ; スタックの設定
JSR @_main ; C言語のmain()関数へジャンプ
OWARI:
BRA OWARI
.END
---この前まで---
注:このファイル(拡張子が「src」)は、これまで作成してきた中に入っています。それをそのまま、ファイル名を変えて利用されても構いません。先に作成したファイル「demo01start.src」のファイル名称を「demo02start.src」変更して流用してもよいです。
■準備-その3
サンプル用のソースプログラムファイル(C言語)を用意します。
ファイル名:demo02.c
フォルダー:プロジェクト指定のフォルダー
注:この時、7セグメントLEDは全消灯とする。
---この次から---
#include "3048f.h"
#include "ry3048fone.h"
void main(void);
void main(void)
{
/* ローカル変数の定義 */
unsigned char LedShifted;
int DuringON;
int IsFirst;
/* 処理 */
InitializeIO();
OE_7SEG = OE_ENABLE;
OE_LED = OE_DISABLE;
LED7SEG_1 = FET_DISABLE;
LED7SEG_2 = FET_DISABLE;
IsFirst = True;
for(;;){
if( GetSW1() == SW_ON ){
LED7SEG_1 = FET_ENABLE;
LED7SEG_2 = FET_DISABLE;
} else {
LED7SEG_1 = FET_DISABLE;
LED7SEG_2 = FET_ENABLE;
}
/*ここにサンプルプログラムを書く*/
}
}
---この前まで---
それでは、次に「/*ここにサンプルプログラムを書く*/」のところに、実際にプログラムを書いてみましょう。
■サンプルプログラムの作成
1)LED1とLED2の全セグメントを点灯する。
LED7SEG_ALL = LED_AL_ON;
全セグメント点灯(し続け)ます。
2)LED1とLED2の全セグメントを消灯する。
LED7SEG_ALL = LED_AL_OFF;
全セグメント消灯(し続け)ます。
3)LED1とLED2のセグメント「a」だけを点灯する。
LED7SEG_ALL = ~0x01;
PA.DR.BIT.B0だけを「0」にして、a を点灯(し続け)ます。
a だけを消灯させたい時は、チルダ「~」を外します。
4)LED1とLED2のセグメント「b」だけを点灯する。
LED7SEG_ALL = ~0x02;
PA.DR.BIT.B1だけを「0」にして、b を点灯(し続け)ます。
b だけを消灯させたい時は、チルダ「~」を外します。
5)LED1とLED2のセグメント「c」だけを点灯する。
LED7SEG_ALL = ~0x04;
PA.DR.BIT.B2だけを「0」にして、c を点灯(し続け)ます。
c だけを消灯させたい時は、チルダ「~」を外します。
6)LED1とLED2のセグメント「d」だけを点灯する。
LED7SEG_ALL = ~0x08;
PA.DR.BIT.B3だけを「0」にして、d を点灯(し続け)ます。
d だけを消灯させたい時は、チルダ「~」を外します。
7)LED1とLED2のセグメント「e」だけを点灯する。
LED7SEG_ALL = ~0x10;
PA.DR.BIT.B4だけを「0」にして、e を点灯(し続け)ます。
e だけを消灯させたい時は、チルダ「~」を外します。
8)LED1とLED2のセグメント「f」だけを点灯する。
LED7SEG_ALL = ~0x20;
PA.DR.BIT.B5だけを「0」にして、f を点灯(し続け)ます。
f だけを消灯させたい時は、チルダ「~」を外します。
9)LED1とLED2のセグメント「g」だけを点灯する。
LED7SEG_ALL = ~0x40;
PA.DR.BIT.B6だけを「0」にして、g を点灯(し続け)ます。
g だけを消灯させたい時は、チルダ「~」を外します。
10)SW2(プッシュスイッチ)でセグメントの点灯をシフトする。
初期状態の時、a のみが点灯し、SW2を一回押下すると次に b が点灯する。
SW2を押下する毎に以後、一つずつセグメントの点灯がシフト(a→b→c→d→e→f→g)する。
g 迄到達したら、次の押下で a に戻り、以後これを繰り返す。
注:この処理では、スイッチのチャタリングが影響し、セグメントのシフト点灯が旨くいかない時がある。
オン状態を確実にするため、フラグ「DuringON」を使ったが、もう少し工夫が必要と思われる。
if( IsFirst == True ){
LedShifted = 0x01;
DuringON = False;
IsFirst = False;
}
if( GetSW2() == SW_ON && DuringON == False ){
DuringON = True;
if( LedShifted == 0x40 ) LedShifted = 0x01;
else LedShifted = LedShifted << 1;
}
if( GetSW2() != SW_ON ) DuringON = False;
LED7SEG_ALL = ~LedShifted;
注:シフト中のLEDだけを消灯する時は、チルダ「~」を外す。
11)SW3(透過センサー)でセグメントの点灯をシフトする。
初期状態の時、a のみが点灯し、SW2を一回押下すると次に b が点灯する。
SW3を遮光する毎に以後、一つずつセグメントの点灯がシフト(a→b→c→d→e→f→g)する。
g 迄到達したら、次の遮光で a に戻り、以後これを繰り返す。
注:透過センサーでは、プッシュスイッチの様なチャタリングがないので、セグメントのシフト点灯は、この処理で問題なく動作する。只、スイッチの操作で初期状態として、遮光(オフ状態)から入るか、透過(オン状態)から入るかを決めないといけない。SW2の時の初期状態と同様に、LedShifted を 0x01 として、透過(オン状態)から入ると、電源投入時、シフト処理が一回入る為、b から点灯開始となる。これを回避するには、LedShifted を 0x40 から始めるとよい。初期状態が透過(オン状態)なので、その最初のシフト処理を通り、LedShifted が 0x40→0x01 となって、最初の点灯が a となる。
if( IsFirst == True ){
LedShifted = 0x40;
DuringON = False;
IsFirst = False;
}
if( GetSW3() == SW_ON && DuringON == False ){
DuringON = True;
if( LedShifted == 0x40 ) LedShifted = 0x01;
else LedShifted = LedShifted << 1;
}
if( GetSW3() != SW_ON ) DuringON = False;
LED7SEG_ALL = ~LedShifted;
注:シフト中のLEDだけを消灯する時は、チルダ「~」を外す。
12)SW2(プッシュスイッチ)でカウント表示(1桁)する。
初期状態の時、0を表示し、SW2を一回押下すると 0→1 とカウントする。
SW2を押下する毎に以後、一つずつカウントアップ(0→1→2→3→4→5→6→7→8→9)する。
9迄到達したら、次の押下で0に戻り、以後これを繰り返す。
注:この処理では、スイッチのチャタリングが影響し、カウント結果の値表示が旨くいかない時がある。オン状態を確実にするため、フラグ「DuringON」を使ったが、もう少し工夫が必要と思われる。
if( IsFirst == True ){
LedShifted = 0;
DuringON = False;
IsFirst = False;
}
if( GetSW2() == SW_ON && DuringON == False ){
DuringON = True;
if( LedShifted == 9 ) LedShifted = 0;
else LedShifted++;
}
if( GetSW2() != SW_ON ) DuringON = False;
LED7SEG_ALL = LEDSegData[LedShifted];
13)SW3(透過センサー)でカウント表示(1桁)する。
初期状態の時、0を表示し、SW3を一回遮光すると 0→1 とカウントする。
SW3を遮光する毎に以後、一つずつカウントアップ(0→1→2→3→4→5→6→7→8→9)する。
9迄到達したら、次の遮光で0に戻り、以後これを繰り返す。
注:透過センサーでは、プッシュスイッチの様なチャタリングがないので、セグメントのシフト点灯は、この処理で問題なく動作する。只、スイッチの操作で初期状態として、遮光(オフ状態)から入るか、透過(オン状態)から入るかを決めないといけない。SW2の時の初期状態と同様に、LedShifted を 0 として、透過(オン状態)から入ると、電源投入時、シフト処理が一回入る為、1 から点灯開始となる。これを回避するには、LedShifted を 9 から始めるとよい。初期状態が透過(オン状態)なので、その最初のシフト処理を通り、LedShifted が 9→0 となって、最初の点灯が 0 となる。
if( IsFirst == True ){
LedShifted = 9;
DuringON = False;
IsFirst = False;
}
if( GetSW3() == SW_ON && DuringON == False ){
DuringON = True;
if( LedShifted == 9 ) LedShifted = 0;
else LedShifted++;
}
if( GetSW3() != SW_ON ) DuringON = False;
LED7SEG_ALL = LEDSegData[LedShifted];