ステップ13

関数電卓の製作

 ここまで学んできたことを活かして実際に関数電卓の基板ましょう。

■必要なもの

●LED ●半固定抵抗 20K                            ●コンデンサ 0.1μF                          ●抵抗    2K                           ●スライドスイッチ                           ●DCジャック                             ●タクトスイッチ                            ●ヘッダーピン                             ●ショートピン                             ●LCD 4×20表記

■関数電卓の回路図

図13-1 字句解析 キーマトリックス回路図
図13-2 字句解析 電源周辺/LCD回路図

■関数電卓のプログラム

●constant.h

#ifndef CONSTANT_H_
#define CONSTANT_H_

// 数学定数
#define MATH_PI	(3.14159265)
#define MATH_E		(2.71828183)
#define MATH_G		(6.67259E-11)

#endif /* CONSTANT_H_ */

●func.c

#include <stdio.h>
#include <math.h>
#include <string.h>
#include "constant.h"
#include "func.h"

extern char angleMode;

/*
 * 四捨五入
 */
double round(double x){
	return (int)(x + 0.5);
}
/*
 * 立方根
 */
double cbrt(double x){
	return pow(x, 1.0/3);
}
double toRadian(double x){
	return MATH_PI * x / 180;
}
double toDegree(double x){
	return 180 * x / MATH_PI;
}
double mysin(double x){
	return sin( angleMode ? toRadian(x) : x );
}
double mycos(double x){
	return cos( angleMode ? toRadian(x) : x );
}
double mytan(double x){
	return tan( angleMode ? toRadian(x) : x );
}
double myasin(double x){
	return angleMode ? toDegree(asin(x)) : asin(x);
}
double myacos(double x){
	return angleMode ? toDegree(acos(x)) : acos(x);
}
double myatan(double x){
	return angleMode ? toDegree(atan(x)) : atan(x);
}
double mysinh(double x){
	return sinh( angleMode ? toRadian(x) : x );
}
double mycosh(double x){
	return cosh( angleMode ? toRadian(x) : x );
}
double mytanh(double x){
	return tanh( angleMode ? toRadian(x) : x );
}
/*
 * 関数表
 */
const Function func_tab[] = {
	{ "abs", fabs },
	{ "sqrt", sqrt },
	{ "cbrt", cbrt },
	{ "ln", log },
	{ "log", log10 },
	{ "sin", mysin },
	{ "cos", mycos },
	{ "tan", mytan },
	{ "asin", myasin },
	{ "acos", myacos },
	{ "atan", myatan },
	{ "sinh", mysinh },
	{ "cosh", mycosh },
	{ "tanh", mytanh },
//	{ "asinh", asinh },
//	{ "acosh", acosh },
//	{ "atanh", atanh },
	{ "exp", exp },
	{ "floor", floor },
	{ "ceil", ceil },
	{ "round", round },
	{ NULL, NULL }
};

/*
 * 関数表から関数を探す
 */
const Function *searchFunc(char *name){
	int i;
	for(i = 0; func_tab[i].name != NULL; i++){
		if (strcmp(func_tab[i].name, name) == 0)
			return &func_tab[i];
	}
	return NULL;
}

●func.h

#ifndef FUNC_H_
#define FUNC_H_

typedef struct {
	char	*name;	// 関数名
	double	(*func)(double x);	// 関数ポインタ
} Function;

/*
 * 関数表から関数を探す
 */
const Function *searchFunc(char *name);

#endif /* FUNC_H_ */

●inthandler.c

#include "inthandler.h"
#include "iodefine.h"

void INT_IMIA0(void) {
	ITU0.TSR.BIT.IMFA = 0; // フラグクリア
	onTimer();
}

●key.c

/*
 * key.c
 */
#include <stdio.h>
#include <string.h>
#include "iodefine.h"
#include "key.h"
#include "token.h"
#include "parser.h"
#include "lcd.h"

extern unsigned char	buff[32];	// 結果出力用バッファ

static unsigned char keyTab[][8] = {
	{ 'C', '@', 'x', 'y', 'z', 'C', 'C', 'C' },
	{ 0xf7, 'e', 'F', 'F', 'F', 'F', 'F', 'C' },
	{ 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'C' },
	{ '7', '8', '9', '/', '!', 'F', 'F', 'C' },
	{ '4', '5', '6', '*', '^', 'F', 'F', 'C' },
	{ '1', '2', '3', '-', 'F', 'F', 'F', 'C' },
	{ '0', '.', '=', '+', ',', 'F', 'F', 'C' },

};

unsigned char 	preCode; // 直前の入力キーコード
unsigned int 	keyCnt;  // 同一キーの連続タイプカウント
unsigned char	shiftMode;	// 0:Off 1:On
unsigned char	angleMode;	// 0:rad 1:deg
unsigned char	sw_prev[7];	// SWの直前のOn/Off状態

