ステップ10

LCD表示

実際にLCDに文字を出力させてみましょう。LCDへ以下のように表示する。  

1行目:ABC
2行目:カウント(約1秒間隔でカウントアップ)

用意するもの

半固定抵抗 100KΩ                        LCD                                  コンデンサ 0.1μF

LCD 各ピン説明

表10-1 LCDピン配置表

LCD制御回路図

図10-2 LCD制御回路

■LCDのタイミングチャート

図10-3 タイミングチャート

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_ */

■完成写真

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です