User avatar
MarkHaysHarris777
Posts: 1820
Joined: Mon Mar 23, 2015 7:39 am
Location: Rochester, MN
Contact: Website

Sparkfun PI Wedge B+ 2bit Binary Counter & Display Demo

Mon Jun 06, 2016 3:52 am

Sparkfun_cobbler.jpg
Sparkfun PI Wedge B+ (compatible with 2B and 3B)
Sparkfun_cobbler.jpg (45.91 KiB) Viewed 2854 times
(right click on the pic for display in another tab to get enlarged pic)

In this thread I'll be introducing the Sparkfun Wedge b+ (compatible with 2B and 3B) for use as a GPIO addon, making GPIO (Broadcom numbering) a snap. This first post is just the Wedge introduction; subsequent posts will provide detailed pics, and some coding examples !

Sorry for the focus; for this intro that's not too important... the Wedge from Sparkfun brings the 40 pin GPIO to the outside with a 40 pin ribbon cable, similar to an old-style IDE cable (but, its not the same!). The 'cobbler' end that plugs into the breadboard (white board) organizes the GPIO as Broadcom numbering with the pins ordered and grouped; wiring is very easy because a wiring chart is not necessary, and pin 'counting' is not required.

I have been quoted on this site as preferring individual jumpers... and while that is true... I should point out that I have a couple of cobblers and I use them! So, I decided to give some examples of the cobbler technique... and because I prefer the Sparkfun Wedge to the AdaFruit Cobbler, articulating that is also in my motivation.

The setup in the pic is two LEDs on BCM GPIO25 & GPIO27 with a push_button switch on GPIO26 with a pullup. A lot of experimenting can be done with this two LED (2bit) system and 1 switch; subsequent posts will provide those examples; later tonight. I avoid placing Vcc (5v) or 3v3 on the white board at all... they are available on the cobbler. The outside rails are ground (pretty common) and the grey wires route each LED and the Switch to ground. The jumpers for the LEDs (yellow and green) and the jumper for the Switch (orange) route the GPIO(+) from the cobbler out to the board.

I must admit some embarrassing humility at this point (as a warning to others mostly); the Wedge comes as a kit... it must be soldered. The up side is that the soldering (all things considered) is easy on this board. The down side is that because the board is printed on both sides, its easy to get mixed up and solder the pins up-side-down... yes, I did that. Its only lucky that I noticed this before I plugged it in! Uffda! Anyway, I pulled the pinblock casing (black) off with pliers and then de-soldered all 40 pins and then started again! It works well, and as said previously, I think it works better than the AdaFruit cobbler because the labeling is better, and the cable comes off the end of the breadboard.

(the PI pictured is rasppi2; my 2B with WiPi... which was actually my first PI)
marcus
:ugeek:

User avatar
MarkHaysHarris777
Posts: 1820
Joined: Mon Mar 23, 2015 7:39 am
Location: Rochester, MN
Contact: Website

Re: Sparkfun PI Wedge B+ 2bit Binary Counter & Display Demo

Mon Jun 06, 2016 6:19 am

cobbler3_sparks.jpg
Wedge whiteboard topview
cobbler3_sparks.jpg (47.43 KiB) Viewed 2786 times
The 2bit codes blink2bit.py and blink2bit.sh are
listed below in this post.

While we're looking at this top view I'll make a few comments about this
layout. First (and maybe most important) you'll notice that the GPIO pins are
exposed on (top) as solder points. This is a problem for two primary reasons:
1) your PI is ESD sensitive; reaching out and touching the top of the Wedge
with your fingers (if you have not been grounded) is likely to destroy your
PI with an ESD flash, and 2) if you drop anything on top of the Wedge
(paper clip, penny, farthing, bobby pin, tweezers &c) your PI can be toast! So
what? So... place a length of electrical tape (not pictured) across the top
of the Wedge when you're finished with your setup to protect the pins!

The grey wires are running the componenets to ground (as well the Wedge). The
Vcc (5v) is exposed on the Wedge (be careful!) I do not run Vcc to the bread
board ever, and I seldom run 3v3 to the breadboard either.

