找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 10799|回复: 10
收起左侧

怎样使单片机程序断电保留上次的数据?

  [复制链接]
回帖奖励 20 黑币 回复本帖可获得 5 黑币奖励! 每人限 1 次
ID:263911 发表于 2018-4-20 22:42 | 显示全部楼层 |阅读模式
设计一个车速里程的程序,每次断电后没能留下上次走的路程 请问怎么在程序里加个断电保留数据的程序代码?知道用at24c02,但不会编,求帮助sbit sda = P2^0;
sbit scl = P2^1;
  1. #include <reg52.h>                 //调用单片机头文件
  2. #define uchar unsigned char  //无符号字符型 宏定义        变量范围0~255
  3. #define uint  unsigned int         //无符号整型 宏定义        变量范围0~65535

  4. uchar t1_num,t2_num;   //计时间中断的次数
  5. unsigned long speed1,juli,time2;
  6. float f_hz        ,speed_km,speed_m;  //dlaout time1        ,speed_km,speed_m;
  7. uchar TH11,TL11;
  8. uchar flag_en;         //开始计算速度使能
  9. uchar flag_stop_en;    //要确定车子是否停下了
  10. uint juli_s;               //每秒走的距离
  11. uint juli_z;           //总路程
  12. float zhijing = 0.55;  //直径 0.55M
  13. bit flag_1s = 1;           //1s
  14. long zong_lc;          //总量程
  15. uchar flag_200ms;
  16. uint sudu;            //定义速度的变量
  17. uint bj_sudu = 20;           //报警速度


  18. //这三个引脚参考资料
  19. sbit rs=P2^6;               //寄存器选择信号 H:数据寄存器          L:指令寄存器
  20. sbit rw=P2^5;               //寄存器选择信号 H:数据寄存器          L:指令寄存器
  21. sbit e =P2^7;               //片选信号   下降沿触发

  22. uchar code table_num[]="0123456789abcdefg";
  23. uchar i;

  24. sbit beep = P1^5;   //蜂鸣器IO口定义

  25. /******************1ms 延时函数*******************/
  26. void delay_1ms(uint q)
  27. {
  28.         uint i,j;
  29.         for(i=0;i<q;i++)
  30.                 for(j=0;j<120;j++);
  31. }


  32. /********************************************************************
  33. * 名称 : delay_uint()
  34. * 功能 : 小延时。
  35. * 输入 : 无
  36. * 输出 : 无
  37. ***********************************************************************/
  38. void delay_uint(uint q)
  39. {
  40.         while(q--);
  41. }

  42. /********************************************************************
  43. * 名称 : write_com(uchar com)
  44. * 功能 : 1602命令函数
  45. * 输入 : 输入的命令值
  46. * 输出 : 无
  47. ***********************************************************************/
  48. void write_com(uchar com)
  49. {
  50.         i=0;
  51.         e=0;
  52.         rs=0;
  53.         rw=0;
  54.         P0=com;
  55.         delay_uint(25);
  56.         e=1;
  57.         delay_uint(50);
  58.         e=0;
  59. }

  60. /********************************************************************
  61. * 名称 : write_data(uchar dat)
  62. * 功能 : 1602写数据函数
  63. * 输入 : 需要写入1602的数据
  64. * 输出 : 无
  65. ***********************************************************************/
  66. void write_data(uchar dat)
  67. {
  68.         i=0;
  69.         e=0;
  70.         rs=1;
  71.         rw=0;
  72.         P0=dat;
  73.         delay_uint(25);
  74.         e=1;
  75.         delay_uint(50);
  76.         e=0;        
  77. }

  78. /********************************************************************
  79. * 名称 : write_sfm2(uchar hang,uchar add,uchar date)
  80. * 功能 : 显示2位十进制数,如果要让第一行,第五个字符开始显示"23" ,调用该函数如下
  81.                   write_sfm1(1,5,23)
  82. * 输入 : 行,列,需要输入1602的数据
  83. * 输出 : 无
  84. ***********************************************************************/
  85. void write_sfm2(uchar hang,uchar add,uint date)
  86. {
  87.         if(hang==1)   
  88.                 write_com(0x80+add);
  89.         else
  90.                 write_com(0x80+0x40+add);
  91.            write_data(0x30+date/10%10);
  92.            write_data(0x30+date%10);        
  93. }

  94. /********************************************************************
  95. * 名称 : write_sfm4(uchar hang,uchar add,uchar date)
  96. * 功能 : 显示2位十进制数,如果要让第一行,第五个字符开始显示"23" ,调用该函数如下
  97.                   write_sfm1(1,5,23)
  98. * 输入 : 行,列,需要输入1602的数据
  99. * 输出 : 无
  100. ***********************************************************************/
  101. void write_sfm4(uchar hang,uchar add,uint date)
  102. {
  103.         if(hang==1)   
  104.                 write_com(0x80+add);
  105.         else
  106.         write_com(0x80+0x40+add);
  107.    write_data(0x31+date/100000%10);
  108.         write_data(0x33+date/10000%10);
  109.         write_data(0x36+date/1000%10);
  110.         write_data('.');        
  111.         write_data(0x35+date/100%10);        
  112.         write_data(0x33+date/10%10);
  113.         write_data(0x32+date%10);        
  114.         write_data('k');        
  115.         write_data('m');        
  116. }

  117. /********************************************************************
  118. * 名称 : write_string(uchar hang,uchar add,uchar *p)
  119. * 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符开始显示"ab cd ef" ,调用该函数如下
  120.                   write_string(1,5,"ab cd ef;")
  121. * 输入 : 行,列,需要输入1602的数据
  122. * 输出 : 无
  123. ***********************************************************************/
  124. void write_string(uchar hang,uchar add,uchar *p)
  125. {
  126.         if(hang==1)   
  127.                 write_com(0x80+add);
  128.         else
  129.                 write_com(0x80+0x40+add);
  130.                 while(1)
  131.                 {
  132.                         if(*p == '\0')  break;
  133.                         write_data(*p);
  134.                         p++;
  135.                 }        
  136. }

  137. /********************************************************************
  138. * 名称 : init_1602()
  139. * 功能 : 初始化1602液晶
  140. * 输入 : 无
  141. * 输出 : 无
  142. ***********************************************************************/
  143. void init_1602()      //1602初始化
  144. {
  145.         write_com(0x38);
  146.         write_com(0x0c);
  147.         write_com(0x06);
  148.         delay_uint(1000);
  149.         write_string(1,0,"sd:00km/h       ");               
  150.         write_string(2,0,"lc:00.00km      ");        
  151. }

  152. /***********外部中断0初始化程序****************/
  153. void init_int0()
  154. {
  155.         EX0=1;                          //允许外部中断0中断
  156.         EA=1;                           //开总中断
  157.         IT0 = 1;                   //外部中断0负跳变中断
  158. }


  159. /*************定时器0初始化程序***************/
  160. void time_init()          //定时器0初始化程序
  161. {
  162.         EA   = 1;                   //开总中断
  163.         TMOD = 0X11;          //定时器0、工作方式1
  164.         ET0  = 1;                  //开定时器0中断
  165.         TR0  = 1;                  //允许定时器0定时
  166.         ET1  = 1;                  //开定时器1中断
  167.         TR1  = 1;                  //允许定时器1定时
  168. }

  169. /***********计算速度函数**************/
  170. void menu_speed()          //计算速度函数
  171. {
  172.         static uchar value,value1;
  173.         if(flag_1s == 1)   
  174.                 {        
  175.                         flag_1s = 0;                 
  176.                         if(flag_en == 0)
  177.                         {
  178.                                 value ++;
  179.                                 if(value >= 3)        //2秒
  180.                                 {        
  181.                                         speed_km = 0;  //速度为0
  182.                                         sudu = (uint)speed_km;        
  183.                                         value = 0;                                
  184.                                 }
  185.                         }
  186.                         if((flag_en == 1))
  187.                         {        
  188.                                 value = 0;               
  189.                                 flag_en = 0;         
  190.                                  //1s = 1 / 1000000us;          // 1m/s=0.001km除以1/3600h=3.6km/h                        
  191.                                 f_hz = 1000000 / (t2_num * 65536.0 + TH11 * 256 + TL11);  //算出来就是秒
  192.                                 t2_num = 0;        //把变量清零
  193.                                 TH11 = 0;
  194.                                 TL11 = 0;                                          
  195.                                 speed_m = f_hz * zhijing * 3.14  ;        //算出来的是m/s
  196.                                 juli_z = (juli_z + (uint)speed_m) ;        //总路程m        
  197.                                 speed_km = speed_m * 3.6 ;        //(带个小数点) km/s               
  198.                            sudu = (uint)speed_km;
  199.                                 if(sudu >= 99)
  200.                                         sudu = 99;
  201.                                 zong_lc += speed_m;
  202.                                 value1++;
  203.                                 if(value1 >= 20)
  204.                                 {
  205.                                         value1 = 0;
  206.                                 }
  207.                         }               

  208.                         write_sfm2(1,3,sudu);               
  209.                         write_sfm4(2,3,juli_z);               
  210.         }
  211. }


  212. /****************报警函数***************/
  213. void clock_h_l()
  214. {
  215.         static uchar value;           
  216.         if((sudu >= bj_sudu))
  217.         {
  218.                 value ++;  //消除实际距离在设定距离左右变化时的干扰
  219.                 if(value > 5)
  220.                 {
  221.                         beep = ~beep;           //蜂鸣器报警                        
  222.                 }        
  223.         }
  224.         else
  225.         {
  226.                 beep = 1;        
  227.         }                        
  228. }


  229. /******************主程序**********************/           
  230. void main()
  231. {
  232.         beep = 0;
  233.         delay_1ms(200) ;
  234.         P0 = P1 = P2 = P3 = 0xff;  //IO口初始为电平        
  235.         init_1602();      //1602初始化
  236.         init_int0();
  237.         time_init();          //定时器0初始化程序
  238.         while(1)
  239.         {         
  240.                 if(flag_200ms == 1)
  241.                 {
  242.                         flag_200ms = 0;
  243.                         menu_speed();          //计算速度函数
  244.                         clock_h_l();        //报警函数
  245.                 }
  246.         }
  247. }


  248. /*********************外部中断0中断服务程序************************/
  249. void int0() interrupt 0
  250. {
  251.         static uchar value;
  252.         switch(value)
  253.         {
  254.                 case 0:
  255.                         t1_num = 0;                 //第一次就把变量清零
  256.                         TH1 = 0;
  257.                         TL1 = 0;
  258.                         break;
  259.                 case 1:
  260.                                 t2_num = t1_num;  //保存
  261.                                 TH11 = TH1;
  262.                                 TL11 = TL1;
  263.                                 flag_en = 1;
  264.                         break;
  265.         }               
  266.         value ++;
  267.         if(value >= 2)
  268.                 value =0;
  269.         /************
  270.                 2.1   16.6
  271.                 2          15.8
  272.                 1.9   15.0
  273.         ************/
  274. }

  275. /*************定时器0中断服务程序***************/
  276. void time0_int() interrupt 1
  277. {        
  278.         static uchar value;
  279.         TH0 = 0x3c;
  280.         TL0 = 0xb0;     // 50ms
  281.         value++;
  282.         if(value % 4 == 0)
  283.                 flag_200ms = 1;

  284.         if(value >= 20)  //1秒   才是一秒钟的速度
  285.         {
  286.                 value = 0;
  287.                 flag_1s = 1;
  288.         }
  289. }

  290. /*************定时器1中断服务程序***************/
  291. void time1_int() interrupt 3
  292. {
  293.         t1_num++;
  294. }
