RT-Threadwilliam hill官网
直播中

文甘翀

7年用户 908经验值
私信 关注
[问答]

rtt4.1.1做滑动平均值滤波的时候,被意外赋值,为什么?

1. 问题描述
我使用rtt4.1.1版本,其中adc采样直接采用cubemx生成的库函数,用DMA读取方式读取AD的值。并在DMA中断内回调AD值计算函数。
结果在做滑动平均值滤波的时候出现了问题。一个未初始化的全局变量在第二次进入中断的时候被意外赋值了。这造成了计算结果的不正确。如果用static修饰这个变量后,则不会出现这个状况。下面是问题描述。

2. 变量声明
int32_t voltage_rms_sum_a;
int32_t voltage_rms_sum_b;
int32_t voltage_rms_sum_c;
3.滑动平均值滤波
    if (adc_convert_full == 1)
    {
        voltage_rms_a = (int)(sqrtf(voltage_square_add_a/20)*10);
        voltage_rms_b = (int)(sqrtf(voltage_square_add_b/20)*10);
        voltage_rms_c = (int)(sqrtf(voltage_square_add_c/20)*10);
        voltage_square_add_a = voltage_square_add_a-voltage_square_a[adc_convert_cnt];
        voltage_square_add_b = voltage_square_add_b-voltage_square_b[adc_convert_cnt];
        voltage_square_add_c = voltage_square_add_c-voltage_square_c[adc_convert_cnt];
        voltage_rms_buf_a[rms_average_calc_cnt]= voltage_rms_a;
        voltage_rms_sum_a=voltage_rms_sum_a+voltage_rms_buf_a[rms_average_calc_cnt];
        voltage_rms_buf_b[rms_average_calc_cnt]= voltage_rms_b;
        voltage_rms_sum_b=voltage_rms_sum_b+voltage_rms_buf_b[rms_average_calc_cnt];
        voltage_rms_buf_c[rms_average_calc_cnt]= voltage_rms_c;
        voltage_rms_sum_c=voltage_rms_sum_c+voltage_rms_buf_c[rms_average_calc_cnt];
        rms_average_calc_cnt++;
}
4. 问题
adc_convert_full这个变量被设计为20次中断后开始滤波,意味着20次循环后,才会进入if语句。但是如果用断点调试后发现,第一次进入时。
第20行,voltage_rms_sum_c变量为0,但是第二次进入中断后,voltage_rms_sum_c变量为0被赋值为一个意外的值。我看了内存的分配,也没有发现内存重复的情况。

5. 临时解决办法
将voltage_rms_sum_a、voltage_rms_sum_b、voltage_rms_sum_c增加static修饰,可以解决问题,但是我不明白为什么会这样。

回帖(1)

殷谷光

7 天前
在这个问题中,您在使用RTT4.1.1版本进行滑动平均值滤波时遇到了一个未初始化的全局变量在第二次进入中断时被意外赋值的问题。这导致了计算结果的不正确。当您使用`static`修饰这个变量后,问题得到了解决。下面我将详细分析这个问题的原因和解决方法。

1. 问题原因:

在您的代码中,`voltage_rms_sum_a`、`voltage_rms_sum_b`和`voltage_rms_sum_c`这三个全局变量没有被初始化。当您在DMA中断内回调AD值计算函数时,这些变量可能会被意外赋值。这是因为在C语言中,全局变量默认会被初始化为0,但在某些编译器或硬件平台上,这个行为可能并不总是发生。因此,当您在中断服务例程(ISR)中使用这些变量时,它们可能已经被其他代码段意外地修改了。

2. 解决方案:

要解决这个问题,您可以采取以下几种方法:

a. 初始化全局变量:

在您的代码中,确保在声明全局变量时对它们进行初始化。例如:

```c
int32_t voltage_rms_sum_a = 0;
int32_t voltage_rms_sum_b = 0;
int32_t voltage_rms_sum_c = 0;
```

这样可以确保在中断服务例程中使用这些变量时,它们已经被正确初始化。

b. 使用`static`修饰符:

您已经发现使用`static`修饰符可以解决问题。这是因为`static`修饰符会将变量的作用域限制在声明它的文件内,从而避免了其他代码段对这些变量的意外访问。例如:

```c
static int32_t voltage_rms_sum_a;
static int32_t voltage_rms_sum_b;
static int32_t voltage_rms_sum_c;
```

c. 使用局部变量:

另一种方法是在中断服务例程中使用局部变量,而不是全局变量。这样可以确保变量的作用域仅限于中断服务例程,从而避免了其他代码段对这些变量的意外访问。例如:

```c
void DMA_IRQHandler(void)
{
    int32_t voltage_rms_sum_a;
    int32_t voltage_rms_sum_b;
    int32_t voltage_rms_sum_c;

    // 滑动平均值滤波
    if (adc_convert_full == 1)
    {
        // ...
    }
}
```

3. 总结:

在您的代码中,未初始化的全局变量在第二次进入中断时被意外赋值,导致了计算结果的不正确。为了解决这个问题,您可以采取以下措施:

- 初始化全局变量
- 使用`static`修饰符
- 使用局部变量

通过采取这些措施,您可以确保在中断服务例程中正确地使用这些变量,从而避免意外的赋值和计算错误。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分