关于未接sensor,adc计算温度出现FPU中断的问题

从你提供的代码来看,问题可能出在以下代码行:

```c
fVin = (adcvalue * VCC_VALUE_MV * (390 + 110000 + 33000.0)) / 33000.0 / 4096.0;  //todo: check reference voltage //MV
```

执行这段代码后直接进入了 FPU(浮点单元)中断处理程序,通常是因为浮点运算中出现了非法操作或异常。以下是可能的原因及解决方法:

---

### 1. **浮点运算异常**
   - **问题**:浮点运算中可能出现非法操作,例如:
     - 除以零。
     - 结果超出浮点数的表示范围(溢出)。
     - 结果为非数字(NaN,Not a Number)。
   - **分析**:
     - `33000.0` 是浮点数,`adcvalue` 和 `VCC_VALUE_MV` 是整数。
     - 如果 `adcvalue` 或 `VCC_VALUE_MV` 的值异常(例如 `adcvalue` 超出 `ADC_MAX_VALUE` 或为负值),可能导致非法浮点运算。
     - 如果 `33000.0` 或 `4096.0` 为零(理论上不可能,但需要确认),会导致除以零异常。

   - **解决方法**:
     在计算前添加检查,确保所有参与运算的值都在合理范围内。例如:
     ```c
     if (adcvalue > ADC_MAX_VALUE || adcvalue < 0 || VCC_VALUE_MV <= 0)
     {
         // 错误处理
         return;
     }
     ```

---

### 2. **浮点硬件未正确初始化**
   - **问题**:如果你的 MCU 使用了硬件浮点单元(FPU),但在系统初始化时未正确启用 FPU,任何浮点运算都会触发硬件异常。
   - **解决方法**:
     确保在系统启动时正确初始化 FPU。例如,在 Cortex-M 系列 MCU 中,通常需要在启动代码中启用 FPU:
     ```c
     SCB->CPACR |= ((3UL << 10*2) | (3UL << 11*2)); // 启用 FPU
     ```
     如果你使用的是裸机开发,请检查启动文件(`startup_xxx.s`)是否包含 FPU 初始化代码。如果使用的是 RTOS(如 FreeRTOS),请确保在配置中启用了 FPU 支持。

---

### 3. **浮点数精度问题**
   - **问题**:浮点数运算可能因为精度问题导致意外的结果。例如,`33000.0` 和 `4096.0` 的运算可能因为精度丢失导致结果不准确。
   - **解决方法**:
     - 确保所有常量和变量的类型一致。例如,将 `390` 和 `110000` 显式转换为浮点数:
       ```c
       fVin = (adcvalue * VCC_VALUE_MV * (390.0 + 110000.0 + 33000.0)) / 33000.0 / 4096.0;
       ```

---

### 4. **非法内存访问**
   - **问题**:如果 `fVin` 或其他变量的内存地址非法(例如未正确初始化或被意外覆盖),可能导致异常。
   - **解决方法**:
     - 确保 `fVin` 和其他变量已正确声明并初始化。
     - 检查是否有其他代码意外修改了这些变量的内存。

---

### 5. **调试方法**
   - **启用浮点异常捕获**:
     在调试环境中启用浮点异常捕获,查看具体的异常类型(如除以零、溢出或 NaN)。
   - **打印调试信息**:
     在计算前打印所有参与运算的变量值,确认它们是否在预期范围内:
     ```c
     printf("adcvalue: %d, VCC_VALUE_MV: %d\n", adcvalue, VCC_VALUE_MV);
     ```

---

### 总结
最可能的原因是浮点运算中出现了非法操作(如除以零或溢出),或者 FPU 未正确初始化。建议按照以下步骤排查问题:
1. 检查 `adcvalue` 和 `VCC_VALUE_MV` 的值是否在合理范围内。
2. 确保 FPU 在系统启动时已正确初始化。
3. 确保所有常量和变量的类型一致,避免隐式类型转换问题。
4. 在调试环境中启用浮点异常捕获,定位具体的异常原因。

最后发现是计算温度是除数里有ADC_MAX_VALUE-adcvalue操作。导致当sensor不接时,两者相等出现除0操作,进而触发FPU中断死机。(假如不再FPU 加while 1循环,则会在下一次的循环中触发hardfault中断)

