Raspberry Pi Python RTC Interface MAX7219 Display Driver

by Lewis Loflin

Also see Raspberry Pi and the 8-Digit LED MAX7219 Display Driver

This Raspberry Pi project uses a MAX7219 display driver under Python to produce a 8-digit LED clock. Here we learn something about Python code and handling date or time strings. It's assumed the system RTC (in my case an add on DS1307 module) is operating. Most of the Python code operates the electronics.

Python has two functions time and datetime useful for far more than a simple time delay. These functions can be formatted to output a string value representing date or time in a number of combinations. The outputs can be directly printed out or saved to a string variable. A number of examples of this are presented below.

The MAX7219 is set up for 8-digits using its internal BCD decoders. They have no code for ":" so I'll use a "-" between the numbers. The main part of the program is as follows:


initMAX7219() # set up the electronics

# time returned as string
# But order is reversed relative to MAX7219.
str1 =  time.strftime("%H:%M:%S")

print str1 # Ex. 21:13:05
# print len(str1) # 8

# x is digit position must be 1 to 8
# y is used for string pointer

while 1:
	y = 7
	for x in range(1, 9):
		if str1[y] == ":":
			# output "-"
			writeMAX7219(10, x)
			y = y - 1
			continue # back to if
		# convert y char to integer
		writeMAX7219(int(str1[y]), x)
		y = y - 1
	str1 =  time.strftime("%H:%M:%S")

To thus of us doing Linux desktops such as Openbox or JWM "%H:%M:%S" is the format for displaying time. In this case the output is saved to a string variable.

A string is returned in str1 and is 8 characters long. An ASCII string is an array of characters where numbering begins at zero with the numbering going from left to right. So the index number would produce the following if the str1 = "21:13:05" :

str1[0] = "2"
str1[1] = "1"
str1[2] = ":"
str1[3] = "1"
str1[4] = "3"
str1[5] = ":"
str1[6] = "0"
str1[7] = "5"

The first problem besides being ASCII characters and not numbers is the order is reversed relative to the LED display on the clock. The inputs in the MAX7219 is numbered right to left then we also have to deal with the ":" character.

The problem was solved by using X as the digit position counter and Y as the string position pointer. Each iteration checks for a ":" and if present sends a the code for "-" (10) to the correct position. At the end of the for loop str1 reads the time again and the process repeats.

Below is more information on the time and datetime functions.





#!/usr/bin/python
# Outputs based on your computer clock
import time


# 12 hour format ##
print (time.strftime("%I:%M:%S"))
# Output: 08:36:25


# Date in dd/mm/yyyy format
print (time.strftime("%d/%m/%Y"))
# Output: 21/03/2015

print (time.strftime("%H:%M:%S"))
# Output: 20:36:25


#!/usr/bin/python
 
import time
 
now = time.strftime("%c")

# date and time representation
print "Current date & time " + time.strftime("%c")
# Output: Current date & time 03/21/15 20:38:34
 
# Only date representation
print "Current date "  + time.strftime("%x")
# Output: Current date 03/21/15
 
# Only time representation
print "Current time " + time.strftime("%X")
# Output: Current time 20:38:34
 
# Display current date and time from now variable 
print ("Current time %s"  % now )
# Output: Current time 03/21/15 20:38:34

Now we use a library datetime. The syntax is:
now = datetime.datetime.now()
now.mintue
now.hour
now.year
now.day
now.month


#!/usr/bin/python

import datetime
j = datetime.datetime.now()

print ("dd/mm/yyyy format =  %s/%s/%s" % (j.day, j.month, j.year) )
 
print ("Current date & time = %s" % i)

print ("Current second =  %s" %j.second)

print ("Current minute = %s" %j.minute)
 
print ("Current hour = %s" %j.hour)

print ("Current date (day) =  %s" %j.day)

print ("Current month = %s" %j.month)

print ("Current year = %s" %j.year)
 
print ("hh:mm:ss format = %s:%s:%s" % (j.hour, j.month, j.second) )

I got the following outputs:



dd/mm/yyyy format =  21/3/2015
Current date & time = 2015-03-21 20:58:26.656000
Current second =  26
Current minute = 58
Current hour = 20
Current date (day) =  21
Current month = 3
Current year = 2015
hh:mm:ss format = 20:3:26

Additional codes for date and datetime and Linux in general. Feel free to experiment.



%a	Weekday name.
%A	Full weekday name.
%b	Abbreviated month name.
%B	Full month name.
%c	Appropriate date and time representation.
%d	Day of the month as a decimal number [01,31].
%H	Hour (24-hour clock) as a decimal number [00,23].
%I	Hour (12-hour clock) as a decimal number [01,12].
%j	Day of the year as a decimal number [001,366].
%m	Month as a decimal number [01,12].
%M	Minute as a decimal number [00,59].
%p	Equivalent of either AM or PM.
%S	Second as a decimal number [00,61].

