07-15-2016, 09:27 AM
(This post was last modified: 08-23-2016, 05:30 PM by MarkHaysHarris777.)
I have reworked my LED lab specifically for the PineA64 board demo codes (uploaded here) which highlight the RPi.GPIO-PineA64 module from github; as well the Sparkfun T cobbler breakout board and 40pin ribbon cable.
The LED layout is changed to a row of blue 5mm diodes in a single line; the GPIO pins are GP20 - GP27 (BCM Broadcom numbering) on the PI bus.
Three files have been uploaded here for convenience sake; I may put them on github later. They are the following:
display8bit.py the main python3 import file using RPi.GPIO-PineA64
dsp_patterns3.sh the main python3 driver GPIO patterns demo script
ssendsig.sh the signal generator for controlling dsp_patterns3.sh
The display8bit.py file may be imported in the Python3 REPL for manual use. The script dsp_patterns3.sh uses display8bit.py (imports it) and is intended to be run in the background. The script is controlled by the ssendsig.sh script which generates either -SIGHUP, -SIGUSR1, -SIGUSR2, or -SIGINT for controlling the frequency|speed, forward pattern, reverse pattern, or keyboard interrupt respectively. They will be explained in more detain below.
Manual Operation of RPi.GPIO-PineA64 (Python3 REPL)
The ssendsig.sh script should be located in your path, maybe your ~/bin directory; as long as its in the $PATH. The other two scripts are located in your ~/Python3/ directory; cd into the ~/Python3/ directory.
To start the REPL for GPIO use enter:
sudo python3
>>> from display8bit import *
The display8bit.py file divides the eight (8) LEDs into two groups ( high_pins, and low_pins ) or high-order and low-order binary digits; each 4 bits in length. They may be addressed four or eight at a time. Any of the defined commands in display8bit may be used directly in the REPL main namespace. Several examples are listed below:
>>> all_on()
>>> all_off()
>>> led_on(high_pins[n]) n is binary digit 0-3
>>> led_off(high_pins[n]) n is binary digit 0-3
>>> led_on(low_pins[n]) n is binary digit 0-3
>>> led_off(low_pins[n]) n is binary digit 0-3
>>> bin_display() not intended to be called directly
>>> dsp8_INV(0xNN) NN 8 bit hex value low-order high-order
>>> dsp8_STD(0xNN) NN 8 bit hex value high-order low-order
>>> walking(1, .7, "STD") digits walk right to left
>>> walking(1, .7, "INV") digits walk left to right
>>> counter_4bit(0x11,low_pins,.7,"STD")
>>> counter_4bit(0x11,low_pins,.7,"INV")
>>> counter_4bit(0x11,high_pins,.7,"STD")
>>> counter_4bit(0x11,high_pins,.7,"INV")
>>> counter_8bit(0x101,.250,"STD")
>>> counter_8bit(0x101,.250,"INV")
>>> end() this command exits the REPL, and cleans up the GPIO
Scripted Operation of RPi.GPIO-PineA64 (dsp_patterns3.sh)
To start the dsp_patterns3.sh script in the background enter:
sudo -b ./dsp_patterns3.sh
The main driver script dsp_patterns3.sh imports display8bit.py and uses it to display twelve (12) light patterns on the LED lab breadboard. The patterns are selected by sending the script (running in the background) one of four signals. Signal handlers then modify the operation of the script on the fly.
USR1: selects on the forward patterns from an indexed list (see code)
USR2: selects on the reverse patterns from an indexed list (see code)
HUP: changes the speed of the display
INT: similar to ctrl-c on the keyboard... stops the background process
The signals may be sent via htop, or the kill command, or from the supplied ssendsig.sh script; examples follow:
sudo ~/bin/ssendsig.sh dsp_pattern INT
sudo ~/bin/ssendsig.sh dsp_pattern HUP
sudo ~/bin/ssendsig.sh dsp_pattern USR1
sudo ~/bin/ssendsig.sh dsp_pattern USR2
The script finds the process number from the process name (dsp_pattern) and then issues the appropriate kill command.
The purpose of the demo codes display8bit.py is to highlight the RPi.GPIO-PineA64 module(s) and to document how to use the GPIO of input | output. At this time the module can not be used for i2c, SPI, nor pwm.
The purpose of the demo codes dsp_patterns3.sh is to highlight a proper way of coding a Python3 script for accessing the GPIO with a 'try block'; also a way to control a background script with the use of signals and signal handlers.
While I hope that these codes will be useful, I do not guarantee that they will be suitable for any purpose what-so-ever; nor do I accept responsibility for their use or subsequent success or failure/ the user herself|himself must bear the responsibility for the use of these codes.
If you have questions about these codes, post your comments here, or even better join us on the irc.pine64.xyz:6697 chat for a friendly discussion. You may also PM me, or send me a private message on this forum.
marcus
edit: PS please notify me asap should you find errors; I will correct them immediately; and thank you !
#*****************************************************************
# author: Mark H. Harris
# license: GPLv3
#
# THIS SOFTWARE IS PROVIDED BY THE COPYLEFT HOLDERS AND
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYleft HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENCIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#*****************************************************************
Code:
ssendsig.sh
#!/bin/bash
echo
PWMPID=$(ps ax |grep -i $1 |grep -v grep |grep -v sudo |grep -v ssendsig |awk '{print $1}' )
echo "PID: $PWMPID"
if [ "$PWMPID" != "" ]
then
if [[ "$2" != "HUP" && "$2" != "INT" && "$2" != "USR1" && "$2" != "USR2" ]]
then
echo "Error: valid signals are HUP INT USR1 USR2"
else
exec kill -SIG$2 $PWMPID
fi
else
echo "PWM_counter.sh does not appear to be running"
fi
Code:
display8bit.py
## display8bit.py
#
# Mark H. Harris
# v.01i
# 07-15-2016
# Rochester, MN
#
#
## IMPORTS
from time import sleep
from sys import argv
import RPi.GPIO as GPIO
## ALL GPIO use Broadcom Numbering
GPIO.setmode(GPIO.BCM)
## PUSH BUTTON SWITCH DEFINED HERE, BUT NOT ALWAYS USED
p_switch = 19
GPIO.setup(p_switch, GPIO.IN, pull_up_down=GPIO.PUD_UP)
## BINARY ROMS
high_pins=[23, 22, 21, 20]
for pin in high_pins:
GPIO.setup(pin, GPIO.OUT)
low_pins=[27, 26, 25, 24]
for pin in low_pins:
GPIO.setup(pin, GPIO.OUT)
## FUNCTION DEFINITIONS
def push_button():
if GPIO.input(p_switch):
return False
else:
return True
def led_on(pin):
GPIO.output(pin, True)
def led_off(pin):
GPIO.output(pin, False)
def bin_display(val, led_rom, nibble, std_inv):
bin_digit = nibble
if (std_inv=="STD"):
start=0; finish=4; incrmt=1
else:
start=3; finish=-1; incrmt=-1
for n in range(start, finish, incrmt):
if (val & bin_digit):
led_on(led_rom[n])
else:
led_off(led_rom[n])
bin_digit = bin_digit<<(1)
def dsp8_STD(val):
bin_display(val, high_pins, 0x10, "STD")
bin_display(val, low_pins, 0x1, "STD")
def dsp8_INV(val):
bin_display(val, low_pins, 0x10, "INV")
bin_display(val, high_pins, 0x1, "INV")
def counter_8bit(max, t_delay, std_inv):
for n in range(max):
if (std_inv=="STD"):
dsp8_STD(n)
else:
dsp8_INV(n)
sleep(t_delay)
def counter_4bit(max, led_rom, t_delay, std_inv):
for n in range(max):
bin_display(n, led_rom, 0x1, std_inv)
sleep(t_delay)
def walking(cycles, t_delay, std_inv):
for m in range(cycles):
digit=0x1
for n in range(9):
if (std_inv=="STD"):
dsp8_STD(digit)
else:
dsp8_INV(digit)
sleep(t_delay)
digit = digit << (1)
def all_off():
dsp8_INV(0x0)
def all_on():
dsp8_INV(0xff)
def end():
GPIO.cleanup()
quit()
Code:
dsp_patterns3.sh
#!/usr/bin/python3
# dsp_patterns3.sh
#
# Mark H. Harris
# v.01i
# 07-15-2016
# Rochester, MN
#
## REQUIRES v.10h display8bit.py
import display8bit as DSP
import signal as SIG
## RUN CYCLE COUNTER DISPLAYED WITH HUP SIGNAL
cycle = 0
## EXIT FLAG FROM SIGINT INTERRUPT HANDLER
interrupt_flag = False
## DISPLAY ORDER OF PATTERNS USED BY SIGUSR1 AND SIGUSR2
led_pattern_index=[2, 12, 3, 1, 4, 9, 11, 5, 7, 6, 8, 0, 10]
## BEGINNING DISPLAY PATTERN (IN THIS EXAMPLE 1)
# led_pattern_index numbered from 0
# pattern_index = 2
# led_pattern_index[2] = 1 (see index above)
pattern_index=2
pattern_num = led_pattern_index[pattern_index]
## FREQUENCY SETTINGS (DELAYS) SET BY HUP
tt_delay_val=[0.023, 0.077, 0.140, 0.258, 0.70]
tt_delay_index=2
tt_delay=tt_delay_val[tt_delay_index]
## DISPLAY LED PATTERN ROMS
circular2R = [0x88, 0xc0, 0x60, 0x30, 0x11, 0x03, 0x06, 0x0c]
dual_walker= [0x81, 0x42, 0x24, 0x18, 0x24, 0x42]
side_side_steps = [0x08, 0x40, 0x02, 0x10, 0x01, 0x20, 0x04, 0x80]
two_led_wave = [0x88, 0x44, 0x22, 0x11, 0x22, 0x44]
all_leds_on_flasher = [0xff, 0x00]
high_low_bars_flasher = [0xf0, 0x0f]
alternating_flasher = [0x69, 0x96]
curtain_scanner = [0x1f, 0x8f, 0xc7, 0xe3, 0xf1, 0xf8, 0xf1, 0xe3, 0xc7, 0x8f]
## SIGUSR2 HANDLER FOR SELECTING PREVIOUS DISPLAY INDEX
def ssigusr2(signum, frame):
global pattern_num
global pattern_index
if (pattern_index>0):
pattern_index-=1
else:
pattern_index=len(led_pattern_index)-1
pattern_num=led_pattern_index[pattern_index]
print("\n USR1: swapping backward to previous pattern: "+str(pattern_num)+"\n")
## SIGUSR1 HANDLER FOR SELECTING NEXT DISPLAY INDEX
def ssigusr1(signum, frame):
global pattern_num
global pattern_index
if (pattern_index<len(led_pattern_index)-1):
pattern_index+=1
else:
pattern_index=0
pattern_num=led_pattern_index[pattern_index]
print("\n USR1: swapping forward to next pattern: "+str(pattern_num)+"\n")
## SIGHUP HANDLER FOR DISPLAYING INFORMATION AND ROTATING DELAY INDEX
def ssighup(signum, frame):
global tt_delay
global tt_delay_index
tt_delay_top = len(tt_delay_val)-1
if (tt_delay_index<tt_delay_top):
tt_delay_index+=1
else:
tt_delay_index=0
tt_delay=tt_delay_val[tt_delay_index]
print("\n cycle: "+str(cycle))
print("\n delay: "+str(tt_delay))
print("\n HUP: presently displaying pattern: "+str(pattern_num)+"\n")
## SIGINT HANDLER FOR EXITING THE DISPLAY PROCESS
def ssigint(signum, frame):
global interrupt_flag
print("\n keyboard interrupt"+"\n")
interrupt_flag = True
## SIGNAL TRAPS
SIG.signal(SIG.SIGINT, ssigint)
SIG.signal(SIG.SIGHUP, ssighup)
SIG.signal(SIG.SIGUSR1, ssigusr1)
SIG.signal(SIG.SIGUSR2, ssigusr2)
## DISPLAY FUNCTION FOR READING AND RESOLVING DISPLAY ROMS INFORMATION
def displayf(pattern, fwd_rvs):
p_pattern=[]
if (fwd_rvs=="RVS"):
for n in range(len(pattern)-1, -1, -1):
p_pattern.append(pattern[n])
else:
p_pattern=pattern
for p_code in p_pattern:
DSP.dsp8_STD(p_code)
DSP.sleep(tt_delay)
## MAIN TRY BLOCK FOR THE DISPLAY PROCESS
while (not interrupt_flag):
try:
if (pattern_num==0):
## 0 FLASHING BARS OF GREEN AND RED
displayf(high_low_bars_flasher, "FWD")
if (pattern_num==1):
## 1 DUAL WALKING PATTERN SIMPLE
displayf(dual_walker, "FWD")
if (pattern_num==2):
## 2x2 ALTERNATE FLASHING PATTERN SIMPLE
DSP.dsp8_STD(0xcc)
DSP.sleep(tt_delay)
DSP.dsp8_STD(0x33)
DSP.sleep(tt_delay)
if (pattern_num==3):
## 3 SINGLE RAPID WALKER FROM DSP
DSP.walking(1, tt_delay, "STD")
DSP.sleep(tt_delay)
DSP.walking(1, tt_delay, "INV")
DSP.sleep(tt_delay)
if (pattern_num==4):
## 4 STEPS BACK-AND-FORTH LEFT-AND-RIGHT
displayf(side_side_steps, "FWD")
DSP.dsp8_STD(0x0)
DSP.sleep(tt_delay)
displayf(side_side_steps, "RVS")
DSP.dsp8_STD(0x0)
DSP.sleep(tt_delay)
if (pattern_num==5):
## 5 CLOCK-WISE 2-LED CIRCULAR WALKING D-RIGHT
displayf(circular2R, "FWD")
if (pattern_num==6):
## 6 COUNTER CLOCK-WISE 2-LED CIRCULAR WALKING D-LEFT
displayf(circular2R, "RVS")
if (pattern_num==7):
## 7 STROBE RIGHT
DSP.walking(1, tt_delay, "INV")
DSP.sleep(tt_delay)
if (pattern_num==8):
## 8 STROBE LEFT
DSP.walking(1, tt_delay, "STD")
DSP.sleep(tt_delay)
if (pattern_num==9):
## 9 TWO LED WAVE DISPLAY
displayf(two_led_wave, "FWD")
if (pattern_num==10):
## 10 ALL LEDS ON FLASHER !
displayf(all_leds_on_flasher, "FWD")
if (pattern_num==11):
## 11 ALTERNATING PATTERN INTERESTING
displayf(alternating_flasher, "FWD")
if (pattern_num==12):
## 12 ALTERNATING PATTERN INTERESTING
displayf(curtain_scanner, "FWD")
finally:
if interrupt_flag:
break
cycle+=1
# print("cycle: "+str(cycle)+"\n") DSP.all_off()
DSP.GPIO.cleanup()