目录
前言
Proteus硬件部分
键盘
程序部分
运算代码逻辑(代码解释)
LCD屏幕显示运算结果
输入部分
键值判断部分
删除按键的实现
程序执行运算
前言
Hello,大家好。想做关于嵌入式的一些小项目已经很久了,今天借着我们课设的机会,给大家展示我自己对代码逻辑的理解,为了方便简易,所有代码我都放在了一个.c文件里面,希望我的代码能给读者带来不一样的收获与编写简易计算机的思路,创作不易,大家觉得好的话点个赞呗~
简易计算机前后最大位均是三位,可以实现加减乘除四种运算功能,输入键盘采用的是4×4行列式的循环扫描按键键盘
Proteus硬件部分
Proteus版本是8.6,我采用的显示屏是LCD1602用来显示计算的结果与输入,其次D1标志灯常用于显示程序运行正常的标志,KEY为复位按键
键盘
键盘扫描逻辑:
键盘部分的接线图如图所示,我看到很多博主都喜欢使用switch(a)...case...的逻辑运行按键,但本次我根据书上的方法(《单片机原理与应用(P103页,林立版)》)使用的是扫描的方法启动按键,即在循环口输出一组扫描码(以P3为例),首先规定键盘的行(图A1 A2 A3 A4)都为高电压,而列(A5 A6 A7 A8 )开启循环扫描,即轮流有一列为0,其余都为1。
利用条件表达式(P3&0x0f)判断按键有无按压,若低4位不全为1,则说明有按键按压,则此时可以执行key_buf函数
key_buf[]={0xee,0xde,0xbe,0x7e,
0xed,0xdd,0xbd,0x7d,
0xeb,0xdb,0xbb,0x7b,
0xe7,0xd7,0xb7,0x77}
键值计算:
若将行列式键盘自左至右,自上至下排列序号作为键值,则通过逐一对比P2读入值与键模数组,可求闭合按键键值j,即:
if((P3&0x0f)!=0x0f){
for(j=0;j<16;j++)
{if (key_buf[j]==P3) return j;
}
}
}
return -1;
以上两步完成对键盘的编写。
程序部分
话不多说,直接上所有程序吧
//Grumpy cat
#include <reg51.h>
char key_buf[]={0xee,0xde,0xbe,0x7e,0xed,0xdd,0xbd,0x7d,0xeb,0xdb,0xbb,0x7b,0xe7,0xd7,0xb7,0x77};//定义键盘按键
unsigned char code sable[]="error!";
unsigned char code table0[]="0";
unsigned char code table[]="1";
unsigned char code table2[]="2";
unsigned char code table3[]="3";
unsigned char code table4[]="4";
unsigned char code table5[]="5";
unsigned char code table6[]="6";
unsigned char code table7[]="7";
unsigned char code table8[]="8";
unsigned char code table9[]="9";
unsigned char code table10[]="+";
unsigned char code table11[]="-";
unsigned char code table12[]="*";
unsigned char code table13[]="/";
unsigned char code table14[]="=";//以上是LCD屏幕需要展现的符号
unsigned char code mode[]={0x00,0x01,0x02,0x03,0x004,0x05,0x06,0x07,0x08,0x09};//10位地址,每当按下一次按键,地址+1,实现右移功能
unsigned char flash[]={0,0,0,0,0,0,0};//存储符号内容,转化为数字
sbit P1_7=P1^7;//灯标志位
sbit RS=P2^0;
sbit RW=P2^1;
sbit EN=P2^2;//LCD设置
int i;
int a=0;
unsigned int p;
char c=0;
char m=0;
char op;
//定义按键
char getkey(void){
char key_scan[]={0xef,0xdf,0xbf,0x7f};
char i=0,j=0;
for(i=0;i<4;i++){
P3=key_scan[i];
if((P3&0x0f)!=0x0f){
for(j=0;j<16;j++)
{if (key_buf[j]==P3) return j;
}
}
}
return -1;
}
//定义延时函数
void delay(unsigned int time){
unsigned int j = 0;
for (;time>0;time--)
for (j=0;j<125;j++);
}
//定义按键中的延时函数
void delay1(unsigned int x){
unsigned int i;
for(i=x;i>0;i--);
}
//初始化设置LCD显示屏
void write_com(unsigned char com){
P0=com;
RS=0;RW=0;EN=1;
delay1(200);
EN=0;}
//LCD显示内容
void write_dat(unsigned char dat){
P0=dat;
RS=1;RW=0;EN=1;
delay1(200);
EN=0;
}
//初始化LCD显示屏
void init(){
write_com(0x01);
write_com(0x38);
write_com(0x0f);
write_com(0x06);
}
//显示得出结果后的地址
void address(unsigned char x,unsigned char y){
unsigned char location;
if(x==0)
location=0x80|y;
else if(x==1)
location=0xc0|y;
write_com(location);}
//加法减法乘法运算函数
void printtemp(unsigned char x,unsigned char y,unsigned long temp3)
{
if(temp3<=99){
address(x,y);
write_dat(temp3/10 + '0');
address(x,y + 1);
write_dat(temp3%10 + '0');}
else if(temp3>99&&temp3<=999){
address(x,y);
write_dat(temp3/100 + '0');
address(x,y + 1);
write_dat(temp3%100/10 + '0');
address(x,y + 2);
write_dat(temp3%10 + '0');
}
else if(temp3>999&&temp3<=9999){
address(x,y);
write_dat(temp3/1000 + '0');
address(x,y + 1);
write_dat(temp3%1000/100 + '0');
address(x,y + 2);
write_dat(temp3%100/10 + '0');
address(x,y +3);
write_dat(temp3%10 + '0');
}
else if(temp3>9999&&temp3<=99999){
address(x,y);
write_dat(temp3/10000 + '0');
address(x,y + 1);
write_dat(temp3%10000/1000 + '0');
address(x,y + 2);
write_dat(temp3%1000/100 + '0');
address(x,y +3);
write_dat(temp3%100/10 + '0');
address(x,y + 4);
write_dat(temp3%10 + '0');
}
else if(temp3>99999&&temp3<=999999){
address(x,y);
write_dat(temp3/100000 + '0');
address(x,y + 1);
write_dat(temp3%100000/10000 + '0');
address(x,y + 2);
write_dat(temp3%10000/1000 + '0');
address(x,y +3);
write_dat(temp3%1000/100 + '0');
address(x,y + 4);
write_dat(temp3%100/10 + '0');
address(x,y + 5);
write_dat(temp3%10 + '0');
}
}
//除法运算函数
void printtemp_c(unsigned char x,unsigned char y,double temp)
{
unsigned int temp1;
temp1=temp*100;
if(temp1<100)
{
address(x,y);
write_dat(temp1/100 + '0');
address(x,y + 1);
write_dat('.');
address(x,y + 2);
write_dat(temp1/10 + '0');
address(x,y + 3);
write_dat(temp1%10 + '0');
}
else if (temp1>=100&&temp1<1000){
address(x,y);
write_dat(temp1/100 + '0');
address(x,y + 1);
write_dat('.');
address(x,y + 2);
write_dat(temp1%100/10 + '0');
address(x,y + 3);
write_dat(temp1%10 + '0');}
else if (temp1>=1000&&temp1<10000){
address(x,y);
write_dat(temp1/1000 + '0');
address(x,y + 1);
write_dat(temp1%1000/100 + '0');
address(x,y + 2);
write_dat('.');
address(x,y + 3);
write_dat(temp1%100/10 + '0');
address(x,y + 4);
write_dat(temp1%10 + '0');}
else if (temp1>=10000&&temp1<100000){
address(x,y);
write_dat(temp1/10000 + '0');
address(x,y + 1);
write_dat(temp1%10000/1000 + '0');
address(x,y + 2);
write_dat(temp1%1000/100 + '0');
address(x,y + 3);
write_dat('.');
address(x,y + 4);
write_dat(temp1%100/10 + '0');
address(x,y + 5);
write_dat(temp1%10 + '0'); }
}
void main(void){
int q=0;
char dir=0,run=0;
unsigned char judge=1;
unsigned long result;
double result2;
unsigned long num1=0,num2=0;
unsigned long num1_t,num2_t;
char key=0;
init();
while(1){
key=getkey();
flash[q]=key;
if(key<=14){
if (flash[5]==4){P1_3=0;}
if(key!=-1) {
a=a+1;
p=a;
delay(400);
if(key==14)
a--;
}
if(a==1){
P1_1=0;
}
else if(a==2){
P1_1=1;
}
else if(a==3){P1_2=0;
}
//judge=1,判断flash[]在0~9之间说明为第一个数值的输入
if(judge==1&&flash[q]>=0&&flash[q]<=9){
if(key==1) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table[i]);
delay1(3000);
}
q++;
num1++;
// HEX_U(a);
}
if(key==2) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table2[i]);
delay1(3000);}
q++;
num1++;
// HEX_U(a);
}
if(key==3) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table3[i]);
delay1(3000);
}
q++;
num1++;
// HEX_U(a);
}
if(key==4) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table4[i]);
delay1(3000);
}
q++;
num1++;
// HEX_U(a);
}
if(key==5) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table5[i]);
delay1(3000);
}
q++;
num1++;
// HEX_U(a);
}
if(key==6) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table6[i]);
delay1(3000);
}
q++;
num1++;
// HEX_U(a);
}
if(key==7) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table7[i]);
delay1(3000);
}
q++;
num1++;
// HEX_U(a);
}
if(key==8) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table8[i]);
delay1(3000);
}
q++;
num1++;
// HEX_U(a);
}
if(key==9) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table9[i]);
delay1(3000);
}
q++;
num1++;
// HEX_U(a);
}
if(key==0) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table0[i]);
delay1(3000);
}
q++;
num1++;
// HEX_U(a);
}
//当位数超过三报错
if(num1>3){
write_com(0x01);
write_com(0x80);
for(i=0;i<6;i++){
write_dat(sable[i]);
delay1(3000);}
}
}
//+
if(key==10){
judge=2;
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table10[i]);
delay1(3000);}
op=111;
}
//-
if(key==11){
judge=2;
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table11[i]);
delay1(3000);}
op=222;
}
//*
if(key==12){
judge=2;
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table12[i]);
delay1(3000);}
op=333;
}
// /
if(key==13){
judge=2;
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table13[i]);
delay1(3000);}
op=444;
}
if(judge==2&&flash[q]>=0&&flash[q]<=9) {
if(key==1) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table[i]);
delay1(3000);
}
q++;
num2++;
// HEX_U(a);
}
if(key==2) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table2[i]);
delay1(3000);}
q++;
num2++;
// HEX_U(a);
}
if(key==3) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table3[i]);
delay1(3000);
}
q++;
num2++;
// HEX_U(a);
}
if(key==4) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table4[i]);
delay1(3000);
}
q++;
num2++;
// HEX_U(a);
}
if(key==5) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table5[i]);
delay1(3000);
}
q++;
num2++;
// HEX_U(a);
}
if(key==6) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table6[i]);
delay1(3000);
}
q++;
num2++;
// HEX_U(a);
}
if(key==7) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table7[i]);
delay1(3000);
}
q++;
num2++;
// HEX_U(a);
}
if(key==8) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table8[i]);
delay1(3000);
}
q++;
num2++;
// HEX_U(a);
}
if(key==9) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table9[i]);
delay1(3000);
}
q++;
num2++;
// HEX_U(a);
}
if(key==0) {
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table0[i]);
delay1(3000);
}
q++;
num2++;
// HEX_U(a);
}
if(num2>3){
write_com(0x01);
write_com(0x80);
for(i=0;i<6;i++){
write_dat(sable[i]);
delay1(3000);}
}
}
if(key==14){
flash[q-1]=0;
q--;
write_com(0x80+mode[p-1]);
write_dat(' ');
// write_com(0x18);
if(judge==1)
num1--;
if(judge==2)
num2--;
}
}
///当按下第15个按键(=),则运行:
if(key==15){
if(num1==1){
num1_t=flash[0];}
else if(num1==2){
num1_t=flash[0]*10+flash[1];}
else if(num1==3){
num1_t=flash[0]*100+flash[1]*10+flash[2];}
///Åжϵڶþ¸ö¼üÖµ
if(num2==1){
num2_t=flash[num1];}
else if(num2==2){
num2_t=flash[num1]*10+flash[num1+1];}
else if(num2==3){
num2_t=flash[num1]*100+flash[num1+1]*10+flash[num1+2];}
delay(400);
switch(op){
case 111: result=num1_t+num2_t;dir=1;break;
case 222: result=num1_t-num2_t;dir=1;break;
case 333: result=num1_t*num2_t;dir=1;break;
case 444: result2=((double)num1_t)/((double)num2_t);run=1;break;
}
if(dir==1){
printtemp(1,1,result);}
else if(run==1){
printtemp_c(1,1,(double)result2);}
if(flash[5]==5){
P1_7=0;
}
}
}
}
运算代码逻辑(代码解释)
LCD屏幕显示运算结果
当我们输出结果之后,应该在屏幕中输出我们想要得到的结果,使用addressprinttemp函数实现
void address(unsigned char x,unsigned char y){
unsigned char location;
if(x==0)
location=0x80|y;
else if(x==1)
location=0xc0|y;
write_com(location);}
void printtemp(unsigned char x,unsigned char y,unsigned long temp3)
{
if(temp3<=99){
address(x,y);
write_dat(temp3/10 + '0');
address(x,y + 1);
write_dat(temp3%10 + '0');}
else if(temp3>99&&temp3<=999){
address(x,y);
write_dat(temp3/100 + '0');
address(x,y + 1);
write_dat(temp3%100/10 + '0');
address(x,y + 2);
write_dat(temp3%10 + '0');
}
else if(temp3>999&&temp3<=9999){
address(x,y);
write_dat(temp3/1000 + '0');
address(x,y + 1);
write_dat(temp3%1000/100 + '0');
address(x,y + 2);
write_dat(temp3%100/10 + '0');
address(x,y +3);
write_dat(temp3%10 + '0');
}
else if(temp3>9999&&temp3<=99999){
address(x,y);
write_dat(temp3/10000 + '0');
address(x,y + 1);
write_dat(temp3%10000/1000 + '0');
address(x,y + 2);
write_dat(temp3%1000/100 + '0');
address(x,y +3);
write_dat(temp3%100/10 + '0');
address(x,y + 4);
write_dat(temp3%10 + '0');
}
else if(temp3>99999&&temp3<=999999){
address(x,y);
write_dat(temp3/100000 + '0');
address(x,y + 1);
write_dat(temp3%100000/10000 + '0');
address(x,y + 2);
write_dat(temp3%10000/1000 + '0');
address(x,y +3);
write_dat(temp3%1000/100 + '0');
address(x,y + 4);
write_dat(temp3%100/10 + '0');
address(x,y + 5);
write_dat(temp3%10 + '0');
}
}
我们取加减乘的函数部分,首先我们显示的最大位为999*999=998001,最大位是六位,当我们经运算得到的代码结果最大也不会超过六位,可能位是1,2,3,4,5,6,因此当temp3<99是(运算值为一位或两位),那么LCD输出的第一位是结果的十位,即write_dat(temp/10 + '0'),其中address为地址函数x,y分别是对应输出在LCD屏幕上的位置,当输入完毕后,address+1输出下一位,当为两位时,我们在屏幕上首先输出第一位是十位之后,需要地址(address+1),之后再输出第二位,即输出完毕,同理一直输出到第六位都是用的同样的逻辑
还有一个部分是我们计算除法的时候,和加减乘除还是有些区别的,因为我们除法需要有小数,则我们在对函数定义temp的时候也需要将其定义为double类型。读者可以自行下载编译代码试一试。
输入部分
在编写函数之前我们要明白,当我们最大输入前三个数值前,需要知道当输入第一个数字后,LCD的地址就要加1,方便之后继续输入,同时flash[0]也要保存第一位,同时num++用于判断之后运算为到底是几位,
首先我们要输入第一个数字,使用write_com(0x80+mode[0]),表明的是输入的起点是第一行第一个字符,其次函数中a需要做a++判断,当我们再次按下另一个数值,这个数字就会被保存在下一个地址中,则我们使用write_com(0x80+mode[a]).
键值判断部分
在我们输入完前半部分数值之后,之后进入加减乘除按键的判断选择,这里我们设置一个变量judge2,当我们还在输入第一个数值的时候,赋值judge1=1,当我们输入完毕之后,按下运算按键,则judge1换为judge2,这时程序就跳出数字输入的循环,直接判断加减乘除符号符号,值得注意的是我们输入符号的时候,其实并没有占用flash[]的位,因此当我们使用DEL删除键,有 ‘ ’ 来占位,之后程序进入op值的判断(以+为例)
if(key==10){
judge=2;
write_com(0x80+mode[a]);
for(i=0;i<1;i++){
write_dat(table10[i]);
delay1(3000);}
op=111;
}
不难看出, ‘+’ 为键值10的表示,op=111,这时程序知道你要做的是加法运算,op=111是一个标志,待会将会直接进入加法运算执行
删除按键的实现
if(key==14){
flash[q-1]=0;
q--;
write_com(0x80+mode[p-1]);
write_dat(' ');
write_com(0x18);
if(judge==1)
num1--;
if(judge==2)
num2--;
}
不难看出,删除键为key=14,我们按下删除按键的时候需要让flash[]和q(q就理解为程序中的a)都减一,,因为只有LCD和flash[]中储存有数值,只有用if判断句,实现num--,目的是减少一位
程序执行运算
if(key==15){
if(num1==1){
num1_t=flash[0];}
else if(num1==2){
num1_t=flash[0]*10+flash[1];}
else if(num1==3){
num1_t=flash[0]*100+flash[1]*10+flash[2];}
if(num2==1){
num2_t=flash[num1];}
else if(num2==2){
num2_t=flash[num1]*10+flash[num1+1];}
else if(num2==3){
num2_t=flash[num1]*100+flash[num1+1]*10+flash[num1+2];}
delay(400);
switch(op){
case 111: result=num1_t+num2_t;dir=1;break;
case 222: result=num1_t-num2_t;dir=1;break;
case 333: result=num1_t*num2_t;dir=1;break;
case 444: result2=((double)num1_t)/((double)num2_t);run=1;break;
}
if(dir==1){
printtemp(1,1,result);}
else if(run==1){
printtemp_c(1,1,(double)result2);}
if(flash[5]==5){
P1_7=0;
}
}
一 首先判断num的位数,然后根据位数将flash[]里面存储的数拿出来进行相应位数的运算,num=1说明前一个数值只有一位,num=2说明有两位,num=3说明有三位,且数值最大不超过三位,其次判断第二个数值(num2),第二个数值程序逻辑与第一个相同
二 判断完前后两个数值大小后,再去判断op,op的判断应用于程序应该进行怎么样的运算操作,运算结果都将保留在result或者result2中,再通过printtemp函数在LCD屏幕中显示出运算结果
以上就是代码的全部内容了,下面是随机的运算。非常感谢大家能够读到这里,喜欢的话,就点个赞再走吧~,还是有什么有疑问的话小伙伴可以在评论区或者留言私信我,我会以最快的速度回复大家,感谢大家的支持!!!!
文章来源:https://www.toymoban.com/news/detail-479578.html
文章来源地址https://www.toymoban.com/news/detail-479578.html
到了这里,关于51单片机实现简易计算机,Keil4代码Proteus工程一步到位的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!