c - 制作 32 位计数器时出现全局变量问题

标签 c embedded microcontroller

我正在尝试使用 atmel xmega avr 微 Controller 进行正交解码。 Xmega 只有 16 位 计数器。此外,我已经用完了所有可用的计时器。

现在制作32位计数器我使用了一个16位计数器并且在它的溢出/欠流中断中我有递增/decrement 一个 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 读取到 current_count 时,我添加了 timer_16bit_count 可能发生溢出,16 位 计时器可能已变为。这可能会导致采用完全错误的值(value)。

我正试图在多个任务中读取这个 32 位值。

有没有办法防止这种数据损坏并获得 32 位值的工作模型。

不同成员寻求的详细信息:

  1. 我的电机可以向前或向后移动,并相应地计算增量/减量。

  2. 在 ISR 的情况下,在启动我的电机之前,我设置了全局变量(quad_enc_mov_forward & quad_enc_mov_backward),以便在出现溢出时/underflow timer_over_flow 将相应更改。

  3. 在 ISR 中修改的变量被声明为 volatile

  4. 多任务意味着我使用 RTOS 内核处理大约 6 个任务(主要是 3 个并行运行的任务)。

  5. 在 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;

来自 user5329483 的评论, 这不能与禁用中断一起使用,因为提取到 b 的硬件计数器可能会发生变化,而修改 timer_over_flow 的中断服务例程 (ISR) 如果中断将不会运行被禁用。如果在此期间发生回绕,则 ISR 有必要中断此代码。

这会获取计数器并检查高位字是否发生了变化。如果是,此代码将重试。当循环退出时,我们知道低位字在读取期间没有回绕。 (除非有可能我们读取高字,然后包装低字,然后我们读取低字,然后以另一种方式包装,然后我们读取高字。如果您的系统中可能发生这种情况,另一种选择是添加一个标志,ISR 在高位字更改时设置该标志。读取器将清除标志,读取定时器字,然后读取标志。如果设置了标志,它会再次尝试。)

请注意,timer_over_flowtimer_16bit_count 和标志(如果使用)必须是 volatile

如果 wrap-two-times 场景不会发生,那么你可以消除循环:

  • 如上所述阅读abc
  • b0x8000 进行比较。
  • 如果 b 有一个高值,要么没有换行,它是在向上换行之前读取的(0xffff 到 0),或者是在向下换行之后读取的。使用 ac 中较小的一个。
  • 否则,要么没有换行,b 是在向上换行后读取的,或者是在向下换行之前读取的。使用 ac 中较大的一个。

关于c - 制作 32 位计数器时出现全局变量问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48513086/

相关文章:

c - dlfunc 的可移植性?

使用 clang 编译程序时,可以在 gdb 中扩展 C 宏吗?

c - 错误 : invalid conversion from ‘void*’ to ‘arguments*’ [-fpermissive]

c - 数据未存储在 EEPROM 中

C:删除新行/空终止输入字符串

c - 在为微 Controller 编译 C 程序时,编译器放置的那些额外的汇编代码是什么?

c - 在 C 中使用双哈希 (##)

assembly - 如何检查 Cortex M3 是否启用了中断?

algorithm - 什么是在线降尺度算法?

c - AVR 模拟器中的意外指针重新分配