Wednesday, 31 December 2014

LCD goodness

The datalogger is essentially going to be an embedded system, but I'd still like to have an idea what's going on.  Attaching a screen to the seat cowl of a Daytona via HDMI is a non-starter, and even this touchscreen looks a bit big (but I might revisit that once I have everything fitted).  A bit of ebaying later and a 16x2, white on blue, HD44780 LCD display arrived through the door - not bad for £3.29 including postage!

I tried various Python classes for driving it, but most of them didn't work.  It seemed to be a 4bit vs 8bit issue.  The wiring diagrams showed 4bit wiring, but the code seemed to write 8bits per character.  Lots more googling later, I stumbled upon RPLCD on github.  After a quick github clone the code was ready to rock 'n roll.  Sure enough, it seemed to work, but the display still was only readable at a very odd angle.  More googling pointed to the contrast pin.  It was tied to GND as per many many articles I'd read, but a number of others used a 10K pot.  Not having one to hand, a mid-range resistor would have to do; so a 3K3 Ω resistor was used from V0 to GND.  Much better!  I butchered one of the test programs to create an infinite loop updating the date/time using cursor positioning (just for the practice).

Finally, I decided that +5v gave a much brighter display than I wanted.  The previous post used GPIO.PWM to dim an LED. After a bit of rewiring and code merging the backlight is now dimmable.


The above layout was taking up a lot of space on the breadboard.  One strip of male to female ribbon cable later:





I think I'm going to have to look into github as these scripts are now getting a bit long, and would probably benefit from some version control as well.  For now, here's the latest code:

#!/usr/bin/env python
import sys
import RPi.GPIO as GPIO
import datetime
from time import sleep

from RPLCD import CharLCD
from RPLCD import Alignment, CursorMode, ShiftMode
from RPLCD import cursor, cleared

try:
    input = raw_input
except NameError:
    pass
try:
    unichr = unichr
except NameError:
    unichr = chr

# Set the numbering scheme to GPIO numbers
GPIO.setmode(GPIO.BCM)

# LED on GPIO 16, initiall set to off
GPIO.setup(16, GPIO.OUT, initial=GPIO.LOW)

