项目最后附有本项目程序源码!!
如果对你有帮助不妨点个赞!
本项目使用:51单片机、矩阵键盘、LCD1602;
使用数码管进行显示的思路相差不大。
电路仿真图:
代码:
为方便大家观看,小编分功能展示,相信具有一定编程基础,再搭配上注释看明白小编的代码应该不成问题,能力有限,如有不对,欢迎在评论区留言!!
在文章最后附有代码链接,如有需要自行下载。
主程序代码:
头文件代码:
#ifndef _MAIN_H_
#define _MAIN_H_
/**********************************
包含头文件
**********************************/
#include<reg52.h>
#include<intrins.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdio.h>
/**********************************
重定义关键词
**********************************/
#define uchar unsigned char
#define uint unsigned int
/**********************************
函数声明
**********************************/
void Delay_function(uint x); //延时x ms函数
#endif
源文件代码:
/**********************************
包含头文件
**********************************/
#include "main.h"
#include "lcd1602.h"
#include "key.h"
/**********************************
变量定义
**********************************/
uchar key_bianma = 0; //按键编码标志位变量
uchar key_num = 0; //按键扫描标志位变量
uint time_num = 0; //10ms计时变量
uchar password_input[7]; //输入数组
uchar password_reset[7]; //重置数组
uchar flag_num_index1= 0; //输入第一个数的数组下标
uchar flag_num_index2= 0; //输入第二个数的数组下标
uchar flag_num_1_2= 0; //第一、二个数据标志位
uchar flag_sign = 0; //符号标志位
double num_a = 0.0; //数据a
double num_b = 0.0; //数据b
double num_result = 0.0; //得出的结果
char resault_buf[10]; //得出的结果数组
uchar flag_sign_offset = 0; //符号偏移量
uchar flag_result = 0; //结果标志位
uchar flag_clean = 1; //清除标志位
uchar flag_lock_time = 0; //锁定时间
double mr= 0.0;
uchar mi= 0;
double m1= 0.0;
double m2= 0.0;
double m3= 0.0;
/**********************************
函数声明
**********************************/
void Delay_function(uint x); //延时函数
void Key_function(void); //按键函数
void Display_function(void); //显示函数
void Ensure_function(void); //确定函数
void Result(void); //求取结果函数
/****
******* 主函数
*****/
void main()
{
Lcd1602_Init(); //LCD1602初始化
Delay_function(50); //延时50ms
lcd1602_clean(); //清屏
Delay_function(50); //延时50ms
while(1)
{
Key_function(); //按键函数
Display_function(); //显示函数
Delay_function(10); //延时10ms
time_num++; //计时变量+1
if(time_num == 5000)
{
time_num = 0;
}
}
}
/****
******* 延时函数
*****/
void Delay_function(uint x)
{
uint m,n;
for(m=x;m>0;m--)
for(n=110;n>0;n--);
}
/****
*******按键函数
*****/
void Key_function(void)
{
key_bianma = matrix_keyboard_scan(); //读按键的位置码
if(key_bianma != 0) //当有按键按下时
{
key_num = matrix_keyboard_coding(key_bianma); //根据按键的位置将其编码,编码值赋值给NUM
{
if(flag_result == 1 && flag_clean == 1) //第一次得出结果,清除输入的数据
{
flag_clean = 0;
lcd1602_display_str(1,4," ");
}
if(flag_result == 2) //得出的结果为error时,只能按复位键
{
if(key_num == 'L') //复位
{
flag_num_1_2 = 0;
flag_clean = 1;
flag_result = 0;
flag_num_index1 = 0;
flag_num_index2 = 0;
flag_sign_offset = 0;
memset(password_input,'\r',7);
memset(password_reset,'\r',7);
lcd1602_clean();
Display_function();
}
}
else
{
switch(key_num)
{
case ('A'): //M1
flag_sign = 1;
lcd1602_display_str(1,4,"M1");
flag_sign_offset = 2;
break;
case ('B'): //M2
flag_sign = 2;
lcd1602_display_str(1,4,"M2");
flag_sign_offset = 2;
break;
case ('C'): //M3
flag_sign = 3;
lcd1602_display_str(1,4,"M3");
flag_sign_offset = 2;
break;
case ('D'): //MR+
flag_sign = 4;
lcd1602_display_str(1,4,"MR+");
flag_sign_offset = 3;
break;
case ('E'): //MR-
flag_sign = 5;
lcd1602_display_str(1,4,"MR-");
flag_sign_offset = 3;
break;
case ('F'): //÷
flag_sign = 6;
flag_num_1_2 = 1;
lcd1602_display_char(1,4+flag_num_index1,'/');
break;
case ('G'): //x
flag_sign = 7;
flag_num_1_2 = 1;
lcd1602_display_char(1,4+flag_num_index1,'*');
break;
case ('H'): //-
flag_sign = 8;
flag_num_1_2 = 1;
lcd1602_display_char(1,4+flag_num_index1,'-');
break;
case ('L'): //+
flag_sign = 9;
flag_num_1_2 = 1;
lcd1602_display_char(1,4+flag_num_index1,'+');
break;
case ('I'): //复位
flag_num_1_2 = 0;
flag_clean = 1;
flag_result = 0;
flag_num_index1 = 0;
flag_num_index2 = 0;
flag_sign_offset = 0;
memset(password_input,'\r',7);
memset(password_reset,'\r',7);
lcd1602_clean();
Display_function();
break;
case ('J'): //.
if(flag_num_1_2 == 0)
{
if(flag_num_index1 < 7)
{
password_input[flag_num_index1] = '.';
lcd1602_display_char(1,4+flag_num_index1+flag_sign_offset,'.');
flag_num_index1++;
}
}
else
{
if(flag_num_index2 < 7)
{
password_reset[flag_num_index2] = '.';
lcd1602_display_char(1,4+flag_num_index1+1+flag_num_index2+flag_sign_offset,'.');
flag_num_index2++;
}
}
break;
case ('K'): //=
Result();
break;
default: //0-9数字键
if(flag_num_1_2 == 0) //用于输入的第一个数据
{
if(flag_num_index1 < 7)
{
password_input[flag_num_index1] = key_num+'0';
lcd1602_display_char(1,4+flag_num_index1+flag_sign_offset,key_num+'0');
flag_num_index1++;
}
}
else //用于输入的第二个数据
{
if(flag_num_index2 < 7)
{
password_reset[flag_num_index2] = key_num+'0';
lcd1602_display_char(1,4+flag_num_index1+1+flag_num_index2+flag_sign_offset,key_num+'0');
flag_num_index2++;
}
}
break;
}
}
}
}
}
/****
*******显示函数
*****/
void Display_function(void)
{
lcd1602_display_str(1,0,"For:");
lcd1602_display_str(2,0,"Res:");
}
/****
*******求取结果函数
*****/
void Result(void)
{
if(flag_result == 0) //第一次输入的公式
{
num_a = atof(password_input); //解析数据a和b
num_b = atof(password_reset);
}
else //未按复位键,第一次的结果当成第一个数
{
num_a = num_result;
num_b = atof(password_reset);
}
switch(flag_sign)
{
case (1): //M1
num_result=m1;
break;
case (2): //M2
num_result=m2;
break;
case (3): //M3
num_result=m3;
break;
case (4):
mr =num_a; //MR+
num_result = num_a + num_b;
break;
case (5):
mr =num_a; //MR-
num_result = num_a - num_b;
break;
case (6): //÷
if(flag_num_index2 == 1 && (password_reset[0] == '0' || password_reset[0] == '.')) //除数不能为0或.
{
lcd1602_display_str(2,4," ");
lcd1602_display_str(2,4,"Error ");
return ;
}
else
{
num_result = num_a / num_b;
}
break;
case (7): //x
num_result = (num_a * num_b);
break;
case (8): //-
num_result = num_a - num_b;
break;
case (9): //+
num_result = num_a + num_b;
break;
}
mr=num_result;
if(mi==3)
{
mi=0;
}
else
{
switch(mi)
{
case 0 :m1=num_result;break;
case 1 :m2=num_result;break;
case 2 :m3=num_result;break;
}
mi++;
}
sprintf(resault_buf,"%.2f",num_result); //将结果解析到数组中
if(num_result > 9999999 || num_result < -9999999) //结果超过-9999999~9999999,显示error
{
lcd1602_display_str(2,4,"Error ");
flag_result = 2;
}
else //未超过,显示结果
{
lcd1602_display_str(2,4," ");
lcd1602_display_str(2,4,resault_buf);
flag_result = 1;
flag_clean = 1;
flag_num_1_2 = 1;
flag_num_index1 = 0;
flag_num_index2 = 0;
flag_sign_offset = 0;
memset(password_input,'\r',7);
memset(password_reset,'\r',7);
}
}
矩阵键盘功能区代码:
头文件代码:
#ifndef _KEY_H_
#define _KEY_H_
/**********************************
包含头文件
**********************************/
#include "main.h"
/**********************************
PIN口定义
**********************************/
#define MATRIX_KEYBOARD_DATA P1 //矩阵键盘引脚
#define MATRIX_KEYBOARD_DATA1 P3 //矩阵键盘引脚
/**********************************
函数声明
**********************************/
uchar matrix_keyboard_coding(uchar m); //矩阵键盘键值编码为数值函数
uchar matrix_keyboard_scan(void); //矩阵键盘扫描函数
#endif
源文件代码:
/**********************************
包含头文件
**********************************/
#include "key.h"
/**********************************
变量定义
**********************************/
extern uchar flag_beep;
/**********************************
函数定义
**********************************/
/****
*******矩阵键盘键值编码为数值函数
*******返回值:键值数值
*****/
uchar matrix_keyboard_coding(uchar m)
{
uchar k;
switch(m)
{
case (46): k='A'; break; //K1按下
case (238): k='B'; break; //K2按下
case (110): k='C'; break; //K3按下
case (102): k='D'; break; //K4按下
case (94): k='E'; break; //K5按下
case (233): k=7; break; //K7按下
case (105): k=8; break; //K8按下
case (97): k=9; break; //K9按下
case (89): k='F'; break; //K10按下
case (223): k=4; break; //K12按下
case (95): k=5; break; //K13按下
case (87): k=6; break; //K14按下
case (79): k='G'; break; //K15按下
case (203): k=1; break; //K17按下
case (75): k=2; break; //K18按下
case (67): k=3; break; //K19按下
case (59): k='H'; break; //K20按下
case (227): k='I'; break; //K21按下
case (163): k='J'; break; //K22按下
case (35): k=0; break; //K23按下
case (27): k='K'; break; //K24按下
case (19): k='L'; break; //K25按下
}
return(k);
}
uchar matrix_keyboard_scan(void)
{
uchar cord_h,cord_l; //行列值中间变量
MATRIX_KEYBOARD_DATA=0x1f; //列线输出全为0
MATRIX_KEYBOARD_DATA1=0xf3; //列线输出全为0
cord_h=MATRIX_KEYBOARD_DATA&0x1f; //读入行线值
if(cord_h!=0x1f) //先检测有无按键按下
{
Delay_function(10); //去抖
if((MATRIX_KEYBOARD_DATA&0x1f)!=0x1f)
{
cord_h=MATRIX_KEYBOARD_DATA&0x1f; //读入行线值
MATRIX_KEYBOARD_DATA=cord_h|0xe0; //输出当前列线值
MATRIX_KEYBOARD_DATA1=0x0c; //输出当前列线值
cord_l=MATRIX_KEYBOARD_DATA&0xe0 | MATRIX_KEYBOARD_DATA1&0x0c; //读入列线值
if(flag_beep == 1)
BEEP = 0;
while((MATRIX_KEYBOARD_DATA&0xe0)!=0xe0 || (MATRIX_KEYBOARD_DATA1&0x0c)!= 0x0c); //等待松开并输出
BEEP = 1;
return(cord_h*5+cord_l*2); //键盘最后组合码值
}
}
return 0; //返回该值
}
LCD1602 显示代码:
头文件:
#ifndef _LCD1602_H_
#define _LCD1602_H_
/**********************************
包含头文件
**********************************/
#include "main.h"
/**********************************
PIN口定义
**********************************/
#define LCD1602_PORT P0 //数据总线P0.0-P0.7
sbit LCD1602_RS=P2^5; //数据/命令选择引脚P2.5
sbit LCD1602_RW=P2^6; //读/写选择P2.6
sbit LCD1602_E=P2^7; //使能信号引脚P2.7
sbit LCD1602_BUSY=P0^7; //检测状态引脚P0.7
/**********************************
函数声明
**********************************/
void lcd1602_display_char(uchar hang, uchar add, uchar dat); //LCD1602显示字符函数
void lcd1602_display_str(uchar hang, uchar add, uchar *dat); //LCD1602显示字符串函数
void lcd1602_clean(); //LCD1602清屏函数
void Lcd1602_Init(); //LCD1602初始化函数
#endif
源文件代码:
/**********************************
包含头文件
**********************************/
#include "lcd1602.h"
/**********************************
函数定义
**********************************/
/****
*******1602检测忙函数
*****/
void lcd1602_check_busy()
{
P0=0xff;
do
{
LCD1602_RS=0;
LCD1602_RW=1;
LCD1602_E=0;
LCD1602_E=1;
} while(LCD1602_BUSY==1);
LCD1602_E=0;
}
/****
*******1602写数据忙函数
*****/
void lcd1602_write_date(uchar date)
{
lcd1602_check_busy();
LCD1602_E=0;
LCD1602_PORT=date;
LCD1602_RS=1;
LCD1602_RW=0;
LCD1602_E=1;
LCD1602_E=0;
}
/****
*******1602写命令函数
*****/
void lcd1602_write_com(uchar com)
{
lcd1602_check_busy();
LCD1602_E=0;
LCD1602_PORT=com;
LCD1602_RS=0;
LCD1602_RW=0;
LCD1602_E=1;
LCD1602_E=0;
}
/****
*******LCD1602显示字符函数
*******参量定义: hang:输入显示行数 1 第一行 2 第二行
******* add:偏移量,0-15
******* dat:所要显示的字符,输入格式 ' '
*****/
void lcd1602_display_char(uchar hang, uchar add, uchar dat)
{
if(hang==1)
lcd1602_write_com(0x80+add); //第一行
else
lcd1602_write_com(0x80+0x40+add); //第二行
lcd1602_write_date(dat);
}
/****
*******LCD1602显示字符串函数
*******参量定义: hang:输入显示行数 1 第一行 2 第二行
******* add:偏移量,0-15
******* dat:所要显示的字符串,输入格式 " "
*****/
void lcd1602_display_str(uchar hang, uchar add, uchar *dat)
{
if(hang==1)
lcd1602_write_com(0x80+add); //第一行
else
lcd1602_write_com(0x80+0x40+add); //第二行
while(*dat != '\0')
{
lcd1602_write_date(*dat++);
}
}
/****
*******LCD1602清屏函数
*****/
void lcd1602_clean()
{
lcd1602_display_str(1,0," ");
lcd1602_display_str(2,0," ");
}
/****
*******LCD1602初始化函数
*****/
void Lcd1602_Init()
{
lcd1602_write_com(0x38);
lcd1602_write_com(0x0c);
lcd1602_write_com(0x06);
lcd1602_write_com(0x01);
}
中断程序代码:
头文件:
#ifndef _UART_H_
#define _UART_H_
/**********************************
包含头文件
**********************************/
#include "main.h"
/**********************************
函数声明
**********************************/
void Uart_init(); //串口初始化函数
#endif
源文件:
/**********************************
包含头文件
**********************************/
#include "uart.h"
/**********************************
变量定义
**********************************/
uchar uart_num;
/**********************************
函数定义
**********************************/
/****
*******串口初始化函数
*****/
void Uart_init()
{
TMOD=0x20;
SCON=0x50;
TH1=0xFD;
TL1=0xFD;
TR1=1;
ES=1;
EA=1;
// UART_EN=1; //485一直在写
}
/****
******* 串口中断服务程序函数
*****/
void ser() interrupt 4
{
static uchar string[1]; //接收一位数据,如果接收两位数据,则string[2]
if(RI)
{
RI=0;
string[0]=SBUF;
switch(string[0])
{
case('1'): uart_num = 1 ;break;
case('2'): uart_num = 2 ;break;
default: break;
}
}
}
以上是小编整理的51单片机简易计算器的实现(带MR+、MR-、存储数据等附加功能)项目的仿真图与所有程序。亲测有效!
http://链接:https://pan.baidu.com/s/1IJNwaztdbampXONvLOmu5Q?pwd=sl3k 提取码:sl3k --来自百度网盘超级会员V4的分享