Input PWM di Raspberry Pi

10

Apakah ada cara untuk membaca sinyal PWM dari pin pada Raspberry Pi?

Saya mencoba googling, tapi saya hanya menemukan output PWM , dan bukan input .

Caio Keto
sumber

Jawaban:

4

Jawaban singkatnya: Anda TIDAK BISA andal membaca PWM di Raspberry Pi.

Membaca PWM membutuhkan ketelitian mikrodetik (kecuali jika Anda membaca PWM yang sangat-sangat lambat), dan itu tidak tersedia pada Raspberry Pi untuk perangkat lunak userland tanpa bermain-main dengan modul kernel.

Cara termudah untuk menangkap PWM adalah dengan mendapatkan mikrokontroler murah (<$ 0,5) dengan serial atau I 2 C output dan menghubungkannya ke Raspberry Pi Anda dan membaca nilai aktual dari mikrokontroler. Ini akan bekerja dengan sangat andal dan cukup tepat.

lenik
sumber
1
Adakah yang tahu di mana mendapatkan IC seperti itu?
Pepijn
@ Paten yang Anda cari adalah konverter analog-ke-digital (ADC). Yang sangat umum yang saya gunakan sangat sering adalah saluran MCP3008 8, unit 10-bit, dan yang lain yang saya miliki secara permanen pada unit pengujian Pi untuk perangkat lunak Perl saya adalah ADS1115 4 channel, unit 16-bit. Yang terakhir membutuhkan sedikit pekerjaan penyolderan, yang pertama tidak. Ada banyak contoh kode yang tersedia untuk menggunakan kedua unit ini (C, Python, Perl dll), jadi jika Anda tidak ingin / tidak dapat menulis sendiri, itu harus sepele untuk memulai.
stevieb
Setiap mikrokontroler sederhana akan berhasil. Saya dulu menggunakan produk Microchip untuk hal semacam ini. Munculnya Arduino telah membawa chip AVR menjadi populer kembali. Sekarang saya hanya menggunakan papan breakout kecil yang berisi mikrokontroler dan apa pun yang mendukung kehidupan kebutuhan chip. Favorit saya adalah seri Teensy 3.x.
NomadMaker
3

Saya dapat melakukan pengukuran lebar pulsa yang cukup akurat menggunakan pustaka piGpio C: http://abyz.me.uk/rpi/pigpio/index.html

Pustaka ini memungkinkan Anda untuk menginstal fungsi panggilan balik yang akan memicu pada setiap transisi tepi pada pin gpio dan memberi Anda cap waktu tingkat mikrodetik untuk setiap transisi. Jangan berpikir Anda bisa mengandalkan ini untuk akurasi mikrodetik - tetapi pengujian saya menunjukkan bahwa akurasi setidaknya +/- 10 us, mungkin lebih baik.

Jauh lebih baik daripada menjalankan loop sibuk polling gpio untuk tingkat ubah sendiri.

stevec
sumber
+1 Mungkin perlu dicatat bahwa keakuratannya mungkin berbeda-beda berdasarkan pada beban CPU (terutama core tunggal), tetapi sebaliknya jawaban yang baik. :)
Jacobm001
Terima kasih stevec, jawaban ini jauh lebih baik daripada mengatakan "itu tidak dapat dilakukan". Lihat jawaban saya yang terpisah untuk informasi lebih lanjut termasuk kode aktual (sangat singkat).
Georgie
2

Ini adalah pertanyaan yang menarik dan salah satu yang Anda anggap benar dalam mengatakan Google Search tidak memberikan solusi yang jelas! (Saya merindukan hari-hari ketika Google dapat menjawab apa pun yang ingin saya ketahui untuk pendidikan / tugas saya dalam hitungan detik.)

Saya berasumsi Anda memahami prinsip-prinsip PWM . Karena itu, saya tidak akan membahasnya. Namun, saya percaya Anda secara teori bisa membaca nilai PWM pada pin input digital biasa dengan beberapa pengkodean yang cerdas.

Saya akui saya belum mencoba ini sendiri, tetapi Anda harus dapat mengukur waktu pin tinggi dan waktu rendah (memberi Anda bacaan PWM) dan kemudian menggunakan rumus matematika apa pun yang disediakan oleh pemasok sensor. untuk mengubah ini menjadi bacaan yang sebenarnya.

Metode ini bekerja untuk saya pada masalah yang sama di mana saya perlu membaca panjang pulsa dari modul ultrasonik dan kemudian mengubahnya menjadi jarak. Masalah yang bisa saya bayangkan adalah memastikan pembacaan yang andal!

Jika Anda pikir itu akan membantu dan ingin melihat kode yang saya gunakan untuk modul ultrasonik katakan saja, dan saya akan menyalinnya ketika saya pulang.

Saya mulai menyalin kode tetapi karena suatu alasan situs web hanya memperbolehkan saya menyalinnya sebagian kecil saja (dan saya terlalu malas untuk mengeluarkan pi saya dari garasi) jadi di sini ada tautannya. abaikan sebagian besar fungsi di bagian bawah karena terkait dengan penggunaan modul sebagai sensor kedekatan. http://pibot.webnode.com/products/ultrasonic-range-sensor/

