|
- /*
- STC15F104E 驱动 74HC138 共阴数码管实现的16进制计数器 - 采用片内Eeprom实现断电保存计数。
- 若改成16进制以上需要添加数码管段码显示数据,10进制则将计数值超过清零值改成10即可,以此类推。
- 并且修改计数检测清零的判断语句即可。
- 本位计数连接P3.0,收到低电平后并且10毫秒后加1,10毫秒为按键消抖延迟,防止一次按键按下导致多次计数。
- 进位输出连接P3.1,计数溢出清零后此口发出低电平,接入下一位的计数器的本位计数端即可,不限量级联。
- 清零输入连接P3.2,与下一位的计数器的清零输入并联即可,触发后全部清零。
- (所有操作低电平触发)
- 74HC138的Y0~Y7连接共阳数码管和VCC。
- P3.3~P3.5连接74HC138的输入端。
- E1接VCC,E2和E3接GND即可。
- 74HC138是一款3线-8线译码器。
- 输入端输入3位二进制数据,输出端可指定8个口的
- 其中1个口输出低电平,其余7个口全部输出高电平
- 由于视觉暂留的作用,74HC238一次只能点亮数码管的1个段码,通过数码管led段码高速扫描而看到多个段码同时被点亮。
- 若不需要Eeprom功能或者片内没有Eeprom功能请将相关调用函数删除或者变成注释即可。
- */
- #include "reg51.h"
- #include "intrins.h"
- //EEPROM相关读写驱动以及寄存器定义
- #define EN_EPROM 0x83;
- #define S_MODE 0x00;
- #define R_MODE 0x01;
- #define W_MODE 0x02;
- #define F_MODE 0x03;
- sfr IAP_DATA = 0xC2;
- sfr IAP_ADDRH = 0xC3;
- sfr IAP_ADDRL = 0xC4;
- sfr IAP_CMD = 0xC5;
- sfr IAP_TRIG = 0xC6;
- sfr IAP_CONTR = 0xC7;
- unsigned char code number[16]= { //数码管段码数据,0~9,A~F 只读数据
- 0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71
- };
- sbit input=P3^0; //计数输入端,低电平触发计数
- sbit output=P3^1; //进位输出端,计数溢出则输出低电平,连接下一个计数器的计数输入端。
- sbit reset=P3^2; //清零端,低电平有效,所有计数器都需要接上。
- sbit a0=P3^3; //连接74HC138的A端
- sbit a1=P3^4; //连接74HC138的B端
- sbit a2=P3^5; //连接74HC138的C端
- void init(){ //EEPROM初始化
- IAP_CONTR = EN_EPROM;
- IAP_CMD = S_MODE;
- IAP_ADDRH = 0x00;
- IAP_ADDRL = 0x00;
- }
- unsigned char read_dat(unsigned int address){ //EEPROM读数据
- unsigned char addr_h = address & 0xFF00/0x100;
- unsigned char addr_l = address & 0x00FF;
- unsigned char E_dat = 0x00;
- IAP_CMD = R_MODE;
- IAP_ADDRH = addr_h;
- IAP_ADDRL = addr_l;
- IAP_TRIG = 0x5A;
- IAP_TRIG = 0xA5;
- E_dat = IAP_DATA;
- return E_dat;
- }
- void write_dat(unsigned int address ,unsigned char w_dat){ //EEPROM写数据
- unsigned char addr_h = address & 0xFF00/0x100;
- unsigned char addr_l = address & 0x00FF;
- IAP_CMD = W_MODE;
- IAP_ADDRH = addr_h;
- IAP_ADDRL = addr_l;
- IAP_DATA = w_dat;
- IAP_TRIG = 0x5A;
- IAP_TRIG = 0xA5;
- }
- void erase_dat(unsigned int address ){ //EEPROM擦除数据
- unsigned char addr_h = address & 0xFF00/0x100;
- unsigned char addr_l = address & 0x00FF;
- IAP_CMD = F_MODE;
- IAP_ADDRH = addr_h;
- IAP_ADDRL = addr_l;
- IAP_TRIG = 0x5A;
- IAP_TRIG = 0xA5;
- }
- void delay1ms(){ //1毫秒延时
- unsigned char i, j;
- _nop_();
- _nop_();
- i = 12;
- j = 168;
- do
- {
- while (--j);
- } while (--i);
- }
- void delay10ms(){ //10毫秒延时
- unsigned char i, j;
- _nop_();
- _nop_();
- i = 117;
- j = 183;
- do
- {
- while (--j);
- } while (--i);
- }
- void set_LED(unsigned char hex) { //通过段码进行轮流导通LED,每次只能导通1个,显示一次数字需要8毫秒。
- unsigned char a;
- a=hex&1;if(a==1) {a2=0;a1=0;a0=0;delay1ms();}
- a=(hex&2)/2;if(a==1) {a2=0;a1=0;a0=1;delay1ms();}
- a=(hex&4)/4;if(a==1) {a2=0;a1=1;a0=0;delay1ms();}
- a=(hex&8)/8;if(a==1) {a2=0;a1=1;a0=1;delay1ms();}
- a=(hex&16)/16;if(a==1) {a2=1;a1=0;a0=0;delay1ms();}
- a=(hex&32)/32;if(a==1) {a2=1;a1=0;a0=1;delay1ms();}
- a=(hex&64)/64;if(a==1) {a2=1;a1=1;a0=0;delay1ms();}
- a=(hex&128)/128;if(a==1) {a2=1;a1=1;a0=1;delay1ms();}
- }
-
-
- void main() {//入口函数
- unsigned char a;//计数值
- bit b;//是否释放进位输出电平
- delay10ms();//延迟10毫秒
- init();//初始化EEPROM
- delay10ms();//延迟10毫秒
- a=read_dat(0); //从EEPROM中读取计数值
- delay10ms();//延迟10毫秒
- if(a>=16){//计数值大于等于16
- a%=16;//取余16
- erase_dat(0);//擦除数据
- write_dat(0,a);//写新数据
- }
- while(1) { //进入死循环
- if(b==1){//有释放
- b=0;//取消释放
- output=1;//进位输出高电平
- }
- if(input == 1){ //没有收到计数信号
- set_LED(number[a]); //输出段码数据
- } else { //收到计数信号,开始计数。
- delay10ms();//延迟10毫秒
- a++;//计数
- erase_dat(0);//擦除计数数据
- write_dat(0,a);//写入计数数据
- while(input==0){ //计数信号始终低电平
- if(reset==0){ //复位信号低电平
- delay10ms(); //延迟10毫秒
- goto reset; //进入复位
- }
- if(a>=16) { //计数满
- a=0; //清零计数
- erase_dat(0); //擦除计数数据
- write_dat(0,a); //写计数数据
- output=0; //输出低电平,给下一个计数器低电平信号。
- b=1;//按键释放后则输出高电平
- }
- set_LED(number[a]);//输出段码数据
- }
- }
- reset://复位程序入口
- if(reset==0){ //复位端低电平
- delay10ms();//延迟10毫秒
- a=0;//计数清零
- erase_dat(0); //擦除计数数据
- write_dat(0,a); //写计数数据
- while(reset==0){//复位端一直低电平
- set_LED(number[a]);//输出段码数据
- }
- }
-
- }}
复制代码
|
|