我正在尝试做正交解码 using 爱特梅尔 Xmega AVR微控制器。 Xmega只有16-bit
柜台。另外,我已经用完了所有可用的计时器。
现在要做32-bit
柜台我用过一个16-bit
柜台并在其over/under flow interrupt
我增加/减少了一个 16 位全局变量,这样通过组合它们我们可以制作 32 位计数器。
ISR(timer_16bit)
{
if(quad_enc_mov_forward)
{
timer_over_flow++;
}
else if (quad_enc_mov_backward)
{
timer_over_flow--;
}
}
到目前为止,一切正常。但我需要在并行运行的各种任务中使用这个 32 位值。我正在尝试读取 32 位值,如下所示
uint32_t current_count = timer_over_flow;
current_count = current_count << 16;
current_count = current_count + timer_16bit_count;
`timer_16_bit_count` is a hardware register.
现在我面临的问题是当我阅读时timer_over_flow
to current_count
在第一个语句中,当我添加时timer_16bit_count
可能会出现溢出并且16bit
计时器可能已经成为zero
。这可能会导致得出总错误值。
我正在尝试在多个任务中读取这个32位值。
有没有办法防止这种数据损坏并获得 32 位值的工作模型。
不同会员寻求的详细信息:
我的电机可以向前或向后移动,并相应地计数增量/减量。
如果是 ISR,在启动电机之前我会创建全局变量(quad_enc_mov_forward
& quad_enc_mov_backward
) 设置以便如果存在上溢/下溢timer_over_flow
将得到相应的改变。
在 ISR 中修改的变量声明为volatile
.
多个任务意味着我使用 RTOS 内核来执行大约 6 个任务(主要是 3 个并行运行的任务)。
在XMEGA中我直接阅读TCCO_CNT
寄存器的低字节。
一种解决方案是:
uint16_t a, b, c;
do {
a = timer_over_flow;
b = timer_16bit_count;
c = timer_over_flow;
} while (a != c);
uint32_t counter = (uint32_t) a << 16 | b;
每条评论来自用户5329483 https://stackoverflow.com/users/5329483/user5329483,这不能在禁用中断的情况下使用,因为硬件计数器被取入b
修改中断服务程序(ISR)时可能会发生变化timer_over_flow
如果中断被禁用,则不会运行。如果在此代码期间发生换行,ISR 必须中断该代码。
这会获取计数器并检查高位字是否发生变化。如果是,此代码会再次尝试。当循环退出时,我们知道低位字在读取期间没有换行。 (除非我们有可能读取高位字,然后将低位字换行,然后我们读取低位字,然后以另一种方式换行,然后我们读取高位字。如果这种情况发生在您的系统中,另一种选择是添加一个标志,当高位字改变时,ISR 设置该标志。读取器将清除该标志,读取定时器字,然后读取该标志。如果该标志已设置,则会再次尝试。)
注意timer_over_flow
, timer_16bit_count
,并且该标志(如果使用)必须是volatile
.
如果两次换行的情况不会发生,那么您可以消除循环:
- Read
a
, b
, and c
如上。
- Compare
b
to 0x8000
.
- If
b
具有较高值,要么没有换行,要么在向上换行之前读取(0xffff 到 0),要么在向下换行之后读取。使用较低者a
or c
.
- 不然要么没有包装,
b
是在向上换行之后读取的,还是在向下换行之前读取的。使用较大的a
or c
.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)