Wie kann ich Frequenz- / Impulssignale erzeugen?

19

Ich suche nach Möglichkeiten, den Raspberry Pi als Signalgenerator zu verwenden. Derzeit arbeite ich daran, ein kostengünstiges AD9850-Modul von ebay anzuschließen . Dies erzeugt ziemlich genaue Frequenzen bis zu 40 MHz (70 MHz beim AD9851).

Bildbeschreibung hier eingeben

Ich denke, der Audioausgang kann auch für beliebige Wellenformen bis zu einer sehr begrenzten Frequenz verwendet werden.

Gibt es noch andere Möglichkeiten?

John La Rooy
quelle

Antworten:

13

Hier ist, wie ich das AD9850-Modul und ein einfaches Python-Programm angeschlossen habe, um zu zeigen, wie die Frequenz auf 1000 Hz eingestellt wird.

Der AD9850 muss mit 5 V betrieben werden, damit er ordnungsgemäß mit dem 125-MHz-Quarz funktioniert. Es wäre wahrscheinlich in Ordnung, 4 GPIO-Pins direkt mit dem Modul zu verbinden, da es sich lediglich um Eingänge handelt. Durch die Verbindung über einen MCP23017 wird das Modul jedoch effektiv in ein anderes I²C- Peripheriegerät verwandelt und sichergestellt, dass die RPi-Eingänge sicher sind.

Wichtiger Hinweis zu + 5V
Der + 5V-Pin am GPIO kann nicht genug Strom liefern, um den AD9850 mit Strom zu versorgen. Sie sollten eine externe 5-V-Versorgung verwenden.

RPi über MCP23017 mit dem AD9850-Modul verbunden

from functools import partial

import smbus

def main():
    addr = 0x20
    bus = smbus.SMBus(0) # or SMBus(1) on newer pis

    # Helper functions    
    wr_dir = partial(bus.write_byte_data, addr, 0x01)
    wr = partial(bus.write_byte_data, addr, 0x13)

    # Set Pins B0-B4 of the MCP23017 to output
    wr_dir(0xF0)

    # Names of the Pins
    RST = 1 << 0
    DATA = 1 << 1
    FQ = 1 << 2
    CLK = 1 << 3

    def send_bit(bit):
        # send a single bit
        wr(DATA * bit)
        wr(CLK | DATA * bit)

    def fq():
        wr(FQ)
        wr(0)

    def init():
        wr(RST)
        wr(0)
        wr(CLK)
        wr(0)
        wr(FQ)
        wr(0) 

    freq = 1000  
    init()
    dphase = int(0.5 + (freq << 32) / 125000000.0)
    for x in range(32):
        send_bit((dphase >> x) & 1)

    # Phase bits can all be 0
for x in range(8):
    send_bit(0)

    fq()

if __name__ == "__main__":
    main()
John La Rooy
quelle
Ist das dein eigenes RPi GPIO Symbol?
Alex Chamberlain
1
@ AlexChamberlain, ja, das ist es. Soweit ich das beurteilen kann, hat der RPF außer dem RPI selbst nichts sehr Nützliches veröffentlicht :)
John La Rooy
Hmm, ich denke, das ist eine dumme Frage, aber was ist ein GPIO-Symbol?
Steven Lu
@StevenLu, das große Rechteck rechts vom Schaltplan. Die alten RPi's hatten 26 Pins, die neueren haben 40 Pins. siehe elinux.org/…
John La Rooy
Oh ok. Es scheint nur sehr natürlich. Ich gehe davon aus, dass Sie die 40-Pin-Version nicht gezeichnet haben, da Sie für das Diagramm ohnehin nur 3 dieser Pins benötigt haben.
Steven Lu
11

Sie könnten theoretisch einen D / A-Wandler an GPIO-Pins anschließen, aber dies ist nicht für die Signalerzeugung geeignet, da Sie es nicht mit genauem Timing steuern können, hauptsächlich, weil Linux kein Echtzeitbetriebssystem ist.

Es gibt auch keine Möglichkeit, dies bei so hohen Frequenzen zu betreiben.

Wenn 44 kHz oder so ausreichen, denke ich, ist die Audiobuchse der einfachste Weg, dies zu tun.


quelle
4

John La Rooy hat eine gute Lösung, aber die Schaltung kann komplizierter sein, als manche bevorzugen würden. Dies beschreibt eine ähnliche Lösung, die von Tom Herbison unter Verwendung nur des AD9850 entwickelt wurde, obwohl 4 GPIO-Signalstifte anstelle von 2 wie bei Johns Lösung verwendet werden.

Tom verbindet sich wie folgt mit GPIO: Schaltplan

Beachten Sie, dass er den AD9850 mit 3,3 V anstelle von 5 V betreibt. Gemäß dieser Diskussion ist der AD9850 für einen Betrieb mit 3,3 V oder 5 V ausgelegt. Einige Boards verwenden jedoch möglicherweise Komponenten, die 5 V nicht über einen längeren Zeitraum verarbeiten können. Daher ist ein Betrieb mit 3,3 V möglicherweise eine bessere Lösung, abhängig von Ihrem Geschmack des AD9850-Boards .

Meine spezielle AD9850- Platine hatte die meisten Pin-Beschriftungen nur unterhalb der Platine, daher machte ich ein Foto von der Unterseite, bevor ich sie in eine Prototyping-Platine drückte. Die Pin-Positionen waren ohnehin identisch mit denen auf Toms Board. Auf meinem Board FQsteht FU_UQ, CLKsteht W_CLKund RSTsteht RESET.

