ステップ10
LCD表示
実際にLCDに文字を出力させてみましょう。LCDへ以下のように表示する。
1行目:ABC
2行目:カウント(約1秒間隔でカウントアップ)
■用意するもの
半固定抵抗 100KΩ LCD コンデンサ 0.1μF
■LCD 各ピン説明
■LCD制御回路図
■LCDのタイミングチャート
Eの変化を起点にして考えると
・RSとR/Wの変化開始は、短くともEの立ち上がりより40nsは早くなくてはならない。
・RSとR/Wの変化終了は、短くともEの立ち下がりより10nsは遅くなくてはならない。
・EがHighとなる時間は、短くとも220nsなくてはならない。
・Dataの変化開始は、短くともEの立ち下がりより60nsは早くなくてはならない。
・Dataの変化終了は、短くともEの立ち下がりより10nsは遅くなくてはならない
・Eの周期(立ち上がりから次の立ち上がりまで)は、短くとも500nsはなくてはならない
各信号の制御がこの条件を満たすようにプログラミングしてください。
■LCD制御プログラミング
●main.c
/***********************************************************************/
/* */
/* PROJECT NAME : A10 */
/* FILE : A10.c */
/* DESCRIPTION : Main Program */
/* CPU SERIES : H8/300H */
/* CPU TYPE : 3052F */
/* */
/* This file is generated by KPIT Eclipse. */
/* */
/***********************************************************************/
#include <stdio.h>
#include "iodefine.h"
#include "intrinsics.h"
#include "sci.h"
#include "ctype.h"
#include "lcd.h"
#ifdef CPPAPP
//Initialize global constructors
extern "C" void __main()
{
static int initialized;
if (! initialized)
{
typedef void (*pfunc) ();
extern pfunc __ctors[];
extern pfunc __ctors_end[];
pfunc *p;
initialized = 1;
for (p = __ctors_end; p > __ctors; )
(*--p) ();
}
}
#endif
unsigned char sw_prev[4]; // SWの直前のOn/Off状態
unsigned char buff[32]; // 結果出力用バッファ
unsigned char scan_cnt; // 入力スキャン用カウンタ
unsigned char state; // 状態変数
unsigned char ope; // 演算子
long left; // 左値
long right; // 右値
unsigned int sec = 0;
static unsigned char keyTab[][4] = {
{ 'C', '0', '=', '/' },
{ '7', '8', '9', '*' },
{ '4', '5', '6', '-' },
{ '1', '2', '3', '+' }
};
void initIO(void){
unsigned char i;
P1.DDR = 0xff;
P2.DDR = 0x00; // キー入力
P3.DDR = 0xff;
P4.DDR = 0xff;
P5.DDR = 0xff;
P6.DDR = 0xf0;
P8.DDR = 0xff;
P9.DDR = 0xff;
PA.DDR = 0xff;
PB.DDR = 0xff;
P2.PCR.BYTE = 0xff; // 下位4ビット:プルアップ有効
P1.DR.BYTE = 0xff;
for(i = 0; i < 4; i++){
P1.DR.BYTE = ~(1 << i);
sw_prev[i] = 0x0f & P2.DR.BYTE;
P1.DR.BYTE = 0xff;
}
}
void all_clear(){
state = 0;
left = right = 0;
ope = ' ';
}
void initApp(void){
scan_cnt = 0;
all_clear();
}
void initITU(void){
set_imask_ccr(1); // 割込み禁止
ITU0.TCR.BIT.CCLR = 1; // GRAコンペアマッチ-->TCNTクリア
ITU0.TCR.BIT.CKEG = 0; // 立ち上がりエッジでカウント
ITU0.TCR.BIT.TPSC = 2; // 分周比 0:φ 1:φ/2 2:φ/4 3:φ/8
ITU0.TCNT = 0;
ITU0.GRA = 62499; // 1/100秒でコンペアマッチ
ITU0.TSR.BIT.IMFA = 0; // フラグクリア
ITU0.TIER.BYTE = 1; // コンペアマッチA-->割込み
ITU.TSTR.BYTE = 1; // ITU0 START
set_imask_ccr(0); // 割込み許可
}
int main(void)
{
initIO();
initApp();
initITU();
initSCI();
lcdInit();
lcdCursorOff();
lcdBlinkOff();
lcdClear();
lcdXY(1,1);
lcdPutString("ABC");
while (1) {
sprintf(buff,"%d", sec);
sci_puts(buff);
lcdXY(1,2);
lcdPutString(buff);
waitMs(1000);
sec++;
}
return 0;
}
void printValue(){
if (state == 0 || state == 1){
sprintf(buff, "%ld\n", left);
sci_puts(buff);
} else if (state == 2){
sprintf(buff, "%ld %c\n", left, ope);
sci_puts(buff);
} else if (state == 3){
sprintf(buff, "%ld %c %ld\n", left, ope, right);
sci_puts(buff);
}
}
int isOperator(unsigned char c){
return((c == '+')||(c == '-')||(c == '*')||(c =='/'));
}
void ope_execute(){
if (ope == '+'){
left += right;
} else if (ope == '-'){
left -= right;
} else if (ope == '*'){
left *= right;
} else if (ope == '/'){
if (right == 0){
sci_puts("ERROR: divided by 0\n");
all_clear();
} else {
left /= right;
}
}
}
// 左下が(0,0)
void keyTyped(int row, int col){
unsigned char c;
c = keyTab[row][col];
if (c == 'C'){
all_clear();
} else if (state == 0){
if (isdigit(c)){
left = c - '0';
state = 1;
} else if (c == '='){
ope_execute();
} else if (isOperator(c)){
ope = c;
state = 2;
}
} else if (state == 1){
if (isdigit(c)){
left = 10*left + c - '0';
} else if (isOperator(c)){
ope = c;
state = 2;
} else if (c == '='){
ope = ' ';
state = 0;
}
} else if (state == 2){
if (isdigit(c)){
state = 3;
right = c - '0';
} else if (c == '='){
right = left;
ope_execute();
state = 0;
} else if (isOperator(c)){
ope = c;
}
} else if (state == 3){
if (isdigit(c)){
right = 10*right + c - '0';
} else if (isOperator(c)){
ope_execute();
ope = c;
state = 2;
} else if (c == '='){
ope_execute();
state = 0;
}
}
printValue();
}
int keyScan(void){
unsigned char sw, sw_on;
int i, j, cnt;
cnt = 0;
for(i = 0; i < 4; i++){
P1.DR.BYTE = ~(1 << i);
sw = 0x0f & P2.DR.BYTE; // i行目をスキャン
P1.DR.BYTE = 0xff;
sw_on = (sw_prev[i] ^ sw) & ~sw; // 押されたスイッチを1
for(j = 0; j < 4; j++){
if (sw_on & (0x08 >> j)){
// i行 j列のキーが Off→On
cnt++;
keyTyped(i, j);
}
}
sw_prev[i] = sw; // i行目の状態を記憶しておく
}
return cnt;
}
/*
* 1/100秒 = 10ms間隔でコールされる。
*/
void onTimer(void){
scan_cnt++;
if (scan_cnt >= 4){
scan_cnt = 0;
keyScan();
}
}
●inthandler.c
#include "inthandler.h"
#include "iodefine.h"
void onTimer(void);
void INT_IMIA0(void) {
ITU0.TSR.BIT.IMFA = 0; // フラグクリア
onTimer();
}
●lcd.c
#include <stdio.h>
#include "iodefine.h"
#include "lcd.h"
volatile static unsigned char entry_mode; // Entry //Mode: Cursor Increment, Don't shift display
volatile static unsigned char display_mode; //Display On/Off: Display On, Cursor Off, Blink Off
volatile static unsigned char function_mode; //Function Set: Data Length=4bit, Line=2, Font=5x7
const static unsigned char base_address[] = { 0x00, 0x40, 0x14, 0x54 };
volatile unsigned int lcd_dummy;
// ------------------------------------------------------------------------
/*
* time[ミリ秒]間だけ、ウェイトする。
*/
void waitMs(unsigned int time){
volatile unsigned int i;
while(time-- > 0){
for(i = 0; i < 900; i++)
;
}
}
/*
* code をLCDへ送る。
* rs: LCD_CMD | LCD_DATA
*/
void lcdWrite(unsigned char code, unsigned char rs){
LCD_DDR = 0xff; // output mode
LCD_DB = code;
LCD_RS = rs;
LCD_RW = LCD_WRITE;
LCD_E = 0;
LCD_E = 1;
lcd_dummy = code;
LCD_E = 0;
}
/*
* BF/Address 読みだし。
*/
unsigned char lcdGet(void){
unsigned char code;
LCD_DDR = 0x00; // input mode
LCD_RS = LCD_CMD;
LCD_RW = LCD_READ; // Read
LCD_E = 0;
LCD_E = 1;
lcd_dummy++;
code = LCD_DB;
LCD_E = 0;
LCD_RW = LCD_WRITE; // Write
LCD_DDR = 0xff; // output mode
return code;
}
/*
* LCDコントローラがビジーか否かチェックする。
*/
int isBusy(void){
return ( (lcdGet() & 0x80) == 0x80 );
}
void lcdPutCommand(unsigned char code){
while (isBusy())
;
lcdWrite(code, LCD_CMD);
}
/*
* LCDへ文字を出力する。
*/
void lcdPutChar(char code){
while (isBusy())
;
lcdWrite(code, LCD_DATA);
}
/*
* LCDへ文字列を表示する。
*/
void lcdPutString(char *s){
for( ; *s ; s++){
lcdPutChar(*s);
}
}
/*
* LCD画面をクリアする。
*/
void lcdClear(void){
lcdPutCommand(0x01);
}
/*
* カーソルをホームポジションへ戻す。
*/
void lcdHome(void){
lcdPutCommand(0x02);
}
/*
* カーソルを座標(x,y)へ移動する。
* 座標は1行目左端を(1,1)とし、
* 右方向がXの正、下方向がYの正方向とする。
*/
void lcdXY(int x, int y){
unsigned char address;
address = base_address[y-1] + x - 1;
lcdPutCommand(address | 0x80);
}
/*
* 文字を表示した後、カーソルが進む方向を設定する。(右|左)
*/
void lcdCursorDir(int right){
if (right)
entry_mode |= 0x02;
else
entry_mode &= ~0x02;
lcdPutCommand(entry_mode);
}
/*
* ディスプレイを右へシフトする。
*/
void lcdShiftRight(void){
lcdPutCommand(0x1C);
}
/*
* ディスプレイを左へシフトする。
*/
void lcdShiftLeft(void){
lcdPutCommand(0x18);
}
/*
* カーソルを右にシフトする。
*/
void lcdCursorRight(void){
lcdPutCommand(0x14);
}
/*
* カーソルを左にシフトする。
*/
void lcdCursorLeft(void){
lcdPutCommand(0x10);
}
/*
* ディスプレイの表示をONにする。
*/
void lcdDisplayOn(void){
display_mode |= 0x04;
lcdPutCommand(display_mode | 0x08);
}
/*
* ディスプレイの表示をOFFにする。
*/
void lcdDisplayOff(void){
display_mode &= ~0x04;
lcdPutCommand(display_mode | 0x08);
}
/*
* カーソルの表示をONにする。
*/
void lcdCursorOn(void){
display_mode |= 0x02;
lcdPutCommand(display_mode | 0x08);
}
/*
* カーソルの表示をOFFにする。
*/
void lcdCursorOff(void){
display_mode &= ~0x02;
lcdPutCommand(display_mode | 0x08);
}
/*
* カーソルの点滅をONにする。
*/
void lcdBlinkOn(void){
display_mode |= 0x01;
lcdPutCommand(display_mode);
}
/*
* カーソルの点滅をOFFにする。
*/
void lcdBlinkOff(void){
display_mode &= ~0x01;
lcdPutCommand(display_mode);
}
/*
* LCDを初期化する。
*/
void lcdInit(void){
lcd_dummy = 0;
entry_mode = 0x06; // Entry Mode : Cursor Increment, Don't shift display
display_mode = 0x0C; // Display On/Off Control : Display On, Cursor Off, Blink Off
function_mode = 0x38; // Function Set : Data Length = 8bit, Line = 2, Font = 5x7dots
waitMs(30); // 30ms Wait
lcdWrite(0x30, LCD_CMD);
waitMs(10); // 10ms Wait
lcdWrite(0x30, LCD_CMD);
waitMs(1); // 1ms Wait
lcdWrite(0x30, LCD_CMD);
lcdPutCommand(function_mode);
lcdPutCommand(0x08); // Display Off
lcdPutCommand(0x01); // Display Clear
lcdPutCommand(entry_mode);
lcdCursorOn(); // Cursor On
lcdBlinkOn();
lcdDisplayOn(); // Display On
}
// ------------------------------------------------------------------------
●lcd.h
/*
* lcd.h
*
* LCD制御関数群
* SC2004CS*B を 8ビット転送モードで使用する。
* 利用者は以下の手順で利用すること。
* (1) lcd.h をインクルードする
* (2) lcdInit()を最初にコールする
*/
#ifndef LCD_H_
#define LCD_H_
#define LCD_RS P5.DR.BIT.B0
#define LCD_E P5.DR.BIT.B1
#define LCD_RW P5.DR.BIT.B2
#define LCD_DB P3.DR.BYTE
#define LCD_DDR P3.DDR
#define LCD_READ (1)
#define LCD_WRITE (0)
#define LCD_CMD (0)
#define LCD_DATA (1)
/*
* 凡そ time[ms] だけウェイトする。
* (正確ではないので時計としては使えない)
*/
void waitMs(unsigned int time);
// LCD制御関数
void lcdInit(void); // LCDを初期化
void lcdClear(void); // スクリーン・クリア
void lcdHome(void); // カーソルをホームポジションへ
void lcdXY(int x, int y);// カーソルを (x,y) ホームポジションは(1,1)
void lcdCursorDir(int right);// 文字表示後のカーソル進行方向設定(右|左)
void lcdDisplayOn(void); // ディスプレイの表示をオン
void lcdDisplayOff(void); // ディスプレイの表示をオフ
void lcdShiftRight(void); // ディスプレイを右へシフト
void lcdShiftLeft(void); // ディスプレイを左へシフト
void lcdCursorRight(void); // カーソルを右にシフト
void lcdCursorLeft(void); // カーソルを左にシフト
void lcdCursorOn(void); // カーソルの表示をオン
void lcdCursorOff(void); // カーソルの表示をオフ
void lcdBlinkOn(void); // カーソルの点滅をオン
void lcdBlinkOff(void); // カーソルの点滅をオフ
// 表示関数
void lcdPutChar(char code); // LCDへ文字を表示
void lcdPutString(char *s); // LCDへ文字列を表示
// 内部関数
int isBusy(void);
unsigned char lcdGet(void);
void lcdSet(unsigned char code);
void lcdWrite(unsigned char code, unsigned char rs);
#endif /* LCD_H_ */
sci.c
/*
* sci.c
*
* Created on: 2018/11/12
* Author: aikawa
*/
#include "iodefine.h"
#include "sci.h"
void sci_putc(unsigned char ch){
while (SCI1.SSR.BIT.TDRE == 0)
;
SCI1.TDR = ch;
SCI1.SSR.BIT.TDRE = 0;
}
void sci_puts(unsigned char *s){
while (*s){
if (*s == '\n')
sci_putc('\r');
sci_putc(*s++);
}
}
unsigned char sci_read(void){
unsigned char c;
if ( (SCI1.SSR.BYTE & 0x78) == 0 )
return '\0'; // 入力なし
if (SCI1.SSR.BIT.RDRF == 1){
c = SCI1.RDR;
SCI1.SSR.BIT.RDRF = 0;
return c;
}
SCI1.SSR.BYTE &= 0x87; // エラーフラグクリア
return -1;
}
void initSCI(void){
SCI1.SCR.BIT.TE = 0; // 送信無効
SCI1.SCR.BIT.RE = 0; // 受信無効
SCI1.SCR.BIT.CKE = 0; // クロックソース:内部クロック
SCI1.SMR.BYTE = 0; // 調歩, キャラクタ8, パリティナシ, ストップ1, クロックφ
SCI1.BRR = 80; // 9600baud
SCI1.SSR.BYTE &= 0x87; // フラグクリア
SCI1.SCR.BIT.TE = 1; // 送信有効
SCI1.SCR.BIT.RE = 1; // 受信有効
}
●sci.h
/*
* sci.h
*/
#ifndef SCI_H_
#define SCI_H_
void initSCI(void);
void sci_putc(unsigned char ch);
void sci_puts(unsigned char *s);
unsigned char sci_read(void);
#endif /* SCI_H_ */
■完成写真