Last active
May 24, 2017 00:39
-
-
Save smittytone/e7f88c317ccb348f7015 to your computer and use it in GitHub Desktop.
Electric Imp Squirrel class for an 8 x 8 monochrome LED matrix driven by the MAX7219
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MAX7219_Matrix | |
{ | |
// Squirrel class for 8 x 8 LED matrix displays driven by the MAX7219 controller | |
// For example: https://www.sparkfun.com/products/11861 | |
// Code by Tony Smith (@smittytone) May 2014 | |
// Version 1.0 | |
// Constants for MAX7219 | |
static MAX7219_REGISTER_BCD = 0x09 | |
static MAX7219_REGISTER_BRIGHT = 0x0A | |
static MAX7219_REGISTER_SCAN = 0x0B | |
static MAX7219_REGISTER_PWR_MODE = 0x0C | |
static MAX7219_REGISTER_TEST_MODE = 0x0F | |
// Constants for the alphanumeric character set | |
static charset = [ | |
[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], // Space - Ascii 32 | |
[0x00,0x10,0x10,0x10,0x10,0x00,0x10,0x00], // ! | |
[0x00,0x24,0x24,0x00,0x00,0x00,0x00,0x00], // ” | |
[0x00,0x24,0x7E,0x24,0x24,0x7E,0x24,0x00], // # | |
[0x00,0x08,0x3E,0x28,0x3E,0x0A,0x3E,0x08], // $ | |
[0x00,0x62,0x64,0x08,0x10,0x26,0x46,0x00], // % | |
[0x00,0x10,0x28,0x10,0x2A,0x44,0x3A,0x00], // & | |
[0x00,0x08,0x10,0x00,0x00,0x00,0x00,0x00], // ‘ | |
[0x00,0x04,0x08,0x08,0x08,0x08,0x04,0x00], // ( | |
[0x00,0x20,0x10,0x10,0x10,0x10,0x20,0x00], // ) | |
[0x00,0x00,0x14,0x08,0x3E,0x08,0x14,0x00], // * | |
[0x00,0x00,0x08,0x08,0x3E,0x08,0x08,0x00], // + | |
[0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x10], // , | |
[0x00,0x00,0x00,0x00,0x3E,0x00,0x00,0x00], // - | |
[0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00], // . | |
[0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x00], // / | |
[0x00,0x3C,0x46,0x4A,0x52,0x62,0x3C,0x00], // 0 - Ascii 48 | |
[0x00,0x30,0x50,0x10,0x10,0x10,0x7C,0x00], // 1 | |
[0x00,0x3C,0x42,0x02,0x3C,0x40,0x7E,0x00], // 2 | |
[0x00,0x3C,0x42,0x0C,0x02,0x42,0x3C,0x00], // 3 | |
[0x00,0x08,0x18,0x28,0x48,0x7E,0x08,0x00], // 4 | |
[0x00,0x7E,0x40,0x7C,0x02,0x42,0x3C,0x00], // 5 | |
[0x00,0x3C,0x40,0x7C,0x42,0x42,0x3C,0x00], // 6 | |
[0x00,0x7E,0x02,0x04,0x08,0x10,0x10,0x00], // 7 | |
[0x00,0x3C,0x42,0x3C,0x42,0x42,0x3C,0x00], // 8 | |
[0x00,0x3C,0x42,0x42,0x3E,0x02,0x3C,0x00], // 9 | |
[0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00], // : - Ascii 58 | |
[0x00,0x00,0x10,0x00,0x00,0x10,0x10,0x20], // ; | |
[0x00,0x00,0x04,0x08,0x10,0x08,0x04,0x00], // < | |
[0x00,0x00,0x00,0x3E,0x00,0x3E,0x00,0x00], // = | |
[0x00,0x00,0x10,0x08,0x04,0x08,0x10,0x00], // > | |
[0x00,0x3C,0x42,0x04,0x08,0x00,0x08,0x00], // ? | |
[0x00,0x3C,0x4A,0x56,0x5E,0x40,0x3C,0x00], // @ | |
[0x00,0x3C,0x42,0x42,0x7E,0x42,0x42,0x00], // A - Ascii 65 | |
[0x00,0x7C,0x42,0x7C,0x42,0x42,0x7C,0x00], // B | |
[0x00,0x3C,0x42,0x40,0x40,0x42,0x3C,0x00], // C | |
[0x00,0x78,0x44,0x42,0x42,0x44,0x78,0x00], // D | |
[0x00,0x7E,0x40,0x7C,0x40,0x40,0x7E,0x00], // E | |
[0x00,0x7E,0x40,0x7C,0x40,0x40,0x40,0x00], // F | |
[0x00,0x3C,0x42,0x40,0x4E,0x42,0x3C,0x00], // G | |
[0x00,0x42,0x42,0x7E,0x42,0x42,0x42,0x00], // H | |
[0x00,0x7C,0x10,0x10,0x10,0x10,0x7C,0x00], // I | |
[0x00,0x02,0x02,0x02,0x02,0x42,0x3C,0x00], // J | |
[0x00,0x44,0x48,0x70,0x48,0x44,0x42,0x00], // K | |
[0x00,0x40,0x40,0x40,0x40,0x40,0x7E,0x00], // L | |
[0x00,0x42,0x66,0x5A,0x42,0x42,0x42,0x00], // M | |
[0x00,0x42,0x62,0x52,0x4A,0x46,0x42,0x00], // N | |
[0x00,0x3C,0x42,0x42,0x42,0x42,0x3C,0x00], // O | |
[0x00,0x7C,0x42,0x42,0x7C,0x40,0x40,0x00], // P | |
[0x00,0x3C,0x42,0x42,0x52,0x4A,0x3C,0x00], // Q | |
[0x00,0x7C,0x42,0x42,0x7C,0x44,0x42,0x00], // R | |
[0x00,0x3C,0x40,0x3C,0x02,0x42,0x3C,0x00], // S | |
[0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x00], // T | |
[0x00,0x42,0x42,0x42,0x42,0x42,0x3C,0x00], // U | |
[0x00,0x42,0x42,0x42,0x42,0x24,0x18,0x00], // V | |
[0x00,0x42,0x42,0x42,0x42,0x5A,0x24,0x00], // W | |
[0x00,0x42,0x24,0x18,0x18,0x24,0x42,0x00], // X | |
[0x00,0x44,0x28,0x10,0x10,0x10,0x10,0x00], // Y | |
[0x00,0x7E,0x04,0x08,0x10,0x20,0x7E,0x00], // Z - Ascii 90 | |
[0x00,0x0E,0x08,0x08,0x08,0x08,0x0E,0x00], // [ | |
[0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x00], // \ | |
[0x00,0x70,0x10,0x10,0x10,0x10,0x70,0x00], // ] | |
[0x00,0x10,0x38,0x54,0x10,0x10,0x10,0x00], // ^ | |
[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF], // _ | |
[0x00,0x1C,0x22,0x78,0x20,0x20,0x7E,0x00], // £ | |
[0x00,0x00,0x38,0x04,0x3C,0x44,0x3C,0x00], // a - Ascii 97 | |
[0x00,0x40,0x40,0x78,0x44,0x44,0x78,0x00], // b | |
[0x00,0x00,0x38,0x40,0x40,0x40,0x38,0x00], // c | |
[0x00,0x04,0x04,0x3C,0x44,0x44,0x3C,0x00], // d | |
[0x00,0x00,0x38,0x44,0x78,0x40,0x3C,0x00], // e | |
[0x00,0x30,0x40,0x60,0x40,0x40,0x40,0x00], // f | |
[0x00,0x3C,0x44,0x44,0x3C,0x04,0x38,0x00], // g | |
[0x00,0x40,0x40,0x40,0x78,0x44,0x44,0x00], // h | |
[0x00,0x20,0x00,0x60,0x20,0x20,0x70,0x00], // i | |
[0x00,0x08,0x00,0x08,0x08,0x48,0x30,0x00], // j | |
[0x00,0x40,0x50,0x60,0x60,0x50,0x48,0x00], // k | |
[0x00,0x40,0x40,0x40,0x40,0x40,0x30,0x00], // l | |
[0x00,0x00,0x68,0x54,0x54,0x54,0x54,0x00], // m | |
[0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x00], // n | |
[0x00,0x00,0x38,0x44,0x44,0x44,0x38,0x00], // o | |
[0x00,0x78,0x44,0x44,0x78,0x40,0x40,0x00], // p | |
[0x00,0x3C,0x44,0x44,0x3C,0x04,0x06,0x00], // q | |
[0x00,0x00,0x1C,0x20,0x20,0x20,0x20,0x00], // r | |
[0x00,0x00,0x38,0x40,0x38,0x04,0x78,0x00], // s | |
[0x00,0x20,0x70,0x20,0x20,0x20,0x18,0x00], // t | |
[0x00,0x00,0x44,0x44,0x44,0x44,0x38,0x00], // u | |
[0x00,0x00,0x44,0x44,0x28,0x28,0x10,0x00], // v | |
[0x00,0x00,0x44,0x54,0x54,0x54,0x28,0x00], // w | |
[0x00,0x00,0x44,0x28,0x10,0x28,0x44,0x00], // x | |
[0x00,0x00,0x44,0x44,0x3C,0x04,0x38,0x00], // y | |
[0x00,0x00,0x7C,0x08,0x10,0x20,0x7C,0x00], // z - Ascii 122 | |
[0x00,0x0E,0x08,0x30,0x08,0x08,0x0E,0x00], // { | |
[0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00], // | | |
[0x00,0x70,0x10,0x0C,0x10,0x10,0x70,0x00], // } | |
[0x00,0x14,0x28,0x00,0x00,0x00,0x00,0x00], // ~ | |
[0x3C,0x42,0x99,0xA1,0xA1,0x99,0x42,0x3C], // © - Ascii 127 | |
[0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF], // Block Graphic 1 | |
[0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,0xFF], | |
[0xF0,0xF0,0xF0,0xF0,0xFF,0xFF,0xFF,0xFF], | |
[0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF], | |
[0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F], | |
[0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F], | |
[0xF0,0xF0,0xF0,0xF0,0x0F,0x0F,0x0F,0x0F], | |
[0x00,0x00,0x00,0x00,0x0F,0x0F,0x0F,0x0F], | |
[0xFF,0xFF,0xFF,0xFF,0x55,0xAA,0x55,0xAA], | |
[0xAA,0x55,0xAA,0x55,0xFF,0xFF,0xFF,0xFF], | |
[0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55] // Block Graphic 11 | |
] | |
// Zero Class properties ahead of Class constructor function | |
_led_clk = null | |
_led_din = null | |
_led_cs = null | |
_inverse_video_flag = false | |
_rotate_matrix_flag = false | |
constructor(clock_pin, data_pin, select_pin, should_rotate = false) | |
{ | |
// Parameters: | |
// 1. imp pin object to handle clock signals | |
// 2. imp pin object to handle data | |
// 3. imp pin object to handle chip selection | |
// 4. Boolean value governing matrix rotation, which depends on the | |
// orientation of your 8 x 8 matrix. Default: no rotation | |
_led_clk = clock_pin; | |
_led_din = data_pin; | |
_led_cs = select_pin; | |
// Set these pins as digital outputs | |
_led_clk.configure(DIGITAL_OUT); | |
_led_cs.configure(DIGITAL_OUT); | |
_led_din.configure(DIGITAL_OUT); | |
// Set screen rotation flag | |
_rotate_matrix_flag = should_rotate; | |
} | |
function write_LED_byte(byte_value) | |
{ | |
// Writes a single byte of data to the MAX7219 display controller one bit at a time. | |
// Writes data to the LED in the MAX7219’s 16-bit serial format, which puts the | |
// register address in the first eight bits then the data in the second set of eight bits. | |
for (local i = 8 ; i > 0 ; i--) | |
{ | |
_led_clk.write(0); | |
_led_din.write(byte_value & 0x80); // Extract bit 8 and write it to the LED | |
byte_value = byte_value << 1; // Shift the data bits left by one bit | |
_led_clk.write(1); | |
} | |
} | |
function write_LED(RegisterAddress, value) | |
{ | |
// Writes a single value to the MAX7219, preceded by the register | |
// it is being written to | |
_led_cs.write(0); | |
write_LED_byte(RegisterAddress); | |
write_LED_byte(value); | |
_led_cs.write(1); | |
} | |
function init() | |
{ | |
// Initialise the MAX7219’s parameter registers by writing | |
// the register’s address followed by its 8-bit value | |
// Address and data values from the Maxim Integrated MAX7219 Datasheet: | |
// http://www.maximintegrated.com/datasheet/index.mvp/id/1339 | |
write_LED(MAX7219_REGISTER_BCD, 0x00) // Set MAX7219’s BCD decode mode to ‘none’ | |
write_LED(MAX7219_REGISTER_BRIGHT, 0x01) // Set MAX7219’s LED intensity to a 2/32 duty cycle | |
write_LED(MAX7219_REGISTER_SCAN, 0x07) // Set MAX7219’s scan limit to all eight LED columns | |
write_LED(MAX7219_REGISTER_PWR_MODE, 0x01) // Set MAX7219’s power mode. 0 = power down, 1 = normal | |
write_LED(MAX7219_REGISTER_TEST_MODE, 0x00) // Set MAX7219’s display test mode off | |
} | |
function clear_display() | |
{ | |
display_line(" "); | |
} | |
function display_icon(input_matrix = [0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF]) | |
{ | |
// Display a custom 8 x 8 character bitmap | |
// Parameter(s) | |
// 1. Array of eight 8-bit integer values as the character bit pattern | |
// Default: a graphic | |
input_matrix = rotate_matrix(input_matrix); | |
for (local k = 0 ; k < 8 ; k++) | |
{ | |
if (inverse_video_flag) | |
{ | |
write_LED(k+1, ~input_matrix[k]); | |
} | |
else | |
{ | |
write_LED(k+1, input_matrix[k]); | |
} | |
} | |
} | |
function display_char(ascii_value = 32) | |
{ | |
// Display a character specified by its Ascii value | |
// Parameter(s) | |
// 1. Integer Ascii value, default: 32 (space) | |
ascii_value = ascii_value - 32; | |
if (ascii_value < 0 || ascii_value > alpha_count) ascii_value = 0; | |
local input_matrix = clone(charset[ascii_value]); | |
input_matrix = rotate_matrix(input_matrix); | |
for (local k = 0 ; k < 8 ; k++) | |
{ | |
if (inverse_video_flag == 1) | |
{ | |
write_LED(k+1, ~input_matrix[k]); | |
} | |
else | |
{ | |
write_LED(k+1, input_matrix[k]); | |
} | |
} | |
} | |
function display_line(line = "No text entered") | |
{ | |
// Display a text string character by character, bit-scrolling | |
// from one to the next | |
// Parameter(s): | |
// 1. String of characters, default: "No text entered" | |
if (line == "") return | |
local a = 0; | |
local b = 0; | |
local count = 0; | |
local output_matrix = [0,0,0,0,0,0,0,0]; | |
local matrix_one = [0,0,0,0,0,0,0,0]; | |
local matrix_two = [0,0,0,0,0,0,0,0]; | |
foreach (index, character in line) | |
{ | |
// Count the number of characters in the line | |
count++; | |
} | |
if (count == 1) | |
{ | |
count = 2; | |
line = " " + line; | |
} | |
for (local k = 0 ; k < (count - 1); k++) | |
{ | |
// Run through the line character by character up to the penultimate character | |
// Get the current character to be displayed and the next character along by | |
// copying them from the character set array | |
a = line[k]; | |
b = line[k + 1]; | |
matrix_one = clone(charset[a - 32]); | |
matrix_two = clone(charset[b - 32]); | |
for (local j = 0 ; j < 8 ; j++) | |
{ | |
// We use two character matrices, one on the left and one on the right. | |
// Line by line, we shift the left matrix's bit pattern one bit at a time. | |
// If the seventh bit of a line in the right-hand matrix is set, | |
// we then set bit 0 of the left-hand matrix. | |
// We then shift the right-hand matrix leftward one bit. | |
output_matrix = matrix_one; | |
output_matrix = rotate_matrix(output_matrix); | |
for (local i = 0 ; i < 8 ; i++) | |
{ | |
// Write the current character’s matrix | |
if (inverse_video_flag) | |
{ | |
write_LED(i+1, ~output_matrix[i]); | |
} | |
else | |
{ | |
write_LED(i+1, output_matrix[i]); | |
} | |
// Use the Logical Shift Left operator to move the line one pixel | |
matrix_one[i] = matrix_one[i] << 1; | |
// Move over second matrix by one pixel | |
if ((matrix_two[i] & 128) > 0) | |
{ | |
// If bit 7 of the right-hand character’s line is set, | |
// carry it over to bit 0 of the left-hand character | |
matrix_one[i] = matrix_one[i] | (1 << 0); | |
} | |
// Shift right-hand character line left one pixel | |
matrix_two[i] = (matrix_two[i] << 1); | |
} | |
imp.sleep(0.04); | |
} | |
} | |
// For the final character, we need to perform a last pixel shift to leave | |
// the character completely on the display | |
output_matrix = matrix_one; | |
output_matrix = rotate_matrix(output_matrix); | |
for (local i = 0 ; i < 8 ; i++) | |
{ | |
if (inverse_video_flag) | |
{ | |
write_LED(i+1, ~output_matrix[i]); | |
} | |
else | |
{ | |
write_LED(i+1, output_matrix[i]); | |
} | |
matrix_one[i] = matrix_one[i] << 1; | |
if ((matrix_two[i] & 128) > 0) matrix_one[i] = matrix_one[i] | (1 << 0); | |
matrix_two[i] = (matrix_two[i] << 1); | |
} | |
imp.sleep(0.04); | |
} | |
function rotate_matrix(input_matrix) | |
{ | |
// Rotate an 8 x 8 character bitmap matrix to reflect orientation of LEDs | |
// Parameter(s): | |
// 1. Array of eight 8-bit values containing the character bit pattern | |
// Returns: | |
// Rotated array of eight 8-bit values containing the character bit pattern | |
// Only rotate the matrix if rotate_matrix_flag has not been set | |
if (rotate_matrix_flag == false) return input_matrix; | |
// Rotate the character matrix through 90 degrees anti-clockwise | |
// Used if the LED matrix pins are connected directly to a breadboard | |
local a = 0; | |
local line_value = 0; | |
local output_matrix = [0,0,0,0,0,0,0,0]; | |
for (local i = 0 ; i < 8 ; i++) | |
{ | |
line_value = input_matrix[i]; | |
for (local j = 7 ; j > -1 ; j--) | |
{ | |
a = (line_value & math.pow(2, j).tointeger()); | |
if (a > 0) output_matrix[7-j] = output_matrix[7-j] + math.pow(2, i).tointeger(); | |
} | |
} | |
return output_matrix; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks! :)