找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3417|回复: 7
打印 上一主题 下一主题
收起左侧

STC15单片机EEPROM-掉电计数程序-TM1637数码管

  [复制链接]
跳转到指定楼层
楼主
ID:507486 发表于 2020-4-4 16:55 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  1. #include "reg52.h"
  2. #include "intrins.h"
  3. #include "TM1637.h"
  4. #define uchar unsigned char //宏定义字符型变量
  5. #define uint unsigned int//宏定义整型变量
  6. /********************************************************************
  7. ************************ 寄存器设置
  8. *********************************************************************/
  9. sfr IAP_DATA =0xc2;//数据寄存器
  10. sfr IAP_ADDRH =0xc3;//地址寄存器
  11. sfr IAP_ADDRL =0xc4;//地址寄存器
  12. sfr IAP_CMD =0xc5; //命令寄存器
  13. sfr IAP_TRIG =0xc6;//触发寄存器
  14. sfr IAP_CONTR =0xc7;//擦除寄存器

  15. sbit P33=P3^3;  //定义继电器控制输出脚
  16. sbit k1=P3^2;  //按键
  17. uchar tmp[4]=0,yw=0,mode=0;
  18. uint i,num=0,num_diaodian=100; //定义整型变量i
  19. uchar g1=0,s1=0,b1=0,q1=0;
  20. uchar g=0,s=0,b=0,q=0;
  21. bit ReadTimeFlag=0,Flag=0;//定义读时间标志
  22. unsigned char keydate=0xff;
  23. /********************************************************************
  24. ************************ 命令定义
  25. *********************************************************************/
  26. #define CMD_IDLE 0 //EEPROM无操作
  27. #define CMD_READ 1 //读取字节
  28. #define CMD_PROGRAM 2//写入字节
  29. #define CMD_ERASE 3 //擦除字节

  30. /********************************************************************
  31. ************************ 编程周期由晶振决定
  32. *********************************************************************/
  33. //#define ENABLE_IAP 0X80 //编程周期由晶振决定(如果<30MHZ选用此项)
  34. //#define ENABLE_IAP 0X81 //编程周期由晶振决定(如果<24MHZ选用此项)
  35. //#define ENABLE_IAP 0X82 //编程周期由晶振决定(如果<20MHZ选用此项)
  36. #define ENABLE_IAP 0X83 //编程周期由晶振决定(如果<12MHZ选用此项)
  37. //#define ENABLE_IAP 0X84 //编程周期由晶振决定(如果<6MHZ选用此项)
  38. //#define ENABLE_IAP 0X85 //编程周期由晶振决定(如果<3MHZ选用此项)
  39. //#define ENABLE_IAP 0X86 //编程周期由晶振决定(如果<2MHZ选用此项)
  40. //#define ENABLE_IAP 0X87 //编程周期由晶振决定(如果<1MHZ选用此项)

  41. #define IAP_ADDRESS 0X0000 //内部EEPROM地址
  42. /********************************************************************
  43. ************************ 函数初始化
  44. *********************************************************************/
  45. void Delay(uchar n); //延时函数
  46. void IapIdle();//操作函数
  47. uchar IapReadByte(uint addr); //读取函数
  48. void IapProgramByte(uint addr,uchar dat); //写入函数
  49. void IapEraseSector(uint addr);//擦除函数

  50. void Delay5ms()                //@11.0592MHz
  51. {
  52.         unsigned char i, j;

  53.         i = 54;
  54.         j = 199;
  55.         do
  56.         {
  57.                 while (--j);
  58.         } while (--i);
  59. }

  60. void key(void) // //读按键值 并做处理
  61. {
  62.   keydate=0XFF;
  63.   if(ReadTimeFlag==1)  //100ms读取
  64.         {
  65.                 ReadTimeFlag=0;
  66.                 keydate=ScanKey();  //读按键值

  67.         }
  68.          switch(keydate)
  69.          {
  70.          case 0xf7:   //K1      
  71.          if(mode++>=1)
  72.          {mode=0;}
  73.          if(mode==0)
  74.          {
  75.         tmp[0]=num%256;
  76.         tmp[1]=num/256;
  77.         tmp[2]=num_diaodian%256;
  78.         tmp[3]=num_diaodian/256;
  79.         Delay(8);//延时
  80.         IapEraseSector(IAP_ADDRESS);  //擦除扇区
  81.         for(i=0;i<4;i++)//对4个字节进行数据写入
  82.         {
  83.         IapProgramByte(IAP_ADDRESS+i,(uchar)tmp[i]);//写入数据
  84.         }
  85.         Delay(8);
  86.          }
  87.          break;         

  88.          case 0xf6:     //K2   
  89.          if(yw++>=3)yw=0;
  90.          break;         

  91.          case 0xf5:   //K3      
  92.    switch(mode)
  93.          {
  94.           case 0:
  95.                   break;        
  96.           case 1:
  97.            if(yw==0){ if(q1++>=9)q1=0;}
  98.             else if(yw==1){ if(b1++>=9)b1=0;}
  99.                  else if(yw==2){ if(s1++>=9)s1=0;}
  100.                   else if(yw==3){ if(g1++>=9)g1=0;}
  101.                      num_diaodian=q1*1000+b1*100+s1*10+g1;
  102.                   break;
  103.           }
  104.          
  105.          break;        
  106.            case 0xf4:   //K4     
  107.    switch(mode)
  108.          {
  109.           case 0:
  110.                   break;        
  111.           case 1:
  112.            if(yw==0){ if(q1--<=0)q1=9;}
  113.             else if(yw==1){ if(b1--<=0)b1=9;}
  114.                  else if(yw==2){ if(s1--<=0)s1=9;}
  115.                   else if(yw==3){ if(s1--<=0)s1=9;}
  116.                      num_diaodian=q1*1000+b1*100+s1*10+g1;
  117.                   break;
  118.           }
  119.          
  120.          break;                 
  121. }

  122. }

  123. /*------------------------------------------------
  124.                     定时器初始化子程序
  125. ------------------------------------------------*/
  126. void Init_Timer0(void)
  127. {
  128. TMOD |= 0x01;          //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响                     
  129. EA=1;            //总中断打开
  130. ET0=1;           //定时器中断打开
  131. TR0=1;           //定时器开关打开
  132. }
  133. /*------------------------------------------------
  134.                  定时器中断子程序
  135. ------------------------------------------------*/
  136. void Timer0_isr(void) interrupt 1
  137. {
  138. static unsigned int num=0,cnt=0;
  139. TH0=(65536-50000)/256;                  //重新赋值 50ms
  140. TL0=(65536-50000)%256;

  141. num++;
  142. if(num==3)        //大致100ms
  143.    {
  144.     num=0;
  145.     ReadTimeFlag=1; //读标志位置1
  146.         }
  147.   if(cnt++>=8)
  148.   {
  149.   cnt = 0;
  150.   Flag= ~ Flag;
  151.   
  152.   }
  153.         }
  154. /********************************************************************
  155. ************************  主函数
  156. *********************************************************************/

  157. void main()
  158. {

  159. P5M0=0;  P5M1=0;
  160. for(i=0;i<4;i++)//对4个字节数据读出
  161. {
  162. tmp[i]=IapReadByte(IAP_ADDRESS+i);//读eeprom数据
  163. }
  164. num=(uint)(tmp[0]+tmp[1]*256);
  165. num_diaodian =(uint)(tmp[2]+tmp[3]*256);
  166. if(num++>=num_diaodian)//到达预定掉电次数后
  167. {

  168. P33 = 0;//输出低电平

  169. }
  170. q=num/1000%10;
  171. b=num/100%10;
  172. s=num/10%10;
  173. g=num%10;
  174. TM1637_display(q,b,s,g,0);
  175. tmp[0]=num%256;
  176. tmp[1]=num/256;
  177. tmp[2]=num_diaodian%256;
  178. tmp[3]=num_diaodian/256;
  179. Delay(8);//延时
  180. IapEraseSector(IAP_ADDRESS);  //擦除扇区
  181. for(i=0;i<4;i++)//对4个字节进行数据写入
  182. {
  183. IapProgramByte(IAP_ADDRESS+i,(uchar)tmp[i]);//写入数据
  184. }
  185. Delay(8);//延时
  186. Init_Timer0();
  187. while(1)
  188. {

  189. key();
  190. if(k1==0)
  191. { Delay5ms();
  192.    if(k1==0)
  193.    {
  194.         P33 = 1;//输出G电平
  195.         /**********上电次数清零*********/
  196.         num=0;
  197.         tmp[0]=0;
  198.         tmp[1]=0;
  199.         tmp[2]=num_diaodian%256;
  200.         tmp[3]=num_diaodian/256;
  201.         Delay(1);//延时
  202.         IapEraseSector(IAP_ADDRESS);  //擦除扇区
  203.         for(i=0;i<4;i++)//对2个字节进行数据写入
  204.         {
  205.         IapProgramByte(IAP_ADDRESS+i,(uchar)tmp[i]);//写入数据
  206.         }
  207.         Delay(1);//延时
  208.         
  209.         }
  210.         Delay5ms();        
  211.         while(!k1) ;
  212. }
  213. q=num/1000%10;
  214. b=num/100%10;
  215. s=num/10%10;
  216. g=num%10;
  217. q1=num_diaodian/1000%10;
  218. b1=num_diaodian/100%10;
  219. s1=num_diaodian/10%10;
  220. g1=num_diaodian%10;

  221. if(mode==0)
  222. {
  223. TM1637_display(q,b,s,g,0);
  224. }
  225. else if(mode==1)
  226. {
  227. if(Flag == 0)
  228. {
  229. TM1637_display(q1,b1,s1,g1,0);
  230. }
  231. else if(Flag == 1)
  232. {
  233. if(yw==0) TM1637_display(21,b1,s1,g1,0);
  234. else if(yw==1) TM1637_display(q1,21,s1,g1,0);
  235. else if(yw==2)        TM1637_display(q1,b1,21,g1,0);
  236. else if(yw==3)         TM1637_display(q1,b1,s1,21,0);
  237. }
  238. }

  239. }

  240. }
  241. /********************************************************************
  242. ************************  延时函数
  243. *********************************************************************/
  244. void Delay(uchar n)
  245. {
  246. uint x;
  247. while(n--)
  248. {
  249. x=0;
  250. while(++x);
  251. }
  252. }
  253. /********************************************************************
  254. ************************  操作函数
  255. *********************************************************************/
  256. void IapIdle()
  257. {
  258. IAP_CONTR=0;
  259. IAP_CMD=0;
  260. IAP_TRIG=0;
  261. IAP_ADDRH=0X80;
  262. IAP_ADDRL=0;
  263. }

  264. /********************************************************************
  265. ************************  读取一个字节函数
  266. *********************************************************************/
  267. uchar IapReadByte(uint addr)
  268. {
  269. uchar dat;
  270. IAP_CONTR=ENABLE_IAP;
  271. IAP_CMD=CMD_READ;
  272. IAP_ADDRL=addr;
  273. IAP_ADDRH=addr>>8;
  274. IAP_TRIG=0X5A;
  275. IAP_TRIG=0XA5;
  276. _nop_();
  277. _nop_();
  278. _nop_();
  279. dat=IAP_DATA;
  280. IapIdle();
  281. return dat;
  282. }

  283. /********************************************************************
  284. ************************  写入一个字节函数
  285. *********************************************************************/
  286. void IapProgramByte(uint addr,uchar dat)
  287. {

  288. IAP_CONTR=ENABLE_IAP;
  289. IAP_CMD=CMD_PROGRAM;
  290. IAP_ADDRL=addr;
  291. IAP_ADDRH=addr>>8;
  292. IAP_DATA=dat;
  293. IAP_TRIG=0X5A;
  294. IAP_TRIG=0XA5;
  295. _nop_();
  296. _nop_();
  297. _nop_();
  298. IapIdle();
  299. }
  300. /********************************************************************
  301. ************************  擦除一个字节函数
  302. *********************************************************************/
  303. void IapEraseSector(uint addr)
  304. {
  305. IAP_CONTR=ENABLE_IAP;
  306. IAP_CMD=CMD_ERASE;
  307. IAP_ADDRL=addr;
  308. IAP_ADDRH=addr>>8;
  309. IAP_TRIG=0X5A;
  310. IAP_TRIG=0XA5;
  311. _nop_();
  312. _nop_();
  313. _nop_();
  314. IapIdle();
  315. }
