Respuestas:
La respuesta corta: NO PUEDE leer PWM de manera confiable en Raspberry Pi.
Leer PWM requiere una precisión de microsegundos (a menos que esté leyendo un PWM muy, muy lento), y eso no está disponible en Raspberry Pi para el software del usuario sin modificar los módulos del núcleo.
La forma más fácil de capturar PWM sería obtener un microcontrolador barato (<$ 0.5) con salida serial o I 2 C y conectarlo a su Raspberry Pi y leer los valores reales del microcontrolador. Esto funcionará de manera muy confiable y es bastante preciso.
Puedo hacer una medición de ancho de pulso bastante precisa utilizando la biblioteca piGpio C: http://abyz.me.uk/rpi/pigpio/index.html
Esta biblioteca le permite instalar una función de devolución de llamada que se activará en cualquier transición de borde en un pin gpio y le proporciona una marca de tiempo de nivel de microsegundos para cada transición. No creo que pueda contar con esto para una precisión de microsegundos, pero mis pruebas sugieren que la precisión es de al menos +/- 10us, tal vez mejor.
Mucho mejor que ejecutar un bucle ocupado sondeando un gpio para que el nivel cambie usted mismo.
¡Esta es una pregunta interesante y correcta al decir que la Búsqueda de Google no proporciona una solución obvia! (Extraño los días en que Google podía responder cualquier cosa que quisiera saber para mis estudios / tareas en cuestión de segundos).
Supongo que entiendes los principios de PWM . Por lo tanto, no voy a entrar en eso. Sin embargo, creo que en teoría podría leer un valor PWM en un pin de entrada digital normal con un poco de codificación inteligente.
Admito que no lo he intentado yo mismo, pero deberías poder medir el tiempo que el pin es alto y el tiempo que es bajo (lo que te da la lectura PWM) y luego usar cualquier fórmula matemática que proporcione el proveedor del sensor para convertir esto a la lectura real.
Este método funciona para mí en un problema similar en el que necesitaba leer la longitud del pulso desde un módulo ultrasónico y luego convertirlo a distancia. ¡Los problemas que puedo imaginar implican garantizar lecturas confiables!
Si cree que ayudará y desea ver el código que utilicé para el módulo ultrasónico, dígalo y lo copiaré cuando llegue a casa.
Comencé a copiar el código, pero por alguna razón el sitio web solo me permite copiar una pequeña sección a la vez (y soy demasiado vago para sacar mi pi del garaje), así que aquí está el enlace. ignore la mayoría de las funciones en la parte inferior ya que están relacionadas con el uso del módulo como sensor de proximidad. http://pibot.webnode.com/products/ultrasonic-range-sensor/
La respuesta larga: ¡en realidad puedes! (Bueno, con un poco de ayuda de nuestros amigos resistencia y condensador)
Puede convertir una salida PWM a un nivel de voltaje analógico (DAC) y leerlo con el pin ADC en su raspberry pi.
Lo que necesita es una resistencia 4k7 y un condensador de 0.1uF:
simular este circuito : esquema creado con CircuitLab
El simple filtro de paso bajo RC anterior convierte la señal PWM en un voltaje proporcional al ciclo de trabajo que puede leer su raspberry pi como un valor analógico.
Si está satisfecho con una respuesta lenta, puede leer un PWM rápido submuestreando. Simplemente lea el GPIO en un bucle y aplique un filtro de paso bajo. La probabilidad de leer un 1 en cada ciclo es proporcional al ancho del pulso. Un filtro de paso bajo IIR fácil de implementar es:
double acc=0.5;
const double k=0.01;
for(;;) {
bool x=GPIO.read();
acc+=k*(x?1:0-acc);
}
A medida que k disminuye, la resolución mejora pero el ancho de banda disminuye.
Aunque mi respuesta no es de los pines, podría usar algo basado en un osciloscopio de tarjeta de sonido para leer una entrada pulsada.
La gente ha estado usando tarjetas de sonido en PC de escritorio durante años para crear osciloscopios. Parece que con una tarjeta de sonido interna moderna puede obtener resultados utilizables de hasta 10 kHz. Con una tarjeta de sonido con conexión USB Raspberry Pi, su frecuencia máxima podría ser menor.
Aquí hay un ejemplo de un proyecto de osciloscopio de tarjeta de sonido para Linux: http://www.yann.com/en/diy-turn-your-gnulinux-computer-into-a-free-oscilloscope-29/09/2010.html
Este script de Python que escribí funciona bien para mí para leer señales PWM de un receptor RC. Las señales PWM de alta frecuencia obviamente no funcionarán como ya se ha señalado.
Conecté directamente los diez pines de salida de señal del receptor RC a los pines Raspberry GPIO. El receptor está alimentado por los pines + 5V y GND del RPI.
Simplifiqué el script ya que hace muchas otras cosas, si encuentra algún error o sobra, avíseme
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()
Es muy posible y relativamente fácil leer entradas PWM en Raspberry Pi usando la biblioteca pigpio C. Si desea un buen rendimiento, le recomiendo usar C, no Python. He proporcionado un pequeño código de muestra a continuación. Al contrario de lo que algunas personas dicen, esto tiene un excelente rendimiento de sincronización y una fluctuación bastante baja. Las lecturas están consistentemente dentro de 5 us en mi RPi 3 B y puede medir pulsos tan cortos como 5 us. Tenga en cuenta que el código provisto es solo una prueba de concepto, no maneja adecuadamente la ausencia de pulsos (ciclo de trabajo del 0% / 100%) o la envoltura 'tick' que ocurre cada 72 minutos. El programa funciona bien en modo de usuario, pero para obtener la mejor resistencia a las fallas de tiempo, ejecute su programa en un nivel agradable negativo como este: sudo nice -n -20 ./program
Vea los documentos de Pigpio en: 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);
}
}
Solución fácil con alta precisión:
Usar un Arduino como esclavo iic o dispositivo UART parece funcionar perfectamente bien. El microcontoller es capaz de leer la información a través del método pulseIn.
Para obtener información detallada: https://www.youtube.com/watch?v=ncBDvcbY1l4