找回密码
 立即注册
查看: 14|回复: 2

请教大家一个问题:一条乘法指令导致MCU复位的原因是什么

[复制链接]
  • 打卡等级:偶尔看看III
  • 打卡总天数:32
  • 最近打卡:2025-10-03 00:02:14
已绑定手机

7

主题

5

回帖

199

积分

注册会员

积分
199
发表于 3 小时前 | 显示全部楼层 |阅读模式
      调试一个ai8051u+电流传感器_ACS712ELCTR-05B-T程序,使用P1.7脚对ACS712ELCTR-05B-T的输出电压进行AD转换后计算电流。程序采用8bit。
根据ACS712ELCTR-05B-T手册,电流在0-5A时,其输出电压:2.5V+-0.925V,输出灵敏度:185mV/A。
      程序主要检测方法是20MS的时间内连续对ACS712ELCTR-05B-T的输出电压进行20次采样,通过冒泡法查找到电压的最大值后,再换算成检测电流值。AD转换程序参考了擎天柱例程中的09.ADC采样NTC数据-软件防抖-过采样使用-串口1返回结果程序。
      在换算时,包含以下语句:
      const float K=Vref/4096/0.185/1.414;           //计算常数
      float Current_temp=0.0;

      Current_temp = (adc - 2048)*K;                  //换算出电流值,ADC为ADC采样值

     调试程序时,用电位器对5V电源分压后接入P1.7脚进行模拟。由于是模拟,当AD输入电压低于2.5V时,冒泡法查找到电压的最大值就会小于2048 ,(adc - 2048)就会变成负数,此时导致程序复位。
     请教一下大家在这条语句中,为什么(adc - 2048)变成负数后会导致MCU复位呢?
     下面是电流换算的程序:
  1. /******************** 计算电流 *********************/
  2. #define     Vref        5.0
  3. #define     Sensitvity  0.185
  4. #define     Zero_point  2.5
  5. float CalculationCurrent(u16 adc)
  6. {
  7.     //电流传感器_ACS712ELCTR-05B-T
  8.     //量程:5A
  9.     //输出灵敏度:185mV/A(对应5A电流时输出约925mV)
  10.     //精度:±1.5%
  11.     //工作电压:4.5V~5.5V
  12.     //输出电压:2.5V+-0.925
  13.        
  14.     const float K=Vref/4096/0.185/1.414;           //计算常数
  15.     float Current_temp=0.0;          //电流计算结果
  16.     Current_temp = (adc - 2048)*K; //Zero_point理论值为2048,对应采样电压2.5V
  17.     return Current_temp;
  18. }
复制代码

下面附上用到的8位擎天柱例程:09.ADC采样NTC数据-软件防抖-过采样使用-串口1返回结果
09.ADC采样NTC数据-软件防抖-过采样使用-串口1返回结果.zip (117.07 KB, 下载次数: 1)

回复

使用道具 举报 送花

3

主题

1928

回帖

704

积分

等待验证会员

积分
704
发表于 3 小时前 | 显示全部楼层
您提出的问题非常具有代表性,涉及嵌入式系统中浮点运算、变量溢出及MCU稳定性等多个方面。以下是对“为什么 (adc - 2048) 变成负数后会导致MCU复位”这一现象的专业分析与建议。

一、问题背景回顾

您使用的是 AI8051u MCU,配合 ACS712ELCTR-05B-T 电流传感器进行电流检测。通过 P17 脚进行 ADC 采样,使用 冒泡法查找最大值,然后进行浮点运算换算为电流值。

在换算过程中,使用了如下关键语句:
  1. c
  2. const float K = Vref / 4096 / 0.185 / 1.414;
  3. float Currenttemp = 0.0;
  4. Currenttemp = (adc - 2048)  K;
复制代码

当 adc < 2048 时,(adc - 2048) 为负数,此时 MCU 出现复位现象。您通过电位器模拟输入电压,确认是当电压低于 2.5V(对应 ADC 值为 2048)时,程序出现异常复位。

二、可能原因分析

1. 浮点运算异常导致硬件异常中断

AI8051u 是 8 位增强型 51 内核的 MCU,其浮点运算能力依赖于软件库(如 Keil 的 float 家族函数库)。浮点运算过程中,若遇到如下情况:
溢出(overflow)
下溢(underflow)
非法操作(如除以 0)
非数字(NaN)

可能会触发异常处理程序,而如果异常处理未正确配置或未实现,MCU 可能会进入 不可恢复状态,最终表现为 复位。
特别注意:某些浮点库在遇到非法操作时,会调用 rtraise() 函数,若未实现该函数,可能导致程序崩溃甚至复位。

2. 堆栈溢出或内存访问越界

在进行浮点运算或冒泡排序等操作时,若局部变量较多、函数嵌套过深,可能导致堆栈溢出。尤其是在使用递归、数组操作或未优化的排序算法时,堆栈空间不足会破坏程序计数器(PC),导致程序跑飞,最终触发看门狗复位或硬件复位。

