Answers:
简短的答案:您无法在Raspberry Pi上可靠地读取PWM。
读取PWM需要几微秒的精度(除非您正在读取非常慢的PWM),并且如果不修改内核模块,在Raspberry Pi上的Userland软件就无法使用。
捕获PWM的最简单方法是获得具有串行或I 2 C输出的任何廉价(<$ 0.5)微控制器,并将其连接到Raspberry Pi并从微控制器读取实际值。这将非常可靠且精确地工作。
我可以使用piGpio C库进行相当准确的脉冲宽度测量:http ://abyz.me.uk/rpi/pigpio/index.html
该库使您能够安装回调函数,该函数将在gpio引脚上的任何边沿转换时触发,并为每个转换提供微秒级的时间戳。不要以为您可以依靠微秒级的精度-但我的测试表明,精度至少为+/- 10us,也许更好。
比运行繁忙的循环轮询gpio来更改级别要好得多。
这是一个有趣的问题,您认为Google搜索没有提供明显的解决方案是正确的!(我想念Google可以在几秒钟内回答我想知道的关于我的学业/作业的任何事情的日子。)
我假设您了解PWM的原理。因此,我将不再赘述。但是,我相信您理论上可以通过一些巧妙的编码在常规数字输入引脚上读取PWM值。
我承认我自己还没有尝试过,但是您应该能够测量引脚为高电平的时间和引脚为低电平的时间(为您提供PWM读数),然后使用传感器供应商提供的任何数学公式将其转换为实际读数。
这种方法对我有用,适用于类似的问题,我需要从超声模块读取脉冲长度,然后将其转换为距离。我能想到的问题涉及确保可靠的读数!
如果您认为这会有所帮助,并且想要查看我用于超声模块的代码,请这样说,然后在我回家时将其复制。
我开始复制代码,但是由于某种原因,该网站一次只允许我复制一小部分(而且我太懒了,无法将我的pi从车库里拿出来),因此这里是其链接。忽略底部的大多数功能,因为它们与将模块用作接近传感器有关。http://pibot.webnode.com/products/ultrasonic-range-sensor/
长答案:您实际上可以!(在我们的朋友电阻器和电容器的帮助下)
您可以将PWM输出转换为模拟电压电平(DAC),并通过树莓派上的ADC引脚读取。
您需要一个4k7电阻和一个0.1uF电容器:
模拟该电路 –使用CircuitLab创建的原理图
上面的简单RC低通滤波器将PWM信号转换为与占空比成比例的电压,您的树莓派pi可以将其读取为模拟值。
尽管我的答案不是来自引脚,但您可以使用基于声卡示波器的东西来读取脉冲输入。
人们多年来一直在台式机中使用声卡来创建示波器。看来,使用现代的内部声卡,您可以获得高达10kHz的可用结果。使用Raspberry Pi USB连接的声卡,您的最大频率可能会更低。
这是一个适用于Linux的声卡示波器项目的示例:http : //www.yann.com/en/diy-turn-your-gnulinux-computer-into-a-free-oscilloscope-29/09/2010.html
我写的这个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()
使用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);
}
}
高精度简单解决方案:
将Arduino用作iic从设备或UART设备似乎工作得很好。微控制器能够通过pulseIn方法读取信息。
有关详细信息,请访问以下网址:https : //www.youtube.com/watch?v=ncBDvcbY1l4