硬件设计
附:http://www.jh-tec.cn/archives/7513
工作原理
利用矩阵键盘进行按键的输入,通过对矩阵键盘的扫描,获取用户的输入,并实时的显示在1602液晶上,每次获取到输入时,根据软件设计的相应方法对输入进行处理、运算,输入结束后(以“=“为标志),将最终的运算结果输出的液晶上。
仿真图1: (LCD1602显示,支持负数和进制运算及有限的连续运算,连续运算时候无法识别优先级,不支持小数;)
仿真图2: LCD1602显示,支持负数和小数及开根号,不支持连续运算;
程序设计1
#include <reg51.h>
#include <stdio.h>
#include <intrins.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#define u8 unsigned char
#define u16 unsigned char
sbit LCDEN=P3^4;
sbit RS=P3^5;
sbit RW=P3^6;
sbit BF=P0^7;
sbit change_m=P3^7;
u8 code keyval[]="789/456*123-c0=+"; //按键对应的符号
u8 data1[10];
u8 k=0;
char m[8]={0};
double sum=0;
int flag;
void WrDatLCD(unsigned char DatVal);
void WrComLCD(unsigned char ComVal);
void delay(u16 x) //延时x毫秒
{
u16 i,j;
for(i=0;i<x;i++)
for(j=0;j<115;j++)
;
}
int convertBinaryToDecimal(long n)
{
int decimalNumber = 0, i = 0, remainder;
while (n != 0)
{
remainder = n % 10;
n /= 10;
decimalNumber += remainder * pow(2, i);
++i;
}
return decimalNumber;
}
int convertBinaryToDecimal8(long n)
{
int decimalNumber = 0, i = 0, remainder;
while (n != 0)
{
remainder = n % 10;
n /= 10;
decimalNumber += remainder * pow(8, i);
++i;
}
return decimalNumber;
}
u8 keypad4_4()//按键扫描函数:要去抖,若有按键按下,返回对应的按键值(0-15),没有按键按下返回16
{
u8 i,row,temp;
u8 key=16;//按键号,初值设置为16,目的是:没有按键按下时返回16;
//若不设初值(默认值为0),没有按键按下时,将返回0,会误认为0被按下
row=0xef; //从第一列开始
for(i=0;i<4;i++)
{
P1=0xff;
P1=row; //第i列信号,对应列为低,其他全为高
row=_crol_(row,1); //生成下一列信号
temp=P1; //读入扫描信号
temp=temp&0x0f; //屏蔽高4位列信号,只保留低4位行信号
if(temp!=0x0f)//有按键被按下,因为第i列某行有按键按下,则低4位中有一位为低
{
delay(20); //延时去抖
temp=P1;
temp=temp&0x0f;
if(temp!=0x0f) //再次确认有按键被按下
{
switch(temp) //根据低4位行信号,判断哪个按键被按下
{
case 0x0e:key=0+i;break; //第i列第1行按键被按下
case 0x0d:key=4+i;break; //第i列第2行按键被按下
case 0x0b:key=8+i;break; //第i列第3行按键被按下
case 0x07:key=12+i; //第i列第4行按键被按下
}
do
{
temp=P1; //再次扫描按键
temp=temp&0x0f;
}while(temp!=0x0f); //等待按键释放
}
}
if(change_m == 0)
{
delay(50);
if(change_m == 0)
{
flag++;
if(flag == 3)
{
flag = 0;
}
} while(!change_m);
}
}
return(key);//扫面结束,返回按键值
}
unsigned char DectectBusyBit(void)//状态判断函数(忙/闲?)
{
bit result;
P0 = 0xff; //读状态前先置高电平,防止误判
RS = 0;
delay(5);
RW = 1;
LCDEN = 1;
delay(5);
result=BF; //若LCM忙,则反复测试,在此处原地踏步;当LCM闲时,才往下继续
LCDEN = 0;
return result;
}
void WrComLCD(unsigned char ComVal)//写命令函数
{
while(DectectBusyBit()==1); //先检测LCM是否空闲
RS = 0;
delay(1);
RW = 0;
LCDEN = 1;
P0 = ComVal;
delay(1);
LCDEN = 0;
}
void WrDatLCD(unsigned char DatVal)//写数据函数
{
while(DectectBusyBit()==1);
RS = 1;
delay(1);
RW = 0;
LCDEN = 1;
P0 = DatVal;
delay(1);
LCDEN = 0;
}
void LCD_Init(void)//1602初始化函数
{
WrComLCD(0x38); // 功能设定:16*2行、5*7点阵、8位数据接口
WrComLCD(0x38);
WrComLCD(0x38);
//多次重复设定功能指令,因为LCD启动后并不知道使用的是4位数据接口还是8位的,所以开始时总是默认为4位
WrComLCD(0x01); // 清屏
WrComLCD(0x06); // 光标自增、屏幕不动
delay(1); // 延时,等待上面的指令生效,下面再显示,防止出现乱码
WrComLCD(0x0c); // 开显示
}
void compute(){
u8 i,j=0,k,n=0;
char data3[3]={0};
int sum1,data2[4]={0};
int a,b,c,d,o;
int getValue[6]={0};
sum=0;
for(i=0;data1[i]!='\0';i++){
if(data1[i]!='+' && data1[i]!='-' && data1[i]!='*' && data1[i]!='/'){
data2[j] =data2[j]*10+(data1[i]-'0');
}
else{
data3[n++] = data1[i];
j++;
}
}
a=data2[0];
b=data2[1];
c=data2[2];
d=data2[3];
if(flag == 1) //如果二进制
{
a=convertBinaryToDecimal(a);
b=convertBinaryToDecimal(b);
c=convertBinaryToDecimal(c);
d=convertBinaryToDecimal(d);
}
if(flag == 2) //如果8进制
{
a=convertBinaryToDecimal8(a);
b=convertBinaryToDecimal8(b);
c=convertBinaryToDecimal8(c);
d=convertBinaryToDecimal8(d);
}
for(i=0;i<n;i++){
if(i==0){
if(data3[0]=='+') sum = a + b;
if(data3[0]=='-') sum = a - b;
if(data3[0]=='*') sum = a * b;
if(data3[0]=='/') sum = a / (double)b;
}
if(i==1){
if(data3[1]=='+') sum = sum+c;
if(data3[1]=='-') sum = sum-c;
if(data3[1]=='*') sum = sum*c;
if(data3[1]=='/') sum = sum/((float)c);
}
if(i==2){
if(data3[2]=='+') sum = sum+d;
if(data3[2]=='-') sum = sum-d;
if(data3[2]=='*') sum = sum*d;
if(data3[2]=='/') sum = sum/((float)d);
}
}