#define BUFF_SIZE	(39)
#define HIST_SIZE	(11)

char	inBuffer[BUFF_SIZE + 1];	// 入力バッファ
short	inCnt;						// 入力文字数
short	curPos;						// 現在のカーソル位置(入力位置)
short	winPos; 					// 表示開始位置

char	ansBuffer[20]; 				// 結果表示用バッファ

char	histBuff[HIST_SIZE][BUFF_SIZE + 1]; // コマンド履歴バッファ
short	histTop;
short	histNxt;
short	histCur;

/*
 * 行番号と列番号から対応する文字へ変換する。
 */
char keyChar(int row, int col){
	if (row < 0 || row > 7 || col < 0 || col > 8)
		return '?';
	return keyTab[row][col];
}

void keyClear(void){
	preCode = 0;
	keyCnt = 0;
	winPos = 0;
	curPos = 0;
	inCnt = 0;
}

void allClear(void){
	keyClear();
	shiftMode = 0;
	angleMode = 0;
}

void cursorLeft(void){
	if (curPos > 0){
		curPos--;
		if (winPos > curPos)
			winPos = curPos;
	}
}
void cursorRight(void){
	if (curPos < inCnt){
		curPos++;
		if (winPos + 20 <= curPos)
			winPos++;
	}
}
/*
 * カーソル位置に文字を挿入する。
 */
void insChar(char c){
	int i, right;
	if (inCnt >= BUFF_SIZE)
		return;
	if (curPos < inCnt){ // 行の途中へ挿入
		right = inCnt < BUFF_SIZE - 1 ? inCnt : BUFF_SIZE - 1;
		for(i = right; i > curPos ; i--){
			inBuffer[i] = inBuffer[i-1];
		}
		inBuffer[curPos] = c;
		inCnt++;
		cursorRight();
	}else{ // 行末へ追加
		inBuffer[curPos] = c;
		inCnt++;
		cursorRight();
	}
}
void delChar(void){
	int i;
	if (inCnt > 0){
		if (inCnt <= curPos){ // 行末の文字を削除
			inCnt--;
			cursorLeft();
		} else {// 行の途中の文字を削除
			for(i = curPos; i < inCnt - 1; i++)
				inBuffer[i] = inBuffer[i+1];
			inCnt--;
		}
	}
}
int insString(char *s){
	if (inCnt + strlen(s) < BUFF_SIZE){
		while (*s)
			insChar(*s++);
		return 1;
	}
	return 0;
}
void insWord(char *s, int back){
	if (insString(s)){
		curPos -= back;
	}
}
int isHistFull(void){
	int next = (histNxt + 1) % HIST_SIZE;
	return next == histTop;
}
int isHistEmpty(void){
	return histTop == histNxt;
}
void storeCommand(void){
	int i;
	for(i = 0; i < inCnt; i++)
		histBuff[histNxt][i] = inBuffer[i];
	histBuff[histNxt][i] = '\0';
	if (isHistFull()){
		histTop = (histTop + 1) % HIST_SIZE;
	}
	histCur = histNxt = (histNxt + 1) % HIST_SIZE;
	histBuff[histNxt][0] = '\0';
}
void history(void){
	int i;
	inCnt = strlen(histBuff[histCur]);
	strcpy(inBuffer, histBuff[histCur]);
	curPos = inCnt;
	if (curPos >= 20){
		winPos = curPos - 19;
	} else {
		winPos = 0;
	}
}
void prevHistory(void){
	if ( !isHistEmpty() ){
		if (histCur != histTop){
			histCur = histCur == 0 ? HIST_SIZE - 1 : histCur - 1;
			history();
		}
	}
}
void nextHistory(void){
	if ( !isHistEmpty() ){
		if (histCur != histNxt){
			histCur = (histCur + 1) % HIST_SIZE;
			history();
		}
	}
}

extern int syntax_error;

void executeCommand(void){
	double answer;
	inBuffer[inCnt] = '\0';
	answer = parse(inBuffer);
	if ( !syntax_error ){
		sprintf(ansBuffer, "Ans = %g", answer);
	} else {
		strcpy(ansBuffer, "Syntax Error!");
	}
	sci_puts(ansBuffer);
}

/*
 * キーがタイプされたときに呼び出される。
 */
