Raspberry Pi中的PWM输入


10

有没有办法从Raspberry Pi的引脚上读取PWM信号?

我尝试使用Google搜索,但只找到PWM 输出,而不是input

Answers:


4

简短的答案:您无法在Raspberry Pi上可靠地读取PWM。

读取PWM需要几微秒的精度(除非您正在读取非常慢的PWM),并且如果不修改内核模块,在Raspberry Pi上的Userland软件就无法使用。

捕获PWM的最简单方法是获得具有串行或I 2 C输出的任何廉价(<$ 0.5)微控制器,并将其连接到Raspberry Pi并从微控制器读取实际值。这将非常可靠且精确地工作。


1
知道从哪里获得这样的IC吗?
2015年

@Pepijn您正在寻找的是一个模数转换器(ADC)。我经常使用的非常常见的一个是MCP3008 8通道10位单元,而在我的Perl软件的Pi测试单元中永久使用的另一个是ADS1115 4通道16位单元。后者需要一些焊接工作,而前者则不需要。有很多可以同时使用这两个单元(C,Python,Perl等)的代码示例,因此,如果您不想/不能编写自己的代码,则开始时应该很简单。
stevieb

任何简单的微控制器都可以。我曾经将Microchip产品用于此类事情。Arduino的问世使AVR芯片再次流行起来。现在,我只使用一个包含微控制器以及芯片所需寿命支持的小型转接板。我最喜欢的是Teensy 3.x系列。
NomadMaker

3

我可以使用piGpio C库进行相当准确的脉冲宽度测量:http ://abyz.me.uk/rpi/pigpio/index.html

该库使您能够安装回调函数,该函数将在gpio引脚上的任何边沿转换时触发,并为每个转换提供微秒级的时间戳。不要以为您可以依靠微秒级的精度-但我的测试表明,精度至少为+/- 10us,也许更好。

比运行繁忙的循环轮询gpio来更改级别要好得多。


+1可能值得注意的是,精度可能会因CPU负载(尤其是单核)而有所不同,但否则会给出一个很好的答案。:)
Jacobm001

谢谢史蒂夫,这个答案比说“做不到”要好得多。请参阅我单独的答案以获取更多信息,包括实际代码(这很短)。
乔治

2

这是一个有趣的问题,您认为Google搜索没有提供明显的解决方案是正确的!(我想念Google可以在几秒钟内回答我想知道的关于我的学业/作业的任何事情的日子。)

我假设您了解PWM的原理。因此,我将不再赘述。但是,我相信您理论上可以通过一些巧妙的编码在常规数字输入引脚上读取PWM值。

我承认我自己还没有尝试过,但是您应该能够测量引脚为高电平的时间和引脚为低电平的时间(为您提供PWM读数),然后使用传感器供应商提供的任何数学公式将其转换为实际读数。

这种方法对我有用,适用于类似的问题,我需要从超声模块读取脉冲长度,然后将其转换为距离。我能想到的问题涉及确保可靠的读数!

如果您认为这会有所帮助,并且想要查看我用于超声模块的代码,请这样说,然后在我回家时将其复制。

我开始复制代码,但是由于某种原因,该网站一次只允许我复制一小部分(而且我太懒了,无法将我的pi从车库里拿出来),因此这里是其链接。忽略底部的大多数功能,因为它们与将模块用作接近传感器有关。http://pibot.webnode.com/products/ultrasonic-range-sensor/


看到代码很不错,所以我可以获得一个基础来启动自己的代码,如果您可以在此处粘贴,我会非常感激^^
Caio Keto 2013年

该建议的问题在于Linux内核没有给您足够的时间来足够精确地读取典型的RC PWM占空比(通常每16毫秒为1000-2000微秒)。如果我们可以在内核模块中安装用于GPIO引脚更改的中断处理程序,并捕获高/低转换时的时间戳,那么这可能是一个有用的解决方案。
乔恩·瓦特

1

长答案:您实际上可以!(在我们的朋友电阻器和电容器的帮助下)

您可以将PWM输出转换为模拟电压电平(DAC),并通过树莓派上的ADC引脚读取。

您需要一个4k7电阻和一个0.1uF电容器:

原理图

模拟该电路 –使用CircuitLab创建的原理图

上面的简单RC低通滤波器将PWM信号转换为与占空比成比例的电压,您的树莓派pi可以将其读取为模拟值。


4
ADC引脚?那会是什么呢?
加纳马马

@Ghanima好吧,新的Microsoft Lightning驱动程序正在开发中,但可以很好地达到此目的(在其页面上有记录)。对于我发现的BCM2837,它可能具有一个位于GPIO0上的硬件ADC(可悲的是,这个ADC未链接至任何插头引脚)..至少他们链接了硬件pwm通道
Quest

0

如果您对慢速响应感到满意,则可以通过欠采样来读取快速PWM。只需循环读取GPIO并应用低通滤波器即可。每个周期读取1的概率与脉冲宽度成正比。一个易于实现的IIR低通滤波器是:

double acc=0.5;
const double k=0.01;
for(;;) {
  bool x=GPIO.read();
  acc+=k*(x?1:0-acc);
}

