2017-09-04 59 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