experimentation; I think I achieved it with this!
This display is an 8 LED common anode mini-board comprised of 8 3mm LEDs each
with a forward current of 2ma, and having a forward voltate of 1.9v. All of the
ballast resistors are 330 ohm, 1/4 watt (the smaller ones).
The anodes of the LEDs are tied together (orange wires) and pinned to GPIO18
pin(12); the cathodes are individually pinned to four low order pins for green
board pins[37, 35, 33, 32), and to four high order pins for red [18, 15, 13, 11].
(The PWM & signal code, that drives this display demo, can be found below.)
Again, even though these diodes have very similar characteristics, they are
quite different, so that for a given set of ballast resistors the brightness
of the green LEDs is less than that for the red LEDs. We solve this problem
with PWM as the +voltage source for this common anode display.
Also, similar to the three-color RGB LED demo, we communicate with this display code
via interrupt signals. I have provided four signal handlers for this binary
display counter:
SIGINT interrupt will end the program (ctl-c)
SIGHUP will shift the counter to the other colored display register
SIGUSR1 will swap the high-low counter order of the display (either color)
SIGUSR2 will flash all LEDs rapidly in sequence in a fast Z pattern
The codes below are free to study, distribute, or to paper your bird cage. The
driver PWM_counter.sh requies the newer version of binary.py.
edit: run the code with:
Code: Select all
./PWM_counter.sh 38 &
Code: Select all
#!/usr/bin/python
#
# PWM_counter.sh
#
# Mark H. Harris
# 06-03-2016
# v.01e
# Rochester, MN 55906
#
#
from binary import *
## obtain red LED pin definitions from binary.py rom dictionary
redHIGH = []
for n in range(4):
redHIGH.append(binH_rom_STD[n][0])
## obtain green LED pin definitions from binary.py rom dictionary
greenLOW = []
for n in range(4):
greenLOW.append(binL_rom_STD[n][0])
## Base duty_cycle <26 - 40>
# red is more intense, need to be dimmed
# green needs a little more intensity
base_duty_cycle = 38
red_duty_offset = -25
green_duty_offset = 40
duty_cycle = base_duty_cycle
## Color LED flag True:Green False:Red
color_led_flag = False
## XOR flag True:use XOR display
xor_flag = True
## STD REV high-low order for display
std_rev = "REV"
## Default pin definitions (colorORDER)
pins = redHIGH
## string value of counter for HUP signal display
hup_value=str(0)
## CMD Flag : gets set if counter>=8 see bin_counter()
# affects USR1 & USR2 signal processing
# cmd_flag: True USR1: inverts high-low order
# cmd_flag: False USR1: inverts xor display
# cmd_flag: True USR2: flasher bars
# cmd_flag: False USR2: highZ pattern
cmd_flag=False
## Single pin ON
def pI_on(pin,duty):
p.ChangeDutyCycle(duty)
led_off(pin)
## Single pin OFF
def pI_off(pin,duty):
p.ChangeDutyCycle(duty)
led_on(pin)
## Set all pins ON
def pI_all(pins, duty):
p.ChangeDutyCycle(duty)
for pin in pins:
pI_on(pin, duty)
## pin on no pwm control
def p_on(pin):
led_off(pin)
## pin off no pwm control
def p_off(pin):
led_on(pin)
def p_all(pins):
for pin in pins:
p_on(pin)
## Set all pins OFF
def p_none():
for pin in redHIGH:
p_off(pin)
for pin in greenLOW:
p_off(pin)
p_none()
## Main Routine
def bin_counter(duty):
global hup_value
global cmd_flag
p.start(duty+red_duty_offset)
while(1):
for n in range(16):
if (n>=8):
cmd_flag=True
else:
cmd_flag=False
hup_value = bin(n)+' '+hex(n)
if (color_led_flag):
p.ChangeDutyCycle(duty+green_duty_offset)
if (xor_flag):
nl_xor(n,std_rev)
else:
nl(n,std_rev)
else:
p.ChangeDutyCycle(duty+red_duty_offset)
if (xor_flag):
nh_xor(n,std_rev)
else:
nh(n,std_rev)
sleep(0.77)
## Signal Handlers for HUP, USR1, USR1
# USR2
def ssigusr2(signum, frame):
if (cmd_flag):
print("USR2:"+str(signum)+" caught: high-Z pattern")
print(" ")
for n in range(7):
for pin in greenLOW:
p_none()
pI_on(pin,duty_cycle+green_duty_offset)
sleep(.047)
for pin in redHIGH:
p_none()
pI_on(pin,duty_cycle+red_duty_offset)
sleep(.047)
p_none()
else:
print("USR2:"+str(signum)+" caught: flasher bars ON")
print(" ")
for n in range(7):
pI_all(greenLOW, duty_cycle+green_duty_offset)
sleep(.128)
p_none()
pI_all(redHIGH, duty_cycle+red_duty_offset)
sleep(.128)
p_none()
# USR1
def ssigusr1(signum, frame):
global std_rev
global xor_flag
if (cmd_flag):
if (std_rev=="REV"):
std_rev="STD"
else:
std_rev="REV"
print("USR1:"+str(signum)+" caught: inverting high-low order")
print(" ")
else:
if (xor_flag):
xor_flag=False
else:
xor_flag=True
print("USR1:"+str(signum)+" caught: inverting xor display")
print(" ")
# HUP
def ssighup(signum, frame):
global color_led_flag
global pins
p_none()
if (color_led_flag):
pins=redHIGH
color_led_flag=False
offset=red_duty_offset
regColor="RED"
else:
pins=greenLOW
color_led_flag=True
offset=green_duty_offset
regColor="GREEN"
p_all(pins)
print("HUP:"+str(signum)+" caught: shifting to "+regColor+" display: "+hup_value)
print(" ")
for n in range(3):
if (color_led_flag):
p.ChangeDutyCycle(duty_cycle+offset+20)
else:
p.ChangeDutyCycle(duty_cycle+offset+5)
sleep(.4)
if (color_led_flag):
p.ChangeDutyCycle(14)
else:
p.ChangeDutyCycle(1)
sleep(.4)
p_none()
signal.signal(signal.SIGHUP, ssighup)
signal.signal(signal.SIGUSR1, ssigusr1)
signal.signal(signal.SIGUSR2, ssigusr2)
## Main Try Block calls Main Routine
#
try:
duty_cycle = base_duty_cycle
bin_counter(duty_cycle)
except KeyboardInterrupt:
print("blinker ended by interrupt, bye!")
print(" ")
except:
print(" ")
print("unmonitored exception in bin_counter()")
finally:
p.stop()
gpio.cleanup()
Code: Select all
#################################################################
## binary.py header for BreadBoard (8) bit LED binary display
# v0.02e
#
# Mark H. Harris
# 6-01-2016
# Rochester, MN
#
#################################################################
##
# Import the GPIO library and set the mode to "board numbering"
#
from time import sleep
from sys import argv
import signal, os
import RPi.GPIO as gpio
gpio.setmode(gpio.BOARD)
# Define the binary pin dictionarys REV {reverse} STD {standard}
# note 1: GPIO #s in these dictionarys are text labels only.
# {index:[pin#,"GPIO#"]}
bin_rom_STD = {0:[37,"GPIO26"], 1:[35,"GPIO19"], 2:[33,"GPIO13"], 3:[32,"GPIO12"], 4:[18,"GPIO24"], 5:[15,"GPIO22"], 6:[13,"GPIO27"], 7:[11,"GPIO17"]}
bin_rom_REV = {7:[37,"GPIO26"], 6:[35,"GPIO19"], 5:[33,"GPIO13"], 4:[32,"GPIO12"], 3:[18,"GPIO24"], 2:[15,"GPIO22"], 1:[13,"GPIO27"], 0:[11,"GPIO17"]}
binH_rom_STD = {0:[18,"GPIO24"], 1:[15,"GPIO22"], 2:[13,"GPIO27"], 3:[11,"GPIO17"]}
binL_rom_STD = {0:[37,"GPIO26"], 1:[35,"GPIO19"], 2:[33,"GPIO13"], 3:[32,"GPIO12"]}
binH_rom_REV = {3:[18,"GPIO24"], 2:[15,"GPIO22"], 1:[13,"GPIO27"], 0:[11,"GPIO17"]}
binL_rom_REV = {3:[37,"GPIO26"], 2:[35,"GPIO19"], 1:[33,"GPIO13"], 0:[32,"GPIO12"]}
# Set the pinblock for PWM on GPIO18
#
gpio.setup(12, gpio.OUT)
p = gpio.PWM(12, 440)
p.stop()
# Set the pinblock for input on GPIO16
#
button1=36
gpio.setup(button1, gpio.IN, pull_up_down=gpio.PUD_UP)
# Set the pinblock for output on all eight dictionary pins
#
for n in range(8):
gpio.setup(bin_rom_STD[n][0],gpio.OUT)
## FUNCTION DEFINTIONS ##########################################
#
def push_button():
if gpio.input(button1):
return False
else:
return True
def led_on(pin):
gpio.output(pin, True)
def led_off(pin):
gpio.output(pin, False)
def test_leds(orient):
if (orient=="REV"):
pins=bin_rom_REV
else:
pins=bin_rom_STD
for n in range(8):
led_on(pins[n][0])
sleep(.68)
for n in range(7,-1,-1):
led_off(pins[n][0])
sleep(.68)
def bin_nibble_display(nval,high_low,orient):
if (orient=="REV"):
if (high_low=="H"):
pins=binH_rom_REV
else:
pins=binL_rom_REV
else:
if (high_low=="H"):
pins=binH_rom_STD
else:
pins=binL_rom_STD
for n in range(3,-1,-1):
if (nval & 2**n != 0):
led_on(pins[n][0])
else:
led_off(pins[n][0])
def nl_xor(val,std_rev):
xor_val = val^0xf
bin_nibble_display(xor_val,"L",std_rev)
def nh_xor(val,std_rev):
xor_val = val^0xf
bin_nibble_display(xor_val,"H",std_rev)
def nl(val,std_rev):
bin_nibble_display(val,"L",std_rev)
def nh(val,std_rev):
bin_nibble_display(val,"H",std_rev)
def binary_display(nval,orient):
if (orient=="REV"):
pins=bin_rom_REV
else:
pins=bin_rom_STD
for n in range(7,-1,-1):
if (nval & 2**n != 0):
led_on(pins[n][0])
else:
led_off(pins[n][0])
def bd(val):
binary_display(val,"REV")
def all_off():
nl(0x0)
nh(0x0)
def all_on():
bd(0xff)
def p_count(orient,t_delay):
button=False
for n in range(1,256,1):
binary_display(n,orient)
sleep(t_delay)
if push_button():
button=True
break
return button
def t_count(orient,t_delay):
for n in range(1,256,1):
binary_display(n,orient)
sleep(t_delay)
if push_button():
sleep(2)
break
def counter(maxVal,orient,t_delay):
for n in range(1,maxVal,1):
binary_display(n,orient)
sleep(t_delay)
def count(orient,t_delay):
for n in range(1,256,1):
binary_display(n,orient)
sleep(t_delay)
def walk(orient,t_delay):
for n in range(8):
binary_display(2**n,orient)
sleep(t_delay)
all_off()
def dsp_rom(high_low,orient):
if (orient=="REV"):
if (high_low=="H"):
pins=binH_rom_REV
else:
pins=binL_rom_REV
else:
if (high_low=="H"):
pins=binH_rom_STD
else:
pins=binL_rom_STD
for n in range(4):
print(pins[n][1]," BRD#:",pins[n][0]," index:",n)
def dsp_bin_rom():
print("L------------------------------------------")
dsp_rom("L","REV")
print("H------------------------------------------")
dsp_rom("H","REV")
def end():
gpio.cleanup()
quit()
marcus
edit: PS When signal SIGHUP is sent the code will shift to the other register... with an intermediate PWM flashing of low-high that somewhat resembles the brake-lights on a modern vehicle. If you scan the area quickly with your eyes, or shake gently the display, you can actually see the PWM working !
I find this extremely annoying on the highway at night; the new Cadillac is particularly annoying... because they have their PWM frequency set to low, and the high brightness set too high. Because red has a VERY intense persistence of vision on the eye's retinas, if PWM is not implemented correctly the effect is somewhat less than desireable !
The PWM freq is set in this demo to concert A, 440 Hz.
marcus