今天,我在Keil uVision4中制作了一个小项目,利用STC29C52单片机实现了简易计算器的功能。
此计算器利用矩阵键盘(线扫描法)输入数据,利用八位数码管显示数据。能实现四位整数(及四位以下)与四位整数(及四位以下)的加减乘除运算。
优势是:操作及界面 与日常计算器相同;
具备按键消抖功能;
缺陷是:计算位数有限;
仅支持整数运算;
运算结果最大为65535(受限于int数据类型);
矩阵键盘扫描程序:
#include "bsp.h"
#define KEYPORT P1
unsigned char val = 0;
unsigned char mkeyvalue = 99;
void mkey_scan(void)
{
KEYPORT = 0xf0;
if(KEYPORT != 0xf0)
{
KEYPORT = 0xfe;
if(KEYPORT != 0xfe)
{
val = KEYPORT;
while(KEYPORT != 0xfe) seg7_show_CC(); //死等
//或者delay;
}
KEYPORT = 0xfd;
if(KEYPORT != 0xfd)
{
val = KEYPORT;
while(KEYPORT != 0xfd) seg7_show_CC();
}
KEYPORT = 0xfb;
if(KEYPORT != 0xfb)
{
val = KEYPORT;
while(KEYPORT != 0xfb) seg7_show_CC();
}
KEYPORT = 0xf7;
if(KEYPORT != 0xf7)
{
val = KEYPORT;
while(KEYPORT != 0xf7) seg7_show_CC();
}
}
else
{
val = 0xff; //没按键按下时,不进入switch语句;
}
}
void mkey_pro(void)
{
if(val != 0xff)
{
switch(val)
{
case(0x7e): mkeyvalue = 1; break;
case(0xbe): mkeyvalue = 2; break;
case(0xde): mkeyvalue = 3; break;
case(0xee): mkeyvalue = 11; break;
case(0x7d): mkeyvalue = 4; break;
case(0xbd): mkeyvalue = 5; break;
case(0xdd): mkeyvalue = 6; break;
case(0xed): mkeyvalue = 12; break;
case(0x7b): mkeyvalue = 7; break;
case(0xbb): mkeyvalue = 8; break;
case(0xdb): mkeyvalue = 9; break;
case(0xeb): mkeyvalue = 13; break;
case(0x77): mkeyvalue = 0; break;
case(0xb7): mkeyvalue = 16; break;
case(0xd7): mkeyvalue = 15; break;
case(0xe7): mkeyvalue = 14; break;
default: mkeyvalue = 99; break;
}
}
}
按键功能程序:
#include "bsp.h"
unsigned char type = 1;
unsigned char distype = 0;
unsigned char num1[4]={0,0,0,0};
unsigned char num2[4]={0};
unsigned char symbol;
unsigned char i = 0;
unsigned char digit1=0, digit2=0;
void key_record(void)
{
if((mkeyvalue==1||mkeyvalue==2||mkeyvalue==3||
mkeyvalue==4||mkeyvalue==5||mkeyvalue==6||
mkeyvalue==7||mkeyvalue==8||mkeyvalue==9||mkeyvalue==0))
{
if(type == 1)
{
distype = 1;
num1[i++] = mkeyvalue;
digit1++;
}
else if(type == 3)
{
distype = 3;
num2[i++] = mkeyvalue;
digit2++;
}
if(i >= 4)
{
if(type == 1)
{
type = 2;
}
else if(type == 3)
{
type = 4;
}
i = 0;
}
mkeyvalue = 99;
}
if((type==1||type==2)&&(mkeyvalue==11||mkeyvalue==12||mkeyvalue==13||mkeyvalue==14))
{
symbol = mkeyvalue;
distype = 2;
i = 0;
type = 3;
mkeyvalue = 99;
}
if((type==3||type==4)&&mkeyvalue==15) //=
{
type = 5;
distype = 5;
result();
mkeyvalue = 99;
// type = 6;
}
// if(type == 6)
// {
// while(mkeyvalue == 99);
// mkeyvalue = 16;
// }
if(mkeyvalue == 16) //清屏
{
num1[0] = 0;
num1[1] = 0;
num1[2] = 0;
num1[3] = 0;
symbol = 0;
num2[0] = 0;
num2[1] = 0;
num2[2] = 0;
num2[3] = 0;
showvalue[0] = 0;
showvalue[1] = 0;
showvalue[2] = 0;
showvalue[3] = 0;
showvalue[4] = 0;
showvalue[5] = 0;
showvalue[6] = 0;
showvalue[7] = 0;
i = 0;
distype = 0;
digit1 = 0;
digit2 = 0;
type = 1;
mkeyvalue = 99;
}
}
运算程序:
#include "bsp.h"
unsigned int cal_result = 0;
unsigned int cal_num1 = 0;
unsigned int cal_num2 = 0;
void result(void)
{
switch(symbol)
{
case(11): cal_result = cal_num1 + cal_num2; result_digit_compute();break; //在此处计算出结果的位数,
case(12): cal_result = cal_num1 - cal_num2; result_digit_compute();break; //避免写在reg显示程序中,
case(13): cal_result = cal_num1 * cal_num2; result_digit_compute();break; //否则扫描的时候重复计算,
case(14): cal_result = cal_num1 / cal_num2; result_digit_compute();break; //占用时间片,造成显示负担
default: break;
}
}
unsigned int adjust(unsigned char *num, unsigned char digit)
{
unsigned char temp_digit = digit;
unsigned int true_num = 0;
true_num = num[0]*1000+num[1]*100+num[2]*10+num[3];
while((4-temp_digit) > 0)
{
true_num = true_num/10;
temp_digit++;
}
return true_num;
}
数码管显示程序:
#include "bsp.h"
//unsigned char distype = 4;
//unsigned char digit1 = 3;
//unsigned char digit2 = 0;
//unsigned int cal_num1 = 0;
//unsigned int cal_num2 = 0;
//unsigned int cal_result = 0;
#define SEGPORT P0
unsigned char code distab_CC[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,
0x77,0x7c,0x39,0x5e,0x79,0x71};
//unsigned char TABLESEL[8] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //位选码
unsigned char TABLESEL[8] = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
unsigned char showvalue[8] = {0};
unsigned char dis_digit = 0;
unsigned char result_digit = 0;
sbit LATCH_DUAN = P2^2;
sbit LATCH_WEI = P2^3;
//8位动态扫描
void seg7_show_CC(void)
{
static unsigned char j = 0;
if(distype == 0)
{
dis_digit = 1;
}
if(distype == 1)
{
dis_digit = digit1;
}
if(distype == 2)
{
dis_digit = 1;
}
if(distype == 3)
{
dis_digit = digit2;
}
if(distype == 5)
{
// if(cal_result <= 65535)
// {
dis_digit = result_digit;
// }
// else if(cal_result > 65535)
// {
// dis_digit = 4;
// }
}
SEGPORT = 0x00;//消除残影
LATCH_DUAN = 1;
LATCH_DUAN = 0;
SEGPORT = TABLESEL[j];
LATCH_WEI = 1;//位锁存
LATCH_WEI = 0;
SEGPORT = showvalue[j];
LATCH_DUAN = 1;//段锁存
LATCH_DUAN = 0;
j++;
if(distype == 5)
{
if((j==dis_digit+1))
{
j = 0;
}
}
else
{
if(j == dis_digit)
{
j = 0;
}
}
}
void showvalue_set(void)
{
if(distype == 0)
{
showvalue[0] = distab_CC[0];
}
if(distype == 1)
{
dis_num_compute(cal_num1, digit1);
}
if(distype == 2)
{
showvalue[0] = distab_CC[0];
}
if(distype == 3)
{
dis_num_compute(cal_num2, digit2);
}
if(distype == 5)
{
// if(cal_result <= 65535)
// {
// result_digit_compute(); //此句会造成,重复计算结果的位数,导致显示负担
dis_num_compute(cal_result, result_digit);
showvalue[result_digit] = 0x48; //显示‘=’号
// }
// else if(cal_result > 65535)
// {
// showvalue[4] = 0x75; //显示Error
// showvalue[3] = 0x50;
// showvalue[2] = 0x50;
// showvalue[1] = 0x5c;
// showvalue[0] = 0x50;
// }
}
}
void result_digit_compute(void)
{
unsigned int result_temp = 0;
result_digit = 0;
if(cal_result==0)
{
result_digit = 1;
}
else
{
result_temp = cal_result;
while(result_temp != 0)
{
result_temp /= 10;
result_digit++;
}
}
}
void dis_num_compute(unsigned int cal, unsigned char digit)
{
unsigned char temp = digit;
unsigned char temp2 = 0;
unsigned int temp3 = 0;
unsigned char temp4 = 0;
while(temp != 0)
{
for(temp3 = cal,temp2 = temp-1; temp2 > 0; temp2--)
{
temp3 /= 10;
}
showvalue[temp-1] = distab_CC[temp3];
temp4 = temp-1;
while(temp4 != 0)
{
temp3 *= 10;
temp4--;
}
cal = cal-temp3;
temp--;
}
}
#ifndef _BSP_H_
#define _BSP_H_
//系统自带的头文件
#include "reg52.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
//外设的头文件
//#include "bsp_xx.h"
#include "bsp_seg7.h"
#include "bsp_delay.h"
//#include "bsp_key.h"
//#include "bsp_int.h"
//#include "bsp_timer.h"
#include "bsp_mkey.h"
#include "bsp_mkeyfunc.h"
//#include "bsp_alarm.h"
#include "process.h"
//初始化外设的函数声明
void bsp_init(void);
#endif
每个外设的头文件就不一一上传了。