我有一个代码需要在定时器中断中读取AD通道(具有精确时间)。
如果我刚读完AD,一切都会好的。但我需要使用数字滤波器,如果我只在内部中放一个乘法,则会发出警告:
没关系:
#int_RTCC
void RTCC_isr(void)
{
set_adc_channel(0);
delay_us(40);
unsigned int16 aD = read_adc();
}
但这会得到警告:
#int_RTCC
void RTCC_isr(void)
{
set_adc_channel(0);
delay_us(40);
unsigned int16 aD = read_adc();
aDfilter = aDfilter * 8 + aD * 2;
}
在呼叫期间禁用中断以防止重入(@ MUL3232)
我不想要禁用定时器,因为我需要精确度。我该如何解决这个问题?
答案 0 :(得分:0)
问题1:PIC通常意味着8位CPU。 8位CPU无法原子读取16位值(aDfilter
)。如果在主程序只读取了一半值时触发了RTC中断,程序将崩溃并烧毁。你需要一些重入的方法,这就是编译器告诉你的。
问题2:PIC通常意味着CPU速度非常慢,中断延迟很大。因此,您不应该在ISR中进行算术运算。这肯定涉及浮点计算。整数的乘法甚至可能很糟糕。
问题3:PIC通常意味着没有FPU的CPU速度非常慢,这意味着您不应该使用浮点数开头。您最终会使用浮动支持来调用软件库,这非常慢。显示的代码中没有任何内容表示需要在此程序中使用浮点。
解决方案:使用整数。用同步化手段实现再生。这对于单核微控制器来说相当容易,中断总是会阻止进一步的中断simple example。然后将数字滤波器计算外包给调用者应用程序。只需添加一个标志即可告诉它有新数据可用。
答案 1 :(得分:0)
你可以通过移位来避免使用int32乘法,例如:
<query>
答案 2 :(得分:0)
(消息)在呼叫期间禁用中断以防止重入(@ MUL3232)
我不想要定时器禁用,因为我需要精确度。
这是一个虚假的问题。
代码只是保护自己免受好的设计可以避免发生的异常情况。
当运行定时器中断服务程序(ISR)时,另一个定时中断的重入通常只会发生在两种情况下:
定时器ISR频率太高。这意味着处理1个定时器ISR所需的时间很短,另一个在此完成之前发生。这不是一个好的设计。要解决,确保定时器频率不是那么高。
延迟。在处理需要很长时间的其他ISR时发生了定时器ISR,从而阻止了此定时器ISR呼叫。到执行此ISR时,发生了另一个定时器中断。要解决这个问题,请确保所有ISR在一起的时间不会超过计时器周期。
如果设计良好,则不会发生第二个定时器中断,暂时禁止进行乘法运算不会阻止定时器中断发生。
或简化代码
需要aDfilter * 8
调用的 @MUL3232
意味着弱优化或不必要地使用签名数学。通过使用无符号数学使编译器更容易编码。
// some_signed_32_bit_type aDfilter
uint32_t aDfilter;
// and if that is not enough change code
// aDfilter = aDfilter * 8 + aD * 2;
aDfilter = (aDfilter << 3) + aD * 2;
潜在的性能提升。根据总体设计,应该能够消除delay_us(40);
。如果仅使用1个通道,则可以进行以下操作 - 具体取决于各种要求。
#int_RTCC
void RTCC_isr(void) {
// delay_us(40); // not needed is timer period >> 40us
unsigned int16 aD = read_adc();
set_adc_channel(0); // select channel now (also at initialization)
aDfilter = aDfilter * 8 + aD * 2;
}
潜在的错误。如果read_adc()
处于一种模式,即设置了最高有效位(例如,向左移动了10位转换),并且编译器具有16位int / unsigned,则aD*2
溢出。在这种情况下使用:
uint32_t aDfilter;
...
aDfilter = aDfilter*8 + (uint32_t)read_adc()*2;