Think of the Switch as a 4x3 block (it is geometrically 4 whiteboard units
long and 3 whiteboard units wide. The pins along the 4 side are
shorted internally on each side. The Switch 'makes' between the pins on the
3 side. Be careful... if you plug the Switch in 'crossways'
by 90 degrees it will be as though the Switch were shorted or always on!
.
This has caused many a nooby fits galore! Why won't my Switch work??
cobbler2_sparky.jpg
looking down the board; notice component layout and pin27!
cobbler2_sparky.jpg (29.51 KiB) Viewed 2786 times
I got these square LEDs off of an old router that quit working; I saved them
and have been breadboarding with them ever since. Looking down the board setup
you can see the placement of the components. Please notice the resistors. The
contact points of the resistors uppermost are the points going
to ground, deliberately. That way GPIO pins are not exposed uppermost and the upper points are harmless grounds. Keep your jumpers as short as is possible and practical; this is not always possible, but its a good rule to try and follow especially for increased frequencies or electrically noisy environments.

Also, notice please on this pic that it looks like the yellow jumper is plugged into the SCL pin... IT IS NOT! It is plugged into GPIO27. This also causes some noobs fits when using the Wedge because unless you're looking
directly down at the board it is VERY easy to be off by one pin... why doesn't it work??
cobbler_sparkfun.jpg
Wedge closeup; notice pin arrangements
cobbler_sparkfun.jpg (45.19 KiB) Viewed 2786 times
This pic is just to show the detail of the Sparkfun Wedge B+ pin arrangement.
Please notice that the pins are mostly in order! Also, the special pins are
arranged by grouping (SPI pins CEx MOSI MISO SCK) are together! The upside of
this arrangement is that if you're using ONLY Broadcom numbering BCM then it
becomes for you very easy to find the pin your looking for without counting
and without a cheat chart; the down side is that with the Wedge there is NO
way of knowing the board number without a chart (they aren't noted and you
cannot count them!). Again, notice the yellow pin! Its really plugged into
GPIO27...

The codes that drive this little setup in Python are now listed below. In the next post I will explain the theory of the codes, how they work, and why they
are split out like they are.

blink2bit.py

Code: Select all

## blink2bit.py
#
#   Mark H. Harris
#   v.01a
#   06-07-2016
#   Rochester, MN
#
from time import sleep
from sys import argv
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)

yellow_LED = 27
green_LED = 25
p_switch = 26
GPIO.setup(yellow_LED, GPIO.OUT)
GPIO.setup(green_LED, GPIO.OUT)
GPIO.setup(p_switch, GPIO.IN, pull_up_down=GPIO.PUD_UP)

led_rom=[green_LED, yellow_LED]

def push_button():
    if GPIO.input(p_switch):
        return False
    else:
        return True

def led_on(led):
    GPIO.output(led, True)

def led_off(led):
    GPIO.output(led, False)

def duty_led(led, Htime, Ltime):
    led_on(led)
    sleep(Htime)
    led_off(led)
    sleep(Ltime)

def blinker(led, t_high, t_low, t_count):
    for n in range(t_count):
        duty_led(led, t_high, t_low)

def bin_display(val):
    bin_digit = 0x1
    for n in range(2):
        if (val & bin_digit):
            led_on(led_rom[n])
        else:
            led_off(led_rom[n])
        bin_digit = bin_digit<<(1)

def counter(max, t_delay):
    bin_digit = 0x1
    for n in range(max):
        bin_display(n)
        sleep(t_delay)

def end():
    GPIO.cleanup()
    quit()


blink2bit.sh

Code: Select all

#!/usr/bin/python
# blink2bit.sh
#
#   Mark H. Harris
#   v.01a
#   06-07-2016
#   Rochester, MN
#
from blink2bit import *

cycle=0

while (True):
    try:
        print("green flasher")
        blinker(green_LED, .2, .3, 7)
        if push_button():
            print("button pressed and held down for exit ...") 
            break
        print("yellow flasher")
        blinker(yellow_LED, .2, .3, 7)
        print("binary counter")
        counter(17, .5)
    except KeyboardInterrupt:
        print("\n keyboard interrupt")
        break
    except:
        print("\n unmonitored exception")
        break
    finally:
        cycle+=1
        print("cycle: "+str(cycle)+"\n")

GPIO.cleanup()


marcus
marcus
:ugeek:

User avatar
MarkHaysHarris777
Posts: 1820
Joined: Mon Mar 23, 2015 7:39 am
Location: Rochester, MN
Contact: Website

