Last active
July 31, 2016 19:33
-
-
Save geekscape/8e7e949c7e610c46ebfebad50c9ed9de to your computer and use it in GitHub Desktop.
Example NodeBots (JavaScript) code for MakeBlock mBot LED Matrix
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
/* | |
* Titan Micro Electronics TM1640: 16 x 8 LED driver datasheet (Chinese) | |
* https://dl.dropboxusercontent.com/u/8663580/TM1640.pdf | |
* | |
* TODO: Turn this code into a module and use it in "nodebots.js". | |
* TODO: Make all functions available to the REPL. | |
*/ | |
var five = require('johnny-five'); | |
var board = five.Board(); | |
// Define Data Command Parameters | |
var MODE_ADDRESS_AUTO_ADD_1 = 0x40; | |
var MODE_PERMANENT_ADDRESS = 0x44; | |
var WIDTH = 16; | |
var HEIGHT = 8; | |
board.on('ready', function() { | |
var pin_clock = five.Pin({ | |
pin: 14, | |
mode: this.io.MODES.OUTPUT, | |
}); | |
var pin_data = five.Pin({ | |
pin: 15, | |
mode: this.io.MODES.OUTPUT, | |
}); | |
console.log('Board ready'); | |
var screen = { | |
pin_clock: pin_clock, pin_data: pin_data, matrix: new Buffer(16) | |
}; | |
write_byte(pin_clock, pin_data, MODE_ADDRESS_AUTO_ADD_1); // Set mode | |
write_byte(pin_clock, pin_data, 0x8c); // Set brightness ? | |
clear_screen(screen); | |
if (true) { | |
draw_character(screen, 1, 0, 'G', state); | |
draw_character(screen, 7, 0, 'o', state); | |
draw_character(screen, 13, 0, '!', state); | |
write_screen(screen); | |
} | |
else { | |
screen.matrix = new Buffer([ // Checkerboard | |
0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, | |
0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 | |
]); | |
write_screen(screen); | |
} | |
clear_screen(screen); | |
var state = false; | |
setInterval(function() { | |
state = ! state; | |
if (true) { // Face ? | |
draw_rectangle(screen, 0, 0, WIDTH, HEIGHT, state); | |
draw_circle(screen, 5, 3, 1, state); | |
draw_circle(screen, 10, 3, 1, state); | |
draw_hline(screen, 7, 5, 2, state); | |
} | |
else { // X marks the spot ! | |
draw_line(screen, 0, 0, WIDTH - 1, HEIGHT - 1, state); | |
draw_line(screen, 0, HEIGHT - 1, WIDTH - 1, 0, state); | |
} | |
// invert_screen(screen); | |
write_screen(screen); | |
}.bind(this), 1000); | |
this.repl.inject({ | |
test: function() { | |
console.log('test'); | |
} | |
}); | |
}); | |
function write_byte(pin_clock, pin_data, buffer) { | |
pin_clock.high(); pin_data.low(); | |
for (var bit = 0; bit < 8; bit ++) { | |
pin_clock.low(); | |
pin_data.write(buffer & 0x01); | |
pin_clock.high(); | |
buffer = buffer >> 1; | |
} | |
pin_clock.low(); pin_data.low(); | |
pin_clock.high(); pin_data.high(); | |
} | |
function write_bytes_to_address(pin_clock, pin_data, address, buffer) { | |
address = address | 0xc0; | |
pin_clock.high(); pin_data.low(); | |
for (var bit = 0; bit < 8; bit ++) { | |
pin_clock.low(); | |
pin_data.write(address & 0x01); | |
pin_clock.high(); | |
address = address >> 1; | |
} | |
for (var byte = 0; byte < buffer.length; byte ++) { | |
var data = buffer[byte]; | |
for (bit = 0; bit < 8; bit ++) { | |
pin_clock.low(); | |
pin_data.write(data & 0x01); | |
pin_clock.high(); | |
data = data >> 1; | |
} | |
} | |
pin_clock.low(); pin_data.low(); | |
pin_clock.high(); pin_data.high(); | |
} | |
function write_screen(screen) { | |
write_bytes_to_address(screen.pin_clock, screen.pin_data, 0, screen.matrix); | |
} | |
function clear_screen(screen, value) { // value = 0xff for all LEDS on | |
if (typeof(value) === 'undefined') value = 0; | |
screen.matrix.fill(value); | |
write_screen(screen); | |
} | |
function invert_screen(screen) { | |
for (var index = 0; index < screen.matrix.length; index ++) { | |
screen.matrix[index] = screen.matrix[index] ^ 0xff; | |
} | |
} | |
function draw_point(screen, column, row, value) { | |
var bit = (typeof(value) === 'undefined') ? 1 : value; | |
var mask = 0xff ^ (1 << row); | |
screen.matrix[column] = screen.matrix[column] & mask | (bit << row); | |
// TODO: This should work and would be much more efficient ! | |
//write_bytes_to_address( | |
// screen.pin_clock, screen.pin_data, column, new Buffer(screen.matrix[column]) | |
//); | |
} | |
function draw_hline(screen, column, row, length, value) { | |
for (var index = column; index < column + length; index ++) { | |
draw_point(screen, index, row, value); | |
} | |
// TODO: More efficient to write_bytes_to_address() for only changed columns ! | |
} | |
function draw_vline(screen, column, row, length, value) { | |
var bit = (typeof(value) === 'undefined') ? 1 : value; | |
var byte = (Math.pow(2, length) - 1) << row; | |
var mask = 0xff ^ byte; | |
if (bit === false) byte = 0; | |
screen.matrix[column] = screen.matrix[column] & mask | byte; | |
// TODO: This should work and would be much more efficient ! | |
//write_bytes_to_address( | |
// screen.pin_clock, screen.pin_data, column, new Buffer(screen.matrix[column]) | |
//); | |
} | |
// Bresenham's line algorithm | |
function draw_line(screen, column0, row0, column1, row1, value) { | |
var column_delta = Math.abs(column1 - column0); | |
var row_delta = Math.abs(row1 - row0); | |
var column_increment = column0 < column1 ? 1 : -1; | |
var row_increment = row0 < row1 ? 1 : -1; | |
var error = (column_delta > row_delta ? column_delta : -row_delta) / 2; | |
while (true) { | |
draw_point(screen, column0, row0, value); | |
if (column0 === column1 && row0 === row1) break; | |
var error2 = error; | |
if (error2 > -column_delta) { | |
error -= row_delta; | |
column0 += column_increment; | |
} | |
if (error2 < row_delta) { | |
error += column_delta; | |
row0 += row_increment; | |
} | |
} | |
} | |
function draw_rectangle(screen, row, column, width, height, value) { | |
draw_hline(screen, column, row, width, value); | |
draw_hline(screen, column, row + height - 1, width, value); | |
draw_vline(screen, column, row, height, value); | |
draw_vline(screen, column + width - 1, row, height, value); | |
} | |
function fill_rectangle(screen, column, row, width, height, value) { | |
for (var index = 0; index < width; index ++) { | |
draw_vline(screen, column + index, row, height, value); | |
} | |
} | |
// Bresenham's line algorithm extended for circles | |
function draw_circle(screen, column, row, radius, value) { | |
var x = radius, y = 0; | |
var radiusError = 1 - x; | |
while (x >= y) { | |
draw_point(screen, -y + column, -x + row, value); | |
draw_point(screen, y + column, -x + row, value); | |
draw_point(screen, -x + column, -y + row, value); | |
draw_point(screen, x + column, -y + row, value); | |
draw_point(screen, -x + column, y + row, value); | |
draw_point(screen, x + column, y + row, value); | |
draw_point(screen, -y + column, x + row, value); | |
draw_point(screen, y + column, x + row, value); | |
y++; | |
if (radiusError < 0) { | |
radiusError += 2 * y + 1; | |
} | |
else { | |
x --; | |
radiusError += 2 * (y - x + 1); | |
} | |
} | |
} | |
function fill_circle(screen, column, row, radius, value) { | |
var x = radius, y = 0; | |
var radiusError = 1 - x; | |
while (x >= y) { | |
draw_line(screen, -y + column, -x + row, y + column, -x + row, value); | |
draw_line(screen, -x + column, -y + row, x + column, -y + row, value); | |
draw_line(screen, -x + column, y + row, x + column, y + row, value); | |
draw_line(screen, -y + column, x + row, y + column, x + row, value); | |
y++; | |
if (radiusError < 0) { | |
radiusError += 2 * y + 1; | |
} | |
else { | |
x --; | |
radiusError+= 2 * (y - x + 1); | |
} | |
} | |
} | |
// Thanks Suz (@noopkat) ... https://github.com/noopkat/oled-font-5x7 ! | |
var font = require('./vendor/oled-font-5x7/oled-font-5x7'); | |
function draw_character(screen, column, row, character, value) { | |
var lookup = index = font.lookup.indexOf(character) * 5; | |
var fontData = font.fontData.slice(lookup, lookup + 5); | |
for (var index = 0; index < fontData.length; index ++) { | |
screen.matrix[column + index] = fontData[index] << 1; | |
} | |
} |
Brilliant - will look at how we get this back into the main side of J5 as well in LED matrix
The prototype code in this Gist has been made into a proper NodeBot driver and moved to https://github.com/geekscape/nodebot_ai ... @ajfisher let's continue the discussion over there (as GitHub issues ?).
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Now includes fill_circle() and draw_character()
Note: You will need to ...
mkdir vendor
cd vendor
git clone https://github.com/noopkat/oled-font-5x