找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1571|回复: 9
收起左侧

ADC掉电检测的算法怎么写,哪个大佬发一个,谢谢

[复制链接]
ID:302293 发表于 2024-4-18 16:59 | 显示全部楼层 |阅读模式
谢谢大家
回复

使用道具 举报

ID:1110945 发表于 2024-4-18 20:07 | 显示全部楼层
不就是掉电检测吗,用端口中断就检测了的,比adc测量简单容易多了。
回复

使用道具 举报

ID:1109793 发表于 2024-4-18 20:37 | 显示全部楼层
对啊,电容大的话用扫描IO状态都可以
回复

使用道具 举报

ID:302293 发表于 2024-4-19 09:45 | 显示全部楼层
明日之星8 发表于 2024-4-18 20:07
不就是掉电检测吗,用端口中断就检测了的,比adc测量简单容易多了。

掉电是有电压变化的,mcu也是接在电源上的,当电源电压低于12V时,mcu是可以检测到ADC电压值的,但是我用定时器去扫不稳定
回复

使用道具 举报

ID:302293 发表于 2024-4-19 09:46 | 显示全部楼层
xiaobendan001 发表于 2024-4-18 20:37
对啊,电容大的话用扫描IO状态都可以

IO口的电压是线性变化的,怎么去扫,怎么判断
回复

使用道具 举报

ID:1109793 发表于 2024-4-19 10:33 | 显示全部楼层
sr861126 发表于 2024-4-19 09:46
IO口的电压是线性变化的,怎么去扫,怎么判断

我是变压器供电,在电容前边加二极管,二极管前的脉动信号经过电阻引入IO,每当IO的低电平时间超过10ms算掉电。或者其他方式也可以,或者二极管前边加一个小电容滤波一下,就不是脉动信号了,总之都可以,只要在二极管后面的电容放电完成之前检测到就可以完美保存几十个字节的数据
回复

使用道具 举报

ID:302293 发表于 2024-11-28 16:56 | 显示全部楼层
sr861126 发表于 2024-4-19 09:45
掉电是有电压变化的,mcu也是接在电源上的,当电源电压低于12V时,mcu是可以检测到ADC电压值的,但是我用 ...

用定时器扫比较稳定,我试过了
回复

使用道具 举报

ID:427868 发表于 2024-11-28 17:53 | 显示全部楼层
STC的单片机有低压中断,也很好用。
回复

使用道具 举报

ID:624769 发表于 2024-11-28 20:16 | 显示全部楼层
单片机检测掉电的方式往少了说,也有十几种,其中唯独定时去用ADC扫描方式是最糟糕的。不说大多数单片机有掉电中断了,哪怕没有掉电中断,随便用个外部中断检测上游供电电平,都比ADC方式强。
回复

使用道具 举报