void keyTyped(int row, int col){
	unsigned char c = keyChar(row, col);
	unsigned char code = 8 * row + col + 1;
//	sprintf(buff, "code = %02x\n", code);
//	sci_puts(buff);

	if (preCode == code){
		keyCnt++;
	} else {
		preCode = code;
		keyCnt = 0;
	}
	if (c == 'F'){
		if (code == 0x36){
			if (shiftMode == 0){
				insWord("def f(x)=", 0);
			} else {
				insWord("def f(x,y)=", 0);
			}
		} else if (code == 0x37){
			insWord("Ans", 0);
		} else if (code == 0x2d){
			insWord("()", 1);
		} else if (code == 0x2e){
			if (shiftMode == 0){
				insWord("f()", 1);
			} else {
				insWord("g()", 1);
			}
		} else if (code == 0x2f){
			if (shiftMode == 0){
				insWord("s()", 1);
			} else {
				insWord("v()", 1);
			}
		} else if (code == 0x26){
			if (shiftMode == 0){
				insWord("def s(x)=", 0);
			} else {
				insWord("def v(x)=", 0);
			}
		} else if (code == 0x27){
			insWord("abs()", 1);
		} else if (code == 0x1e){
			if (shiftMode == 0){
				insWord("^2", 0);
			} else {
				insWord("^(-1)", 0);
			}
		} else if (code == 0x1f){
			if (shiftMode == 0){
				insWord("exp()", 1);
			} else {
				insWord("round()", 1);
			}
		} else if (code == 0x11){
			if (shiftMode == 0){
				insWord("sqrt()", 1);
			} else {
				insWord("cbrt()", 1);
			}
		} else if (code == 0x12){
			if (shiftMode == 0){
				insWord("mod(,)", 2);
			} else {
				insWord("div(,)", 2);
			}
		} else if (code == 0x13){
			insWord("sinh()", 1);
		} else if (code == 0x14){
			insWord("cosh()", 1);
		} else if (code == 0x15){
			insWord("tanh()", 1);
		} else if (code == 0x16){
			if (shiftMode == 0){
				insWord("log()", 1);
			} else {
				insWord("ln()", 1);
			}
		} else if (code == 0x17){
			if (shiftMode == 0){
				insWord("floor()", 1);
			} else {
				insWord("ceil()", 1);
			}
		} else if (code == 0x0b){
			if (shiftMode == 0){
				insWord("sin()", 1);
			} else {
				insWord("asin()", 1);
			}
		} else if (code == 0x0c){
			if (shiftMode == 0){
				insWord("cos()", 1);
			} else {
				insWord("acos()", 1);
			}
		} else if (code == 0x0d){
			if (shiftMode == 0){
				insWord("tan()", 1);
			} else {
				insWord("atan()", 1);
			}
		} else if (code == 0x0e){
			if (shiftMode == 0){
				insWord("P(,)", 2);
			} else {
				insWord("C(,)", 2);
			}
		} else if (code == 0x0f){
			if (shiftMode == 0){
				insWord("gcd(,)", 2);
			} else {
				insWord("lcm(,)", 2);
			}
		}
	} else if (c == 'C'){
		if (code == 0x01){			// rad/deg
			angleMode = 1 - angleMode;
		} else if (code == 0x06){	// DEL
			delChar();
		} else if (code == 0x07){	// BS
			cursorLeft();
			delChar();
		} else if (code == 0x08){	// AC
			allClear();
		} else if (code == 0x10){	// shift
			shiftMode = 1 - shiftMode;
		} else if (code == 0x18){	// ↑
			prevHistory();
		} else if (code == 0x20){	// ↓
			nextHistory();
		} else if (code == 0x28){	// →
			cursorRight();
		} else if (code == 0x30){	// ←
			cursorLeft();
		} else if (code == 0x38){	// Enter
			if (inCnt > 0){
				storeCommand();
				executeCommand();
				keyClear();
			}
		}
	} else if (c == '?'){
	} else if ((c == 'x') || (c == 'y') || (c == 'z')){
		if (shiftMode == 1)
			insChar(c + 'X' - 'x');
		else
			insChar(c);
	} else {
		if ( shiftMode == 1 && isdigit(c) && (c != '0')){
			char	base;
			int		n;

			if (c == '7'){
				base = 'a';
			} else if (c == '8'){
				base = 'd';
			} else if (c == '9'){
				base = 'g';
			} else if (c == '4'){
				base = 'j';
			} else if (c == '5'){
				base = 'm';
			} else if (c == '6'){
				base = 'p';
			} else if (c == '1'){
				base = 's';
			} else if (c == '2'){
				base = 'v';
			} else if (c == '3'){
				base = 'x';
			}
			n = keyCnt % 3;
			if (keyCnt > 0){
				curPos--;
				delChar();
			}
			insChar(base + n);
		} else if (shiftMode == 1 && (c == 0xf7)){
			insChar('G');
		} else if (shiftMode == 1 && (c == 'e')){
			insChar('E');
		} else {
			insChar(c);
		}
	}
}

