【问题标题】:Interruption PIC CCS中断PIC CCS
【发布时间】:2017-09-26 23:10:59
【问题描述】:

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

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

【问题讨论】:

  • 警告是什么?可能您需要进行如下计算:aDfilter = (float)aDfilter * 0.8f + (float)aD * 0.2f; 顺便说一句,您想通过禁用中断来防止重入?没有意义,或者您可能需要不同的词,例如 prevent recursion?
  • 抱歉,正确的是:aDfilter = aDfilter * 8 + aD * 2 不需要浮动。问题是我在中断内部和外部使用乘法。有没有办法做到这一点?
  • 基本上所有问题都源于此:PIC 不是 PC。
  • "在调用期间禁用中断以防止重入" 嗯?什么时候打电话? “防止重入”是什么意思,您的问题是缺乏重入。
  • @Lundin 我猜错误应该是“在调用期间禁用中断以防止重新进入”。

标签: c pic


【解决方案1】:

问题 1:PIC 通常表示 8 位 CPU。 8 位 CPU 无法自动读取 16 位值 (aDfilter)。如果您的 RTC 中断在主程序仅读取一半值时触发,您的程序将崩溃并烧毁。你需要一些重入方法,这是编译器告诉你的。

问题 2:PIC 通常意味着 CPU 速度极慢,中断延迟很大。因此,您不应该在 ISR 中进行算术运算。这当然涉及浮点计算。整数的乘法甚至可能已经够糟糕了。

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

解决方案:使用整数。使用同步方式实现重入。这在中断总是阻止进一步中断的单核微控制器上相当容易做到,simple example。然后将数字滤波器计算外包给调用者应用程序。只需添加一个标志,告诉它有新数据可用。

【讨论】:

  • '你最终会调用支持浮点的软件库,这非常慢',另外,如果你也在中断之外使用 FP,你需要一个可重入的 FP 库,(如如果使用 PIC 没有带来足够的问题)。
  • 更糟 - FP 库,如果可重入,将使用堆栈。这意味着所有被中断的东西都必须有足够的堆栈来支持它,或者交换到一个单独的中断堆栈。每次使用时可能需要调用一些冗长的“FPinit()”函数。这一切都非常混乱,即使它有效:(
  • @MartinJames 然后... PIC... 意思是 1970 年代的架构,具有固定的堆栈深度。浮动库将使用多深的调用?将它包含在 ISR 中非常有趣。
【解决方案2】:

您可以通过移位避免使用 int32 乘法,例如:

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

【讨论】:

    【解决方案3】:

    (消息)在调用期间禁用中断以防止重入 (@MUL3232)
    我不希望禁用计时器,因为我需要精度。

    这是一个错误的担忧。

    代码只是保护自己免受优秀设计可以避免发生的异常情况。


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

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

    2. 延迟。在处理其他需要很长时间的 ISR 时发生了计时器 ISR,因此阻塞了此计时器 ISR 调用。当这个 ISR 被执行时,另一个定时器中断已经发生。要解决此问题,请确保所有 ISR 一起使用的时间不超过计时器周期。

    如果设计良好,则不会发生第二个定时器中断,并且暂时禁用执行乘法的时间不会阻止定时器中断的发生。


    简化代码

    aDfilter * 8 需要 @MUL3232 调用意味着弱优化或不必要地使用 signed 数学。使用无符号数学使编译器的代码更容易。

    // 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 位转换左移 6 位)并且编译器具有 16 位 int/unsigned,则 aD*2 溢出。在这种情况下使用:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多