C语言中的模运算

时间:2017-09-04 12:04:30

标签: c integer embedded unsigned

我在C语言中遇到模数算术问题。 我定义了全局变量uint16_t Tmr_1ms 每1毫秒递增一次。我想在这里使用这个变量 软件振荡器实现,在下面实现 给定功能

 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 个答案:

答案 0 :(得分:1)

从行为时间减去开始时间,当行动时间结束时,是有问题的。你从较小的一个中减去一个较大的无符号数,这不太可能给你你想要的。如果这些是签名号码,差异将是负面的;在无符号数字中,你会得到一些等于负数的东西,它将是一个很大的无符号数(但显然仍然小于你以前保存的起始值)。

您需要检测并处理环绕声。要么具有另一个寄存器类型值以指示环绕(在读取时清除,或者在读取时清除),或者具有计算增量注释的功能,即开始值比delta更接近最大值。然后计算差异的函数计算出正确的差异。

由于您已将值放在浮点变量中,您可以转换为unsigned int,然后在环绕后您将获得一个负数,清楚地指示环绕并允许您计算正确的差异。

看看this discussion of unsigned subtraction,它有进一步的解释和建议。

old_timer在评论中提出的最佳解决方案(old_timer,如果你想让它成为答案并接受它,我会从我的答案中删除它)。将16位无符号值提升为32位无符号值(浮点数,如原始代码中所做,可以但不需要或推荐)。使用32位(或浮点)值进行减法。 减法之后,将这些位屏蔽回16位(按位 - 并使用0xFFFF或分配给无符号的16位变量)。减法然后起作用,因为算法是在32位(或浮点数)中完成的,它不会回绕。通过屏蔽高位来获得“模”效应。