void repaintDisplay(void){
	int i, h;

	lcdClear();
	// 状態を1行目に表示
	lcdXY(1, 1);
	lcdPutString("Status:");
	if (shiftMode == 1){
		lcdPutString("Shift ");
	} else {
		lcdPutString("      ");
	}
	if (angleMode == 1){
		lcdPutString("Degree");
	} else {
		lcdPutString("Radian");
	}

	// 直前のコマンドを表示
	lcdXY(1, 2);
	h = histNxt == 0 ? HIST_SIZE - 1 : histNxt - 1;
	for(i = 0; i < 20 ; i++){
		if (histBuff[h][i] == '\0')
			break;
		lcdPutChar(histBuff[h][i]);
	}

	// 結果表示
	lcdXY(1, 3);
	for(i = 0; ansBuffer[i] != '\0'; i++){
		lcdPutChar(ansBuffer[i]);
	}

	// コマンド行表示
	lcdXY(1,4);
	for(i = winPos; i < winPos + 20; i++){
		if (i >= inCnt)
			break;
		lcdPutChar(inBuffer[i]);
	}
	lcdXY(curPos - winPos + 1, 4);
}

int keyScan(void){
	unsigned char sw, sw_on;
	int i, j, cnt;

	cnt = 0;
	for(i = 0; i < 7; i++){
		P1.DR.BYTE = ~(1 << i);
		sw = P2.DR.BYTE;      // i行目をスキャン
		P1.DR.BYTE = 0xff;
		sw_on = (sw_prev[i] ^ sw) & ~sw; // 押されたスイッチを1
		for(j = 0; j < 8; j++){
			if (sw_on & (0x01 << j)){
				// i行 j列のキーが Off→On
				cnt++;
				keyTyped(i, j);
			}
		}
		sw_prev[i] = sw; // i行目の状態を記憶しておく
	}
	return cnt;
}

void keyInit(void){
	unsigned char i;

	allClear();

	P2.PCR.BYTE = 0xff; // プルアップ有効
	P1.DR.BYTE = 0xff;
	for(i = 0; i < 7; i++){
		P1.DR.BYTE = ~(1 << i);
		sw_prev[i] = P2.DR.BYTE;
		P1.DR.BYTE = 0xff;
	}
}

●key.h

/*
 * key.h
 */
#ifndef KEY_H_
#define KEY_H_

void keyInit(void);
int keyScan(void);
void repaintDisplay(void);

#endif /* KEY_H_ */

●lcd.c

/*
 * lcd.c
 *
 *  LCD制御関数群
 *   SC2004CS*B を 8ビット転送モードで使用する。
 *
 *  LCDを接続するポートに合わせ、
 *  LCD_RS, LCD_RW, LCR_E, LCD_DB, LCD_DDR の定義を行うこと。
 *  最初に lcd_init() をコールし、LCDの初期化を行うこと。
 *
 */
#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_ */

●main.c

/***********************************************************************/
/*  													               */
/*      PROJECT NAME :  C02                                            */
/*      FILE         :  C02.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"
#include "key.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[7];	// SWの直前のOn/Off状態
unsigned char	buff[32];	// 結果出力用バッファ
unsigned char	scan_cnt;	// 入力スキャン用カウンタ

unsigned char state;		// 状態変数

void initIO(void){
	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; // プルアップ有効
}

void all_clear(){
	state = 0;
}

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();
	keyInit();
	initApp();
	initITU();
	initSCI();
	lcdInit();
//	lcdXY(1,1);
//	lcdPutString("Type Key.");
	repaintDisplay();

    while (1) {}

    return 0;
}

/*
 * 1/100秒 = 10ms間隔でコールされる。
 */
void onTimer(void){
	scan_cnt++;
	if (scan_cnt >= 4){
		scan_cnt = 0;
		if (keyScan() > 0){
			repaintDisplay();
		}
	}
}

●parser.c

/*
 * parser.c
 *
 */

#include <stdio.h>
#include <string.h>
#include <math.h>
#include "token.h"
#include "parser.h"
#include "func.h"
#include "sci.h"
#include "var.h"
#include "constant.h"

#define DEBUG

//extern jmp_buf  jumpbuff;
int syntax_error = 0;

static DefFunc	*defp;
static DefFunc	def_tab[DEF_TAB_SIZE];
static int	defCnt = 0;

int isSyntaxError(void){
	return syntax_error;
}
double syntaxError(char *s){
#ifdef DEBUG
	sci_puts("Syntax Error (");
	sci_puts(s);
	sci_puts(")\n");
#endif
	syntax_error = 1;
//	longjmp(jumpbuff, 1);
	return 0;
}

