1

这是一个学术问题(我不一定打算这样做),但我很好奇它是如何工作的。我正在考虑用户级软件(而不是硬件)解决方案。

我想产生 PWM 信号(假设为少量数字 GPIO 引脚,但超过 1 个)。我可能会编写一个创建 Pthread 的程序,然后在该线程中使用适当的 s 等在占空比上无限循环sleep()以获得正确的比例。

这不会严重破坏 CPU 吗?我想频率会在 100 Hz 左右。我以前没有做过这样的事情,但我可以想象不断循环、上下文切换等对于多任务处理或 CPU 使用来说不是很好。

在这种情况下使用和多任务处理有关 CPU 的任何建议?FWIW 我正在考虑单核处理器。我感觉答案的范围从“这将使您的系统无法使用”“所涉及的数字比对现代处理器产生影响的数量级要小几个数量级”

假设 C,因为它似乎最合适。

编辑:假设机器上的 Linux 或其他一些通用 POSIX 操作系统可以访问硬件 GPIO 引脚。

编辑:我认为我将如何实现带睡眠的 PWM 是显而易见的。为免生疑问,如下所示:

while (TRUE)
{
    // Set all channels high
    for (int c = 0; x < NUM_CHANNELS)
    {
        set_gpio_pin(c, 1);
    }

    // Loop over units within duty cycle
    for (int x = 0; x < DUTY_CYCLE_UNITS; x++)
    {   
        // Set channels low when their number is up
        for (int c = 0; x < NUM_CHANNELS)
        {
            if (x > CHANNELS[c])
            {
                set_gpio_pin(c, 0);
            }
        }

        sleep(DUTY_CYCLE_UNIT);
    }
}
4

7 回答 7

2

您并没有很清楚地说明这样做的最终目的,但是由于您已经标记了这个嵌入式和 pthreads,我将假设您有一个运行 linux 变体的专用芯片。

在这种情况下,我建议创建 PWM 输出的最佳方法是通过您的主程序循环,因为我假设 PWM 是更大控制应用程序的一部分。大多数简单的嵌入式应用程序(无 UI)可以在单个线程中运行,并定期更新主线程中的 GPIO。

例如:

InitIOs();

while(1)
{
   // Do stuff
   UpdatePWM();
}  

话虽如此,请检查您的芯片规格,在大多数嵌入式设备中,都有专用的 PWM 输出引脚(也可以用作 GPIO),并且可以通过设置占空比并根据需要更新占空比,在硬件中简单地配置这些引脚。在这种情况下,硬件将为您完成工作。

如果你能稍微澄清一下你的情况,我可能会给你一个更详细的答案。

于 2012-03-14T12:44:35.567 回答
2

如果可以,请使用驱动程序。如果您的嵌入式设备有一个 PWM 控制器,那很好,否则专用一个硬件定时器来生成 PWM 间隔和驱动 GPIO 引脚。

如果您必须在用户级别执行此操作,将进程/线程提高到高优先级并使用 sleep() 调用肯定会产生大量抖动和较差的脉冲宽度范围。

于 2012-03-14T13:18:58.110 回答
1

更好的方法可能是使用某种中断驱动的方法。我想这取决于你的系统,但 IIRC Arduino 使用 PWM 中断。

于 2012-03-14T12:27:30.917 回答
1

从用户空间来看,100Hz 似乎是可行的。典型的 OS 任务调度器时间片也大约为 10 毫秒,因此您的 CPU 将在该时间间隔内进行多任务处理。您可能希望使用高进程优先级(低 niceness)来确保睡眠不会超出(过多),并跟踪实际的挂钟时间,并可能根据该反馈调整您的睡眠值以避免漂移。您还需要确保内核在您的硬件上为此使用的计时器具有足够高的分辨率!

如果您的 RAM 非常低并且交换量很大,您可能会遇到程序被分页到磁盘的问题。此外,如果内核正在执行其他 CPU 密集型工作,这也会引入不可接受的延迟。(其他,较低优先级的用户空间任务应该没问题)如果保持频率恒定至关重要,那么最好在内核中解决这个问题(甚至运行实时内核)。

于 2012-03-14T13:18:46.990 回答
1

使用线程并在不是 RTOS 的操作系统上休眠不会产生非常准确或一致的结果。

更好的方法是使用定时器中断并在 ISR 中切换 GPIO。与在硬件定时器上使用硬件 PWM 输出不同,这种方法允许您将单个定时器用于多个信号和其他用途。您可能仍然会看到更多的抖动,硬件 PWM 和实际频率范围和脉冲分辨率会低得多,这是硬件可实现的,但至少抖动将在微秒而不是毫秒的数量级。

于 2012-03-14T16:13:22.253 回答
1

如果您有定时器,您可以将其设置为在每次需要新的 PWM 边沿时触发中断。通过一些巧妙的编码,您可以将它们排队,以便中断处理程序知道许多 PWM 通道中的哪一个以及是否需要高电平或低电平沿,然后自行安排下一个所需的沿。

If you have enough of these timers, then its even easier as you can allocate one per PWM channel.

On an embedded controller with a low-latency interrupt response, this can produce surprisingly good results.

于 2012-03-15T11:07:12.387 回答
0

我不明白你为什么要在软件中使用中断服务和软件交互将引入的所有固有时序抖动进行 PWM(例如,当中断被禁用时 PWM 中断命中,处理器正在为长的不间断指令提供服务,或其他服务程序处于活动状态)。大多数现代微控制器(ARM-7、ARM Cortex-M、AVR32、MSP...)都有定时器,可以配置为产生或专用于 PWM 发生器。这些将产生多个稳定的 PWM 信号,一旦设置,需要零处理器输入来保持运行。可以配置这些 PWM 输出,使两个信号不重叠或同时具有应用所需的边沿。

如果您依靠操作系统睡眠功能来设置 PWM 边沿之间的时间,那么这将运行缓慢。睡眠功能将设置任务激活之间的最短时间,并且这些之间的时间将因任务切换、更高优先级线程的存在或其他内核函数运行而延迟。

于 2012-03-14T14:10:43.227 回答