概括
我正在尝试为MC9S12VR 微控制器编写嵌入式应用程序。这是一个 16 位微控制器,但我处理的一些值是 32 位宽,在调试时,我捕获了一些异常值,这些值似乎是由于读取撕裂造成的。
我正在用 C89 为这个微控制器编写固件并通过飞思卡尔 HC12 编译器运行它,我想知道是否有人对如何在这个特定的微控制器上防止它们有任何建议,假设是这种情况。
细节
我的部分应用程序涉及驱动电机并根据编码器产生的脉冲估计其位置和速度(电机每转一圈就会产生一个脉冲)。
为此,我需要配置一个 MCU 定时器,以便跟踪脉冲之间经过的时间。然而,定时器的时钟频率为 3 MHz(预分频后),定时器计数器寄存器只有 16 位,因此计数器每 ~22ms 溢出一次。作为补偿,我设置了一个在定时器计数器溢出时触发的中断处理程序,这会将“溢出”变量增加 1:
// TEMP
static volatile unsigned long _timerOverflowsNoReset;
// ...
#ifndef __INTELLISENSE__
__interrupt VectorNumber_Vtimovf
#endif
void timovf_isr(void)
{
// Clear the interrupt.
TFLG2_TOF = 1;
// TEMP
_timerOverflowsNoReset++;
// ...
}
然后我可以从中计算出当前时间:
// TEMP
unsigned long MOTOR_GetCurrentTime(void)
{
const unsigned long ticksPerCycle = 0xFFFF;
const unsigned long ticksPerMicrosecond = 3; // 24 MHZ / 8 (prescaler)
const unsigned long ticks = _timerOverflowsNoReset * ticksPerCycle + TCNT;
const unsigned long microseconds = ticks / ticksPerMicrosecond;
return microseconds;
}
在main.c
中,我临时编写了一些调试代码,以一个方向驱动电机,然后定期拍摄各种数据的“快照”:
// Test
for (iter = 0; iter < 10; iter++)
{
nextWait += SECONDS(secondsPerIteration);
while ((_test2Snapshots[iter].elapsed = MOTOR_GetCurrentTime() - startTime) < nextWait);
_test2Snapshots[iter].position = MOTOR_GetCount();
_test2Snapshots[iter].phase = MOTOR_GetPhase();
_test2Snapshots[iter].time = MOTOR_GetCurrentTime() - startTime;
// ...
在这个测试中,我MOTOR_GetCurrentTime()
在两个非常接近的地方阅读代码并将它们分配给全局可用结构的属性。
在几乎所有情况下,我发现第一个读取的值比 while 循环应该终止的点多几微秒,而第二次读取是在那之后几微秒 - 这是预期的。但是,有时我发现第一次读取明显高于 while 循环应该终止的点,然后第二次读取小于第一个值(以及终止值)。
下面的屏幕截图给出了一个例子。在我能够重现它之前,我花了大约 20 次重复测试。在代码中,<snapshot>.elapsed
是之前写入的,<snapshot>.time
因此我希望它的值略小:
对于snapshot[8]
,我的应用程序首先读取20010014
(超过应该终止忙循环的 10 毫秒),然后读取19988209
. 正如我上面提到的,每 22 毫秒发生一次溢出 - 具体来说,_timerOverflowsNoReset
一个单位的差异将产生65535 / 3
计算出的微秒值的差异。如果我们考虑到这一点:
40 的差异与我在其他读取对之间看到的差异(~23/24)相差不远,所以我的猜测是,涉及到_timerOverflowsNoReset
. 就像在 while busy-looping 中一样,它会执行一次调用MOTOR_GetCurrentTime()
,错误地认为_timerOverflowsNoReset
比实际值大一,导致循环提前结束,然后在下一次读取时再次看到正确的值。
我的应用程序有其他问题,我无法确定,我希望如果我解决了这个问题,如果它们有类似的原因,它也可以解决这些其他问题。
编辑:在其他更改中,_timerOverflowsNoReset
在我现在拥有的实现中,我已经将其他一些全局变量从 32 位无符号更改为 16 位无符号。