DefFunc *searchDef(char *name){
	int i;
	for(i = 0; i < defCnt; i++){
		if (strcmp(def_tab[i].name, name) == 0)
			return &def_tab[i];
	}
	return NULL;
}
Param *searchParam(DefFunc *dp, char *name){
	int i;
	for(i = 0; i < dp->paramCnt; i++){
		if (strcmp(dp->param[i].name, name) == 0)
			return &dp->param[i];
	}
	return NULL;
}
double addDef(DefFunc *dp){
	if (defCnt < DEF_TAB_SIZE){
		def_tab[defCnt++] = *dp;
		return 0;
	} else {
		return syntaxError("addDef");
	}
}
void printDef(DefFunc *def){
	int i;
	printf("%s(", def->name);
	for(i = 0; i < def->paramCnt - 1 ; i++){
		printf("%s,", def->param[i].name);
	}
	printf("%s)=", def->param[i].name);
	printf("%s\n", def->expr);
}
void printDefs(void){
	int i;
	for(i = 0; i < defCnt; i++){
		printDef(&def_tab[i]);
	}
}

/*
void printFloat(float f){
	char buff[20];
	sprintf(buff,"%f\r", f);
	sci_puts(buff);
}
*/

int gcd(int m, int n){
	int mod;
	if (m < 0)
		m *= -1;
	if (n < 0)
		n *= -1;
	if (m == 0)
		return n;
	if (n == 0)
		return m;
	mod = m % n;
	while (mod != 0){
		m = n;
		n = mod;
		mod = m % n;
	}
	return n;
}
int lcm(int m, int n){
	return m * n / gcd(m, n);
}

int permu(int n, int r){
	int ans = 1, i;

	for(i = 1; i <= r; i++){
		ans = ans * n--;
	}
	return ans;
}

int combi(int n, int r){
	int ans = 1, i;

	for(i = 1; i <= r; i++){
		ans = ans * n-- / i;
	}
	return ans;
}

/*
 * <原子>   ::= <数値> | '(' <式> ')' | <識別子> '(' <式> ')'
 */
double atom(void){
	double	expr(void);
	Token	token;
	int		id;
	double	e;

	if ((id = nextToken(&token)) == TOKEN_NUMBER)
		return token.value;
	if (id == TOKEN_LPAR) {// '('
		e = expr();
		if (nextToken(&token) != TOKEN_RPAR)
			return syntaxError("atom1");
		return e;
	}
	if (id == TOKEN_WORD) {// 識別子
		Variable *var;
		const Function *f;
		DefFunc *df;


		if (token.word[0] == 0xf7){
			return MATH_PI; // π
		}
		if (strcmp(token.word, "e") == 0){
			return MATH_E;	// ネイピア数
		}
		if (strcmp(token.word, "G") == 0){
			return MATH_G;	// 万有引力定数
		}

		if (defp != NULL){
			Param *param;
			// def文の中ならパラメータを検索
			if ((param = searchParam(defp, token.word)) != NULL)
				return param->value;
		}

		var = searchVar(token.word);
		if (var != NULL) // 変数
			return var->value;

		df = searchDef(token.word);
		if (df != NULL){
			DefFunc *tmp;
			char	buff[MAX_DEF_LENGTH + 1];
			double	e;
			int		i;

			if ((id = nextToken(&token)) != TOKEN_LPAR)
				return syntaxError("atom2");
			for(i = 0; i < df->paramCnt - 1; i++){
				df->param[i].value = expr();
				if (nextToken(&token) != TOKEN_COMMA)
					return syntaxError("atom3");
			}
			df->param[i].value = expr();

			if ((id = nextToken(&token)) != TOKEN_RPAR)
				return syntaxError("atom4");
			tmp = defp;
			defp = df;
			mvLeftStrings(buff);
			setText(df->expr);
			e = expr();
			setText(buff);
			defp = tmp;
			return e;
		}

		if ((strcmp(token.word, "gcd") == 0) || (strcmp(token.word, "lcm") == 0)){
			int e1, e2, gcdflag = 0;
			if (strcmp(token.word, "gcd") == 0)
				gcdflag = 1;
			if (nextToken(&token) != TOKEN_LPAR)
				return syntaxError("atom5");
			e1 = (int)expr();
			while ( (id = nextToken(&token)) != TOKEN_RPAR ){
				if (id != TOKEN_COMMA)
					syntaxError("atom6");
				e2 = (int)expr();
				e1 = gcdflag ? gcd(e1, e2) : lcm(e1, e2);
			}
			return (double)e1;
		}

		if ((strcmp(token.word, "mod") == 0) || (strcmp(token.word, "div") == 0) ||
				(strcmp(token.word, "P") == 0) || (strcmp(token.word, "C") == 0)){
			int e1, e2, sel;
			if (strcmp(token.word, "div") == 0)
				sel = 1;
			else if(strcmp(token.word, "P") == 0)
				sel = 2;
			else if (strcmp(token.word, "C") == 0)
				sel = 3;
			else
				sel = 0;
			if (nextToken(&token) != TOKEN_LPAR)
				return syntaxError("atom7");
			e1 = (int)expr();
			if (nextToken(&token) != TOKEN_COMMA)
				syntaxError("atom8");
			e2 = (int)expr();
			if (nextToken(&token) != TOKEN_RPAR)
				return syntaxError("atom9");
			if (sel == 0)
				return (double)(e1 % e2);
			if (sel == 1)
				return (double)(e1 / e2);
			if (sel == 2)
				return (double)(permu(e1,e2));
			return (double)(combi(e1,e2));
		}

		f = searchFunc(token.word);
		if (f == NULL)
			return syntaxError("atom10");
		if ((id = nextToken(&token)) != TOKEN_LPAR)
			return syntaxError("atom11");
		e = expr();
		if ((id = nextToken(&token)) != TOKEN_RPAR)
			return syntaxError("atom12");
		return f->func(e);
	}
	return syntaxError("atom13");
}
/*
 * n! (階乗を計算する)
 */
