使用C++ libgpiod计算事件之间的间隔和速度

问题描述 投票:0回答:1

我在 C++ 上使用

libpgid
来根据 GPIO 事件计算 RPM。

这个想法是从给定的 GPIO 线路读取所有

RISING_EDGE
事件并递增计数器(脉冲计数器)。计数器有 3 个属性:

typedef struct counter_t
{
    unsigned long count;           // Incremented on every RISING_EDGE pulse
    unsigned long start_timestamp; // Timestamp of the first event pulse read
    unsigned long last_timestamp;  // Timestamp of the last event pulse read
}

因此,在从

gpiod
读取的每个事件中,我都会:

auto event = line.event_read();
if (event.event_type == GPIOD_LINE_EVENT_RISING_EDGE)
{
    counter->count++;
    if (counter->start_timestamp == 0) counter->start_timestamp = event.timestamp;
    counter->last_timestamp = event.timestamp;
}

它在监听新事件并更新计数器的线程上运行。一切正常 - 我的计数器正在正确增加。

我的问题出现在 RPM 计算上。

为此,我以 100 毫秒的固定间隔运行另一个线程,该线程读取计数器、计算 RPM 并重置计数器,如下所示:

void thread_loop()
{
    std::cout << "Start thread" << std::endl;

    bool first_run = true;

    while (true)
    {
        if (!first_run)
        {
            // Get interval
            unsigned long interval = counter->last_timestamp - counter->start_timestamp;

            // Calculate speed
            double speed = (counter->count / interval) * 600000000;  //calculates speed

            // Print results
            std::cout << "SPEED: " << speed << std::endl;
            std::cout << "COUNTER: " << counter->count << std::endl;
            std::cout << "COUNTER START TIMESTAMP: " << counter->start_timestamp << std::endl;
            std::cout << "COUNTER: LAST TIMESTAMP: " << counter->last_timestamp << std::endl;
            std::cout << "INTERVAL: " << interval << std::endl;

            // Reset counter
            counter->reset(); // Sets count, start_timestamp and last_timestamp to 0
        }

        first_run = false;

        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

对于给定的输出,我的速度不一致:

SPEED: 0
COUNTER: 40
COUNTER START TIMESTAMP: 13953904635016
COUNTER: LAST TIMESTAMP: 13956976823743
INTERVAL: 3072188727

根据我的理解,所有

libgpiod
事件都是基于毫秒的,因此 3072188727 相当于 3072 毫秒,但我的线程以 100 毫秒的间隔运行(我预计不完全是这个值,而是大约这个值,而不是 30 次)。机器中没有运行其他任何东西,代码没有过载。

此外,速度计算始终为零。

我想我对

libgpiod
转换的理解或转换有问题,但不知道出了什么问题。我搜索了
libgpiod
文档
但找不到任何详细的解释。

所以,这是我的问题:

a) 我如何解释

event.timestamp
中的
libgpiod
。这是一个
time_point
事件吗?纪元日期时间?是绝对的日期和时间吗?

b) 如何计算两个

libgpiod
事件之间的时间间隔(以纳秒为单位)?

c) 如何将此间隔转换为速度 (RPM) 计算?

c++ embedded embedded-linux libgpiod
1个回答
0
投票

有很多问题:

  1. 您尚未显示

    counter
    的声明,但必须声明
    volatile
    ,因为它是在独立执行线程中读写的。

  2. 在进行非原子访问时,还必须防止异步更改。例如,互斥锁或自旋锁。即使单个成员也可能不是原子的,例如 64 位

    unsigned long
    (在 Linux 上)在 32 位系统上不会是原子的。

  3. Linux 不是实时操作系统,无法保证您的 GPIO 轮询线程能够捕获所有输入状态更改。可能是由其他线程或进程提示的时间长于脉冲周期。

最后一个问题显然不是您所显示的严重错误的原因,但有时它会导致大多数小错误,并且肯定会限制可以检测到的最大转速。您期望的最大“事件率”是多少?

© www.soinside.com 2019 - 2024. All rights reserved.