C语言中的模运算
Modulo arithmetic in C language
我对 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 溢出之前起作用。我不明白为什么。请问有人可以给我任何指导吗?提前致谢。
当动作时间回绕时,从动作时间减去开始时间是有问题的。您正在从一个较小的无符号数中减去一个较大的无符号数,这不太可能给您想要的结果。如果这些是带符号的数字,则差异将为负;在无符号数中,你会得到一些位等价于负数的东西,这将是一个大的无符号数(但显然仍然小于你之前保存的起始值)。
您需要检测并处理回绕。要么有另一个寄存器类型值来指示环绕(在读取时清除,或者在读取时清除),或者有一个函数来计算 delta 注意起始值比 delta 更接近最大值。然后计算差异的函数计算出正确的差异。
因为你已经把值放在浮点变量中,你可以不转换为unsigned int,然后在环绕之后你会得到一个负数,清楚地表明环绕并允许您计算出正确的差异。
看看this discussion of unsigned subtraction,里面有进一步的解释和建议。
评论中建议的最佳解决方案old_timer(old_timer,如果您想将其作为答案并接受它,我将从我的答案中删除它)。将 16 位无符号值提升为 32 位无符号值(浮点数,如在原始代码中所做的那样,是可能的,但不需要或不推荐)。使用 32 位(或浮点数)值进行减法。 在 减法之后,将这些位屏蔽回 16 位(按位与 0xFFFF 或分配给无符号的 16 位变量)。然后减法起作用,因为算术是在 32 位(或浮点数)中完成的,不会回绕。 "modulo" 效果是通过屏蔽掉高位得到的。
我对 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 溢出之前起作用。我不明白为什么。请问有人可以给我任何指导吗?提前致谢。
当动作时间回绕时,从动作时间减去开始时间是有问题的。您正在从一个较小的无符号数中减去一个较大的无符号数,这不太可能给您想要的结果。如果这些是带符号的数字,则差异将为负;在无符号数中,你会得到一些位等价于负数的东西,这将是一个大的无符号数(但显然仍然小于你之前保存的起始值)。
您需要检测并处理回绕。要么有另一个寄存器类型值来指示环绕(在读取时清除,或者在读取时清除),或者有一个函数来计算 delta 注意起始值比 delta 更接近最大值。然后计算差异的函数计算出正确的差异。
因为你已经把值放在浮点变量中,你可以不转换为unsigned int,然后在环绕之后你会得到一个负数,清楚地表明环绕并允许您计算出正确的差异。
看看this discussion of unsigned subtraction,里面有进一步的解释和建议。
评论中建议的最佳解决方案old_timer(old_timer,如果您想将其作为答案并接受它,我将从我的答案中删除它)。将 16 位无符号值提升为 32 位无符号值(浮点数,如在原始代码中所做的那样,是可能的,但不需要或不推荐)。使用 32 位(或浮点数)值进行减法。 在 减法之后,将这些位屏蔽回 16 位(按位与 0xFFFF 或分配给无符号的 16 位变量)。然后减法起作用,因为算术是在 32 位(或浮点数)中完成的,不会回绕。 "modulo" 效果是通过屏蔽掉高位得到的。