中断PIC CCS

中断PIC CCS

问题描述:

我有一段代码需要在定时器中断(精确时间)内读取AD通道。中断PIC CCS

如果我刚读完广告,一切都还好。但我需要使用数字滤波器,如果我把刚才乘法内部中断有一个警告:

这是确定的:

#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

什么是警告?可能你需要做如下计算:'aDfilter =(float)aDfilter * 0.8f +(float)aD * 0.2f;'顺便说一句,你想通过禁止中断来防止重入?没有意义或者你需要不同的单词,如*防止递归*? – tilz0R

+0

Sory,正确的是:aDfilter = aDfilter * 8 + aD * 2 不需要浮动。 问题是我正在使用乘法内外中断。有没有办法做到这一点? –

+0

基本上所有的问题都源于此:PIC不是PC。 – Lundin

问题1:PIC通常意味着8位CPU。 8位CPU不能自动读取16位值(aDfilter)。如果您的RTC中断触发,而主程序只读取了一半的值,则程序将崩溃并烧毁。你需要一些重入手段,这正是编译器告诉你的。

问题2:PIC通常意味着可怕的CPU速度很慢,中断延迟很大。所以你不应该在ISR中有算术。这当然涉及浮点计算。整数乘法甚至可能足够糟糕。

问题3:PIC通常意味着没有FPU的速度非常慢的CPU,这意味着您不应该使用浮点数来开始。你最终会调用带有float支持的软件库,这非常缓慢。显示的代码中没有任何内容表示在此程序中需要使用浮点。

解决方案:使用整数。通过同步化手段实施重新招聘。这在单核微控制器上很容易实现,其中中断总是会阻塞进一步的中断,simple example。然后将数字滤波器计算外包给调用者应用程序。只需添加一个标志来告诉它有新的数据可用。

+1

'你最终会调用具有浮点支持的软件库,这非常缓慢',另外,如果你也在中断外使用FP,则需要一个可重入的FP库(如果使用PIC不会带来足够的问题)。 –

+0

更糟 - FP库,如果可重入,将使用堆栈。这意味着所有被中断的东西都必须有足够的堆栈来支持它,或者交换到单独的中断堆栈。可能需要在每次使用时调用一些冗长的'FPinit()'函数。这一切都非常混乱,即使它工作:( –

+0

@MartinJames然后... PIC ...意思是1970年代固定堆栈深度的架构。浮点库会使用多深的调用?在ISR中有非常有趣的内容。 – Lundin

您可以通过移动避免使用INT32乘法,是这样的:

#int_RTCC 
void RTCC_isr(void) 
{ 
    set_adc_channel(0);  
    delay_us(40); 
    unsigned int16 aD = read_adc(); 
    aDfilter = aDfilter << 3 + aD * 2; 
} 

(消息)在通话过程中断关闭,以防止重入(@ MUL3232)
我不想定时器禁用,因为我需要精确度。

这是一个错误的担心。

代码只是保护自己免受良好设计可避免发生的异常情况的影响。


当运行定时器中断服务程序(ISR),另一定时中断的再entrantcy通常只发生在两种情况:

  1. 定时器ISR频率太高。这意味着处理1个定时器所需的时间很短,另外还有一个时间是在这个完成之前发生的。这不是一个好设计。为了解决这个问题,确保定时器频率不是很高。

  2. 延迟。处理某些需要很长时间的其他ISR时发生定时器ISR,从而阻止该定时器ISR调用。在执行此ISR时,又发生了另一个定时器中断。为了解决这个问题,确保所有ISR一起不要超过计时器周期。

有了良好的设计,则第2个定时器中断将不会发生,并暂时禁用时间做乘法不会阻止一个定时器中断发生。


或者简化代码

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; 
} 

潜在的bug。如果read_adc()处于设置最高有效位的模式(例如,10位转换向左移位6)并且编译器具有16位整数/无符号,则aD*2溢出。在那种情况下使用:

uint32_t aDfilter; 
... 
aDfilter = aDfilter*8 + (uint32_t)read_adc()*2;