单片机
返回首页

【51单片机】七段数码管和矩阵键盘的综合实验——计算器

2024-04-07 来源:elecfans

前言

系列文章中的四篇是我学习单片机以来写下的4篇学习记录。在有了以上知识的了解后,我也掌握了部分80C51单片机的编程思想,当然80C51可以挂载很多不同的芯片和设备,还有很多内容需要学习的。就目前而言,对I/O设备的使用有了基础,平时也在学习中编写程序,这让我的小目标——做一个计算器,有了一定的基础。所以趁今天有时间,把这个计算器实现的过程记录下来。

【51单片机】矩阵键盘逐行扫描法仿真实验+超详细Proteus仿真和Keil操作步骤和【51单片机】七段数码管显示实验+详细讲解,这里不再赘述。


2、软件程序

大部分的程序与线反转法+动态显示的程序差不多,主要改变的是键盘扫描程序和显示的程序,并且对部分代码进行了优化。以下是改变的部分。

代码如下:


1)初始化

#include

int ans=0;

int newnum=0;

char op='';

int b[4]={12,12,12,0};

int cs[4]={0x07,0x0B,0x0D,0x0E};

int digit[13]={0x3f,0x06,0x5B,0x4f,0x66,0x6D,0x7D,0x07,0x7f,0x6f,0x71,0x40,0x00};//在数码管上显示0~9、'F'、'-'和不显示

int p1line[4]={0xf7,0xfb,0xfd,0xfe};//逐行扫描法时给键盘的行值

2)主程序(键盘扫描程序)

void main(void){ 

unsigned int key1=0;

unsigned int key2=0;

unsigned int key=0;

int i;

show(0);

    while (1){

key=key1=key2=0;

    P1=0xf0;

key1=P1&0xf0;

    if(key1!=0xf0){

    delayms(1);

    for(i=0;i<4;i++){

P1=p1line[i];

key2=P1&0xf0;

if(key2!=0xf0){

key=(p1line[i]&0x0f)|key1;

break;

}

}

while((P1&0xf0)!=0xf0);

act(key);

}

}

 }

3)定义按键的功能

void act(){

switch(key){

case 0x77:clear();turnLight();break;//清零键,清零+跑马灯

case 0xB7:savenum(0);break;//按下数字0,保存数字0

case 0xD7:output();break;//按下等于号,输出结果

case 0xE7:saveop('+');break;//按下运算符,保存符号

case 0x7B:savenum(1);break;

case 0xBB:savenum(2);break;

case 0xDB:savenum(3);break;

case 0xEB:saveop('-');break;

case 0x7D:savenum(4);break;

case 0xBD:savenum(5);break;

case 0xDD:savenum(6);break;

case 0xED:saveop('*');break;

case 0x7E:savenum(7);break;

case 0xBE:savenum(8);break;

case 0xDE:savenum(9);break;

case 0xEE:saveop('/');break;

}

}

4)其他函数

主要的程序是上面的主程序、键盘扫描程序、中断服务程序和按键功能配置函数。其他的函数可以按照自己需要的功能修改。


①延时程序:

void delayms(int n){

int i,j;

for(i=0;i for(j=0;j<120;j++);

}

②跑马灯函数:

void turnlight(){

int i=24;

int light=0x03;

while(i){

P2=0x00;

P0=light;

P2=0xff;

light=(light>>7)|(light<<1);

delayms(50);

}

}

③显示函数:

void show(int num){

int i;

todigit(num);

for(i=0;i<4;i++){

P2=cs[i];

P0=digit[b[i]];

P2=0xff;

}

}

④清零函数:

void clear(){

ans=newnum=0;

op='';

turnlight();

show(0);

⑤运算函数:

void operat(){

switch(op){

case '+':ans=ans+newnum;break;

case '-':ans=ans-newnum;break;

case '*':ans=ans*newnum;break;

case '/':ans=(newnum==0)?10000:(ans/newnum);break;

}

newnum=0;

}

⑥保存符号:

void saveop(char p){

if(op!='')

operat();

op=p;

show(ans);

}

⑦保存数字:

void savenum(int n){

if(op==''){

ans=ans*10+n;

show(ans);

}

else{

newnum=newnum*10+n;

show(newnum);

}

}

⑧转化字形码:

void todigit(int num){

int i;

int j;

if(num<10000&&num>= 0){

for(i=0;i<4;i++){

b[i]=num%10;

num=(num-b[i])/10;

if(num==0) break;

}

for(j=i+1;j<4;j++){//没有的位上不显示

b[j]=12;

}

}

else if(num>=-999&&num<0){

num=-num;

for(i=0;i<4;i++){

b[i]=num%10;

num=(num-b[i])/10;

if(num==0) break;

}

b[++i]=11;//显示负号

for(j=i+1;j<4;j++){

b[j]=12;

}

}

else b[0]=b[1]=b[2]=b[3]=10;//超出显示范围

}

⑨输出函数:

void output(){

operat();

show(ans);

}


3、效果

在这里插入图片描述


总结

此次的小目标已经完成,对单片机的I/O也有了了解,并对前面的代码做出优化,包括显示负数。后面将学习单片机的其它内容,并且在闲暇之余也会学习python,在原有的基础上更进一步。作为一名单片机小白,这段时间的收获颇丰,以后也会继续在CSDN记录我的学习。


进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 永不缺相启动运行的电动机控制电路

  • MT3608构成3.7V转12V的升压电路图

  • 比较常见的功率整流器和滤波电路

  • 一个简单的红外耳机电路

  • 基于CA3193的热电偶放大器电路

  • 基于TDA1554的立体声放大器电路

    相关电子头条文章