|
本帖最后由 1428327352 于 2019-4-19 19:29 编辑
由于新学习的单片机C语言,写程序手法稚嫩,但适合新手做参考。算法比较繁琐,但是经过我一上午的修复,现在已经没有任何漏洞了!!!
四位数于四位数之间的加减乘除计算
已经能够显示小数点后两位,例:10/3=3.33;1/2=0.5;1/20=0.05
能够计算负数,例:1-20=-19;
基于1602液晶显示屏
由于按键个数原因,目前只打了以下16个键
以后在扩展的话会更新
1 | 2 | 3 | + | 4 | 5 | 6 | - | 7 | 8 | 9 | * | ce | 0 | = | / |
1602我的想法是送一行地址,再送一行数据
计算器主要分为显示程序,计算程序,和按键扫描程序
将其结合
电路图;
元器件:
源代码:
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
uchar z,x,num,key,m,n;
uint a; //a,b代表算子
ulong b, c; //这个c代表结果,原只想将c用ulong的,因为c是结果需要的数据范围大,但是试了不行,只有将
ac或bc或abc设成大范围才可以。在这里为节省存储,设了bc。可以正常运行到一个很大的数了。
uchar c1,c2,c3,c4,c5,c6,c7,c8;
void delay(uint xms)
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
sbit rs=P2^6;
sbit rw=P2^5;
sbit en=P2^7;
uchar code table[]="ERROR!"; // 在除数为0时直接报错
void write_com(uchar com) //д???? //读命令
{
rs=0;
rw=0;
delay(5);
P0=com;
delay(5);
en=1;
delay(5);
en=0;
delay(5);
}
void write_date(uchar date) //д???? //读数据
{
rs=1;
rw=0;
delay(5);
P0=date;
delay(5);
en=1;
delay(5);
en=0;
delay(5);
}
void init() //????? 初始化函数
{
n=0;
m=5;
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
write_com(0x80);
write_date('0');
}
short keycheckdown() /* ???????????? */键盘扫描函数,带回一个返回值,所以这里不用void
{
short temp1,temp2,temp,x=0xff;
P1=0xf0; /* ???????????????? */
delay(20); /* ??? */
temp1=P1; /* ?????????????? */
P1=0xff;
delay(20); /* ??? */
P1=0x0f; /* ???????????????? */
delay(20); /* ??? */
temp2=P1; /* ?????????????? */
P1=0xff;
temp=(temp1&0xf0)|(temp2&0xf); /* ?????ζ?????????? */
switch(temp) /* ???????????????ж????λ?? */
{
case 0x7e :x=0x0d;break;// ????/
case 0x7d :x=0x0e; break;// ????=
case 0x7b: x=0; break;// ????0
case 0x77 :x=0x0f; break;// ????CE
case 0xbe :x=0x0c;break;// ????*
case 0xbd :x=0x09;break; // ????9
case 0xbb :x=0x08;break; // ????8
case 0xb7 :x=0x07;break; // ????7
case 0xde :x=0x0b;break;// ????-
case 0xdd:x=0x06;break; // ????6
case 0xdb :x=0x05;break; // ????5
case 0xd7 :x=0x04;break; // ????4
case 0xee :x=0x0a; break;// ????+
case 0xed :x=0x03;break; // ????3
case 0xeb :x=0x02;break; // ????2
case 0xe7 :x=0x01;break; // ????1
default :x=0xff;
}
return x; /* ???????? */ 返回x
}
void axian() //算子a的显示程序
{
uchar a1,a2,a3,a4;
write_com(0x01);
a1=a%10000/1000; //? 0
a2=a%1000/100; //?? 0
a3=a%100/10; //? 1
a4=a%10; //?? 2
if(999<a) {
write_com(0x80);
write_date('0'+a1);
delay(5);
}
if(99<a) {
write_com(0x81);
write_date('0'+a2);
delay(5);
}
if(9<a) {
write_com(0x82);
write_date('0'+a3);
delay(5);
}
if(0<a) {
write_com(0x83);
write_date('0'+a4);
delay(5);
}
}
void bxian() //算子b的4位,即上限为9999,a上限也是9999;
{
uchar b1,b2,b3,b4; // 1*10+2=12
b1=b%10000/1000; //? 0
b2=b%1000/100; //?? 0
b3=b%100/10; //? 1
b4=b%10; //?? 2
if(999<b)
{
write_com(0x88);
write_date('0'+b1);
delay(5);
}
if(99<b) {
write_com(0x89);
write_date('0'+b2);
delay(5);
}
if(9<b) {
write_com(0x8a);
write_date('0'+b3);
delay(5);
}
if(0<b) {
write_com(0x8b);
write_date('0'+b4);
delay(5);
}
if(b==0) { init(); //若除数为0,初始化并且报错
write_com(0x80);
for(num=0;num<6;num++)
{
write_date(table[num]);
delay(5);
}
}
}
void gong() 这个是一些程序中重复使用的部分,将其提取成一个子函数,会更简洁
{
if(c>999)
{
write_com(0xc5);
write_date('0'+c5);
delay(5);
}
if(c>99)
{
write_com(0xc6);
write_date('0'+c6);
delay(5);
}
if(c>9)
{
write_com(0xc7);
write_date('0'+c7);
delay(5);
}
if(c>0)
{
write_com(0xc8);
write_date('0'+c8);
delay(5);
}
}
void jian() 减法会出现负号,需要特殊处理,显示程序就和其他三个不一样了
{
c5=c%10000/1000; //? 0
c6=c%1000/100; //?? 0
c7=c%100/10; //? 1
c8=c%10;
if(z==2) 当减号键被按下时
{
if(b>a) 当后一个数大于前一个数时
{
write_com(0xc4); 显示负号
write_date('-');
delay(5);
if(b-a>999) 显示负号后面的结果
{
write_com(0xc5);
write_date('0'+c5);
delay(5);
}
if(b-a>99)
{
write_com(0xc6);
write_date('0'+c6);
delay(5);
}
if(b-a>9)
{
write_com(0xc7);
write_date('0'+c7);
delay(5);
}
if(b-a>0)
{
write_com(0xc8);
write_date('0'+c8);
delay(5);
}
}
if(a>b) 如果前数大于后数的话
{
gong();
}
}
}
void chu() 除号会出现小数点,所以将其特殊处理,自成函数
{
if(z==4)
{
c=a*100/b;
c1=c/100000;
c2=c%100000/10000;
c3=c%10000/1000;
c4=c%1000/100;
c6=c%100/10;
c7=c%10;
if(a%b!=0) 如果不能整除
{
if(c>100)
{
if(c>99999)
{
write_com(0xc1);
write_date('0'+c1);
delay(5);
}
if(c>9999)
{
write_com(0xc2);
write_date('0'+c2);
delay(5);
}
if(c>999)
{
write_com(0xc3);
write_date('0'+c3);
delay(5);
}
if(c>99)
{
write_com(0xc4);
write_date('0'+c4);
delay(5);
}
write_com(0xc5);
write_date('.');
delay(5);
if(c>9)
{
write_com(0xc6);
write_date('0'+c6);
delay(5);
}
write_com(0xc7);
write_date('0'+c7);
delay(5);
}
}
if(9<c&&c<99) 在这里需注意不能写成9<c<99!!!
{
write_com(0xc4);
write_date('0');
delay(5);
write_com(0xc5);
write_date('.');
delay(5);
if(c>9)
{
write_com(0xc6);
write_date('0'+c6);
delay(5);
}
write_com(0xc7);
write_date('0'+c7);
delay(5);
}
if(c<9)
{
write_com(0xc4);
write_date('0');
delay(5);
write_com(0xc5);
write_date('.');
delay(5);
write_com(0xc6);
write_date('0');
write_com(0xc7);
write_date('0'+c7);
delay(5);
}
}
if(a%b==0) 如果能够整除
{
c=a/b;
c1=c/1000;
c2=c%1000/100;
c3=c%100/10;
c4=c%10;
if(c>999)
{
write_com(0xc1);
write_date('0'+c1);
delay(5);
}
if(c>99)
{
write_com(0xc2);
write_date('0'+c2);
delay(5);
}
if(c>9)
{
write_com(0xc3);
write_date('0'+c3);
delay(5);
}
if(c>0)
{
write_com(0xc4);
write_date('0'+c4);
delay(5);
}
}
}
}
void cxian() c的显示程序
{
if(z==1||z==3) 若按下的是加号或乘号,因为减法可能出现-,除法可能出现".",所以显示要分开
{
c1=c%100000000/10000000;
c2=c%10000000/1000000;
c3=c%1000000/100000;
c4=c%100000/10000; // 1*10+2=12
c5=c%10000/1000; //? 0
c6=c%1000/100; //?? 0
c7=c%100/10; //? 1
c8=c%10; //?? 2
if(9999999<c)
{
write_com(0xc1);
write_date('0'+c1);
delay(5);
}
if(c>999999)
{
write_com(0xc2);
write_date('0'+c2);
delay(5);
}
if(c>99999)
{
write_com(0xc3);
write_date('0'+c3);
delay(5);
}
if(c>9999)
{
write_com(0xc4);
write_date('0'+c4);
delay(5);
}
gong();
}
}
void eql() 计算程序
{
switch(z)
{
case 0: break;
case 1: c=a+b; break;
case 2: c=a-b;
if(b>a)
{
c=b-a;
}
break;
case 3: c=a*b; break;
case 4: c=a/b; break;
}
}
void main() 主函数
{
uint key;
init();
while(1)
{
key=keycheckdown(); 将返回的值x赋给key
if(0xff!=key)
{
if(key<10)
{
if(n<4) n初始值为0, 每按下一次,n加一,当按下第五次时就不执行此if语句。用此方法将a的值固定
{
a=a*10+key;
m=5;
axian();
n++;
}
if(m<4) m的初始值为5,此时不会进入这个程序,只有在运算符打出后,才将m的值命令得符合这个if语句
{
b=b*10+key;
n=5;
bxian();
m++;
}
}
else
{
switch(key) 判断是那个运算符,并且将其显示出来。
{
case 0x0a:
n=5;
m=0; 在运算符给出后,放开后一个数,可以打后一个数了
z=1;
write_com(0x85);
write_date('+');
break;
case 0x0b:
n=5;
m=0;
z=2;
write_com(0x85);
write_date('-');
break;
case 0x0c:
n=5;
m=0;
z=3;
write_com(0x85);
write_date('*');
break;
case 0x0d:
n=5;
m=0;
z=4;
write_com(0x85);
write_date('/');
break;
case 0x0e: 当是等号时,锁定两个算子a,b,此时已经固定
m=5;
n=5;
eql(); 对a,b进行计算
jian();
chu();
write_com(0xc0);
write_date('=');
cxian();
break;
case 0x0f: ce键,清零
n=0;
z=0;
m=5;
a=0;
b=0;
c=0;
init();
break;
}
do{P1=0xf0;}
while(P1!=0xf0);
}
}
}
}
|
评分
-
查看全部评分
|