制作 32 位计数器时出现全局变量问题 [英] Issue with global variable while making 32-bit counter

查看:19
本文介绍了制作 32 位计数器时出现全局变量问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to do quadrature decoding using atmel xmega avr microcontroller. Xmega has only 16-bit counters. And in addition I have used up all the available timers.

现在要制作 32 位 计数器,我使用了一个 16 位 计数器,并在其 溢出/欠流中断 中增加/递减一个 16 位全局变量,以便通过组合它们我们可以生成 32 位计数器.

Now to make 32-bit counter I have used one 16-bit counter and in its over/under flow interrupt I have increment/decrement a 16-bit global variable, so that by combining them we can make 32-bit counter.

ISR(timer_16bit)
{

   if(quad_enc_mov_forward)
    {
      timer_over_flow++;
    }

   else if (quad_enc_mov_backward)
    {
      timer_over_flow--;
    }
}

到目前为止,它工作正常.但我需要在并行运行的各种任务中使用这个 32 位值.我正在尝试读取 32 位值,如下所示

so far it is working fine. But I need to use this 32-bit value in various tasks running parallel. I'm trying to read 32-bit values as below

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_flowcurrent_count 以及添加 timer_16bit_count 时> 可能出现溢出,16bit 计时器可能已变为 0.这可能会导致总的错误值.

Now the problem I am facing is when I read the read timer_over_flow to current_count in the first statement and by the time I add the timer_16bit_count there may be overflow and the 16bit timer may have become zero. This may result in taking total wrong value.

我正在尝试在多个任务中读取这个 32 位值.

And I am trying to read this 32-bit value in multiple tasks .

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

Is there a way to prevent this data corruption and get the working model of 32-bit value.

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

  1. 我的电机可以向前或向后移动,并相应地计数器递增/递减.

  1. My motor can move forward or backward and accordingly counter increments/decrements.

在 ISR 的情况下,在启动我的电机之前,我正在设置全局变量(quad_enc_mov_forward & quad_enc_mov_backward),以便在发生溢出时/underflow timer_over_flow 会相应改变.

In case of ISR, before starting my motor I'm making the global variables(quad_enc_mov_forward & quad_enc_mov_backward) set so that if there is a overflow/underflow timer_over_flow will get changed accordingly.

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

Variables that are modified in the ISR are declared as volatile.

多任务意味着我使用的 RTOS 内核包含大约 6 个任务(大部分是 3 个并行运行的任务).

Multiple tasks means that I'm using RTOS Kernel with about 6 tasks (mostly 3 tasks running parallel).

在 XMEGA 中,我直接读取 TCCO_CNT 寄存器的低字节.

In the XMEGA I'm directly reading TCCO_CNT register for the lower byte.

推荐答案

一个解决方案是:

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 必须中断此代码.

Per comment from user5329483, this must not be used with interrupts disabled, since the hardware counter fetched into b may be changing while the interrupt service routine (ISR) that modifies timer_over_flow would not run if interrupts are disabled. It is necessary that the ISR interrupt this code if a wrap occurs during it.

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

This gets the counters and checks whether the high word changed. If it did, this code tries again. When the loop exits, we know the low word did not wrap during the reads. (Unless there is a possibility we read the high word, then the low word wrapped, then we read the low word, then it wrapped the other way, then we read the high word. If that can happen in your system, an alternative is to add a flag that the ISR sets when the high word changes. The reader would clear the flag, read the timer words, and read the flag. If the flag is set, it tries again.)

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

Note that timer_over_flow, timer_16bit_count, and the flag, if used, must be volatile.

如果不能发生两次换行的情况,则可以消除循环:

If the wrap-two-times scenario cannot happen, then you can eliminate the loop:

  • 如上阅读abc.
  • 比较 b0x8000.
  • 如果 b 的值很高,要么没有回绕,要么在向上回绕之前读取(0xffff 为 0),要么在向下回绕之后读取.使用 ac 中的较低者.
  • 否则,要么没有回绕,b 在向上回绕之后读取,或者在向下回绕之前读取.使用 ac 中较大的一个.
  • Read a, b, and c as above.
  • Compare b to 0x8000.
  • If b has a high value, either there was no wrap, it was read before a wrap upward (0xffff to 0), or it was read after a wrap downward. Use the lower of a or c.
  • Otherwise, either there was no wrap, b was read after a wrap upward, or it was read before a wrap downward. Use the larger of a or c.

这篇关于制作 32 位计数器时出现全局变量问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