随着k的减小,分辨率提高,但是带宽减小。


0

尽管我的答案不是来自引脚,但您可以使用基于声卡示波器的东西来读取脉冲输入。

人们多年来一直在台式机中使用声卡来创建示波器。看来,使用现代的内部声卡,您可以获得高达10kHz的可用结果。使用Raspberry Pi USB连接的声卡,您的最大频率可能会更低。

这是一个适用于Linux的声卡示波器项目的示例:http : //www.yann.com/en/diy-turn-your-gnulinux-computer-into-a-free-oscilloscope-29/09/2010.html


0

我写的这个Python脚本对读取RC接收器的PWM信号非常有效。正如已经指出的那样,高频PWM信号显然不起作用。

我直接将RC接收器的十个信号输出引脚连接到Raspberry GPIO引脚。接收器由RPI的+ 5V和GND引脚供电。

我简化了脚本,因为它还有很多其他功能,如果您发现任何错误或遗漏,请告诉我

import RPi.GPIO as GPIO
import time
import numpy as np
inPINS = [2,3,4,14,15,18,17,27,22,23]
smoothingWindowLength=4

def getTimex():
    return time.time()

GPIO.setup(inPINS, GPIO.IN)
upTimes = [[0] for i in range(len(inPINS))]
downTimes = [[0] for i in range(len(inPINS))]
deltaTimes = [[0] for i in range(len(inPINS))]

def my_callback1(channel):
  i = inPINS.index(channel)
  v = GPIO.input(inPINS[i])
  #GPIO.output(outPINS[0], v) # mirror input state to output state directly (forward servo value only) - don't set PWM then for this pin
  if (v==0):
    downTimes[i].append(getTimex())
    if len(downTimes[i])>smoothingWindowLength: del downTimes[i][0]
  else:
    upTimes[i].append(getTimex())
    if len(upTimes[i])>smoothingWindowLength: del upTimes[i][0]
  deltaTimes[i].append( (downTimes[i][-1]-upTimes[i][-2])/(upTimes[i][-1]-downTimes[i][-1]) )
  if len(deltaTimes[i])>smoothingWindowLength: del deltaTimes[i][0]

GPIO.add_event_detect(inPINS[0], GPIO.BOTH, callback=my_callback1)
GPIO.add_event_detect(inPINS[1], GPIO.BOTH, callback=my_callback1)

try:
  while True:
    ovl = deltaTimes[0][-smoothingWindowLength:] # output first pin PWM
    ov = sorted(ovl)[len(ovl) // 2] #ov = np.mean(ovl)
    print ov
    time.sleep(0.1)
except KeyboardInterrupt:
  GPIO.cleanup()

0

使用Pigpio C库在Raspberry Pi上读取PWM输入非常有可能并且相对容易。如果您想要良好的性能,我建议您使用C而不是Python。我在下面提供了一些简短的示例代码。与某些人所说的相反,它具有出色的定时性能和相当低的抖动。RPi 3 B上的读数始终在5 us以内,它可以测量短至5 us的脉冲。请注意,所提供的代码仅是概念证明,不能正确处理没有脉冲(0%/ 100%占空比)或每72分钟发生一次“滴答”环绕声的情况。该程序在用户模式下运行良好,但为了最大程度地抵抗定时故障,请以负的好水平运行程序,如下所示:sudo nice -n -20 ./program

请参阅以下网站上的Pigpio文档:http://abyz.me.uk/rpi/pigpio/pdif2.html

#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include "pigpiod_if2.h"

static uint32_t rise_tick = 0;    // Pulse rise time tick value
static uint32_t pulse_width = 0;  // Last measured pulse width (us)

// Callback function for measuring PWM input
void pwm_cbfunc(int pi, unsigned user_gpio, unsigned level, uint32_t tick) {
    if (level == 1) {  // rising edge
        rise_tick = tick;
    }
    else if (level == 0) {  // falling edge
        pulse_width = tick - rise_tick;  // TODO: Handle 72 min wrap-around
    }
}

int main(int argc, char **argv)
{
    const unsigned int pwm_in = 23; // GPIO Pin # for PWM in, change as reqd

    int pi = pigpio_start(0, 0);
    if (pi < 0) {
        fprintf(stderr, "pigpio initialization failed (%d)\n", pi);
        return pi;
    }

    // Set up callback for PWM input 
    callback(pi, pwm_in, EITHER_EDGE, pwm_cbfunc);

    while (true) {
        printf("PWM pulse width: %u\n", pulse_width);
        usleep(500000);
    }
}

-3

高精度简单解决方案:

将Arduino用作iic从设备或UART设备似乎工作得很好。微控制器能够通过pulseIn方法读取信息。

有关详细信息,请访问以下网址https : //www.youtube.com/watch?v=ncBDvcbY1l4


欢迎来到Raspberry Pi!虽然从理论上讲这可以回答问题,但最好在此处包括答案的基本部分,并提供链接以供参考。我们正在尝试针对此处无信息的仅链接答案的新政策。如果该帖子未经过编辑以包含可以作为答案的信息(无论是最少的信息),那么它将在48小时内转换为Community Wiki,以简化由社区更正的信息。
加纳玛
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.