%U	Week number of the year (Sunday as the first 
day of the week) as a decimal number [00,53]. 
All days in a new year preceding the first 
Sunday are considered to be in week 0.

%w	Weekday as a decimal number [0(Sunday),6].
%W	Week number of the year (Monday as the first 
day of the week) as a decimal number [00,53]. 
All days in a new year preceding the first Monday 
are considered to be in week 0.

%x	Appropriate date representation.
%X	Appropriate time representation.
%y	Year without century as a decimal number [00,99].
%Y	Year with century as a decimal number.
%Z	Time zone name (no characters if no time zone exists).
%%	A literal '%' character.


MAX7219 Display driver internal block diagram.

Raspberry Pi Clock Code in Python

Note I used a pre-made module which is labeled as above.


#!/usr/bin/env python
# File rpi_7219b.py
# http://www.bristolwatch.com/index.htm
# By Lewis Loflin - lewis@bvu.net
# Output time from system clock.

# Two bytes are shifted in first being address, second being data.
# Works the same as two 74165 SSRs in series or 16-bits.
# LD "pulseCS()" clocks 16-bit address/data into working registers.



# access to GPIO must be through root
import RPi.GPIO as GPIO
import time

LATCH = 11 # CS
CLK = 12
dataBit = 7 # DIN


GPIO.setup(LATCH, GPIO.OUT) # P0 
GPIO.setup(CLK, GPIO.OUT) # P1 
GPIO.setup(dataBit, GPIO.OUT) # P7


# Setup IO
GPIO.output(LATCH, 0)
GPIO.output(CLK, 0)


def pulseCLK():
    GPIO.output(CLK, 1)
    # time.sleep(.001) 
    GPIO.output(CLK, 0)
    return

def pulseCS():
    GPIO.output(LATCH, 1)
    # time.sleep(.001)
    GPIO.output(LATCH, 0)
    return
   
 

# shift byte into MAX7219
# MSB out first!
def ssrOut(value):
    for  x in range(0,8):
        temp = value & 0x80
        if temp == 0x80:
           GPIO.output(dataBit, 1) # data bit HIGH
        else:
           GPIO.output(dataBit, 0) # data bit LOW
        pulseCLK()
        value = value << 0x01 # shift left       
    return 



# initialize MAX7219 4 digits BCD
def initMAX7219():
    
    # set decode mode
    ssrOut(0x09) # address
    #	ssrOut(0x00); // no decode
    ssrOut(0xFF) # 4-bit BCD decode eight digits
    pulseCS();

    # set intensity
    ssrOut(0x0A) # address
    ssrOut(0x04) # 9/32
    pulseCS()

    # set scan limit 0-7
    ssrOut(0x0B); # address
    ssrOut(0x07) # 8 digits
    # ssrOut(0x03) # 4 digits
    pulseCS()


    # set for normal operation
    ssrOut(0x0C) # address
    # ssrOut(0x00); // Off
    ssrOut(0x01)  # On
    pulseCS()
	# clear to all 0s.
    for x in range(0,9):
        ssrOut(x)
        ssrOut(0)
        pulseCS()
    return


def writeMAX7219(data, location):
    ssrOut(location)
    ssrOut(data)
    pulseCS()
    return


def displayOff():
   # set for normal operation
    ssrOut(0x0C) # address
    ssrOut(0x00); # Off
    # ssrOut(0x01)  # On
    pulseCS()


def displayOn():
   # set for normal operation
    ssrOut(0x0C) # address
    # ssrOut(0x00); # Off
    ssrOut(0x01)  # On
    pulseCS()



initMAX7219()

# time returned as string
# But order is reversed relative to MAX7219.
str1 =  time.strftime("%H:%M:%S")
# str2 =  time.strftime("%d:%m:%Y")

print str1
# print len(str1) # 8

# x is digit position must be 1 to 8
# y is used for string pointer

while 1:
	y = 7
	for x in range(1, 9):
		if str1[y] == ":":
			# output "-"
			writeMAX7219(10, x)
			y = y - 1
			continue # back to if
		# convert y char to integer
		writeMAX7219(int(str1[y]), x)
		y = y - 1
	str1 =  time.strftime("%H:%M:%S")
	
	
	


print "Good by!"  
time.sleep(20)
displayOff()


exit


TA8050P H-Bridge Motor Control

Optical Isolation of H-Bridge Motor Controls YouTube
Optical Isolation of H-Bridge Motor Controls

Opto-Couplers Theory and Circuits YouTube
Opto-Isolated Transistor Drivers for Micro-Controllers

All NPN Transistor H-Bridge Motor Control YouTube
All NPN Transistor H-Bridge Motor Control

Pulse-Width Modulation Tutorial YouTube
Pulse-Width Modulation Tutorial

PIC12F683 Microcontroller and Circuits YouTube
PIC12F683 Microcontroller and Circuits