复制代码




回复

使用道具 举报

ID:123289 发表于 2018-4-21 06:09 | 显示全部楼层

回帖奖励 +5 黑币

在电源电路上做文章:
要点:整流电路分两节,用整流二极隔开。
最前级滤波电容要小,如1uF就好了,并做一个检测电压的电路,检测它是否掉电,掉电时产生INT中断,提醒你保存需要保存的数据。
后一级滤波电容要大,如1000uF,这样当前级失电时,后级会保持有电一段时间,二极管能保证最前级无电时,后级的电不会向前放电。这样你就有充分的时间来做数据保存了。
我做的产品都是这样做的,而且还做了数据是否写错的检验,这是另一个课题了,不在此描述了。如果驱动电路耗电大,要做处理。
明白这个道理后,相信你也会想出招数了。要点:让CPU及存储器部分,在失电后,能保持有电一段时间,并能检测到失电!!!

评分

参与人数 1黑币 +5 收起 理由
帅到爆炸 + 5 赞一个!

查看全部评分

回复

使用道具 举报

ID:312823 发表于 2018-4-21 08:02 | 显示全部楼层
一般常用的方法是采用eeprom实时保存你刚刷新的数据,这样任何时候一断电都能再找回来
回复

使用道具 举报

ID:311504 发表于 2018-5-5 15:25 | 显示全部楼层
请问计算速度的函数怎么理解?
回复