# DOWN switch on GPIO 20
GPIO.setup(20, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# UP Switch on GPIO 21
GPIO.setup(21, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# Set initial dutycycle to 50
dc = 50

# Set the frequency to 200Hz.
freq = 200

# Set up the LED
led = GPIO.PWM(16,freq)
led.start(dc)

def set_pwm(gpio_id):
  global dc
  global led

  # If the down switch is pressed, decrement dc
  if gpio_id == 20:
    if dc > 0:
      dc = dc - 5
      print "Down switch pressed. Setting dc to %s" % dc
    else:
      print "Down switch pressed. dc already at min value!"
  # If the up switch is pressed, increment dc
  if gpio_id == 21:
    if dc < 100:
      dc = dc + 5
      print "Up switch pressed. Setting dc to %s" % dc
    else:
      print "Up switch pressed. dc already at max value!"
  led.ChangeDutyCycle(dc)

# Add callbacks for both switches
GPIO.add_event_detect(20, GPIO.FALLING, set_pwm, bouncetime=200)
GPIO.add_event_detect(21, GPIO.FALLING, set_pwm, bouncetime=200)

lcd = CharLCD(cols=16, rows=2, numbering_mode=GPIO.BCM, pin_rs=11, pin_rw=None, pin_e=5, pins_data=[6,13,19,26])

lcd.clear()
lcd.cursor_pos = (0, 0)
lcd.write_string('Date:')
lcd.cursor_pos = (1, 0)
lcd.write_string('Time:')
try:
  while True:
    now = datetime.datetime.now()
    lcd.cursor_pos = (0, 6)
    lcd.write_string(now.strftime('%Y-%m-%d'))
    lcd.cursor_pos = (1, 6)
    lcd.write_string(now.strftime('%H:%M:%S'))
    sleep(0.1)
except KeyboardInterrupt:
  lcd.clear()
  led.stop()
  GPIO.cleanup()

Sunday, 21 December 2014

Getting to grips with GPIO

As GPIO is going to be a big part of this project, I wanted to learn a bit more about the library before I start the project for real. The next step was to mess around with a single LED and a couple of buttons to see if I could get them to do fun stuff like changing the flash rate or brightness.  After a bit of messing about and falling foul of the wait_for_edge bug in the GPIO library, I eventually settled on thread based callbacks (another first for me).  I'll spare you the gory details of all the intermediate version of the code, but this script has an LED/resistor attached to GPIO 11 and two switches on 20/21 to act as up and down buttons:




#!/usr/bin/python
import RPi.GPIO as GPIO

# Set the numbering scheme to GPIO numbers
GPIO.setmode(GPIO.BCM)
# LED on GPIO 11, initiall set to off
GPIO.setup(11, GPIO.OUT, initial=GPIO.LOW)
# UP switch on GPIO 20
GPIO.setup(20, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# DOWN switch on GPIO 21
GPIO.setup(21, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# Set dutycycle to 50%
dc = 50
# Set inital flash frequency to 20Hz
freq = 20

# Create a callback function
def set_freq(gpio_id):
  global freq
  global led

  # If the up switch is pressed, increment freq
  if gpio_id == 20:
    if freq < 50:
      freq += 1
      print "Up switch pressed. Setting freq to %s" % freq
    else:
      print "Up switch pressed. Frequency already at max value!"
  if gpio_id == 21:
    if freq > 1:
      freq -= 1
      print "Down switch pressed. Setting freq to %s" % freq
    else:
      print "Down switch pressed. Frequency already at min value!"
  led.ChangeFrequency(freq)

# Set up the LED
led = GPIO.PWM(11,freq)
led.start(dc)

# Add callbacks for both switches, using the same  callback
# The callback function will be notified which GPIO pin is falling
GPIO.add_event_detect(20, GPIO.FALLING, set_freq, bouncetime=200)
GPIO.add_event_detect(21, GPIO.FALLING, set_freq, bouncetime=200)

try:
  # Wait for a key press
  entry = raw_input("Press something fool!\n")
except KeyboardInterrupt:
  print "Except that!!!"

led.stop()
GPIO.cleanup()

Thursday, 4 December 2014

Popping my GPIO cherry

Today I had to shut down the rPi, and realised that the only way to do it is to log in, and sudo a shutdown command.  Surely there must be a hardware way to do a controlled shutdown?
A bit of googling later it turns out that it's quite easy to do this in a python script that waits on a GPIO pin being grounded.  The script is run from rc.local when raspbian boots, which means that it's already running as root!

The script looks like this:

 #!/usr/bin/env python2.7  
 import RPi.GPIO as GPIO  
 import subprocess  
 GPIO.setmode(GPIO.BCM)  
 GPIO.setup(21, GPIO.IN, pull_up_down=GPIO.PUD_UP)  
 try:  
   GPIO.wait_for_edge(21, GPIO.FALLING)  
   subprocess.call(['shutdown -h now "System halted by GPIO action"'], shell=True)  
 except KeyboardInterrupt:  
   GPIO.cleanup()  
 GPIO.cleanup()

Just to run through it quickly it does the following:

  1. Loads the libraries
  2. Sets the GPIO mode to the GPIO numbering scheme rather than pin numbering
  3. Pulls GPIO pin 21 high (sets the voltage to +5V)
  4. Waits for the voltage to drop (shorted to GND)
  5. When it does, it runs a system shutdown
  6. Resets the GPIO pins
The script runs the whole time, but because it's listening for a pin to go to GND it doesn't use any resources.

So, how do you send pin 40 (GPIO 21) to ground?  Well, normally you'd wire in a "push to make" button, but I don't have any of those yet, so for now, a wire will have to do:


I guess I'm just going to have to go shopping (again)!