D Mason
sumber
Itu bagus untuk melihat kode, jadi saya bisa mendapatkan basis untuk memulai kode saya sendiri, jika Anda dapat menempelkannya di sini saya akan sangat berterima kasih ^^
Caio Keto
Masalah dengan saran ini adalah bahwa kernel Linux tidak memberi Anda waktu yang cukup untuk membaca siklus tugas RC PWM khas (yang biasanya 1000-2000 mikrodetik setiap 16 milidetik) dengan presisi yang cukup. Jika kita dapat menginstal interrupt handler untuk perubahan pin GPIO, dan menangkap stempel waktu pada transisi tinggi / rendah, dalam modul kernel, maka ini mungkin solusi yang berguna.
Jon Watte
1

Jawaban panjangnya: Anda benar-benar bisa! (baik dengan sedikit bantuan dari teman-teman kita resistor dan kapasitor)

Anda dapat mengonversi output PWM ke level tegangan analog, (DAC) dan membacanya dengan pin ADC pada pi raspberry Anda.

Yang Anda butuhkan adalah resistor 4k7 dan kapasitor 0.1uF:

skema

mensimulasikan rangkaian ini - Skema dibuat menggunakan CircuitLab

Filter low-pass RC sederhana di atas mengubah sinyal PWM ke tegangan yang sebanding dengan siklus kerja yang dapat dibaca oleh raspberry pi Anda sebagai nilai analog.

Pencarian
sumber
4
Pin ADC? Dan apakah itu?
Ghanima
@ Ghima Yah, driver Microsoft Lightning baru sedang dalam pengembangan tetapi melayani tujuan ini dengan cukup baik (ini didokumentasikan pada halaman mereka). Untuk apa yang telah ditemukan untuk BCM2837 mungkin memiliki ADC hardware yang pada GPIO0 (sayangnya satu ini tidak terhubung dengan pin header) .. setidaknya mereka terkait saluran PWM hardware
Quest
0

Jika Anda senang dengan respons yang lambat, Anda dapat membaca PWM cepat dengan undersampling. Cukup baca GPIO dalam satu lingkaran dan terapkan filter low pass. Probabilitas membaca 1 setiap siklus sebanding dengan lebar pulsa. Filter low pass IIR yang mudah diterapkan adalah:

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

Saat k menurun, resolusi meningkat tetapi bandwidth berkurang.

wdg
sumber
0

Meskipun jawaban saya bukan dari pin, Anda dapat menggunakan sesuatu berdasarkan Oscilloscope Kartu Suara untuk membaca input berdenyut.

Orang-orang telah menggunakan Kartu Suara di PC desktop selama bertahun-tahun untuk membuat osiloskop. Tampaknya dengan kartu suara internal modern Anda bisa mendapatkan hasil yang dapat digunakan hingga 10kHz. Dengan Kartu Suara yang terhubung dengan Raspberry Pi USB, frekuensi maks Anda mungkin lebih rendah.

Berikut adalah contoh dari satu proyek Oscilloscope Kartu Suara untuk Linux: http://www.yann.com/en/diy-turn-your-gnulinux-computer-into-a-free-oscilloscope-29/09/2010.html

pierce.jason
sumber
0

Skrip python yang saya tulis ini berfungsi dengan baik bagi saya untuk membaca sinyal PWM dari RC Receiver. Sinyal PWM frekuensi tinggi jelas tidak akan berfungsi seperti yang telah ditunjukkan.

Saya langsung menghubungkan sepuluh pin sinyal keluar dari penerima RC ke pin Raspberry GPIO. Penerima ini ditenagai oleh pin + 5V dan GND dari RPI.

Saya menyederhanakan skrip karena ia melakukan banyak hal lain, jika Anda menemukan kesalahan atau sisa, beri tahu saya

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()
pengguna2707001
sumber
0

Sangat mungkin dan relatif mudah untuk membaca input PWM di Raspberry Pi menggunakan perpustakaan pigpio C. Jika Anda ingin kinerja yang baik saya sarankan menggunakan C, bukan Python. Saya telah memberikan beberapa kode contoh singkat di bawah ini. Berlawanan dengan apa yang dikatakan beberapa orang, ini memiliki kinerja pengaturan waktu yang sangat baik dan jitter yang cukup rendah. Bacaan secara konsisten dalam 5 us pada RPi 3 B saya dan dapat mengukur pulsa sesingkat 5 us. Perhatikan bahwa kode yang disediakan adalah bukti konsep saja, ia tidak menangani dengan benar tidak adanya pulsa (siklus tugas 0% / 100%) atau sampul 'tick' yang terjadi setiap 72 menit. Program ini berjalan dengan baik dalam mode pengguna tetapi untuk ketahanan terbaik terhadap gangguan waktu menjalankan program Anda pada tingkat negatif baik seperti ini: sudo nice -n -20 ./program

Lihat dokumentasi pigpio di: 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);
    }
}
Georgie
sumber
-3

Solusi mudah dengan akurasi tinggi:

Menggunakan Arduino sebagai perangkat iic slave atau UART tampaknya berfungsi dengan baik. Microcontoller mampu membaca informasi melalui metode pulseIn.

Informasi detail kedepan: https://www.youtube.com/watch?v=ncBDvcbY1l4

Simon
sumber
Selamat datang di Raspberry Pi! Sementara ini secara teoritis dapat menjawab pertanyaan, akan lebih baik untuk memasukkan bagian-bagian penting dari jawaban di sini, dan menyediakan tautan untuk referensi. Kami sedang mencoba kebijakan baru sehubungan dengan jawaban tanpa tautan saja di sini . Jika posting ini tidak diedit mengandung informasi yang dapat dijadikan jawaban, namun minimal, dalam 48 jam akan dikonversi ke Komunitas Wiki untuk menyederhanakan setelah diperbaiki oleh komunitas.
Ghanima