标题: 一个简单的计算器 单片机程序(含原理图,代码注释) [打印本页]
作者: 张大仙123 时间: 2019-10-13 12:43
标题: 一个简单的计算器 单片机程序(含原理图,代码注释)
用的是普中的开发板,下面是程序:#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
sbit LcdEn_P = P2^5; // 1602液晶的EN管脚
sbit LcdRw_P = P2^6; // 1602液晶的RW管脚
sbit LcdRs_P = P2^7; // 1602液晶的RS管脚
ulong num1; // 运算数1
ulong num2; // 运算数2
ulong num3; // 计算结果
uchar cal; // 运算符号,1加,2减,3乘,4除
uchar num1_flag; // 运算数1的输入标志
uchar num2_flag; // 运算数2的输入标志
/*********************************************************/
// 毫秒级的延时函数,time是要延时的毫秒数
/*********************************************************/
void DelayMs(uint time)
{
uint i,j;
for(i=0;i<time;i++)
for(j=0;j<112;j++);
}
/*********************************************************/
// 1602液晶写命令函数,cmd就是要写入的命令
/*********************************************************/
void LcdWriteCmd(uchar cmd)
{
LcdRs_P = 0;
LcdRw_P = 0;
LcdEn_P = 0;
P0=cmd;
DelayMs(2);
LcdEn_P = 1;
DelayMs(2);
LcdEn_P = 0;
}
/*********************************************************/
// 1602液晶写数据函数,dat就是要写入的数据
/*********************************************************/
void LcdWriteData(uchar dat)
{
LcdRs_P = 1;
LcdRw_P = 0;
LcdEn_P = 0;
P0=dat;
DelayMs(2);
LcdEn_P = 1;
DelayMs(2);
LcdEn_P = 0;
}
/*********************************************************/
// 1602液晶初始化函数
/*********************************************************/
void LcdInit()
{
LcdWriteCmd(0x38); // 16*2显示,5*7点阵,8位数据口
LcdWriteCmd(0x0C); // 开显示,不显示光标
LcdWriteCmd(0x06); // 地址加1,当写入数据后光标右移
LcdWriteCmd(0x01); // 清屏
}
/*********************************************************/
// 液晶光标定位函数
/*********************************************************/
void LcdGotoXY(uchar line,uchar column)
{
// 第一行
if(line==0)
LcdWriteCmd(0x80+column);
// 第二行
if(line==1)
LcdWriteCmd(0x80+0x40+column);
}
/*********************************************************/
// 液晶输出字符串函数
/*********************************************************/
void LcdPrintStr(uchar *str)
{
while(*str!='\0')
LcdWriteData(*str++);
}
/*********************************************************/
// 液晶输出数字
/*********************************************************/
void LcdPrintNum(uchar num)
{
LcdWriteData(num+0x30);
}
/**********************************************************
矩阵键盘扫描程序.
如果扫描到有按键按下,则返回按键值,返回值情况如下所示:
-------------------------------------------------------------
| 第1列 第2列 第3列 第4列 |
|第1行 1 2 3 10 |
|第2行 4 5 6 11 |
|第3行 7 8 9 12 |
|第4行 13 0 14 15 |
------------------------------------------------------------
如果扫描不到有按键按下,则返回99
**********************************************************/
uchar KeyScanf()
{
uchar ret,temp1,temp2;
P1=0x0f;
if(P1!=0x0f)
{
DelayMs(15);
if(P1!=0x0f)
{
temp1=P1; // 判断出是哪一行按键按下
P1=0xf0;
DelayMs(5);
temp2=P1; // 判断出是哪一列按键被按下
ret=temp1|temp2; // 通过行和列的值,确定是哪个按键被按下
switch(ret)
{
case 0xe7: return 1;
case 0xd7: return 2;
case 0xb7: return 3;
case 0x77: return 10;
case 0xeb: return 4;
case 0xdb: return 5;
case 0xbb: return 6;
case 0x7b: return 11;
case 0xed: return 7;
case 0xdd: return 8;
case 0xbd: return 9;
case 0x7d: return 12;
case 0xee: return 13;
case 0xde: return 0;
case 0xbe: return 14;
case 0x7e: return 15;
}
return ret;
}
}
return 99;
}
/*********************************************************/
// 主函数
/*********************************************************/
void main()
{
uchar ret;
uchar i;
LcdInit();
while(1)
{
LcdWriteCmd(0x01); // 清除屏幕显示
LcdWriteCmd(0x0f); // 开启光标闪烁
num1=0; // 运算数1 清零
num2=0; // 运算数2 清零
num3=0; // 计算结果 清零
cal=0; // 运算符号 清零
i=0; // 临时变量 清零
num1_flag=0; // 运算数1输入标志 清零
num2_flag=0; // 运算数2输入标志 清零
while(1)
{
ret=KeyScanf(); // 读取矩阵键盘的扫描结果
if(ret!=99) // 返回值不等于99,说明有按键按下了
{
DelayMs(20);
ret=KeyScanf(); // 读取矩阵键盘的扫描结果
if(ret!=99)
{
/*检测到的是按下数字*/
if(ret<10)
{
if(cal==0) // 如果cal的值为0,说明现在在输入运算数1
{
if(num1<1000) // 限制运算数1的大小小于10000
{
LcdPrintNum(ret); //将按下的数字键刷新显示
num1=num1*10+ret; // 把运算数1放大10倍
num1_flag=1; // 将运算数1的标志变量num1_flag置1,说明运算数1已输入
}
}
else // 如果cal的值不为0,说明现在在输入运算数2
{
if(num2<1000) // 限制运算数2的大小小于10000
{
LcdPrintNum(ret); // 将按下的数字键显示
num2=num2*10+ret; // 把运算数2放大10倍
num2_flag=1; // 将运算数2的标志变量num2_flag置1,说明运算数2已输入
}
}
}
/*检测到的是按下加号*/
if(ret==10)
{
if(cal==0) // 判断是否是第一次输入计算符号
{
if(num1_flag==0) // 判断运算数1是否还未输入
{
LcdPrintNum(0); // 如果是的话,在液晶显示数字0
num1=0; // 给运算数1一个计算初值0
}
cal=1; // 将运算符变量改为1,代表即将进行加法运算
LcdWriteData('+'); // 把加法运算符号显示到屏幕上
}
}
/*检测到的是按下减号*/
if(ret==11)
{
if(cal==0) // 判断是否是第一次输入计算符号
{
if(num1_flag==0) // 判断运算数1是否还未输入
{
LcdPrintNum(0); // 如果是的话,在液晶上面显示0
num1=0; // 给运算数1一个计算初值0
}
cal=2; // 将运算符变量改为2,代表即将进行减法运算
LcdWriteData('-'); // 把减法运算符号显示到屏幕上
}
}
/*检测到的是按下乘号*/
if(ret==12)
{
if(cal==0) // 判断是否是第一次输入计算符号
{
if(num1_flag==0) // 判断运算数1是否还未输入
{
LcdPrintNum(0); // 如果是的话,在液晶上面显示0
num1=0; // 给运算数1一个计算初值0
}
cal=3; // 将运算符变量改为3,代表即将进行乘法运算
LcdWriteData('*'); // 把乘法运算符号显示到屏幕上
}
}
/*检测到的是按下除号*/
if(ret==15)
{
if(cal==0) // 判断是否是第一次输入计算符号
{
if(num1_flag==0) // 判断运算数1是否还未输入
{
LcdPrintNum(0); // 如果是的话,在液晶上面显示0
num1=0; // 给运算数1一个计算初值0
}
cal=4; // 将运算符变量改为4,代表即将进行除法运算
LcdWriteData('/'); // 把除法运算符号显示到屏幕上
}
}
/*检测到的是按下清除键*/
if(ret==13)
{
break; // 退出当前的while循环
}
/*检测到的是按下等于号*/
if(ret==14)
{
if(num2_flag==0) // 判断运算数2是否还未输入
{
LcdPrintNum(0); // 如果是的话,在液晶上面显示0
num2=0; // 给运算数2一个计算初值0
}
switch(cal) // 根据cal这个变量的不同值,采取不同的四则运算
{
/*加法运算*/
case 1:
LcdGotoXY(1,15); // 定位到液晶的第2行最后一列
LcdWriteCmd(0x04); // 光标左移
num3=num1+num2; // 计算结果
if(num3==0) // 如果计算结果为0
{
LcdPrintNum(0); // 在屏幕上显示0
}
while(num3!=0) // 显示计算结果
{
LcdPrintNum(num3%10);
num3=num3/10;
}
LcdWriteData('='); // 显示等于号
LcdWriteCmd(0x06); // 光标右移
break;
/*减法运算*/
case 2:
LcdGotoXY(1,15); // 定位到液晶的第2行最后一列
LcdWriteCmd(0x04); // 光标左移
if(num1>num2)
{
num3=num1-num2; // 计算结果
while(num3!=0) // 显示计算结果
{
LcdPrintNum(num3%10);
num3=num3/10;
}
}
else if(num1<num2)
{
num3=num2-num1; // 计算结果
while(num3!=0) // 显示计算结果
{
LcdPrintNum(num3%10);
num3=num3/10;
}
LcdWriteData('-'); // 显示负号
}
else
{
LcdPrintNum(0); // 显示数字0
}
LcdWriteData('='); // 显示等于号
LcdWriteCmd(0x06); // 光标右移
break;
/*乘法运算*/
case 3:
LcdGotoXY(1,15); // 定位到液晶的第2行最后一列
LcdWriteCmd(0x04); // 光标左移
num3=num1*num2; // 计算结果
if(num3==0) // 如果计算结果为0
{
LcdPrintNum(0); // 在屏幕上显示0
}
while(num3!=0) // 显示计算结果
{
LcdPrintNum(num3%10);
num3=num3/10;
}
LcdWriteData('='); // 显示等于号
LcdWriteCmd(0x06); // 光标右移
break;
/*除法运算*/
case 4:
if(num2!=0)
{
LcdGotoXY(1,15); // 定位到液晶的第2行最后一列
LcdWriteCmd(0x04); // 光标左移
num3=(ulong)(((float)num1/num2)*1000); // 计算结果(放大了1000倍)
if(num1<num2) // 如果是小数除以大数
{
num3=num3+1000;// 先给计算结果加1000
}
while(num3!=0) // 显示计算结果
{
LcdPrintNum(num3%10);
num3=num3/10;
i++;
if(i==3) // 显示小数点
{
LcdWriteData('.');
}
}
if(num1<num2) // 如果是小数除以大数
{
LcdGotoXY(1,11); // 把之前加的1000给清除
LcdPrintNum(0);
}
LcdWriteData('='); // 显示等于号
LcdWriteCmd(0x06); // 光标右移
break;
}
else // 如果除数位0,显示“ERROR!”
{
LcdGotoXY(1,10);
LcdPrintStr("ERROR!");
}
}
LcdWriteCmd(0x0C); // 光标不闪烁
while(KeyScanf()!=13); // 计算后,只能通过按下清除键,才能进入新一轮的计算
break;
}
DelayMs(10); // 去除按键按下的抖动
while(KeyScanf()!=99); // 等待按键释放
DelayMs(10); // 去除按键松开的抖动
}
}
}
}
}
-
-
计算器程序 原理图.rar
89.25 KB, 下载次数: 25, 下载积分: 黑币 -5
作者: zzzzz.c 时间: 2019-10-15 11:04
真全,,谢谢了
欢迎光临 (http://www.51hei.com/bbs/) |
Powered by Discuz! X3.1 |