Re: Sparkfun PI Wedge B+ 2bit Binary Counter & Display Demo

Mon Jun 06, 2016 8:04 am

Sparky_running.jpg
Sparkfun Wedge working fine, notice the protective tape !
Sparky_running.jpg (35.58 KiB) Viewed 2738 times
I had intended all of the coloring to be consistent... yellow-yellow, green-green, rats... in the previous pics the LEDs were plugged into the wrong wires.

Please notice the protective electrical tape covering the pins of the Wedge;
this does not have to be fancy, of course, but it should not be over-looked.

Again, take a look at the pin arrangment of the Switch. The contact points
[F30 - I30] (Switch side closest to you) are shorted internally. Likewise,
[F28 - I28] are also shorted internally. When the Switch is pressed down
momentarily the internal short points FI30 and FI28 are then 'closed' and
the Switch 'makes'.

The push_button() logic found in blink2bit.py is reversed. That is because the Switch is actually providing a 'ground shot' to pin GPIO26 (which has a pullup on it!) the read internal to the function sees 'low' when the button is pressed and sees 'high' when it normal is. So, the logic is coded to do what the function name suggests NOT what the actual state of the pin is! When the read sees 'high' it returns False, and when it sees 'low' it returns True.

blink2bit.py contains all of what we might call header information (as programmers) which has includes as well as global variables, and function definitions that the main script will need to call. Reading this file (as a human being) will tell you what 'functions()' the system has, and might give you ideas for how you might expand on the concepts yourself. blink2bit.sh is the main script driver code. It imports the header information (blink2bit.py) and then executes its primary 'try block'; which calls the functions it needs, as well as handling an exit strategy and various errors that might occur.

To run this code place both files in the same working directory and make the file name blink2bit.sh executable with:

Code: Select all

chmod 0754 blink2bit.sh
To run the demo codes use sudo (this is for legacy Raspbian on older 2bs):

Code: Select all

sudo ./blink2bit.sh
To exit the code press ctrl-c (-SIGINT) on your keyboard. Otherwise you can exit the code while it is running by pressing and holding the push_button() [Switch] through the transition from 'green flasher' to 'yellow flasher'.

The codes will loop forever (reporting status to the console) until told explicitly to quit (see above).

The codes are short and simple (yet profound). They form what some of us call might call a boiler plate. All Python GPIO driver codes can be structured this same way using almost the exact same approach. To build a new project just copy and tweak, as we say! This blink2bit example (and some others like it) are nice because they can be used to test GPIO pins quickly just by changing the Wedge connections (modifying the blink2bit.py pin defs) and running. The changes could also be passed in as parameters with the redefinitions being somewhat automatic! I have used this little example to test all of the GPIO pins on my PI in just minutes.

In subsequent posts I will expand on this concept to provide the 4bit and 8bit equivalent setups.

I would not be complete except to also point out that you can very deliberately wire the Sparkfun board pins up-side-down... so that the pins on the labeled extension have pins that point UP rather than DOWN. Then you can use individual male-female jumpers (as I prefer to do) without wasting a lot of space on your whiteboard!

... until next time.

marcus
marcus
:ugeek:

User avatar
MarkHaysHarris777
Posts: 1820
Joined: Mon Mar 23, 2015 7:39 am
Location: Rochester, MN
Contact: Website

Re: Sparkfun PI Wedge B+ 2bit Binary Counter & Display Demo

Mon Jun 06, 2016 4:15 pm

This post includes the blink4bit.sh and blink4bit.py source codes for the 4 and 8 bit counter | display demo using the Sparkfun Wedge B+ addon breakout board; listed below.