double fact(int n){
	double ans = 1.0;
	while (n > 1){
		ans *= n--;
	}
	return ans;
}
/*
 * <分子>   ::= <原子> | <分子> '!' <原子>
 */
double element(void){
	Token	token;
	double	e;

	e = atom();
	while (nextToken(&token) == TOKEN_EXCLAM){
		e = fact((int)e);
	}
	putBack(&token);
	return e;
}

/*
 * <因子>   ::= <分子> | <分子> '^' <因子>
 */
double factor(void){
	Token	token;
	double	e;

	e = element();
	if (nextToken(&token) == TOKEN_HAT){
		double e2 = factor();
		return pow(e, e2);
	}
	putBack(&token);
	return e;
}
/*
 * <項> ::= <因子> | <項> (*?|/) <因子>
 */
double term(void){
	Token	token;
	double	f1, f2;
	int		id;

	f1 = factor();
	while ((id = nextToken(&token)) == TOKEN_ASTER || id == TOKEN_SLASH || id == TOKEN_NUMBER || id == TOKEN_WORD || id == TOKEN_LPAR){
		if (id == TOKEN_NUMBER || id == TOKEN_WORD || id == TOKEN_LPAR){
			putBack(&token);
		}
		f2 = factor();
		if (id == TOKEN_ASTER){
			f1 *= f2;
		} else if (id == TOKEN_SLASH){
			if (f2 == 0)
				return syntaxError("term");
			f1 /= f2;
		} else {
			f1 *= f2;
		}
	}
	putBack(&token);
	return f1;
}
/*
 * <算術式> ::= (+|-)? <項> | <算術式> (+|-) <項>
 */
double arithmetic(void){
	Token	token;
	double	t1, t2;
	int		id, sign;

	if ((id = nextToken(&token)) == TOKEN_PLUS){
		sign = 1;
	} else if (id == TOKEN_MINUS){
		sign = -1;
	} else {
		sign = 1;
		putBack(&token);
	}
	t1 = sign * term();
	while ((id = nextToken(&token)) == TOKEN_PLUS || id == TOKEN_MINUS){
		t2 = term();
		if (id == TOKEN_PLUS)
			t1 += t2;
		else
			t1 -= t2;
	}
	putBack(&token);
	return t1;
}

/*
 * <式> ::= <算術式> | <識別子> '=' <式>
 */
double expr(void){
	Token	token;
	Variable *var;

	if (nextToken(&token) == TOKEN_WORD){
		Token token2;
		if (nextToken(&token2) == TOKEN_EQUAL){
			double e = expr();
			// 変数に代入
			var = searchVar(token.word);
			if (var == NULL){
				if (addVar(token.word, e) == NULL)
					return syntaxError("expr");
			} else {
				var->value = e;
			}
			return e;
		}
		putBack(&token2);
	}
	putBack(&token);
	return arithmetic();
}


/*
 * <def文> ::= def <識別子> '(' <パラメータリスト> ')' '=' <算術式>
 */