Tom stellt dieses Python 3-Skript zur Steuerung des Funktionsgenerators zur Verfügung. Hier ist eine Kopie von v1.0 für den Fall, dass der Download-Link jemals unterbrochen wird:

# RPi RF Signal Generator v1.0

# Copyright (C) 2013 Tom Herbison MI0IOU
# Email (hidden to discourage spammers - see original rpi_rfsiggen.py file)
# Web <http://www.asliceofraspberrypi.co.uk>

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# import GUI module
from tkinter import *

# import GPIO module
import RPi.GPIO as GPIO

# setup GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)

# Define GPIO pins
W_CLK = 15
FQ_UD = 16
DATA = 18
RESET = 22

# setup IO bits
GPIO.setup(W_CLK, GPIO.OUT)
GPIO.setup(FQ_UD, GPIO.OUT)
GPIO.setup(DATA, GPIO.OUT)
GPIO.setup(RESET, GPIO.OUT)

# initialize everything to zero
GPIO.output(W_CLK, False)
GPIO.output(FQ_UD, False)
GPIO.output(DATA, False)
GPIO.output(RESET, False)

# Function to send a pulse to GPIO pin
def pulseHigh(pin):
    GPIO.output(pin, True)
    GPIO.output(pin, True)
    GPIO.output(pin, False)
    return

# Function to send a byte to AD9850 module
def tfr_byte(data):
    for i in range (0,8):
        GPIO.output(DATA, data & 0x01)
        pulseHigh(W_CLK)
        data=data>>1
    return

# Function to send frequency (assumes 125MHz xtal) to AD9850 module
def sendFrequency(frequency):
    freq=int(frequency*4294967296/125000000)
    for b in range (0,4):
        tfr_byte(freq & 0xFF)
        freq=freq>>8
    tfr_byte(0x00)
    pulseHigh(FQ_UD)
    return


# Class definition for RPiRFSigGen application
class RPiRFSigGen:
        # Build Graphical User Interface
        def __init__(self, master):
                frame = Frame(master, bd=10)
                frame.pack(fill=BOTH,expand=1)
                # set output frequency
                frequencylabel = Label(frame, text='Frequency (Hz)', pady=10)
                frequencylabel.grid(row=0, column=0)
                self.frequency = StringVar()
                frequencyentry = Entry(frame, textvariable=self.frequency, width=10)
                frequencyentry.grid(row=0, column=1)
                # Start button
                startbutton = Button(frame, text='Start', command=self.start)
                startbutton.grid(row=1, column=0)
                # Stop button
                stopbutton = Button(frame, text='Stop', command=self.stop)
                stopbutton.grid(row=1, column=1)


        # start the DDS module
        def start(self):
                frequency = int(self.frequency.get())
                pulseHigh(RESET)
                pulseHigh(W_CLK)
                pulseHigh(FQ_UD)
                sendFrequency(frequency)

        # stop the DDS module
        def stop(self):
                pulseHigh(RESET)

# Assign TK to root
root = Tk()

# Set main window title
root.wm_title('RPi RFSigGen')

# Create instance of class RPiRFSigGen
app = RPiRFSigGen(root)

# Start main loop and wait for input from GUI
root.mainloop()

Da für die Verwendung der GPIO-Pins auf dem Pi die Ausführung als Root erforderlich ist, beschreibt Tom zwei Methoden zum Starten seines Python-Codes mit Root-Berechtigungen. Seine erste Methode besteht darin, das Python IDE-Desktopsymbol so zu ändern, dass es immer als root ausgeführt wird. Das erscheint mir jedoch unsicher. Sie möchten nicht alle Python-GUI-Programme als root ausführen, wenn Sie dies nicht müssen. Die zweite Methode besteht darin, sudo idle3_von einer Eingabeaufforderung aus zu starten, wenn Python 3 Integrated Development Environment Root-Berechtigungen benötigt.

Tom erwähnt die Installation der RPi.GPIO-Python 3-Bibliothek nicht, sodass sie möglicherweise bereits in einigen Pi-OS-Versionen verfügbar ist, aber in Occidentalis v0.2, das ich verwendet habe, nicht verfügbar war sudo apt-get install python3-rpi.gpio. Beachten Sie, dass Python 3 einen anderen Speicherort für RPi.GPIO verwendet, sodass sudo apt-get install python-rpi.gpionur Python 2 auf die Bibliothek zugreifen kann .

Sobald die Python 3-IDE mit Root-Rechten geöffnet ist, öffnen Sie die Datei rpi_rfsiggen.pyund wählen Sie sie Run -> Run Moduleaus dem Menü aus oder drücken Sie F5.

Beim ZOUT2ersten Versuch konnte ich eine stabile 18-kHz-Sinuswelle bei 1 Vss vom SinB-Ausgangspin ( auf meiner Platine beschriftet ) abrufen .

Chris Dragon
quelle
3

Wenn Sie nur einen Funktionsgenerator für Audio und NF implementieren möchten, dann holen Sie sich ein billiges AD9833-Modul von EBAY. Dadurch erhalten Sie Sinus-, Rechteck- und Dreieckswellen sowie eine variable Phase. Anscheinend nicht viel Gutes nach 7 MHz ....

Bildbeschreibung hier eingeben

Steve
quelle
Es muss einen Grund geben, warum diese Module so viel teurer sind als AD9850-Module. Irgendeine Idee warum?
John La Rooy