1

I'm creating a simple script that outputs a text input to morse with an LED and a transducer via the GPIO pins on a Raspberry Pi 4 Model B. I tried to add input functionality with buttons that can change the frequency of the transducer while the program is running, however I ran into some problems doing this as the frequency only changes for the first dot or dash of each letter then defaults to the initial value

import RPi.GPIO as GPIO
from time import sleep

LED_GPIO = 17
BUZZER_GPIO = 14
BUTTON1_GPIO = 26
BUTTON2_GPIO = 13
freq = 1500

GPIO.setmode(GPIO.BCM)

GPIO.setup(LED_GPIO, GPIO.OUT)
GPIO.setup(BUZZER_GPIO,GPIO.OUT)
GPIO.setup(BUTTON1_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(BUTTON2_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)

MORSE_CODE_DICT = { 'A':'.-', 'B':'-...',
                    'C':'-.-.', 'D':'-..', 'E':'.',
                    'F':'..-.', 'G':'--.', 'H':'....',
                    'I':'..', 'J':'.---', 'K':'-.-',
                    'L':'.-..', 'M':'--', 'N':'-.',
                    'O':'---', 'P':'.--.', 'Q':'--.-',
                    'R':'.-.', 'S':'...', 'T':'-',
                    'U':'..-', 'V':'...-', 'W':'.--',
                    'X':'-..-', 'Y':'-.--', 'Z':'--..',
                    '1':'.----', '2':'..---', '3':'...--',
                    '4':'....-', '5':'.....', '6':'-....',
                    '7':'--...', '8':'---..', '9':'----.',
                    '0':'-----', ', ':'--..--', '.':'.-.-.-',
                    '?':'..--..', '/':'-..-.', '-':'-....-',
                    '(':'-.--.', ')':'-.--.-'} 
            
def increase_freq(channel):
    global freq
    print("Incresaing frequency")
    freq+=100
    print(freq)

def decrease_freq(channel):
    global freq
    print("Decresaing frequency")
    freq-=100
    print(freq)

def set_led(state):
    if state:
        GPIO.output(LED_GPIO, True)
    else:
        GPIO.output(LED_GPIO, False)

def blink_morse(morse):
    for char in morse:
        set_led(True)
        print(freq)
        buzzer = GPIO.PWM(BUZZER_GPIO, freq)
        buzzer.start(80)
        if char == ".":
            sleep(0.2)
        else:
            sleep(1)
        set_led(False)
        buzzer.stop()
        sleep(0.2)
        
GPIO.add_event_detect(BUTTON1_GPIO, GPIO.FALLING, callback=increase_freq, bouncetime=500) 
GPIO.add_event_detect(BUTTON2_GPIO, GPIO.FALLING, callback=decrease_freq, bouncetime=500)

while True:
    try:
        message=input("Enter message:\n>")
        if message=="q":
            break
        message=message.upper()
        for letter in message:
            if letter == " ":
                sleep(2)
            else:
                print(letter)
                morse=MORSE_CODE_DICT[letter]
                print(morse)
                blink_morse(morse)
                sleep(1)
    finally:
        pass

I think the problem lies in this function

def blink_morse(morse):
    for char in morse:
        set_led(True)
        print(freq)
        buzzer = GPIO.PWM(BUZZER_GPIO, freq)
        buzzer.start(80)
        if char == ".":
            sleep(0.2)
        else:
            sleep(1)
        set_led(False)
        buzzer.stop()
        sleep(0.2)

I redefine the buzzer every dot or dash so that every loop it is "checking" for an update in the frequency, however for example, if the letter in question is "s" which translates to "dot dot dot" the updated frequency will only sound for the first "dot" and then default to the original value. When it goes to the next letter it will also sound the updated frequency for the first dot or dash but then default back again.

I've done some checks and I'm sure that each time the

buzzer = GPIO.PWM(BUZZER_GPIO, freq)

line runs, the frequency is what I want it to be, but for some reason it only comes out correct in sound for the first dot or dash of each letter.

Anyone know why this is?

1 Answer 1

0

There are multiple issues associated with RPi.GPIO PWM.

E.g. #132 PWM becomes inaccurate after stop() and start().

I suggest you try the workaround of using ChangeDutyCycle instead of start/stop.

1
  • I had tried that but if instead of buzzer.stop() I use buzzer.ChangeDutCycle(0), when it comes to redefining the buzzer with a different frequency i get "RuntimeError: A PWM object already exists for this GPIO channel" Edit: I managed to get it to work by instead using buzzer.stop(), Instead just added the line buzzer=0 after changing the duty cycle which managed to avoid the "A PWM object already exists for this GPIO channel" error. Thank you
    – Leo Gortz
    Sep 12, 2021 at 10:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.