S Lazy-H
  • Home
  • About
  • Posts
  • Contact
  • Slide Rules
  • A Biker’s Tale

Rpi 4 PWM - Part 1

electronics
Raspberry Pi
Author

Sam Hutchins

Published

October 24, 2019

UPDATE: Sometimes it is worth the time to double check things if there is something odd going on. For example, in the below post, I noted the O’scope and Multimeter seemed to be at odds with each other, but because I was in a bit of a rush, I didn’t check everything like I should have. Came to find out the scope vertical input was on AC instead of DC, so of course there would be discrepancies between the two. Now that I have had time to spend a bit more looking, I discovered the error right away. Read the post again because I have added another snippet of code at the bottom that performs a bit more like a potentiometer would but in a digital fashion.

———————————-

Every once in a while, we deviate into the realm of electronics here. A friend was looking for a way to use the Raspberry Pi 4 to control the output of a power supply using pulse width modulation (PWM).

Admittedly, the RPie is way overkill for that, but this is more in the line of how do you do that? Just for fun, learning, experimentation, you understand. Plus, it is interesting finding the different ways to use the Raspberry Pi 4.

So, with that in mind, here is a simple way to output a PWM signal from a GPIO pin that could be used to control a voltage regulator (VR, like a LM317, etc.) to vary the power supply output. For sure, it would be simpler to use a pot; but, what’s the adventure in that?

Here is a simple Python program to create a PWM signal that varies from 1ms to 2ms at 50 Hz over a period of time. Notice this is the same signal most servos use for positional control (i.e. 0 to 180 degrees). In this case it is not position we need, but average voltage to turn on and off a silicon junction of a VR. Given this signal’s average output of 0.38 to 0.8 volts, it should drive a transistor from off to full saturation. Here is the code. You might save it as “servo_exerciser” or some such.


import RPi.GPIO as GPIO # control the GPIO interface. 
import time

GPIO.setmode(GPIO.BOARD) # use physical pin numbering
GPIO.setup(12, GPIO.OUT) # Set GPIO18 to output pin.
GPIO.setwarnings(False)
p = GPIO.PWM(12, 50) # physical pin 12 (GPIO18) at 50 Hz
dc = 4.6
p.start(dc)
try: # output 1-2mS pulse @ 50Hz/3.3v level.
    while True:
        while dc < 10.01:
            p.ChangeDutyCycle(dc)
            time.sleep(.01) # sleep 10 mS
            dc+=0.01
        time.sleep(1)
        while dc > 4.6:
            p.ChangeDutyCycle(dc)
            time.sleep(0.01)
            dc-=0.01
        time.sleep(1)

except KeyboardInterrupt:
    p.stop()
    GPIO.cleanup()

NOTE: In Python the indentation determines what goes under what. So sometimes the spaces or tabs don’t come out correctly. A way to do that is wrap the code block with <pre><code> your text here </code></pre> tags. A bit cumbersome, but it works.

Another snippet of code to allow keyboard input for changing the duty cycle (dc) value during program execution. Save the above program under a different name, then replace all lines in the “try” block with the below code.


    while True:
        dc = input("Value? ").strip()
        dc = float(dc)
        p.ChangeDutyCycle(dc)
        time.sleep(1)

The first line under “while True” accepts a keyboard input and saves it as a string. This is not what we want! So the next line converts the string to a float value the program can use. BTW, the .strip() in the first line gets rid of the garbage at the end of the input, such an newline characters, etc. Then, the value is acted upon in the third line. The sleep is there just to allow for possible latencies to resolve themselves, and may not be necessary, or the value could be changed.

To make the program a little bit safer and to limit input to sane values, we can add some value limitations and error catching. After doing that, we will wrap this up with the new complete program. Other if statements and additional code could be added to limit to only number input, but we are trying to keep it simple.


import RPi.GPIO as GPIO # a Python module to control the GPIO interface. 
import time

GPIO.setmode(GPIO.BOARD) # use physical pin numbering
GPIO.setup(12, GPIO.OUT) # Set GPIO18 to output pin.
GPIO.setwarnings(False)
p = GPIO.PWM(12, 50) # physical pin 12 (GPIO18) at 50 Hz
dc = 4.6
p.start(dc)
try: # output 1-2mS pulse @ 50Hz/3.3v level.
    while True:
        dc = input("Recommend 0-25%, Value (%): ").strip() # accept keyboard input
        if len(dc) > 0: # catch null entry
            dc = float(dc) # convert string to float
            if dc <= 100: # limit to 100%
                p.ChangeDutyCycle(dc)
        time.sleep(1)
except ValueError:
    print("This is not a number!")
    
except KeyboardInterrupt:
    p.stop()
    GPIO.cleanup()

So, there you have it. Please modify and experiment and enjoy your Raspberry Pi 4.

© S Lazy-H 2019 -