STC15F104E驱动74HC138共阴数码管实现的16进制计数器,采用片内Eeprom实现断电保存计数
/*
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= { //数码管段码数据,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); //输出段码数据
} 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);//输出段码数据
}
}
reset://复位程序入口
if(reset==0){ //复位端低电平
delay10ms();//延迟10毫秒
a=0;//计数清零
erase_dat(0); //擦除计数数据
write_dat(0,a); //写计数数据
while(reset==0){//复位端一直低电平
set_LED(number);//输出段码数据
}
}
}}
{:5_118:}现在还没接触单片机,只能单纯的四处暖(水)贴。消灭零回复。
页:
[1]