I'll be showing three ways to breakout this project from the Wedge to the breadboards, and how to save breadboard space by thinking outside the box a bit.
blink4bit_3b.jpg
Sparkfun Wedge breakout facilitating 4bit and 8bit display
blink4bit_3b.jpg (37.66 KiB) Viewed 2625 times
In the above pic I've transferred the compact binary display to my whiteboard; but, please notice that the Sparkfun Wedge takes up more than half the board. There are three primary ways to solve this problem. One of course is to use a larger board! One way is to remove the Wedge from the board entirely and turn it over. The GPIO pins are exposed pointing upwards; which requires care, especially since two of them have five volts hanging on them! This saves breakboard space (obviously) but requires that you have a set of male-female jumpers. If you prefer to use the Wedge this way, the kit may be soldered so that the cable does not have to be folded over; please notice that the back side of the Wedge is also printed so that wiring is easy without a chart. (see below)
blink4bit_1b.jpg
inverted Wedge eliminates extra bread board
blink4bit_1b.jpg (50.01 KiB) Viewed 2625 times
The third option for breakout with the Wedge is to use the mini-board which holds just the Wedge (the mini-board has 17 columns of pin rows, and the Wedge just happens to have two rows of 17 pins; so, it fits perfectly, as in the following pic. This leaves the main whiteboard open for your project, and it keeps the pins of the wedge protected. This method also usually gives the shortest possible jumper wires in most cases; of course smaller ribbon cables can be hand-made rather than using commercial jumpers (I've done this frequently; it works well and looks great).
blink4bit_8b.jpg
mini-breadboard holds just the Wedge to save space on main whiteboard
blink4bit_8b.jpg (43.56 KiB) Viewed 2625 times
The following codes provide several functions in blink4bit.py for displaying 4bit and 8bit values to this display. The codes are straight-forward and easy to study. As always, blink4bit.sh is the main driver, which shows how to use the primary functions and provides an excellent boilerplate for experimentation or extending the demo for your own purposes.

blink4bit.py

Code: Select all

## blink4bit.py
#
#   Mark H. Harris
#   v.01d
#   06-07-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)

p_switch = 26
GPIO.setup(p_switch, GPIO.IN, pull_up_down=GPIO.PUD_UP)

## BINARY ROMS 
red_pins=[24, 25, 26, 27]
for pin in red_pins:
    GPIO.setup(pin, GPIO.OUT)

green_pins=[17, 16, 13, 12]
for pin in green_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 counter_8bit(max, t_delay, std_inv):
    for n in range(max):
        if (std_inv=="STD"):
            bin_display(n, green_pins, 0x1, std_inv)
            bin_display(n, red_pins, 0x10, std_inv)
        else:
            bin_display(n, red_pins, 0x1, std_inv)
            bin_display(n, green_pins, 0x10, std_inv)
        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):
    for m in range(cycles):
        digit=0x1
        for n in range(9):
            if (n<=4):
                bin_display(digit, red_pins, 0x1, "INV")
            if (n>=4):
                bin_display(digit, green_pins, 0x10, "INV")
            sleep(t_delay)
            digit = digit << (1)
        digit=0x80
        for n in range(9):
            if (n<=4):
                bin_display(digit, green_pins, 0x10, "INV")
            if (n>=4):
                bin_display(digit, red_pins, 0x1, "INV")
            sleep(t_delay)
            digit = digit >> (1)

def all_off():
    bin_display(0x0, green_pins, 0x1, "STD")
    bin_display(0x0, red_pins, 0x1, "STD")

def all_on():
    bin_display(0xf, green_pins, 0x1, "STD")
    bin_display(0xf, red_pins, 0x1, "STD")

def end():
    GPIO.cleanup()
    quit()

blink4bit.py

Code: Select all

#!/usr/bin/python
# blink2bit.sh
#
#   Mark H. Harris
#   v.01d
#   06-07-2016
#   Rochester, MN
#
from blink4bit import *

cycle=0

while (True):
    try:
        walking(5, .049)
        for n in range(7):
            all_on()
            sleep(.25)
            all_off()
            sleep(.25)
        counter_8bit(0x101, .077, "INV")
        sleep(.14)
        counter_8bit(0x101, .077, "STD")
        sleep(.14)
        walking(5, .053)
        for n in range(12):
            bin_display(0xa, green_pins, 0x1, "INV") 
            bin_display(0x5, red_pins, 0x1, "INV") 
            sleep(.077)
            bin_display(0x5, green_pins, 0x1, "INV") 
            bin_display(0xa, red_pins, 0x1, "INV") 
            sleep(.077)
    except KeyboardInterrupt:
        print("\n keyboard interrupt")
        break
    except:
        print("\n unmonitored exception")
        break
    finally:
        cycle+=1
        print("cycle: "+str(cycle)+"\n")

GPIO.cleanup()

marcus
marcus
:ugeek:

User avatar
MarkHaysHarris777
Posts: 1820
Joined: Mon Mar 23, 2015 7:39 am
Location: Rochester, MN
Contact: Website

Re: Sparkfun PI Wedge B+ 2bit Binary Counter & Display Demo

Tue Jun 07, 2016 4:10 am

The culmination of this project may be found in the codes listed bellow. blink8bit.py and blink8bit.sh v.01f provide the highest abstraction for the concept of turning on|off GPIO pins with a binary display. It simply boils down to one of two trival commands:


dsp8_STD(hex-value)

dsp8_INV(hex-value)


... the first if from the perspective of the user if the display is 'right-side-up' STD, or rather, 'up-side-down' INV.

So what? With one python command I can turn any, or all, of the 8 defined GPIO pins on|off without knowing anything at all about GPIO, hardware, electronics nor much of anything else. With a single Python command I can control all eight LEDs and all I have to know is the single display command... because the LEDs correspond to bits in a hexidecimal number. So, if I want to turn on (bring HIGH) the following GPIO pins (17, 16, 13, 12, 24, 25, 26, 27) (highlighted ON) all I need to do to 'turn ON' the highlighted pins is to issue the single trival command:

dsp8_INV(0xda)
blink8bit.jpg
dsp8_INV(0xda) 8 bit controller
blink8bit.jpg (39.36 KiB) Viewed 2521 times
Light patterns of all kinds (or relay control, &c), or counting, can be done simply by manipulating that one 8 bit display command.

blink8bit.py

Code: Select all

## blink8bit.py
#
#   Mark H. Harris
#   v.01f
#   06-08-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)

p_switch = 26
GPIO.setup(p_switch, GPIO.IN, pull_up_down=GPIO.PUD_UP)

## BINARY ROMS 
red_pins=[24, 25, 26, 27]
for pin in red_pins:
    GPIO.setup(pin, GPIO.OUT)

green_pins=[17, 16, 13, 12]
for pin in green_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, red_pins, 0x10, "STD")
    bin_display(val, green_pins, 0x1, "STD")