3. 看门狗定时器未喂狗

如果在 ADC 采样与计算过程中耗时较长,导致主循环延迟超过看门狗定时器周期,而看门狗又未被及时“喂狗”,则会触发看门狗复位。

特别是在 ADC 采样、冒泡排序、浮点运算等耗时操作中,若未在合适位置喂狗,容易引发此问题。

4. 除法或乘法运算中的异常

虽然 (adc - 2048) 是负数本身不会直接导致复位,但结合后续的浮点运算(如乘法、除法)时,如果运算结果溢出或产生 NaN,可能触发异常处理机制。

此外,某些编译器或库函数在处理负数与浮点数混合运算时,可能存在兼容性问题,尤其是在未启用浮点支持或编译器优化设置不当的情况下。

三、调试与验证建议

1. 检查浮点库异常处理机制

在 Keil μVision 等环境中,可通过以下方式检查是否触发了浮点异常:
在 rtraise() 函数中添加断点或打印信息,观察是否进入该函数。
检查是否链接了正确的浮点支持库(例如 fpl、fplib)。
尝试禁用浮点运算,改用定点运算,观察是否仍复位。

2. 启用调试器观察程序崩溃点

使用 JTAG/SWD 调试器连接 MCU,设置断点于:
Currenttemp = (adc - 2048)  K;
浮点运算函数内部
看门狗喂狗位置

观察程序是否在该语句执行后立即崩溃,或进入异常中断。

3. 检查堆栈使用情况

查看编译器生成的 .map 文件,确认各函数堆栈使用量,尤其是 ADC 采样、冒泡排序、浮点运算函数的栈空间是否超出系统分配。

可尝试:
增加堆栈大小
减少局部变量
避免递归调用

4. 使用看门狗喂狗机制

在主循环关键位置添加喂狗代码:
  1. c
  2. WDTFEED(); // 假设喂狗函数名
复制代码

特别是在 ADC 采集、排序、计算等耗时操作后添加,避免看门狗超时复位。

四、优化建议

1. 使用定点运算替代浮点运算

由于 AI8051u 不具备硬件浮点单元,建议尽量避免使用浮点运算。可将 Currenttemp 改为整型,通过放大倍数进行定点运算。

例如:
  1. c
  2. define Kfixed  ( (int32t)( (Vref  1000000) / 4096 / 185 / 1414 ) )  // 放大倍数
  3. int32t Currenttempfixed = (adc - 2048)  Kfixed;
复制代码

最终显示时再除以放大倍数转换为浮点或小数。

2. 避免负值导致异常

在进行 (adc - 2048) 前,可先进行判断:
  1. c
  2. if (adc >= 2048)
  3.     Currenttemp = (adc - 2048)  K;
  4. else
  5.     Currenttemp = 0.0;  // 或负值处理逻辑
复制代码

或使用绝对值函数:
  1. c
  2. Currenttemp = abs(adc - 2048)  K;
复制代码

但需注意是否影响电流方向判断。

3. 优化冒泡排序算法

冒泡排序效率较低,且容易导致堆栈溢出。建议使用更高效的排序算法(如快速排序、插入排序)或直接使用最大值查找逻辑:
  1. c
  2. uint16t maxadc = 0;
  3. for (int i = 0; i < 20; i++) {
  4.     uint16t adcval = ReadADC();
  5.     if (adcval > maxadc)
  6.         maxadc = adcval;
  7. }
复制代码

五、总结

综上所述,导致 MCU 在 (adc - 2048) 为负数时复位的原因,最有可能是:
浮点运算异常触发异常中断
堆栈溢出或内存访问越界
看门狗未及时喂狗
除法或乘法运算溢出

建议通过以下步骤进行排查与优化:

1. 检查浮点库异常处理机制(如 rtraise());
2. 使用调试器定位崩溃位置;
3. 检查堆栈使用情况;
4. 在耗时操作后添加喂狗代码;
5. 使用定点运算替代浮点运算;
6. 优化排序算法,避免低效排序;
7. 对负值进行边界判断或处理。

通过以上方法,可以有效定位并解决 MCU 因乘法指令导致复位的问题。

如需进一步协助,欢迎提供完整代码或编译环境信息。

[本文内容由国芯人工智能辅助生成,仅供参考]
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:316
  • 最近打卡:2025-10-03 13:31:13
已绑定手机

83

主题

3210

回帖

7098

积分

荣誉版主

无情的代码机器

积分
7098
发表于 1 小时前 | 显示全部楼层

上传的代码里未见问题函数调用,并且复制这个函数到例程中调用未见复位异常:
09.ADC采样NTC数据-软件防抖-过采样使用-串口1返回结果-test.zip (128.22 KB, 下载次数: 0)


上传可复现问题工程看看
三天不学习,赶不上刘少奇~
回复

使用道具 举报 送花

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

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-10-3 15:18 , Processed in 0.120945 second(s), 63 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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