double parseDef(void){
	DefFunc	def, *dp;
	Token	token;
	char	*str;

	if (nextToken(&token) != TOKEN_WORD)
		return syntaxError("parseDef...1");
	strcpy(def.name, token.word);
	if (nextToken(&token) != TOKEN_LPAR)
		return syntaxError("parseDef...2");

	if (nextToken(&token) != TOKEN_WORD)
		return syntaxError("parseDef...3");
	strcpy(def.param[0].name, token.word);
	def.paramCnt = 1;
	while (nextToken(&token) == TOKEN_COMMA){
		if (nextToken(&token) != TOKEN_WORD)
			return syntaxError("parseDef...4");
		if (def.paramCnt >= MAX_PARAMS)
			return syntaxError("parseDef...5");
		strcpy(def.param[def.paramCnt].name, token.word);
		def.paramCnt++;
	}
	if (token.id != TOKEN_RPAR)
		return syntaxError("parseDef...6");
	if (nextToken(&token) != TOKEN_EQUAL)
		return syntaxError("parseDef...7");
	mvLeftStrings(def.expr);
	if (strlen(def.expr) > MAX_DEF_LENGTH)
		return syntaxError("parseDef...8");
	setText(def.expr);

	dp = defp;
	defp = &def;
	arithmetic();
	defp = dp;
	if (isSyntaxError())
		return syntaxError("parseDef...9");

	if ((dp = searchDef(def.name)) != NULL){
		*dp = def;
	} else {
		addDef(&def);
	}
//	printDef(&def);

	return 0;
}

/*
 * 一行解析
 * <行> ::= <式> <EOF>
 */
double parse(char *s){
	Token token;
	double value;
	Variable *var;

	syntax_error = 0;
	setText(s);

	if (nextToken(&token) == TOKEN_WORD){
		if (strcmp(token.word, "def") == 0){
			parseDef();
			return 0;
		}
	}
	putBack(&token);

	value = expr();
//	printf("Ans = %g\n", value);

	if (nextToken(&token) != TOKEN_EOF)
		return syntaxError("parse1");
	var = searchVar("Ans");
	if (var == NULL){
		if (addVar("Ans", value) == NULL)
			return syntaxError("parse2");
	} else {
		var->value = value;
	}
	return value;
}

●parser.h

/*
 * parser.h
 *
 */

#include "token.h"

#ifndef PARSER_H_
#define PARSER_H_

#define MAX_PARAMS		(3)
#define MAX_DEF_LENGTH	(39)
#define DEF_TAB_SIZE	(10)

typedef struct {
	char		name[WORD_SIZE + 1];	// パラメータ名
	double		value;					// 変数値(保存用)
} Param;

typedef struct {
	char		name[WORD_SIZE + 1];		// 関数名
	int			paramCnt;					// パラメータ数
	Param		param[MAX_PARAMS];			// パラメータ情報
	char		expr[MAX_DEF_LENGTH + 1];	// 式の最大長
} DefFunc;

/*
 * 構文解析の結果、エラーがあった場合は1を返す。
 */
int isSyntaxError(void);

/*
 * 一行の構文解析及び評価を行い、評価結果を返す。
 */
double parse(char *s);

void printDefs(void);

#endif /* PARSER_H_ */

●sci.c

/*
 * sci.c
 *

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

●token.h

/*
 * token.h
 *
 */

#ifndef TOKEN_H_
#define TOKEN_H_

#define TOKEN_EOF		(-1)
#define TOKEN_WORD		(0)
#define TOKEN_NUMBER	(1)
#define TOKEN_PLUS		(10)
#define TOKEN_MINUS	(11)
#define TOKEN_ASTER	(12)
#define TOKEN_SLASH	(13)
#define TOKEN_HAT		(14)
#define TOKEN_EXCLAM	(15)
#define TOKEN_LPAR		(16)
#define TOKEN_RPAR		(17)
#define TOKEN_EQUAL	(18)
#define TOKEN_COMMA	(19)
#define TOKEN_UNDEF	(99)

#define WORD_SIZE	(7)
#define STACK_SIZE	(3)

typedef struct {
	int		id;
	double	value;			  // 数値の場合のみ有効
	char	word[WORD_SIZE+1];// 字句テキスト
} Token;

typedef struct {
	int		cnt;	/* スタックに積まれているデータ数 */
	Token	data[STACK_SIZE];
} Stack;

void setText(char *s);
int nextChar(void);
int getToken(char *word);
int nextToken(Token *token);
void putBack(Token *token);
int stackIsEmpty(void);

#endif /* TOKEN_H_ */

●tokenizer.c

/*
 * tokenizer.c
 *
 */

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "token.h"

static char *next_cp;
static Stack stack = { 0 };

void setText(char *s){
	next_cp = s;
	stack.cnt = 0;
}

/*
 * 残りの文字列をsへ移す。
 */
void mvLeftStrings(char *s){
	while ( (*s++ = *next_cp++) != '\0' )
		;
}

int nextChar(void){
	if (*next_cp == '\0')
		return -1;
	return *next_cp++;
}

int isSpace(int c){
	return c == ' ' || c == '\t' || c == '\n';
}

/*
 * 次の字句を返す。
 */
