中断PIC CCS

时间:2017-09-26 13:01:20

标签: c pic

我有一个代码需要在定时器中断中读取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)

我不想要禁用定时器,因为我需要精确度。我该如何解决这个问题?

3 个答案:

答案 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)时,另一个定时中断的重入通常只会发生在两种情况下:

  1. 定时器ISR频率太高。这意味着处理1个定时器ISR所需的时间很短,另一个在此完成之前发生。这不是一个好的设计。要解决,确保定时器频率不是那么高。

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

  3. 如果设计良好,则不会发生第二个定时器中断,暂时禁止进行乘法运算不会阻止定时器中断发生。

    简化代码

    需要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;