更改用户名CRC32解密回帖奖励召回投票记录删除领夜猫子帮助中心 本站已运行
查看: 214|回复: 1
收起左侧

STC15F104E驱动74HC138共阴数码管实现的16进制计数器,采用片内Eeprom实现断电保存计数

[复制链接]
发表于 2017-6-18 09:58:10 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册有礼

x

  1. /*

  2. STC15F104E驱动74HC138共阴数码管实现的16进制计数器,采用片内Eeprom实现断电保存计数。
  3. 若改成16进制以上需要添加数码管段码显示数据,10进制则将计数值超过清零值改成10即可,以此类推。
  4. 并且修改计数检测清零的判断语句即可。
  5. 本位计数连接P3.0,收到低电平后并且10毫秒后加1,10毫秒为按键消抖延迟,防止一次按键按下导致多次计数。


  6. 进位输出连接P3.1,计数溢出清零后此口发出低电平,接入下一位的计数器的本位计数端即可,不限量级联。
  7. 清零输入连接P3.2,与下一位的计数器的清零输入并联即可,触发后全部清零。
  8. (所有操作低电平触发)
  9. 74HC138的Y0~Y7连接共阳数码管和VCC。
  10. P3.3~P3.5连接74HC138的输入端。
  11. E1接VCC,E2和E3接GND即可。
  12. 74HC138是一款3线-8线译码器。
  13. 输入端输入3位二进制数据,输出端可指定8个口的
  14. 其中1个口输出低电平,其余7个口全部输出高电平
  15. 由于视觉暂留的作用,74HC238一次只能点亮数码管的1个段码,通过数码管led段码高速扫描而看到多个段码同时被点亮。
  16. 若不需要Eeprom功能或者片内没有Eeprom功能请将相关调用函数删除或者变成注释即可。

  17. */
  18. #include "reg51.h"
  19. #include "intrins.h"
  20. //EEPROM相关读写驱动以及寄存器定义
  21. #define EN_EPROM 0x83;               
  22. #define S_MODE         0x00;               
  23. #define R_MODE         0x01;               
  24. #define W_MODE         0x02;               
  25. #define F_MODE         0x03;               
  26. sfr IAP_DATA  =  0xC2;               
  27. sfr IAP_ADDRH =  0xC3;               
  28. sfr IAP_ADDRL =  0xC4;               
  29. sfr IAP_CMD   =  0xC5;       
  30. sfr IAP_TRIG  =  0xC6;       
  31. sfr IAP_CONTR =  0xC7;       


  32. unsigned char code number[16]= { //数码管段码数据,0~9,A~F 只读数据
  33. 0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71
  34. };
  35. sbit input=P3^0; //计数输入端,低电平触发计数
  36. sbit output=P3^1; //进位输出端,计数溢出则输出低电平,连接下一个计数器的计数输入端。
  37. sbit reset=P3^2; //清零端,低电平有效,所有计数器都需要接上。
  38.         sbit a0=P3^3;  //连接74HC138的A端
  39.         sbit a1=P3^4;  //连接74HC138的B端
  40.         sbit a2=P3^5;  //连接74HC138的C端




  41. void init(){ //EEPROM初始化
  42.         IAP_CONTR        = EN_EPROM;               
  43.         IAP_CMD         = S_MODE;               
  44.         IAP_ADDRH        = 0x00;
  45.         IAP_ADDRL        = 0x00;

  46. }
  47. unsigned char read_dat(unsigned int address){ //EEPROM读数据
  48.                 unsigned char addr_h = address & 0xFF00/0x100;
  49.                 unsigned char addr_l = address & 0x00FF;

  50.         unsigned char E_dat = 0x00;
  51.         IAP_CMD         = R_MODE;               
  52.         IAP_ADDRH        = addr_h;
  53.         IAP_ADDRL        = addr_l;
  54.         IAP_TRIG        = 0x5A;               
  55.         IAP_TRIG        = 0xA5;               
  56.         E_dat                = IAP_DATA;
  57.         return E_dat;
  58. }

  59. void write_dat(unsigned int address ,unsigned char w_dat){ //EEPROM写数据

  60.                 unsigned char addr_h = address & 0xFF00/0x100;
  61.                 unsigned char addr_l = address & 0x00FF;

  62.         IAP_CMD         = W_MODE;               
  63.         IAP_ADDRH        = addr_h;
  64.         IAP_ADDRL        = addr_l;
  65.         IAP_DATA        = w_dat;
  66.         IAP_TRIG        = 0x5A;       
  67.         IAP_TRIG        = 0xA5;               

  68. }

  69. void erase_dat(unsigned int address ){        //EEPROM擦除数据
  70.                 unsigned char addr_h = address & 0xFF00/0x100;
  71.                 unsigned char addr_l = address & 0x00FF;

  72.         IAP_CMD         = F_MODE;               
  73.         IAP_ADDRH        = addr_h;
  74.         IAP_ADDRL        = addr_l;
  75.         IAP_TRIG        = 0x5A;       
  76.         IAP_TRIG        = 0xA5;       
  77. }



  78. void delay1ms(){        //1毫秒延时
  79.         unsigned char i, j;

  80.         _nop_();
  81.         _nop_();
  82.         i = 12;
  83.         j = 168;
  84.         do
  85.         {
  86.                 while (--j);
  87.         } while (--i);
  88. }

  89. void delay10ms(){        //10毫秒延时
  90.         unsigned char i, j;

  91.         _nop_();
  92.         _nop_();
  93.         i = 117;
  94.         j = 183;
  95.         do
  96.         {
  97.                 while (--j);
  98.         } while (--i);
  99. }


  100.         void set_LED(unsigned char hex) { //通过段码进行轮流导通LED,每次只能导通1个,显示一次数字需要8毫秒。
  101.                         unsigned char a;
  102.                 a=hex&1;if(a==1) {a2=0;a1=0;a0=0;delay1ms();}
  103.                 a=(hex&2)/2;if(a==1) {a2=0;a1=0;a0=1;delay1ms();}
  104.                 a=(hex&4)/4;if(a==1) {a2=0;a1=1;a0=0;delay1ms();}
  105.                 a=(hex&8)/8;if(a==1) {a2=0;a1=1;a0=1;delay1ms();}
  106.                 a=(hex&16)/16;if(a==1) {a2=1;a1=0;a0=0;delay1ms();}
  107.                 a=(hex&32)/32;if(a==1) {a2=1;a1=0;a0=1;delay1ms();}
  108.                 a=(hex&64)/64;if(a==1) {a2=1;a1=1;a0=0;delay1ms();}
  109.                 a=(hex&128)/128;if(a==1) {a2=1;a1=1;a0=1;delay1ms();}

  110.                 }
  111.                
  112.        
  113.         void main() {//入口函数
  114.         unsigned char a;//计数值
  115.         bit b;//是否释放进位输出电平
  116.         delay10ms();//延迟10毫秒
  117.         init();//初始化EEPROM
  118.         delay10ms();//延迟10毫秒
  119.         a=read_dat(0); //从EEPROM中读取计数值
  120.         delay10ms();//延迟10毫秒
  121.                 if(a>=16){//计数值大于等于16
  122.                         a%=16;//取余16
  123.                         erase_dat(0);//擦除数据
  124.                         write_dat(0,a);//写新数据
  125.                 }
  126.                 while(1) { //进入死循环
  127.         if(b==1){//有释放
  128.         b=0;//取消释放
  129.         output=1;//进位输出高电平
  130.         }
  131.         if(input == 1){ //没有收到计数信号
  132.                 set_LED(number[a]); //输出段码数据
  133.         } else { //收到计数信号,开始计数。
  134.                         delay10ms();//延迟10毫秒
  135.                         a++;//计数
  136.                         erase_dat(0);//擦除计数数据
  137.                         write_dat(0,a);//写入计数数据
  138.                                 while(input==0){ //计数信号始终低电平

  139.                                         if(reset==0){ //复位信号低电平
  140.                                                 delay10ms(); //延迟10毫秒
  141.                                         goto reset; //进入复位
  142.                                         }
  143.                                 if(a>=16) { //计数满
  144.                                 a=0; //清零计数
  145.                                         erase_dat(0); //擦除计数数据
  146.                                         write_dat(0,a); //写计数数据
  147.                                 output=0; //输出低电平,给下一个计数器低电平信号。
  148.                                 b=1;//按键释放后则输出高电平

  149.                 }
  150.                         set_LED(number[a]);//输出段码数据
  151.                         }
  152.                 }
  153.                         reset://复位程序入口
  154.                         if(reset==0){ //复位端低电平
  155.                         delay10ms();//延迟10毫秒
  156.                         a=0;//计数清零
  157.                         erase_dat(0); //擦除计数数据
  158.                         write_dat(0,a); //写计数数据
  159.                                 while(reset==0){//复位端一直低电平
  160.                         set_LED(number[a]);//输出段码数据
  161.                                 }
  162.                         }
  163.                
  164.         }}

复制代码

回复

使用道具 举报

发表于 2017-7-3 18:10:45 | 显示全部楼层
现在还没接触单片机,只能单纯的四处暖(水)贴。消灭零回复。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册有礼

本版积分规则