2017-09-26 78 views
0

我有一段代碼需要在定時器中斷(精確時間)內讀取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

回答

0

問題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

0

您可以通過移動避免使用INT32乘法,是這樣的:

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

(消息)在通話過程中斷關閉,以防止重入(@ 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;