static unsigned char ADC_2_NTC3K_Rin(uint16_t adcvalue, float *pResistanceVal)

{

    float fResistance;

    if (pResistanceVal == NULL)

    {

        return 0;

    }

    if (adcvalue >= ADC_MAX_VALUE || adcvalue < 0)

    {

        *pResistanceVal = -20.0;

        return 0;

    }

    fResistance = (adcvalue * 3000.0);

    fResistance = fResistance / (ADC_MAX_VALUE - adcvalue);  //4096-adc)/3000 = adc / fresistance;

    *pResistanceVal = fResistance;

    return 1;

}

另外一例触发FPU中断的例子:

当NTC值为-20的时候,会触发FPU中断死机。

float         NTC_val;

temp_val = (uint16_t)(NTC_val * 10.0);
memcpy(&temp[0], &temp_val, sizeof(uint16_t));

问题分析 在代码中,以下部分可能导致问题:          

1. 问题原因:浮点数到无符号整数的转换

NTC_val 是一个 float 类型的变量,当其值为负数(如 -20)时,乘以 10.0 的结果为 -200.0。 • 将 -200.0 转换为 uint16_t 类型时,会发生未定义行为,因为 uint16_t 是无符号整数,无法表示负值。 • 这种非法转换可能触发 FPU 异常,导致进入 FPU 中断。  

2. FPU 中断的触发条件

• Cortex-M 系列的 FPU(浮点单元)可能会在以下情况下触发中断:

◦ 浮点运算结果为 NaN(非数字)。

◦ 浮点运算结果超出表示范围(溢出)。

◦ 非法的浮点数到整数的转换。      

修复方法 为了避免进入 FPU 中断,需要在进行浮点数到整数的转换之前,确保值在合法范围内。以下是修复方法:  

方法 1:

检查 NTC_val 的值范围 在进行浮点数到整数的转换之前,检查 NTC_val 是否为负数。如果是负数,可以将其限制为 0 或其他合理的值。        

if (NTC_val < 0)
{
    temp_val = 0;  // 将负值限制为 0
}
else
{
    temp_val = (uint16_t)(NTC_val * 10.0);
}
memcpy(&temp[0], &temp_val, sizeof(uint16_t));    

方法 2:

使用有符号整数类型 如果需要保留负值,可以将 temp_val 的类型改为 int16_t,以支持负数的表示。           同时,确保接收端能够正确解析有符号整数。  

int16_t temp_val = (int16_t)(NTC_val * 10.0);
memcpy(&temp[0], &temp_val, sizeof(int16_t));

方法 3:

启用浮点异常捕获(调试用) 在调试阶段,可以启用浮点异常捕获,以便更清楚地了解问题的根源。以下代码可以在系统初始化时启用 FPU 异常捕获:           这将帮助你捕获浮点异常并定位问题。  

SCB->CPACR |= ((3UL << 10*2) | (3UL << 11*2));  // 启用 FPU
FPU->FPCCR |= (1 << 4);  // 启用浮点异常捕获

方法 4:限制浮点数的范围 如果 NTC_val 的值可能超出预期范围,可以在计算之前对其进行限制。

例如:

float clamped_NTC_val = NTC_val;
if (clamped_NTC_val < -100.0)
{
    clamped_NTC_val = -100.0;  // 限制最小值
}
else if (clamped_NTC_val > 100.0)
{
    clamped_NTC_val = 100.0;  // 限制最大值
}

temp_val = (uint16_t)(clamped_NTC_val * 10.0);
memcpy(&temp[0], &temp_val, sizeof(uint16_t));

推荐使用 方法 2,将 temp_val 的类型改为 int16_t,以支持负值的表示。这是最直接的修复方法,且不会丢失负值信息。

修改后的代码如下:  

int16_t temp_val = (int16_t)(NTC_val * 10.0);
memcpy(&temp[0], &temp_val, sizeof(int16_t));       

同时,确保接收端能够正确解析有符号整数。  

总结

• 问题原因:NTC_val 为负数时,浮点数到无符号整数的转换导致非法操作,触发 FPU 中断。

• 修复方法: 1. 检查并限制 NTC_val 的值范围。 2. 使用有符号整数类型(推荐)。 3. 启用浮点异常捕获(调试用)。 4. 限制浮点数的范围。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值