def dsp8_INV(val):
    bin_display(val, green_pins, 0x10, "INV")
    bin_display(val, red_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()

blink8bit.sh

Code: Select all

#!/usr/bin/python
# blink8bit.sh
#
#   Mark H. Harris
#   v.01f
#   06-08-2016
#   Rochester, MN
#
import blink8bit as BDSP

cycle=0

while (True):
    try:
        ## RAPID DIGIT WALKING PATTERN INVERTED
        BDSP.walking(7, .049, "INV")

        ## ALL LIGHTS FLASH ON AND OFF 
        for n in range(7):
            BDSP.all_on()
            BDSP.sleep(.25)
            BDSP.all_off()
            BDSP.sleep(.25)

        ## 8 BIT BINARY COUNTER DISPLAY GREEN-HIGH RED-LOW
        BDSP.counter_8bit(0x101, .077, "INV")
        BDSP.sleep(.14)

        ## 8 BIT BINARY COUNTER DISPLAY RED-HIGH GREEN-LOW
        BDSP.counter_8bit(0x101, .077, "STD")
        BDSP.sleep(.14)

        ## RAPID ALTERNATING LIGHT PATTERM 
        for n in range(12):
            BDSP.dsp8_INV(0xa5)
            BDSP.sleep(.077)
            BDSP.dsp8_INV(0x5a)
            BDSP.sleep(.077)

        ## RAPID DIGIT WALKING PATTERN STANDARD
        BDSP.walking(7, .049, "STD")

        ## ALL LIGHTS OFF 
        BDSP.dsp8_INV(0x0)
        BDSP.sleep(2)
    except KeyboardInterrupt:
        print("\n keyboard interrupt")
        break
    except:
        print("\n unmonitored exception")
        break
    finally:
        cycle+=1
        print("cycle: "+str(cycle)+"\n")

BDSP.all_off()
BDSP.GPIO.cleanup()

marcus
marcus
:ugeek:

User avatar
MarkHaysHarris777
Posts: 1820
Joined: Mon Mar 23, 2015 7:39 am
Location: Rochester, MN
Contact: Website

Re: Sparkfun PI Wedge B+ 2bit Binary Counter & Display Demo

Tue Jun 07, 2016 9:52 pm

This post speaks to a few of the engineering aspects (electrical characteristics) of my eight diode display. First, I updated the codes (previous post) to v.01f last night; made a couple of things a bit more consistent.

All light emitting diodes are a bit different (even within the same batch) and determining their characteristics from a 'grab bag' requires experimentation. My diodes arrived in a plastic zip bag labeled "diode assortment, 20ma max". It turns out that they are low power LEDs having a forward voltage of about 1.9v and a forward current of about 2-4ma (for nominal light output). The green ones require a bit more current to match the brightness of the red LEDs. I need to choose a ballast resistor that will limit the current to protect the diode, but still have a bright LED... but, without harming the PI if all LEDs are ON during the same period for a length of time !

The specs on the pinblock of the RPi limits the current per pin to 16ma, with the total current (source or sink) to 54ma for the entire pinblock. So, each LED needs to draw less than 16ma (easily accomplished) and the combined current of all LEDs (on at the same time) must not exceed 54ma (perhaps a bit more challenging).
diode_red.jpg
red low power light emitting diode schematic
diode_red.jpg (10.3 KiB) Viewed 2424 times
The two diagrams may be helpful. Keep in mind, the specs for your LEDs will probably be different from mine! My red LEDs run fine with 470 ohm resistors. But they are a little 'happier' with 330 ohms (brighter). By measuring the voltage drop acress the resistor (orange) and then dividing the voltage drop by the resistance ((volts / ohms)*1000 = milli-amps) I find that each red LED is drawing 3.9ma of current; or the diode @ a forward voltage of 1.8v has a forward current of 3.9ma. (1.3v / 330 ohms * 1000 = 3.9ma)
diode_green.jpg
green low power light emitting diode schematic
diode_green.jpg (10.26 KiB) Viewed 2424 times
The green LED needs more current to produce the same lumens as the red LED. I tried a 120 ohm ballast resistor (orange) and found it to be a good compromise. The current for the green LED is found to be ( 0.9 volts / 120 ohms * 1000 = 7.5 ma ) not quite double that for the red LED; about 7.5ma. These measurements are simple empirical hand measurements made with a sensitive digital multimeter (about $9.00). Once you know the characteristics of your LEDs, write it in your notebook for reference later.

So, each LED current is well within the 16ma limit per pin. What about the PI? To find the total current on the pinblock if all LEDs a lit, we multiply and add:

( 7.5 x 4 ) + ( 3.9 x 4 ) = 45.6ma

The LEDs all_on() function draw considerably less than the 54ma max current for the pinblock. Consequently I can be confident that I can run my display safely (for the PI) under all lighting possibilities for the display.

Its now time to transfer my bread-boarded display to a small circuit board 'tester' with a ribbon cable that will be more permanent and will allow me to test my control circuits easily before I connect my driver boards, motors & relays. This display board is not only a fun educational project to play with, but it has uses on the bench (diagnostics test equipment); as well it may be used as a binary output device for debugging and monitoring.

I'll return when I have the prototype display board soldered up...
diodes_pic.jpg
resistor viewpoint 8bit diode display
diodes_pic.jpg (41.87 KiB) Viewed 2424 times
marcus
marcus
:ugeek:

User avatar
MarkHaysHarris777
Posts: 1820
Joined: Mon Mar 23, 2015 7:39 am
Location: Rochester, MN
Contact: Website

Re: Sparkfun PI Wedge B+ 2bit Binary Counter & Display Demo

Wed Jun 08, 2016 4:25 am

dsp_ribbon2.jpg
display board with ribbon cable
dsp_ribbon2.jpg (38.53 KiB) Viewed 2390 times
The 8 bit binary display board hardware has been transferred to the perf-board for eventual install in the chest-plate of my robot. In the mean time it will be used as a diagnostic board. The colored ribbon cable is 46cm x9 wire flexible flat cable; this works really well for routing any bus around the interior of a robot (or anywhere else, for that matter). The ribbon attaches at the other end to a standard set of header pins which can plug into a block (as pictured) or another standard female header.
dsp_ribbon.jpg
display board with UNL2803 driver socket
dsp_ribbon.jpg (51.39 KiB) Viewed 2390 times
marcus
:ugeek:

User avatar
MarkHaysHarris777
Posts: 1820
Joined: Mon Mar 23, 2015 7:39 am
Location: Rochester, MN
Contact: Website

Re: Sparkfun PI Wedge B+ 2bit Binary Counter & Display Demo

Wed Jun 08, 2016 4:40 am

bin_dsp_reverse.jpg
reverse side of the 8 bit binary display & driver board
bin_dsp_reverse.jpg (49.56 KiB) Viewed 2385 times
This PIC shows the reverse side of the display & driver board. The center carries the common ground(s) cathode contact points and the outside edges carry the RPi contact points.
bin_dsp1.jpg
dsp8_STD(0xda) display standard
bin_dsp1.jpg (35.68 KiB) Viewed 2385 times
Each of these pics show the hex value 0xda displayed depending on the inversion of the display board. It can be mounted either way round -- using the correct display command. This is only for display purposes... from a driver standpoint the lines ARE what they are.
bin_dsp2.jpg
dsp8_INV(0xda) display inverted
bin_dsp2.jpg (43.46 KiB) Viewed 2385 times
marcus
:ugeek:

User avatar
MarkHaysHarris777
Posts: 1820
Joined: Mon Mar 23, 2015 7:39 am
Location: Rochester, MN
Contact: Website

Re: Sparkfun PI Wedge B+ 2bit Binary Counter & Display Demo

Wed Jun 08, 2016 6:19 am

consequtive_pins.jpg
An advantage of the Sparkfun Wedge is the consecutive pins arrangement !
consequtive_pins.jpg (57.38 KiB) Viewed 2365 times
This pic shows the ribbon jumper tail header plugged directly into the Sparkfun mini-block. This is one of the primary advantages of the Sparkfun Wedge over the AdaFruit Cobbler; the pins are arranged sequentially (consecutively), and also have the unnecessary ground pins removed (so there are only 34 pins total ! All I had to do was to change my pin numbering for green [27, 26, 25, 24] and red [23, 22, 21, 20], I placed the push_button on 19, and the pwm pin on 18.

The disadvantage (and its minor) is that I have to move the ground wire from the ribbon tail and extend it to be able to plug it into one of the two ground pins the Wedge does provide.

So, with this upgrade, all of my jumpers are hand-made... for whoever was asking about that !

marcus
marcus
:ugeek:

User avatar
MarkHaysHarris777
Posts: 1820
Joined: Mon Mar 23, 2015 7:39 am
Location: Rochester, MN
Contact: Website

Re: Sparkfun PI Wedge B+ 2bit Binary Counter & Display Demo

Thu Jun 09, 2016 9:16 am

This post is to demonstate how to bring a py file into a script.sh file (as a python script library) in order to use the one library command ( dsp8_STD(value) ) to create various display patterns (in this case) or for any other output that might be desired from an 8bit digital LED panel; from art to a temperature readout, to boot-up codes, to robotics status registers, &c.

The codes listed below are based on the codes posted previously in this thread; however, they have been modified and generalized to be useful in a variety of situations, as examples for coding and as boiler-plates for modified projects that you might imagine. They are designed to be studied and played around with, as well to have some fun.

display8bit.py

This is the library file imported by the dsp_patterns.sh driver code. It contains the headers, imports, function definitions, and most importantly our interface function dsp8_STD(value). This code should be in your PYTHONPATH, or in your working directory.

dsp_patterns.sh

This code is the driver code that displays several interesting 8bit patterns which imply motion. They are selectable via interrupt signals and run at various speeds selectable via SIGHUP. Whether you use my board or not, all that is required is that you have 8 LEDs hanging off of 8 GPIO lines (I'm using GPIO 20-27 high-order to low-order) and that whatever lines you choose -- they must be defined in display8bit.py. These codes run fine with the Gertboard, for instance (and you have lots of LEDs to choose from there!) although the patterns are designed to run on two parallel rows of four LEDs each for affect.

Adding patterns to this code is easy; the code is readable and the boiler plate ideology is easily expanded. The same techniques could be used to control multiple relays, motors, art-boards, &c; its an imagination thing. To run:

Code: Select all

sudo /home/pi/bin/dsp_patterns.sh &
ssendsig.sh

This script is a universal signal sender... it can send a signal to any process by name; you don't need to know the process number, it figures that out. The signals which may be sent are SIGINT, SIGHUP, SIGUSR1, and SIGUSR2. To run:

Code: Select all

sudo /home/pi/bin/ssendsig.sh dsp_pattern SIGHUP
Signals:
SIGINT Terminates the process, which is running in the background
SIGHUP Displays process status, and toggles frequency t_delay values
SIGUSR1 Selects the next indexed display pattern (forward)
SIGUSR2 Selects the previous indexed display pattern (reverse)
pattern_two.jpg
... this pattern #2 was running with 23ms between frames and the g6 stopped the motion ...
pattern_two.jpg (54.04 KiB) Viewed 2325 times
While the display process is running the speed of any of the displays and the display itself are selectable via signal handler. The order of the displays is determined by an indexed array (python list) so that rearranging the pattern number in led_pattern_index[] will change the order selectable via SIGUSRx. The displays run at five different speeds, which are toggled forward by SIGHUP. The HUP signal also causes the process to send its cycle number, current t_delay, and present running display.

The pic above shows pattern #2 (the four LEDs 'move' as a unit left and right at whatever speed you choose). I included the pic because I was surprised by the stop motion of my Samsung g6; I had the pattern oscillating with only 23ms between sleep frames (looked like pwm running, a slight flicker) and the camera stopped the motion completely. I guess I expected a blur, or to catch some of the LEDs lit partially.

Should you decide to play with these codes, I will answer questions. Just post here, or PM me... no problema. But, while I trust that someone will find them useful, no promise is made for fitness of purpose or warranty of any kind.

display8bit.py

Code: Select all

## display8bit.py
#
#   Mark H. Harris
#   v.01h
#   06-10-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 
red_pins=[23, 22, 21, 20]
for pin in red_pins:
    GPIO.setup(pin, GPIO.OUT)

green_pins=[27, 26, 25, 24]
for pin in green_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, red_pins, 0x10, "STD")
    bin_display(val, green_pins, 0x1, "STD")

def dsp8_INV(val):
    bin_display(val, green_pins, 0x10, "INV")
    bin_display(val, red_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()

dsp_patterns.sh

Code: Select all

#!/usr/bin/python
# dsp_patterns.sh
#
#   Mark H. Harris
#   v.01h
#   06-10-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, 1, 4, 3, 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]
figure_eight = [0x80, 0x40, 0x02, 0x01, 0x10, 0x20, 0x04, 0x08]
two_led_wave = [0x88, 0x44, 0x22, 0x11, 0x22, 0x44]
all_leds_on_flasher = [0xff, 0x00]
green_red_bars_flasher = [0xf0, 0x0f]
alternating_flasher = [0x69, 0x96]
curtain_scanner = [0xf, 0x8f, 0xc7, 0xe3, 0xf1, 0xf0, 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(green_red_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 FIGURE EIGHT X1 WALKING
            displayf(figure_eight, "FWD")
        if (pattern_num==8):
            ## 8 FIGURE EIGHT X1 WALKING
            displayf(figure_eight, "RVS")
        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()

ssendsig.sh

Code: Select all

#!/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


marcus
marcus
:ugeek:

User avatar
MarkHaysHarris777
Posts: 1820
Joined: Mon Mar 23, 2015 7:39 am
Location: Rochester, MN
Contact: Website

Re: Sparkfun PI Wedge B+ 2bit Binary Counter & Display Demo

Thu Jun 09, 2016 8:55 pm

The codes display8bit.py v.01h and dsp_patterns.sh v.01h were developed on an RPi 2B, Raspbian Wheezy. They have been moved and tested on an RPi 3B, Raspbian Jessie; without modification. Also, the codes run in either the Python2 or the Python3 interpreter without modification.

In the following pic I have moved the application and codes to my rasppi4 machine in preparation for the first 'real world' application use of the display and display codes as a temperature display to be used in conjunction with my fan contoller codes currently running on the Gertboard. From the pic, there really is no rhyme nor reason behind the layout of the pinblock in terms of BCM GPIO pin numbering. I place a Gert jumper on board pin 25 (ground) of the pinblock for orientation purposes while I'm counting pins and making sure my connections are sound.
wire_nest.jpg
blue-board is being used to provide GPIO access to the display ribbon ...
wire_nest.jpg (56.17 KiB) Viewed 2260 times
The display board shares a common ground point with rasppi4 and the Gertboard. The ribbon cable snakes out on the desk for easy viewing near my notebook. For the purposes of a permanent temperature display on my robot I plan to use a 12 LED bar.

marcus
marcus
:ugeek:

Return to “HATs and other add-ons”