赞
踩
IMG_1120
通过查看这三个原理图我们可以得知控制K1、K2、K3及K4是通过P31、P30、P32及P33来实现的,控制8个数码管是P22、P23及P24来实现,
控制发光二极管则由P00-P07来实现。
代码分为三部分分别为main.c、key.h、key.c
#include<reg52.h> #include"key.h" //这里定义了一个10个元素的只读数组zxCode,用于存放0~9的数码管显示码。 code unsigned char zxCode[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //这里定义了一个10个元素的只读数组_zxCode,用于存放0~9的数码管带点显示码。 code unsigned char _zxCode[10]={0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF}; //这里定义了一个长度为8的数组DsBuf,用于存放需要显示的数码管数据,数组的每一个元素代表数码管的一个位置。 unsigned char DsBuf[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; /*控制数码管显示的函数。在该代码中,使用P0口来控制8个数码管的段选信号,同时使用P2口的3个引脚(即A、B、C)来控制数码管的位选信号。通过display函数,可以将DsBuf数组中存储的数值依次显示在8个数码管上,实现时分秒的动态显示。该函数中使用了一个静态变量n来循环控制位选信号A、B、C的输出,从而实现了数码管显示的循环刷新。*/ void display(){ static unsigned char n=0; zixin=0x00; if(n&0x01) A=1; else A=0; if(n&0x02) _B=1; else _B=0; if(n&0x04) C=1; else C=0; zixin=DsBuf[n]; n++; n%=8; } /*filldisbuf函数的作用是将传入的时分秒的值按照一定的格式进行转换,并将转换后的结果存储在DsBuf数组中,以便后续的数码管显示*/ void filldisbuf(unsigned int n,unsigned int m,unsigned int h){ DsBuf[0]=zxCode[n%10]; n /=10; DsBuf[1]=zxCode[n%10]; DsBuf[2]=_zxCode[m%10]; m /=10; DsBuf[3]=zxCode[m%10]; DsBuf[4]=_zxCode[h%10]; h /=10; DsBuf[5]=zxCode[h%10]; } //这里定义了一个延时函数,用于延时一段时间,用于稳定数码管的显示效果。 void delay(){ char i; for(i=-100;i<100;i++); } //负责时间的走动与暂停 void start(unsigned int s,unsigned int m,unsigned int h){ unsigned char i=0; unsigned char paused = 0;//一个标志,用来区分时间是在走动的还是停止的 filldisbuf(s,m,h); while(1){ if (!paused){ display(); delay(); i++; if(i>=200){ i=0; s = (++s) % 60; if (s == 0) { m = (++m) % 60; if (m == 0) { h = (++h) % 24; } } filldisbuf(s, m, h); } } else{ display(); delay(); i++; if(i>=200){ i=0; filldisbuf(s, m, h);} } //和main函数相同的功能,不同的是K4按键负责改变paused这个标志的值 scankey(); if (k1_down) { k1_down = 0; h = (++h) % 24; } if (k2_down) { k2_down = 0; m = (++m) % 60; } if (k3_down) { k3_down = 0; s = (++s) % 60; } if (k4_down) { k4_down = 0; paused = !paused; } } } int main(){ unsigned int s=0;//表示秒 unsigned int m=0;//表示分 unsigned int h=0;//表示时 unsigned char i=0; while(1){ scankey();//用来扫描按键的状态 if(k1_down){//按下K1按键,数码管负责显示时的数值加1 k1_down=0; h = (++h) % 24; } if(k2_down){//按下K2按键,数码管负责显示分的数值加1 k2_down=0; m = (++m) % 60; } if(k3_down){ k3_down=0;//按下K3按键,数码管负责显示秒的数值加1 s = (++s) % 60; } if(k4_down){//按下K4按键,时间开始走动,再按下K4按键,时间停止走动 k4_down=0; start(s,m,h); } delay();//主要功能时稳定的显示时间 display(); i++; if(i>=200){ i=0; filldisbuf(s, m, h); } } }
#ifndef __KEY_H_ #define __KEY_H_ #include<reg52.h> 这里定义了4个端口位,分别命名为K1、K2、K3及K4,分别代表P3口的1、0、2、3位。 sbit K1=P3^1; sbit K2=P3^0; sbit K3=P3^2; sbit K4=P3^3; //这里定义了3个端口位,分别命名为A、_B、C,分别代表P2口的2、3、4位。 sbit A=P2^2; sbit _B=P2^3; sbit C=P2^4; //这里定义了一个宏定义,P0代表的是单片机的一个8位数据总线口 #define zixin P0 extern bit k1_down,k2_down,k3_down,k4_down; void scankey(void); #endif
scankey()函数的主要代码,通过软件入手提高系统的可靠性,防止外界干扰或用户按下按钮时的轻微抖动可能引起系统的误判。
它的主要策略如下:1
#include"key.h" bit k1_down=0,k2_down=0,k3_down=0,k4_down=0; bit k1_up=0,k2_up=0,k3_up=0,k4_up=0; void scankey(){ static unsigned char filter1=0xFF,filter2=0xFF,filter3=0xFF,filter4=0xFF; filter1<<=1; filter2<<=1; filter3<<=1; filter4<<=1; if(K1)filter1|=0x01; if(K2)filter2|=0x01; if(K3)filter3|=0x01; if(K4)filter4|=0x01; if((filter1&0x0F)==0x0D)filter1|=0x02; if((filter2&0x0F)==0x0D)filter2|=0x02; if((filter3&0x0F)==0x0D)filter3|=0x02; if((filter4&0x0F)==0x0D)filter4|=0x02; if((filter1&0x0F)==0x02)filter1&=0x0D; if((filter2&0x0F)==0x02)filter2&=0x0D; if((filter3&0x0F)==0x02)filter3&=0x0D; if((filter4&0x0F)==0x02)filter4&=0x0D; if(filter1==0xF0)k1_down=1; if(filter2==0xF0)k2_down=1; if(filter3==0xF0)k3_down=1; if(filter4==0xF0)k4_down=1; if(filter1==0x0F)k1_up=1; if(filter2==0x0F)k2_up=1; if(filter3==0x0F)k3_up=1; if(filter4==0x0F)k4_up=1; }
杜隆胤 面向系统集成的C51单片机教程 P54 ↩︎
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。