ステップ13
関数電卓の製作
ここまで学んできたことを活かして実際に関数電卓の基板ましょう。
■必要なもの
●LED ●半固定抵抗 20K ●コンデンサ 0.1μF ●抵抗 2K ●スライドスイッチ ●DCジャック ●タクトスイッチ ●ヘッダーピン ●ショートピン ●LCD 4×20表記
■関数電卓の回路図
■関数電卓のプログラム
●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_ */
■関数電卓への書き込み
赤い丸で囲っているところを変えることによって書き込みか実行かを変えることができます。
●書き込みモード
●実行モード
■関数電卓完成品