我有一个在定时器中断(精确时间)中读取AD通道所需的代码。
只要我看一下广告,一切都没问题。但我需要使用数字滤波器,如果我只在中断a中放了一个乘法,就会有一个警告:
这是可以的:
#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)
我不想禁用计时器,因为我需要精确度。我该如何解决这个问题呢?
发布于 2017-09-26 21:20:05
问题1: PIC通常意味着8位CPU。8位CPU不能自动读取16位值(aDfilter)。如果您的RTC中断触发时,主程序只读取了一半的值,您的程序将崩溃和烧毁。你需要一些可重入性的方法,这是编译器告诉你的。
问题2: PIC通常意味着CPU速度非常慢,具有很大的中断延迟。因此,您不应该在ISR中使用算术运算。这当然涉及到浮点计算。整数的乘法甚至可能已经很糟糕了。
问题3: PIC通常意味着没有FPU的CPU非常慢,这意味着你不应该从一开始就使用浮点数。你最终会调用支持浮动的软件库,这是非常慢的。所显示的代码中没有任何内容表明需要在此程序中使用浮点。
解决方案:使用整数。用同步化的方法来实现可重用性。这在单核微控制器上很容易做到,在单核微控制器中,中断总是阻止进一步的中断,simple example。然后将数字滤波器计算外包给调用者应用程序。只需添加一个标志,告诉它有新数据可用。
发布于 2017-09-26 22:42:50
可以通过移位来避免使用int32乘法,如下所示:
#int_RTCC
void RTCC_isr(void)
{
set_adc_channel(0);
delay_us(40);
unsigned int16 aD = read_adc();
aDfilter = aDfilter << 3 + aD * 2;
}发布于 2017-09-26 22:55:42
在调用期间禁用
(消息)中断,以防止重入(@MUL3232)
我不想禁用计时器,因为我需要精确度。
这是一种错误的担忧。
代码只是在保护自己不受好的设计可以避免的不寻常情况的影响。
当运行定时器中断服务例程(ISR)时,通常仅在以下两种情况下才会发生另一个定时中断的重新进入:
如果设计良好,那么第二个定时器中断将不会发生,并且暂时禁用乘法时间不会阻止定时器中断的发生。
或简化代码
需要@MUL3232调用的aDfilter * 8意味着弱优化或不必要地使用带符号的数学运算。通过使用无符号数学使编译器更容易编写代码。
// 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);。如果只使用一个通道,则根据不同的要求,以下情况是可能的。
#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;
}潜在的bug。如果read_adc()处于设置最高有效位的模式(例如,10位转换左移6),并且编译器具有16位int/unsigned,则aD*2溢出。在这种情况下,使用:
uint32_t aDfilter;
...
aDfilter = aDfilter*8 + (uint32_t)read_adc()*2;https://stackoverflow.com/questions/46427314
复制相似问题