2017-09-04 235 views
-3

我用C語言進行模運算有問題。 我已經定義了全局變量uint16_t Tmr_1ms,它是每1毫秒遞增 。我想用這個變量 這是考慮功能用C語言進行模運算

void OSC(uint32_t output, Osc_t *p){ 

    float act_time; 

    if(p->start){ 

     taskENTER_CRITICAL(); 
      act_time = Tmr_1ms; 
     taskEXIT_CRITICAL(); 


     if(p->init){ 

      SetLogicSignal(output); 
      p->start_time = act_time; 
      p->delta = ((p->period)/(2*p->T)); 
      p->init = FALSE; 

     } 

     if(((uint16_t)act_time - (uint16_t)(p->start_time)) >= ((uint16_t)(p->delta))){ 

      NegLogicSignal(output); // my defined function for negation of a bit variable 
      p->start_time = act_time; 

     } 

    }else{ 

     ClearLogicSignal(output); 
     p->init = TRUE; 

    } 

} 

振盪器狀態被存儲在如下結構

// oscillator state (oscillator with fixed duty cycle) 
typedef struct{ 
    float period;   // period of the oscillations (ms) 
    float T;    // function execution period (ms) 
    BOOL start;   // oscillator start signal (start==TRUE, stop==FALSE) 
    BOOL init;   // initiate the oscillator state 
    float delta;   // time after which expiration the oscillator output is negated 
    float start_time;  // captured Tmr_1ms value 
}Osc_t; 

下面的實例實現以下 軟件振盪器實現代碼

// oscillator instance init 
Test_Oscillator_state.T = 20; 
Test_Oscillator_state.period = 1000; 
Test_Oscillator_state.init = TRUE; 

// calling the function 
Test_Oscillator_state.start = TRUE; 
OSC(LTestBlink, &Test_Oscillator_state); 

的問題是在下面的代碼

if(((uint16_t)act_time - (uint16_t)(p->start_time)) >= ((uint16_t)(p->delta))){ 

      NegLogicSignal(output); 
      p->start_time = act_time; 

} 

輸出否定僅在Tmr_1ms溢出之前起作用。我不明白爲什麼。請有人給我任何指導?提前致謝。

+1

提供一個[mcve]並按[ask [。 「funcional」是什麼意思?沒有否定運算符,並且'NegLogicSignal'不是標準函數。學習使用調試器。 – Olaf

+0

您的代碼中沒有任何模運​​算符,因此不確定哪些模運算有問題? –

+0

我根本不知道你的問題是什麼。你的意思是說,一旦Tmr_1ms環繞着你,再也不會進入調用「NegLogicSignal(output)」的「if」語句了嗎? – Basya

回答

1

當行爲時間環繞時,從行爲時間減去開始時間是有問題的。你正在從較小的一個減去一個更大的無符號數,這不太可能讓你得到你想要的。如果這些是有符號的數字,則差異是負的;在無符號數字中,你會得到一些相當於負數的數字,這將是一個很大的無符號數(但顯然仍然小於以前保存的起始數值)。

您需要檢測並處理環繞。要麼有另一個寄存器類型值來指示環繞(在讀取時清除,或者在讀取時清除),或者有一個計算delta的函數,說明起始值比delta更接近最大值。然後計算差異的函數計算出正確的差異。

既然你已經把值浮動的變量,你可以不到unsigned int類型,然後環繞後,你會得到一個負數,清楚地表明瞭概括,並允許你來計算正確的差別。

看看this discussion of unsigned subtraction,它有進一步的解釋和建議。

最好的解決方案old_timer在評論中建議(old_timer,如果你想讓它成爲一個答案,並接受它,我會從我的答案中刪除這個)。將16位無符號值提升爲32位無符號值(float,如原始代碼中所做,可能但不需要或推薦)。用32位(或浮點)值進行相減。 經過之後的減法,將這些位掩碼回16位(按位和用0xFFFF或分配給一個無符號的16位變量)。然後減法運行,因爲算術是在32位(或浮點數)中完成的,它不會環繞。通過屏蔽高位來獲得「模數」效果。

+0

謝謝Basya Perlman的回答。我寫了類似的程序,其中Tmr_1ms變量已被16位硬件定時器/計數器的狀態所取代。我讀取某個任務開始時的計數器值(存儲在uint16_t prev_state變量中的值),然後在任務結束時讀取計數器值(存儲在uint16_t cur_state變量中的值)。以下語句返回適當的結果diff = cur_state - prev_state(其中diff是uint16_t)。請你能告訴我爲什麼在這種情況下,減法返回適當的結果。謝謝。我是一個autodidact。 – Steve

+0

我會再考慮一下,但乍一看,不,我不能告訴你它爲什麼起作用:-) - 我不會期待它,除非在那種情況下,你永遠不會得到包裝。 – Basya

+0

基於硬件定時器/計數器的結果,我用「軟件定時器」Tmr_1ms使用了相同的方法。由於無符號變量,我期望例如12-65528 = 20。硬件定時器/計數器被配置爲自由運行。現在我很困惑。 – Steve