int getToken(char *word){
	int work;

	while ( isSpace(*next_cp) )
		next_cp++;

	if (*next_cp == '\0')
		return TOKEN_EOF;

	if (isdigit(*next_cp)){
		while ( isdigit(*next_cp) ){
			*word++ = *next_cp++;
		}
		if(*next_cp == '.'){
			*word++ = *next_cp++;
			while( isdigit(*next_cp) ){
				*word++ = *next_cp++;
			}
		}
		if (*next_cp != 'E'){
			*word = '\0';
			return TOKEN_NUMBER;
		}
		*word++ = *next_cp++;
		if ((*next_cp == '+') || (*next_cp == '-')){
			*word++ = *next_cp++;
		}
		while ( isdigit(*next_cp) ){
			*word++ = *next_cp++;
		}
		*word = '\0';
		return TOKEN_NUMBER;
	}
	if(*next_cp == '.'){
		*word++ = '0';
		*word++ = *next_cp++; // .
		while( isdigit(*next_cp) ){
			*word++ = *next_cp++;
		}
		*word = '\0';
		return TOKEN_NUMBER;
	}

	if (*next_cp == 0xf7){ // π
		*word++ =*next_cp++;
		*word = '\0';
		return TOKEN_WORD;
	}

	if (isalpha(*next_cp)){
		int n = 0;
		while ( isalnum(*next_cp) ){
			if (n < WORD_SIZE){
				*word++ = *next_cp++;
				n++;
			}
		}
		*word = '\0';
		return TOKEN_WORD;
	}

	work = *next_cp;
	*word++ = *next_cp++;
	*word = '\0';

	if (work == '+'){
		return TOKEN_PLUS;
	}
	if (work == '-'){
		return TOKEN_MINUS;
	}
	if (work == '*'){
		return TOKEN_ASTER;
	}
	if (work == '/'){
		return TOKEN_SLASH;
	}
	if (work == '^'){
		return TOKEN_HAT;
	}
	if (work == '!'){
		return TOKEN_EXCLAM;
	}
	if (work == '('){
		return TOKEN_LPAR;
	}
	if (work == ')'){
		return TOKEN_RPAR;
	}
	if (work == '='){
		return TOKEN_EQUAL;
	}
	if (work == ','){
		return TOKEN_COMMA;
	}

	return TOKEN_UNDEF;
}

int stackIsEmpty(void){
	return stack.cnt == 0;
}

void putBack(Token *token){
	if (stack.cnt < STACK_SIZE){
		stack.data[stack.cnt++] = *token;
	}
}

int nextToken(Token *token){
	if ( !stackIsEmpty() ){
		*token = stack.data[--stack.cnt];
		return token->id;
	}
	token->id = getToken(token->word);
	if (token->id == TOKEN_NUMBER)
		sscanf(token->word, "%lf", &token->value);
	return token->id;
}

●var.c

/*
 * var.c
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sci.h"
#include "var.h"

extern unsigned char	buff[32];	// 結果出力用バッファ

// 変数表
static Variable var_tab[VAR_TAB_SIZE];
static int varCnt = 0;

/*
 * 変数表へ変数と値を追加する。
 */
Variable *addVar(char *key, double value){
	Variable *var;
	if (varCnt >= VAR_TAB_SIZE)
		return NULL;
	var = &var_tab[varCnt++];
	strcpy(var->name, key);
	var->value = value;
	return var;
}
/*
 * 変数表から変数を探す。
 */
Variable *searchVar(char *key){
	int i;
	for(i = 0; i < varCnt; i++){
		if (strcmp(var_tab[i].name, key) == 0)
			return &var_tab[i];
	}
	return NULL;
}
/*
 * 変数表に変数が登録されているか調べる。
 */
int containsVar(char *key){
	return searchVar(key) != NULL;
}
/*
 * 変数表をクリアする。
 */
void clearVar(void){
	varCnt = 0;
}

void printVars(void){
	int i;
	for(i = 0; i < varCnt; i++){
		sprintf("%s ---> %f\n", var_tab[i].name, var_tab[i].value);
//		sci_puts(var_tab[i].name);
//		sci_puts(" ---> ");
//		sci_putDouble(var_tab[i].value);
//		sci_puts("\n");
	}
}

●var.h

/*
 * var.h
 */
#include "token.h"

#ifndef VAR_H_
#define VAR_H_

// 変数表の大きさ(変数の数の上限)
#define VAR_TAB_SIZE	(20)

typedef struct {
	char		name[WORD_SIZE + 1];	// 変数名
	double		value;					// 変数値
} Variable;

Variable *addVar(char *key, double value);
Variable *searchVar(char *key);
int  containsVar(char *key);
void clearVar(void);
void printVars(void);

#endif /* VAR_H_ */

■関数電卓への書き込み

 赤い丸で囲っているところを変えることによって書き込みか実行かを変えることができます。

●書き込みモード

●実行モード

■関数電卓完成品

表面
裏面

コメントを残す

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