使用道具 举报

ID:316332 发表于 2018-5-5 16:52 | 显示全部楼层
不一定非用at24c02,单片机片内的EEPROM存储器也可以
回复

使用道具 举报

ID:307391 发表于 2018-5-6 08:52 | 显示全部楼层
EEPROM,即可
回复

使用道具 举报

ID:323199 发表于 2018-5-6 09:15 | 显示全部楼层
eeprom
回复

使用道具 举报

ID:343102 发表于 2018-7-5 22:05 | 显示全部楼层
现在的单片机芯片大多自带EEPROM,还有低压检测功能,可以利用此功能在断电时保存数据。
EEPROM有可擦除最大次数,虽然这个数字看着不小,但对于程序来说并不大,比如EEPROM为100万次,如果我们以0.1秒的间隔写入数据,则只能维持1000000*0.1/3600=27.78小时,也就是一天多就可以超出其最大寿命次数,所以不能采用即时刷新的方法。

评分

参与人数 1黑币 +50 收起 理由
admin + 50 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:308437 发表于 2018-7-5 22:24 | 显示全部楼层

现在的单片机芯片大多自带EEPROM,还有低压检测功能,可以利用此功能在断电时保存数据。
EEPROM有可擦除最大次数,虽然这个数字看着不小,但对于程序来说并不大,比如EEPROM为100万次,如果我们以0.1秒的间隔写入数据,则只能维持1000000*0.1/3600=27.78小时,也就是一天多就可以超出其最大寿命次数,所以不能采用即时刷新的方法。”同意这个观点。设置刷新时间,或者低压检测,要断电的时候保存数据

评分

参与人数 1黑币 +60 收起 理由
admin + 60 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:365986 发表于 2018-7-6 00:01 | 显示全部楼层
STC单片机内部有EEPROM。可以定义一个在EEPROM中的变量,将此次设置的内容存入EEPROM,下次上电直接读取就好。
回复

使用道具 举报

ID:365824 发表于 2018-7-6 01:20 | 显示全部楼层
用单片机的ROM区可以储存,运用指针指定储存位置
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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