LscmunaixMG 发表于 2017-6-18 09:58:10

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);//输出段码数据
                                }
                        }
               
        }}


demon 发表于 2017-7-3 18:10:45

{:5_118:}现在还没接触单片机,只能单纯的四处暖(水)贴。消灭零回复。
页: [1]
查看完整版本: STC15F104E驱动74HC138共阴数码管实现的16进制计数器,采用片内Eeprom实现断电保存计数