ID:1133081 发表于 2024-11-29 06:30 | 显示全部楼层
sr861126 发表于 2024-11-28 16:56
用定时器扫比较稳定,我试过了


  1. //测试条件:TX-1C实验板,MCU型号IAP15W4K58S4
  2. //注意:测试本示例时,需在ISP下载时将【低压复位】功能和【低压时禁止EEPROM操作】关闭
  3. //说明:本示例采用一个扇区写满再擦除的方式是尝试延长EEPROM使用寿命,如需要频繁写
  4. //EEPROM,可改为所有扇区写满再擦除的方式。
  5. #include "STC15Fxxxx.H"
  6. #include <intrins.h>                                //库头文件
  7. #define uint unsigned int                         //宏定义数据类型uint
  8. #define uchar unsigned char                 //宏定义数据类型uchar
  9. //宏定义ISP的操作命令
  10. #define CMD_IDLE    0               //空闲模式
  11. #define CMD_READ    1               //IAP字节读命令
  12. #define CMD_PROGRAM 2               //IAP字节编程命令
  13. #define CMD_ERASE   3               //IAP扇区擦除命令
  14. #define ENABLE_IAP  0x82            //CPU的等待时间
  15. #define IAP_ADDRESS 0x0800                        //测试地址
  16. sbit duan=P2^6;
  17. sbit wein=P2^7;
  18. sbit buzzer=P2^3;
  19. //顺序共阴极数码管段码表,段码a-h顺序接PX0-PX7
  20. uchar code table[]={//共阴数码管段码"0~f-."
  21.                 0x3f,0x06,0x5b,0x4f,
  22.                 0x66,0x6d,0x7d,0x07,
  23.                 0x7f,0x6f,0x77,0x7c,
  24.                 0x39,0x5e,0x79,0x71,0x40,0x80};
  25. uchar data dis_buf[8];                //缓存数组
  26. uint num,sec;
  27. uchar i;
  28. uint sign;
  29. void Timer0Init();                                        //定时器初始化声明
  30. void IapIdle();                                                //关闭IAP/EEPROM
  31. uchar IapReadByte(uint addr);                //读取EEPROM数据
  32. void IapProgramByte(uint addr, uchar dat);//写入EEPROM数据
  33. void IapEraseSector(uint addr);                //擦除EEPROM数据

  34. void main()                                                       
  35. {
  36.         P0M0 = 0x00;
  37.         P0M1 = 0x00;
  38.         P1M0 = 0x00;
  39.         P1M1 = 0x00;
  40.         P2M0 = 0x00;
  41.         P2M1 = 0x00;
  42.         P3M0 = 0x00;
  43.         P3M1 = 0x00;
  44.         P4M0 = 0x00;
  45.         P4M1 = 0x00;
  46.         P5M0 = 0x00;
  47.         P5M1 = 0x00;
  48.         P6M0 = 0x00;
  49.         P6M1 = 0x00;
  50.         P7M0 = 0x00;
  51.         P7M1 = 0x00;
  52.         if(IapReadByte(IAP_ADDRESS)==0xff)//如果没有保存过数据存储器初始值=0xff
  53.         {
  54.                 IapProgramByte(IAP_ADDRESS, 0);//扇区首地址写0
  55.                 sec=0;
  56.                 sign=1;
  57.         }
  58.         else
  59.         {
  60. //                for(i=1;i<12;i++)//测试写10次
  61.                 for(i=1;i<511;i++)//测试写满510个字节
  62.                 {
  63.                         if(IapReadByte(IAP_ADDRESS+i)==0xff)//如果遇到没有保存数据的单元
  64.                         {
  65.                                 sec=IapReadByte(IAP_ADDRESS+i-1);//读取前一个字节保存的数据
  66.                                 sign=i;//地址缓存
  67.                                 break;//跳出循环
  68.                         }
  69.                 }
  70.         }
  71. //        if(sign==11)//测试写10次
  72.         if(sign==510)//如果写满510
  73.         {
  74.                 IapEraseSector(IAP_ADDRESS);//擦除扇区
  75.                 IapProgramByte(IAP_ADDRESS, 0);//首地址写0
  76.                 sign=1;
  77.                 buzzer=0;
  78.         }
  79.         PCON &= 0xDF;//清0掉电标志
  80.         ELVD = 1;//开低压中断
  81.         EA   = 1;//开总中断

  82.         Timer0Init();//初始化定时器

  83.         while(1)
  84.         {
  85.                 if(TF0)//查询T0中断请求标志
  86.                 {               
  87.                         TF0=0;//T0中断请求标志清0
  88.                         if(++num>=1000)//1秒
  89.                         {
  90.                                 buzzer=1;
  91.                                 num=0;                               
  92.                                 sec=++sec%250;
  93.                         }
  94.                         dis_buf[0]=table[sec/100%10];
  95.                         dis_buf[1]=table[sec/10%10];
  96.                         dis_buf[2]=table[sec%10];
  97.                         P0=0x00;duan=1;duan=0;
  98.                         P0=~(0x01<<i);wein=1;wein=0;
  99.                         P0=dis_buf[i];duan=1;duan=0;
  100.                         i=++i%3;
  101.                 }//耗时569us
  102.         }
  103. }

  104. void Timer0Init(void)        //1毫秒@11.0592MHz
  105. {
  106.         AUXR |= 0x80;                //定时器时钟1T模式
  107.         TMOD &= 0xF0;                //设置定时器模式
  108.         TL0 = 0xCD;                        //设置定时初始值
  109.         TH0 = 0xD4;                        //设置定时初始值
  110.         TF0 = 0;                        //清除TF0标志
  111.         TR0 = 1;                        //定时器0开始计时
  112. }
  113. /*----------------------------
  114.         关闭IAP功能
  115. ----------------------------*/
  116. void IapIdle()
  117. {
  118.     IAP_CONTR = 0;                  //关闭IAP功能
  119.     IAP_CMD = 0;                    //清除命令寄存器
  120.     IAP_TRIG = 0;                   //清除触发寄存器
  121.     IAP_ADDRH = 0x80;               //将地址设置到非IAP区域
  122.     IAP_ADDRL = 0;
  123. }
  124. /*----------------------------
  125. 从ISP/IAP/EEPROM区域读取一字节
  126. ----------------------------*/
  127. uchar IapReadByte(uint addr)
  128. {
  129.     uchar dat;                       //数据缓冲区

  130.     IAP_CONTR = ENABLE_IAP;         //使能IAP
  131.     IAP_CMD = CMD_READ;             //设置IAP命令
  132.     IAP_ADDRL = addr;               //设置IAP低地址
  133.     IAP_ADDRH = addr >> 8;          //设置IAP高地址
  134.     IAP_TRIG = 0x5a;                //写触发命令(0x5a)
  135.     IAP_TRIG = 0xa5;                //写触发命令(0xa5)
  136.     _nop_();                        //等待ISP/IAP/EEPROM操作完成
  137.     dat = IAP_DATA;                 //读ISP/IAP/EEPROM数据
  138.     IapIdle();                      //关闭IAP功能
  139.     return dat;                     //返回
  140. }
  141. /*-------------------------------
  142. 写一字节数据到ISP/IAP/EEPROM区域
  143. --------------------------------*/
  144. void IapProgramByte(uint addr, uchar dat)
  145. {
  146.     IAP_CONTR = ENABLE_IAP;         //使能IAP
  147.     IAP_CMD = CMD_PROGRAM;          //设置IAP命令
  148.     IAP_ADDRL = addr;               //设置IAP低地址
  149.     IAP_ADDRH = addr >> 8;          //设置IAP高地址
  150.     IAP_DATA = dat;                 //写ISP/IAP/EEPROM数据
  151.     IAP_TRIG = 0x5a;                //写触发命令(0x5a)
  152.     IAP_TRIG = 0xa5;                //写触发命令(0xa5)
  153.     _nop_();                        //等待ISP/IAP/EEPROM操作完成
  154.     IapIdle();                      //关闭IAP功能
  155. }
  156. /*----------------------------
  157. ISP/IAP/EEPROM扇区擦除
  158. ----------------------------*/
  159. void IapEraseSector(uint addr)
  160. {
  161.     IAP_CONTR = ENABLE_IAP;         //使能IAP
  162.     IAP_CMD = CMD_ERASE;            //设置IAP命令
  163.     IAP_ADDRL = addr;               //设置IAP低地址
  164.     IAP_ADDRH = addr >> 8;          //设置IAP高地址
  165.     IAP_TRIG = 0x5a;                //写触发命令(0x5a)
  166.     IAP_TRIG = 0xa5;                //写触发命令(0xa5)
  167.     _nop_();                        //等待ISP/IAP/EEPROM操作完成
  168.     IapIdle();                      //关闭IAP功能
  169. }
  170. void PowerLost() interrupt 6
  171. {

  172.         EA = 0;                                                //关闭总中断
  173.         P0M1 = 0xff;                                //根据实际硬件环境,设置端口模式减少耗电
  174.         P1M1 = 0xff;
  175.         P2M1 = 0xff;
  176.         P3M1 = 0xff;
  177.         P4M1 = 0xff;
  178.         P5M1 = 0xff;
  179.         P6M1 = 0xff;
  180.         P7M1 = 0xff;
  181.         IapProgramByte(IAP_ADDRESS+sign,sec);//写数据到EEPROM
  182.         while((PCON & 0x20) != 0)         //复查低压标志
  183.         {
  184.                 PCON &= 0xDF;                  //清除低压标志
  185.                 _nop_();               
  186.                 _nop_();                            //坐等掉电
  187.         }
  188.         IAP_CONTR = 0x20;                 //发现是误报,重启单片机,恢复正常工作
  189. }
复制代码



回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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