复制代码


STC15_EEPROM_掉电计数.rar

449.08 KB, 下载次数: 65, 下载积分: 黑币 -5

程序

原理图.pdf

130.86 KB, 下载次数: 27, 下载积分: 黑币 -5

原理图

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏7 分享淘帖 顶1 踩
回复

使用道具 举报

沙发
ID:90212 发表于 2020-11-5 23:07 | 只看该作者
stc15用#include "reg52.h" 头文件?
编译一堆问题,不知道有没有用心。
回复

使用道具 举报

板凳
ID:828160 发表于 2020-11-5 23:44 | 只看该作者
没几天FLASH就写坏了
回复

使用道具 举报

地板
ID:95375 发表于 2021-8-28 00:24 | 只看该作者
这个程序有错误,不能编译通过
回复

使用道具 举报

5#
ID:1112852 发表于 2024-3-13 10:39 | 只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

6#
ID:89072 发表于 2024-3-31 09:43 | 只看该作者
楼主程序有问题,修改了参考

STC15_EEPROM_掉电计数.rar

456.07 KB, 下载次数: 5, 下载积分: 黑币 -5

回复

使用道具 举报

7#
ID:961114 发表于 2024-4-3 09:52 | 只看该作者

上电后将 EEPROM中的数据读到RAM中,平常是读写RAM,
掉电时及时将RAM中需要掉电保存的数据保存到EEPROM,
就无 EEPROM 擦写寿命这种问题
回复

使用道具 举报

8#
ID:485350 发表于 2024-4-3 11:32 | 只看该作者
添加数据读写校验,再加上能在flash扇区内循环写(例如写数据8个字节,第一次写入数据写入扇区的0x00-0x07,第二次写入扇区的0x08-0x0f,第三次写入扇区的,0x10-0x17)就差不多了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表