Contents
Introduction
Design and Implimentation
Considerations for LED Uses
Demo
Source Code (Python)
Comments
Introduction
This is a proof of concept for basic electronics and a home project just for a bit of fun. To demonstrate some simple LED concepts with microcontrollers. In this case, it is a microprocessor on a microcomputer board with a Linux operating system but the LED control principles are basically the same. I have written a program in python that runs on a Raspberry Pi to control a tri-colour light-emitting diode (LED). Technically it is actually three diodes in one package. This includes red, green and blue. I brought the tri-colour LED from CPC which was designed for Raspberry Pi (with pin connectors and built-in resistors). I am using an easier Pi and at some point, I will try this on the latest available.
Design and Implimentation
The LED colour is varied by flashing the LED at a high frequency with varying duty. This is known as pulse width modulation (PWM). In the context of my project this provides for a dimming effect on each of the red, green and blue colours and therefore, changes the colour appearance of the LED. To improve this flashing a timer interrupt would be an interesting route forward. This will stabilise the flashing a bit better as delays in processing other parts of the program will cause gaps in the flash effect.
The PWM method can be used to dim a LED on microcontrollers to provide optional brightnesses and to reduce power consumption. Many microcontrollers have a PWM output and there are chipsets available to provide multi-channel PWM outputs. My PWM is a software implementation rather than a hardware one. The LED has four wires that include, common ground and the red, green and blue lines with resistors in-line and connected to the I/O header of the Raspberry Pi embedded microcomputer. PWM can be used in audio too along with numerous other applications.
Considerations for LED Uses
It is important to note, an LED that is being used to indicate data being passed through a device should not be directly connected into the data line. This is because as it is possible to create a device that can read the LED and gather the data straight from it! This is one consideration of many for using an LED so you can imagine the amount of design that has to go into an electronic device!
Demo
Warning: Video contains flashing images that might cause problems for some individuals.
Note that the flashing may be more obvious in the video because the frame rate of the camera is not synchronised with the LED and the camera works differently from the human brain.
Note also, that this is running on a slower earlier version of a Pi computer. The newer versions have faster processing.
Source Code (Python)
# This is a very basic piece of code just to strobe three combined LEDs to produce different colours.
# I should look to use a timer interrupt instead as this would be more effective.
# There is an intention to provide control of the LED via TCP/IP. But not implemented yet.
import RPi.GPIO as GPIO
import time
import threading
import Queue
import random
import signal, os
# The strober will strobe the LED at high frequency which causes the dimming effect.
class LED_Strober():
STROBE_ON = 0.0001
STROBE_OFF = 0.003
def __init__(self,name,pin):
self.name = name
self.halt = False
self.pin = pin
self.on = 0
self.strobe = self.STROBE_OFF
self.thread = threading.Thread(target=self.run,name=self.name)
self.thread.start()
def setStrobe(self,value):
self.strobe = value
def setValue(self,value):
if value > 0:
self.on = 1
# if the value has been set to 1 this overrides the strobe value if strobe is 0 led is on all the time
if value >= 1:
self.strobe = 0
else:
self.strobe = value
else:
self.on = 0
def run(self):
while not self.halt:
# if strobe is greater than 0, strobe the LED else led always on
if self.strobe > 0:
# LED strobe
GPIO.output(self.pin,self.on)
time.sleep(self.STROBE_ON)
GPIO.output(self.pin,0)
time.sleep(self.strobe)
else:
# LED on
GPIO.output(self.pin,self.on)
time.sleep(0.01) # allow some sleep time giving 10ms response time
def stop(self):
self.halt = True
# Tri-Colour LED controller that controls the colour to display.
class LED_Controller():
# GPIO (General-purpose input/output)
RED_PIN = 17
GREEN_PIN = 18
BLUE_PIN = 27
# RGB Timers for soft PWM
resetR = 0
resetG = 0
resetB = 0
thread = None
name = ""
red = 0
green = 0
blue = 0
STROBE_ON = 0.0001
STROBE_OFF = 0.04
halt = False
def __init__(self):
# Set the control mode to use GPIO numbers (not pinout numbers)
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
# Enable outputs for GPIO
self.enable()
# Just give this object a name
self.name = "LED Controller"
# Provide a strober (software PWM) controller for RED, GREEN and BLUE leds
self.red_LED = LED_Strober("Red",self.RED_PIN)
self.green_LED = LED_Strober("Green",self.GREEN_PIN)
self.blue_LED = LED_Strober("Blue",self.BLUE_PIN)
print "Init Complete"
# Method stops LED strobers and waits for threads to end
def stop(self):
self.red_LED.stop()
self.green_LED.stop()
self.blue_LED.stop()
self.red_LED.thread.join()
self.green_LED.thread.join()
self.blue_LED.thread.join()
# Sets color by setting up strobers PWM low time
def setColor(self,array):
self.red = array[0]
self.green = array[1]
self.blue = array[2]
# I've been a bit lazy here and just put calibration values directly in :)
if self.red > 0:
self.resetR = (0.005 - (0.005 * self.red))
if self.resetR == 0:
self.resetR = 1
else:
self.resetR = 0
if self.green > 0:
self.resetG = (0.0390 - (0.0390 * self.green)) + 0.0010
else:
self.resetG = 0
if self.blue > 0:
self.resetB = (0.0395 - (0.0395 * self.blue)) + 0.0005
else:
self.resetB = 0
self.red_LED.setValue(self.resetR)
self.green_LED.setValue(self.resetG)
self.blue_LED.setValue(self.resetB)
# Sets led output (use setColor instead)
def leds(self, red, green, blue):
GPIO.output([self.RED_PIN,self.GREEN_PIN,self.BLUE_PIN],(red,green,blue))
# Enable outputs
def enable(self):
GPIO.setup(self.RED_PIN,GPIO.OUT,initial=GPIO.LOW)
GPIO.setup(self.GREEN_PIN,GPIO.OUT,initial=GPIO.LOW)
GPIO.setup(self.BLUE_PIN,GPIO.OUT,initial=GPIO.LOW)
# Set outputs back to inputs
def disable(self):
GPIO.setup(self.RED_PIN,GPIO.IN)
GPIO.setup(self.GREEN_PIN,GPIO.IN)
GPIO.setup(self.BLUE_PIN,GPIO.IN)
# Class holds color names
class Color():
black = [0,0,0]
red = [1,0,0]
orange = [1, 0.5, 0]
yellow = [1,1,0]
green = [0,1,0]
cyan = [0,1,1]
blue = [0,0,1]
purple = [0.5,0,1]
magenta = [1,0,1]
white = [1,1,1]
colors = [black,white,red,green,blue,yellow,cyan,magenta,orange,purple]
# Class holds test patterns for LED. Fun!
class LED_Test():
def __init__(self):
self.led = LED_Controller()
# Show rainbow
def rainbow(self, delay):
color = Color()
# Only uses solid colours (no dimming)
sequence = [color.red, color.yellow, color.green, color.cyan, color.blue, color.purple]
# Run the sequence
self.doSequence(sequence, delay)
# Show extended rainbow
def rainbowEx(self, delay):
color = Color()
sequence = []
sequence.append(color.red)
sequence.append(color.orange)
sequence.append(color.yellow)
sequence.append([0.5, 1, 0])
sequence.append(color.green)
sequence.append([0, 1, 0.5])
sequence.append(color.cyan)
sequence.append([0, 0.5, 1])
sequence.append(color.blue)
sequence.append(color.purple)
sequence.append(color.magenta)
sequence.append([1, 0, 0.7])
# Run the sequence
self.doSequence(sequence, delay)
# Execute a sequence
def doSequence(self, sequence, delay):
for newColor in sequence:
self.led.setColor(newColor)
time.sleep(delay)
# Set random color
def random(self):
red = random.random()
green = random.random()
blue = random.random()
if red < 0.5:
red = 0
if green < 0.5:
green = 0
if blue < 0.5:
blue = 0
self.led.setColor([red,green,blue])
# Loop random color
def randomForever(self, delay):
while 1:
self.random()
time.sleep(delay)
# Loop rainbow effect
def rainbowExForever(self, delay):
while 1:
self.rainbowEx(delay)
# Set a color by color array.
def setColor(self,color):
self.led.setColor(color)
# Set a color on the LED controller.
def leds(self, rgb):
self.led.leds(rgb[0], rgb[1], rgb[2])
# Stop and reset I/O and stop thread
def cleanUp(self):
self.led.stop()
self.led.disable()
# Get LED tester
led = LED_Test()
# Get color table
color = Color()
# Do a custom sequence
#s = [[1,1,1],[1,0.95,1]]
#while 1:
# led.doSequence(s,0.5)
# Do rainbow sequence continously
led.rainbowExForever(0.1)
# Clean up I/O (never gets here on loop forever)
led.cleanUp()
..

Thinking more about the video demo, I think I could change the video to extend selected frames to provide a simulation of what this might look like to the human eye. I might come back to this when I have more time.
I’ve been thinking a bit more about the timer interrupt and think that I would have to use C instead because the python may have too much code behind it and not be efficient enough. So I will have to transfer the concept over to C instead.
It works better using a LED driver for stabilizing the power supply and to get a better response using something like this: http://www.farnell.com/datasheets/2786856.pdf (Note it still takes PWM as input.) There’s probably a 3 channel version for tri-colour but I’m not spending hours looking over products.