Skip to content

Instantly share code, notes, and snippets.

@smittytone
Last active May 24, 2017 00:39
Show Gist options
  • Save smittytone/e7f88c317ccb348f7015 to your computer and use it in GitHub Desktop.
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
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;
}
}
@5pecia1
Copy link

5pecia1 commented May 24, 2017

Thanks! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment