Comment générer des signaux de fréquence / impulsion?

19

Je cherche des moyens d'utiliser le Raspberry Pi comme générateur de signaux. Actuellement, je travaille à brancher un module AD9850 bon marché sur ebay. Cela générera des fréquences assez précises jusqu'à 40 MHz (70 MHz avec l'AD9851).

entrez la description de l'image ici

Je suppose que la sortie audio pourrait également être utilisée pour des formes d'onde arbitraires jusqu'à une fréquence très limitée.

Y a-t-il d'autres possibilités?

John La Rooy
la source

Réponses:

13

Voici comment j'ai connecté le module AD9850 et un simple programme Python pour montrer comment régler la fréquence à 1000 Hz.

L'AD9850 doit fonctionner à 5 V pour fonctionner correctement avec le cristal 125 MHz. Il serait probablement correct de câbler 4 broches GPIO directement au module car ce ne sont que des entrées, mais la connexion via un MCP23017 transforme efficacement le module en un autre périphérique I²C et garantit que les entrées RPi sont sûres.

Remarque importante à propos de + 5V
La broche + 5V du GPIO ne peut pas vraiment fournir suffisamment de courant pour alimenter l'AD9850. Vous devez utiliser une alimentation 5V externe.

RPi connecté au module AD9850 via MCP23017

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
la source
Est-ce votre propre symbole RPi GPIO?
Alex Chamberlain
1
@AlexChamberlain, c'est vrai. Pour autant que je sache, le FPR n'a rien publié de très utile à part le RPi lui-même :)
John La Rooy
Hmm, je suppose que cela pourrait être une question idiote, mais qu'est-ce qu'un symbole GPIO?
Steven Lu
@StevenLu, le grand rectangle à droite du schéma. Les anciens RPi avaient 26 broches, les plus récents ont 40 broches. voir elinux.org/…
John La Rooy
Ah d'accord. Cela semble tout simplement très naturel. Je pense que vous n'avez pas dessiné la version à 40 broches car vous n'aviez besoin que de 3 de ces broches pour le diagramme.
Steven Lu
11

Vous pourriez en théorie brancher un convertisseur N / A sur des broches GPIO, mais cela ne convient pas à la génération de signal car vous ne pourrez pas le piloter avec un timing précis, principalement parce que Linux n'est pas un système d'exploitation en temps réel.

De plus, il n'y a aucun moyen que cela puisse fonctionner à des fréquences aussi élevées.

Si 44 kHz environ suffisent, je pense que la prise audio peut être le moyen le plus simple de le faire.


la source
4

John La Rooy a une bonne solution mais le circuit peut être plus compliqué que certains ne le souhaiteraient. Cela décrit une solution similaire conçue par Tom Herbison en utilisant uniquement l'AD9850, bien qu'il utilise 4 broches de signal GPIO au lieu de 2 comme la solution de John.

Tom se connecte à GPIO comme ceci: diagramme de connexion

Notez qu'il exécute l'AD9850 sur 3,3 V au lieu de 5 V. Selon cette discussion , l'AD9850 est conçu pour fonctionner à 3,3 V ou 5 V, mais certaines cartes peuvent utiliser des composants incapables de gérer 5 V pendant longtemps, donc un fonctionnement à 3,3 V peut en fait être une meilleure solution, selon la saveur de la carte AD9850. .

Ma carte AD9850 particulière avait la plupart des étiquettes de broches uniquement sous la carte, j'ai donc pris une photo de la face inférieure avant de la presser dans une carte de prototypage. Les emplacements des broches ont finalement été identiques à ceux de la carte de Tom. Sur mon tableau, FQest étiqueté FU_UQ, CLKest W_CLKet RSTest RESET.

Tom fournit ce script Python 3 pour contrôler le générateur de fonctions. Voici une copie de la v1.0 en cas de rupture du lien de téléchargement:

# 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()

Étant donné que toute utilisation des broches GPIO sur le pi nécessite de s'exécuter en tant que root, Tom décrit deux méthodes de lancement de son code python avec des privilèges root. Sa première méthode consiste à modifier l'icône du bureau Python IDE pour qu'elle s'exécute toujours en tant que root, mais cela me semble dangereux - vous ne voulez pas exécuter tous les programmes GUI python en tant que root si vous n'êtes pas obligé. La deuxième méthode consiste à exécuter à sudo idle3_partir d'une invite de commandes pour lancer l'environnement de développement intégré Python 3 avec des privilèges root chaque fois qu'il a besoin de privilèges root.

Tom ne mentionne pas l'installation de la bibliothèque RPi.GPIO python 3 donc elle peut déjà être disponible sur certaines versions de Pi OS, mais elle n'était pas disponible sur l'Occidentalis v0.2 que j'utilisais alors j'ai couru sudo apt-get install python3-rpi.gpio. Notez que Python 3 utilise un emplacement différent pour RPi.GPIO donc sudo apt-get install python-rpi.gpione rendra la bibliothèque accessible qu'à Python 2.

Une fois l'IDE Python 3 ouvert avec les privilèges root, ouvrez le fichier rpi_rfsiggen.py, puis choisissez Run -> Run Moduledans le menu ou appuyez sur F5.

J'ai pu obtenir une belle onde sinusoïdale stable de 18 kHz à 1 Vpp à partir de la broche de sortie SinB (étiquetée ZOUT2sur ma carte) lors de mon premier essai.

Chris Dragon
la source
3

Si vous souhaitez simplement implémenter un générateur de fonctions pour l'audio et le Lf rf, choisissez un module AD9833 bon marché d'EBAY. Cela vous donnera des ondes sinusoïdales, carrées et triangulaires ainsi qu'une phase variable. Apparemment, pas beaucoup de bien après 7 MHz ....

entrez la description de l'image ici

Steve
la source
Il doit y avoir une raison pour laquelle ces modules sont beaucoup plus chers que les modules AD9850. Une idée pourquoi?
John La Rooy