diff --git a/Arduino/HT1632/HT1632.cpp b/Arduino/HT1632/HT1632.cpp deleted file mode 100644 index 9208b71..0000000 --- a/Arduino/HT1632/HT1632.cpp +++ /dev/null @@ -1,449 +0,0 @@ -#include "HT1632.h" - -#if (ARDUINO >= 100) - #include -#else - #include -#endif - -/* - * HIGH LEVEL FUNCTIONS - * Functions that perform advanced tasks using lower-level - * functions go here: - */ - -void HT1632Class::drawText(const char text [], int x, int y, const char font [], const char font_width [], char font_height, int font_glyph_step, char gutter_space) { - int curr_x = x; - char i = 0; - char currchar; - - // Check if string is within y-bounds - if(y + font_height < 0 || y >= COM_SIZE) - return; - - while(true){ - if(text[i] == '\0') - return; - - currchar = text[i] - 32; - if(currchar >= 65 && currchar <= 90) // If character is lower-case, automatically make it upper-case - currchar -= 32; // Make this character uppercase. - if(currchar < 0 || currchar >= 64) { // If out of bounds, skip - ++i; - continue; // Skip this character. - } - // Check to see if character is not too far right. - if(curr_x >= OUT_SIZE) - break; // Stop rendering - all other characters are no longer within the screen - - // Check to see if character is not too far left. - if(curr_x + font_width[currchar] + gutter_space >= 0){ - drawImage(font, font_width[currchar], font_height, curr_x, y, currchar*font_glyph_step); - - // Draw the gutter space - for(char j = 0; j < gutter_space; ++j) - drawImage(font, 1, font_height, curr_x + font_width[currchar] + j, y, 0); - - } - - curr_x += font_width[currchar] + gutter_space; - ++i; - } -} - -// Gives you the width, in columns, of a particular string. -int HT1632Class::getTextWidth(const char text [], const char font_width [], char font_height, char gutter_space) { - int wd = 0; - char i = 0; - char currchar; - - while(true){ - if(text[i] == '\0') - return wd - gutter_space; - - currchar = text[i] - 32; - if(currchar >= 65 && currchar <= 90) // If character is lower-case, automatically make it upper-case - currchar -= 32; // Make this character uppercase. - if(currchar < 0 || currchar >= 64) { // If out of bounds, skip - ++i; - continue; // Skip this character. - } - wd += font_width[currchar] + gutter_space; - ++i; - } -} - -/* - * MID LEVEL FUNCTIONS - * Functions that handle internal memory, initialize the hardware - * and perform the rendering go here: - */ - -void HT1632Class::begin(int pinCS1, int pinWR, int pinDATA) { - _numActivePins = 1; - _pinCS[0] = pinCS1; - initialize(pinWR, pinDATA); -} -void HT1632Class::begin(int pinCS1, int pinCS2, int pinWR, int pinDATA) { - _numActivePins = 2; - _pinCS[0] = pinCS1; - _pinCS[1] = pinCS2; - initialize(pinWR, pinDATA); -} -void HT1632Class::begin(int pinCS1, int pinCS2, int pinCS3, int pinWR, int pinDATA) { - _numActivePins = 3; - _pinCS[0] = pinCS1; - _pinCS[1] = pinCS2; - _pinCS[2] = pinCS3; - initialize(pinWR, pinDATA); -} -void HT1632Class::begin(int pinCS1, int pinCS2, int pinCS3, int pinCS4, int pinWR, int pinDATA) { - _numActivePins = 4; - _pinCS[0] = pinCS1; - _pinCS[1] = pinCS2; - _pinCS[2] = pinCS3; - _pinCS[3] = pinCS4; - initialize(pinWR, pinDATA); -} - -void HT1632Class::initialize(int pinWR, int pinDATA) { - _pinWR = pinWR; - _pinDATA = pinDATA; - - for(int i=0; i<_numActivePins; ++i){ - pinMode(_pinCS[i], OUTPUT); - // Allocate new memory for mem - mem[i] = (char *)malloc(ADDR_SPACE_SIZE); - drawTarget(i); - clear(); // Clean out mem - } - pinMode(_pinWR, OUTPUT); - pinMode(_pinDATA, OUTPUT); - - select(); - - mem[4] = (char *)malloc(ADDR_SPACE_SIZE); - // Each 8-bit mem array element stores data in the 4 least significant bits, - // and meta-data in the 4 most significant bits. Use bitmasking to read/write - // the meta-data. - drawTarget(4); - clear(); - // Clean out memory - int i=0; - - - // Send configuration to chip: - // This configuration is from the HT1632 datasheet, with one modification: - // The RC_MASTER_MODE command is not sent to the master. Since acting as - // the RC Master is the default behaviour, this is not needed. Sending - // this command causes problems in HT1632C (note the C at the end) chips. - - // Send Master commands - - select(0b1111); // Assume that board 1 is the master. - writeData(HT1632_ID_CMD, HT1632_ID_LEN); // Command mode - - writeCommand(HT1632_CMD_SYSDIS); // Turn off system oscillator - // N-MOS or P-MOS open drain output and 8 or 16 common option -#if USE_NMOS == 1 && COM_SIZE == 8 - writeCommand(HT1632_CMD_COMS00); -#elif USE_NMOS == 1 && COM_SIZE == 16 - writeCommand(HT1632_CMD_COMS01); -#elif USE_NMOS == 0 && COM_SIZE == 8 - writeCommand(HT1632_CMD_COMS10); -#elif USE_NMOS == 0 && COM_SIZE == 16 - writeCommand(HT1632_CMD_COMS11); -#else -#error Invalid USE_NMOS or COM_SIZE values! Change the values in HT1632.h. -#endif - - if(false && _numActivePins > 1){ - select(0b0001); // - writeData(HT1632_ID_CMD, HT1632_ID_LEN); // Command mode - writeCommand(HT1632_CMD_RCCLK); // Switch system to MASTER mode - select(0b1110); // All other boards are slaves - writeData(HT1632_ID_CMD, HT1632_ID_LEN); // Command mode - - writeCommand(HT1632_CMD_MSTMD); // Switch system to SLAVE mode. - // The use of the MSTMD command to switch to slave is explained here: - // http://forums.parallax.com/showthread.php?117423-Electronics-I-O-%28outputs-to-common-anode-RGB-LED-matrix%29-question/page4 - - - select(0b1111); - writeData(HT1632_ID_CMD, HT1632_ID_LEN); // Command mode - } - - writeCommand(HT1632_CMD_SYSEN); //Turn on system - writeCommand(HT1632_CMD_LEDON); // Turn on LED duty cycle generator - writeCommand(HT1632_CMD_PWM(16)); // PWM 16/16 duty - - select(); - - - for(int i=0; i<_numActivePins; ++i) { - drawTarget(i); - _globalNeedsRewriting[i] = true; - clear(); - // Perform the initial rendering - render(); - } - // Set drawTarget to default board. - drawTarget(0); -} - -void HT1632Class::drawTarget(char targetBuffer) { - if(targetBuffer == 0x04 || (targetBuffer >= 0 && targetBuffer < _numActivePins)) - _tgtBuffer = targetBuffer; -} - -void HT1632Class::drawImage(const char * img, char width, char height, char x, char y, int offset){ - char length = width*height/4; - char mask; - - // Sanity checks - if(y + height < 0 || x + width < 0 || y > COM_SIZE || x > OUT_SIZE) - return; - // After looking at the rest of this function, you may need one. - - // Copying Engine. - // You are not expected to understand this. - for(char i=0; i= OUT_SIZE) // Skip this column if it is out of range. - continue; - for(char j=0; j < (carryover_valid ? (height+4):height) ; j+=4) { - char loc_y = j + y; - if(loc_y <= -4 || loc_y >= COM_SIZE) // Skip this row if it is out of range. - continue; - // Direct copying possible when render is on boundaries. - // The bit manipulation here is designed to copy from img only the relevant sections. - - // This mask is only not used when emptying the cache (for copying to non-4-bit aligned spaces) - - //if(j= 4)?0b00001111:(0b00001111 >> (4-(height-j))) & 0b00001111; // Mask bottom - - if(loc_y % 4 == 0) { - mask = (height-loc_y >= 4)?0b00001111:(0b00001111 >> (4-(height-j))) & 0b00001111; - mem[_tgtBuffer][GET_ADDR_FROM_X_Y(loc_x,loc_y)] = (mem[_tgtBuffer][GET_ADDR_FROM_X_Y(loc_x,loc_y)] & (~mask) & 0b00001111) | (img[(int)ceil((float)height/4.0f)*i + j/4 + offset] & mask) | MASK_NEEDS_REWRITING; - } else { - // If carryover_valid is NOT true, then this is the first set to be copied. - // If loc_y > 0, preserve the contents of the pixels above, copy to mem, and then copy remaining - // data to the carry over buffer. If y loc_y < 0, just copy data to carry over buffer. - // It is expected that this section is only reached when j == 0. - // COPY START - if(!carryover_valid) { - if(loc_y > 0) { - mask = (height-loc_y >= 4)?0b00001111:(0b00001111 >> (4-(height-j))) & 0b00001111; // Mask bottom - mask = (0b00001111 << carryover_num) & mask; // Mask top - mem[_tgtBuffer][GET_ADDR_FROM_X_Y(loc_x,loc_y)] = (mem[_tgtBuffer][GET_ADDR_FROM_X_Y(loc_x,loc_y)] & (~mask) & 0b00001111) | ((img[(int)ceil((float)height/4.0f)*i + j/4 + offset] << carryover_num) & mask) | MASK_NEEDS_REWRITING; - } - carryover_valid = true; - } else { - // COPY END - if(j >= height) { - // Its writing one line past the end. - // Use this line to get rid of the final carry-over. - mask = (0b00001111 >> (4 - carryover_num)) & 0b00001111; // Mask bottom - mem[_tgtBuffer][GET_ADDR_FROM_X_Y(loc_x,loc_y)] = (mem[_tgtBuffer][GET_ADDR_FROM_X_Y(loc_x,loc_y)] & (~mask) & 0b00001111) | (carryover_y >> (4 - carryover_num) & mask) | MASK_NEEDS_REWRITING; - // COPY MIDDLE - } else { - // There is data in the carry-over buffer. Copy that data and the values from the current cell into mem. - // The inclusion of a carryover_num term is to account for the presence of the carryover data when calculating the bottom clipping. - mask = (height-loc_y >= 4)?0b00001111:(0b00001111 >> (4-(height+carryover_num-j))) & 0b00001111; // Mask bottom - mem[_tgtBuffer][GET_ADDR_FROM_X_Y(loc_x,loc_y)] = (mem[_tgtBuffer][GET_ADDR_FROM_X_Y(loc_x,loc_y)] & (~mask) & 0b00001111) | ((img[(int)ceil((float)height/4.0f)*i + j/4 + offset] << carryover_num) & mask) | (carryover_y >> (4 - carryover_num) & mask) | MASK_NEEDS_REWRITING; - } - } - carryover_y = img[(int)ceil((float)height/4.0f)*i + j/4 + offset]; - } - } - } -} - -void HT1632Class::clear(){ - for(char i=0; i < ADDR_SPACE_SIZE; ++i) - mem[_tgtBuffer][i] = 0x00 | MASK_NEEDS_REWRITING; // Needs to be redrawn -} - -// Draw the contents of map to screen, for memory addresses that have the needsRedrawing flag -void HT1632Class::render() { - if(_tgtBuffer >= _numActivePins || _tgtBuffer < 0) - return; - - char selectionmask = 0b0001 << _tgtBuffer; - - bool isOpen = false; // Automatically compact sequential writes. - for(int i=0; i= _numActivePins || _tgtBuffer < 0) - return; - - switch(mode) { - case TRANSITION_BUFFER_SWAP: - { - char * tmp = mem[_tgtBuffer]; - mem[_tgtBuffer] = mem[BUFFER_SECONDARY]; - mem[BUFFER_SECONDARY] = tmp; - _globalNeedsRewriting[_tgtBuffer] = true; - } - break; - case TRANSITION_NONE: - for(char i=0; i < ADDR_SPACE_SIZE; ++i) - mem[_tgtBuffer][i] = mem[BUFFER_SECONDARY][i]; // Needs to be redrawn - _globalNeedsRewriting[_tgtBuffer] = true; - break; - case TRANSITION_FADE: - time /= 32; - for(int i = 15; i > 0; --i) { - setBrightness(i); - delay(time); - } - clear(); - render(); - delay(time); - transition(TRANSITION_BUFFER_SWAP); - render(); - delay(time); - for(int i = 2; i <= 16; ++i) { - setBrightness(i); - delay(time); - } - break; - } - -} - - -/* - * LOWER LEVEL FUNCTIONS - * Functions that directly talk to hardware go here: - */ - -void HT1632Class::writeCommand(char data) { - writeData(data, HT1632_CMD_LEN); - writeSingleBit(); -} -// Integer write to display. Used to write commands/addresses. -// PRECONDITION: WR is LOW -void HT1632Class::writeData(char data, char len) { - for(int j=len-1, t = 1 << (len - 1); j>=0; --j, t >>= 1){ - // Set the DATA pin to the correct state - digitalWrite(_pinDATA, ((data & t) == 0)?LOW:HIGH); - NOP(); // Delay - // Raise the WR momentarily to allow the device to capture the data - digitalWrite(_pinWR, HIGH); - NOP(); // Delay - // Lower it again, in preparation for the next cycle. - digitalWrite(_pinWR, LOW); - } -} -// REVERSED Integer write to display. Used to write cell values. -// PRECONDITION: WR is LOW -void HT1632Class::writeDataRev(char data, char len) { - for(int j=0; j>= 1; - } -} -// Write single bit to display, used as padding between commands. -// PRECONDITION: WR is LOW -void HT1632Class::writeSingleBit() { - // Set the DATA pin to the correct state - digitalWrite(_pinDATA, LOW); - NOP(); // Delay - // Raise the WR momentarily to allow the device to capture the data - digitalWrite(_pinWR, HIGH); - NOP(); // Delay - // Lower it again, in preparation for the next cycle. - digitalWrite(_pinWR, LOW); -} -// Choose a chip. This function sets the correct CS line to LOW, and the rest to HIGH -// Call the function with no arguments to deselect all chips. -// Call the function with a bitmask (0b4321) to select specific chips. 0b1111 selects all. -void HT1632Class::select(char mask) { - for(int i=0, t=1; i<_numActivePins; ++i, t <<= 1){ - digitalWrite(_pinCS[i], (t & mask)?LOW:HIGH); - /*Serial.write(48+_pinCS[i]); - Serial.write((t & mask)?"LOW":"HIGH"); - Serial.write('\n'); - */} - //Serial.write('\n'); -} -void HT1632Class::select() { - for(int i=0; i<_numActivePins; ++i) - digitalWrite(_pinCS[i], HIGH); -} - -/* - * HELPER FUNCTIONS - * "Would you like some fries with that?" - */ - -void HT1632Class::recursiveWriteUInt (int inp) { - if(inp <= 0) return; - int rd = inp % 10; - recursiveWriteUInt(inp/10); - Serial.write(48+rd); -} - -void HT1632Class::writeInt (int inp) { - if(inp == 0) - Serial.write('0'); - else - if (inp < 0){ - Serial.write('-'); - recursiveWriteUInt(-inp); - } else - recursiveWriteUInt(inp); -} - -HT1632Class HT1632; - diff --git a/Arduino/HT1632/HT1632.h b/Arduino/HT1632/HT1632.h deleted file mode 100644 index 5ae2935..0000000 --- a/Arduino/HT1632/HT1632.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - HT1632.h - Library for communicating with the popular HT1632/HT1632C - LED controllers. This library provides higher-level access (including - text drawing) for these chips. Currently, the library supports writing - to a single chip at a time, and has been tested with a single - Sure Electronics 3208 5mm red board. - - Created by Gaurav Manek, April 8, 2011. - Released into the public domain. -*/ -#ifndef HT1632_h -#define HT1632_h - -/* - * USER OPTIONS - * Change these options - */ - -// Size of COM and OUT in bits: -#define COM_SIZE 8 -#define OUT_SIZE 32 -// COM_SIZE MUST be either 8 or 16. - -// Target buffer -// Each board has a "render" buffer, and all boards share one "secondary" buffer. All calls to -// render() draw the contents of the render buffer of the currently selected board to the board -// itself. All calls to any drawing function (including clear()) only affect the selected buffer -// of the selected board. you can move the contents of the secondary buffer to the render -// buffer by calling transition(), with an appropriate transition. See transition() for more details. -// board_num = [1..4] -#define BUFFER_BOARD(board_num) ((board_num)-1) -#define BUFFER_SECONDARY 0x04 - -// Transition Modes -// Transitions copies the contents of the "secondary" buffer to the currently selected board buffer. -// Pass one of these transition types to the transition() function and the contents of the -// "secondary" buffer will be moved to that using some animation. transition() is a blocking function. -// In all transitions other than the first one, the contents of the board buffer is lost and render() -// is automatically called. -#define TRANSITION_BUFFER_SWAP 0x00 - // Swap the current buffer and the transition buffer. This is the only transition that preserves - // the contents of the current buffer. -#define TRANSITION_NONE 0x01 - // Simply copy the buffer. -#define TRANSITION_FADE 0x02 - // Uses the PWM feature to fade through black. Does not preserve current brightness level. -#define TRANSITION_WIPE_FROM_RIGHT 0x03 -// Wrap settings -// For advanced rendering (currently only text rendering) - -// Address space size (number of 4-bit words in HT1632 memory) -// Exactly equal to the number of 4-bit address spaces available. -#define ADDR_SPACE_SIZE (COM_SIZE*OUT_SIZE/4) - -// Use N-MOS (if 1) or P-MOS (if 0): -#define USE_NMOS 1 -// There are known issues with this. If the default doesn't work, -// try changing the value. - -// NOTE: THIS HARDCODES THE DIMENSIONS OF THE 3208! CHANGE! -#define GET_ADDR_FROM_X_Y(_x,_y) ((_x)*2+(_y)/4) - -/* - * END USER OPTIONS - * Don't edit anything below unless you know what you are doing! - */ - -// Meta-data masks -#define MASK_NEEDS_REWRITING 0b00010000 - -// Round up to multiple of 4 function - -// NO-OP Definition -#define NOP(); __asm__("nop\n\t"); -// The HT1632 requires at least 50 ns between the change in data and the rising -// edge of the WR signal. On a 16MHz processor, this provides 62.5ns per NOP. - -// Standard command list. -// This list is modified from original code by Bill Westfield - -#define HT1632_ID_CMD 0b100 /* ID = 100 - Commands */ -#define HT1632_ID_RD 0b110 /* ID = 110 - Read RAM */ -#define HT1632_ID_WR 0b101 /* ID = 101 - Write RAM */ -#define HT1632_ID_LEN 3 /* IDs are 3 bits */ - -// Do note that SYSON has been changed to SYSEN -#define HT1632_CMD_SYSDIS 0x00 /* CMD= 0000-0000-x Turn off oscil */ -#define HT1632_CMD_SYSEN 0x01 /* CMD= 0000-0001-x Enable system oscil */ -#define HT1632_CMD_LEDOFF 0x02 /* CMD= 0000-0010-x LED duty cycle gen off */ -#define HT1632_CMD_LEDON 0x03 /* CMD= 0000-0011-x LEDs ON */ -#define HT1632_CMD_BLOFF 0x08 /* CMD= 0000-1000-x Blink ON */ -#define HT1632_CMD_BLON 0x09 /* CMD= 0000-1001-x Blink Off */ -#define HT1632_CMD_SLVMD 0x10 /* CMD= 0001-00xx-x Slave Mode */ -#define HT1632_CMD_MSTMD 0x14 /* CMD= 0001-01xx-x Master Mode */ -#define HT1632_CMD_RCCLK 0x18 /* CMD= 0001-10xx-x Use on-chip clock */ -#define HT1632_CMD_EXTCLK 0x1C /* CMD= 0001-11xx-x Use external clock */ -#define HT1632_CMD_COMS00 0x20 /* CMD= 0010-ABxx-x commons options */ -#define HT1632_CMD_COMS01 0x24 /* CMD= 0010-ABxx-x commons options */ -#define HT1632_CMD_COMS10 0x28 /* CMD= 0010-ABxx-x commons options */ -#define HT1632_CMD_COMS11 0x2C /* CMD= 0010-ABxx-x commons options */ -#define HT1632_CMD_PWM_T 0xA0 /* CMD= 101x-PPPP-x PWM duty cycle - template*/ -#define HT1632_CMD_PWM(lvl) (HT1632_CMD_PWM_T | (lvl-1)) - /* Produces the correct command from the given value of lvl. lvl = [0..15] */ -#define HT1632_CMD_LEN 8 /* Commands are 8 bits long, excluding the trailing bit */ -#define HT1632_ADDR_LEN 7 /* Addresses are 7 bits long */ -#define HT1632_WORD_LEN 4 /* Words are 4 bits long */ - -class HT1632Class -{ - private: - char _pinCS [4]; - char _numActivePins; - char _pinWR; - char _pinDATA; - char _tgtBuffer; - char _globalNeedsRewriting [4]; - char * mem [5]; - void writeCommand(char); - void writeData(char, char); - void writeDataRev(char, char); - void writeSingleBit(); - void initialize(int, int); - void select(); - void select(char mask); - - // Debugging functions, write to Serial. - void writeInt(int); - void recursiveWriteUInt(int); - - public: - void begin(int pinCS1, int pinWR, int pinDATA); - void begin(int pinCS1, int pinCS2, int pinWR, int pinDATA); - void begin(int pinCS1, int pinCS2, int pinCS3, int pinWR, int pinDATA); - void begin(int pinCS1, int pinCS2, int pinCS3, int pinCS4, int pinWR, int pinDATA); - void sendCommand(char command); - void drawTarget(char targetBuffer); - void render(); - void transition(char mode, int time = 1000); // Time is in miliseconds. - void clear(); - void drawImage(const char * img, char width, char height, char x, char y, int offset = 0); - void drawText(const char [], int x, int y, const char font [], const char font_width [], char font_height, int font_glyph_step, char gutter_space = 1); - int getTextWidth(const char [], const char font_width [], char font_height, char gutter_space = 1); - void setBrightness(char brightness, char selectionmask = 0b00010000); -}; - -extern HT1632Class HT1632; - -#else -//#error "HT1632.h" already defined! -#endif diff --git a/Arduino/HT1632/font_5x4.h b/Arduino/HT1632/font_5x4.h deleted file mode 100644 index b04020f..0000000 --- a/Arduino/HT1632/font_5x4.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 5-high FONT FOR RENDERING TO THE LED SCREEN. - * Includes kerning support - * Gaurav Manek, 2011 - */ - -#define FONT_5X4_HEIGHT 5 - -#define FONT_5X4_STEP_GLYPH 10 -// Number of bytes per glyph - -char FONT_5X4 [] = { - 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // SPACE - 0b0111, 0b0001, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // ! - 0b0011, 0b0000, 0b0000, 0b0000, 0b0011, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // " - 0b1010, 0b0000, 0b1111, 0b0001, 0b1010, 0b0000, 0b1111, 0b0001, 0b1010, 0b0000, // # - 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // $ - 0b0011, 0b0001, 0b1011, 0b0000, 0b0100, 0b0000, 0b1010, 0b0001, 0b1001, 0b0001, // % - 0b1010, 0b0000, 0b0101, 0b0001, 0b1001, 0b0001, 0b1010, 0b0001, 0b0000, 0b0000, // & - 0b0011, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // ' - - 0b1110, 0b0000, 0b0001, 0b0001, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // ( - 0b0001, 0b0001, 0b1110, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // ) - 0b0101, 0b0000, 0b0010, 0b0000, 0b0101, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // * - 0b0100, 0b0000, 0b0100, 0b0000, 0b1111, 0b0001, 0b0100, 0b0000, 0b0100, 0b0000, // + - 0b0000, 0b0001, 0b1000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // , - 0b0100, 0b0000, 0b0100, 0b0000, 0b0100, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // - - 0b0000, 0b0001, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // . - 0b0000, 0b0001, 0b1100, 0b0000, 0b0110, 0b0000, 0b0001, 0b0000, 0b0000, 0b0000, // / - - 0b1110, 0b0000, 0b0001, 0b0001, 0b1110, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // 0 - 0b0010, 0b0001, 0b1111, 0b0001, 0b0000, 0b0001, 0b0000, 0b0000, 0b0000, 0b0000, // 1 - 0b0010, 0b0001, 0b1001, 0b0001, 0b0101, 0b0001, 0b0010, 0b0001, 0b0000, 0b0000, // 2 - 0b0101, 0b0001, 0b0101, 0b0001, 0b1010, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // 3 - 0b1100, 0b0000, 0b1010, 0b0000, 0b1111, 0b0001, 0b1000, 0b0000, 0b0000, 0b0000, // 4 - 0b0111, 0b0001, 0b0101, 0b0001, 0b1101, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // 5 - 0b1110, 0b0000, 0b0101, 0b0001, 0b0101, 0b0001, 0b1000, 0b0000, 0b0000, 0b0000, // 6 - 0b0001, 0b0000, 0b1101, 0b0001, 0b0101, 0b0000, 0b0011, 0b0000, 0b0000, 0b0000, // 7 - - 0b1010, 0b0000, 0b0101, 0b0001, 0b0101, 0b0001, 0b1010, 0b0000, 0b0000, 0b0000, // 8 - 0b0010, 0b0000, 0b0101, 0b0000, 0b0101, 0b0001, 0b1110, 0b0000, 0b0000, 0b0000, // 9 - 0b1010, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // : - 0b0000, 0b0001, 0b1010, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // ; - 0b0100, 0b0000, 0b1010, 0b0000, 0b0001, 0b0001, 0b0000, 0b0000, 0b0000, 0b0000, // < - 0b1010, 0b0000, 0b1010, 0b0000, 0b1010, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // = - 0b0001, 0b0001, 0b1010, 0b0000, 0b0100, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // > - 0b0010, 0b0000, 0b0001, 0b0000, 0b1001, 0b0001, 0b0110, 0b0000, 0b0000, 0b0000, // ? - - 0b1110, 0b0000, 0b0001, 0b0000, 0b1101, 0b0000, 0b0101, 0b0001, 0b1111, 0b0000, // @ - 0b1110, 0b0001, 0b0101, 0b0000, 0b0101, 0b0000, 0b1110, 0b0001, 0b0000, 0b0000, // A - 0b1111, 0b0001, 0b0101, 0b0001, 0b1010, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // B - 0b1110, 0b0000, 0b0001, 0b0001, 0b0001, 0b0001, 0b1010, 0b0000, 0b0000, 0b0000, // C - 0b1111, 0b0001, 0b0001, 0b0001, 0b1110, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // D - 0b1111, 0b0001, 0b0101, 0b0001, 0b0001, 0b0001, 0b0000, 0b0000, 0b0000, 0b0000, // E - 0b1111, 0b0001, 0b0101, 0b0000, 0b0101, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // F - 0b1110, 0b0000, 0b0001, 0b0001, 0b1001, 0b0001, 0b1010, 0b0000, 0b0000, 0b0000, // G - - 0b1111, 0b0001, 0b0100, 0b0000, 0b0100, 0b0000, 0b1111, 0b0001, 0b0000, 0b0000, // H - 0b0001, 0b0001, 0b1111, 0b0001, 0b0001, 0b0001, 0b0000, 0b0000, 0b0000, 0b0000, // I - 0b1001, 0b0000, 0b0001, 0b0001, 0b1111, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // J - 0b1111, 0b0001, 0b0100, 0b0000, 0b1010, 0b0000, 0b0001, 0b0001, 0b0000, 0b0000, // K - 0b1111, 0b0001, 0b0000, 0b0001, 0b0000, 0b0001, 0b0000, 0b0000, 0b0000, 0b0000, // L - 0b1111, 0b0001, 0b0010, 0b0000, 0b0100, 0b0000, 0b0010, 0b0000, 0b1111, 0b0001, // M - 0b1111, 0b0001, 0b0010, 0b0000, 0b0100, 0b0000, 0b1000, 0b0000, 0b1111, 0b0001, // N - 0b1110, 0b0000, 0b0001, 0b0001, 0b0001, 0b0001, 0b1110, 0b0000, 0b0000, 0b0000, // O - - 0b1111, 0b0001, 0b0101, 0b0000, 0b0010, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // P - 0b1110, 0b0000, 0b0001, 0b0001, 0b0001, 0b0001, 0b1001, 0b0000, 0b0110, 0b0001, // Q - 0b1111, 0b0001, 0b0101, 0b0000, 0b1010, 0b0001, 0b0000, 0b0000, 0b0000, 0b0000, // R - 0b0010, 0b0001, 0b0101, 0b0001, 0b0101, 0b0001, 0b1001, 0b0000, 0b0000, 0b0000, // S - 0b0001, 0b0000, 0b1111, 0b0001, 0b0001, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // T - 0b1111, 0b0000, 0b0000, 0b0001, 0b0000, 0b0001, 0b1111, 0b0000, 0b0000, 0b0000, // U - 0b0011, 0b0000, 0b1100, 0b0000, 0b0000, 0b0001, 0b1100, 0b0000, 0b0011, 0b0000, // V - 0b1111, 0b0000, 0b0000, 0b0001, 0b1100, 0b0000, 0b0000, 0b0001, 0b1111, 0b0000, // W - - 0b1011, 0b0001, 0b0100, 0b0000, 0b1011, 0b0001, 0b0000, 0b0000, 0b0000, 0b0000, // X - 0b0011, 0b0000, 0b1100, 0b0001, 0b0011, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // Y - 0b1001, 0b0001, 0b0101, 0b0001, 0b0101, 0b0001, 0b0011, 0b0001, 0b0000, 0b0000, // Z - 0b1111, 0b0001, 0b0001, 0b0001, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // [ - 0b0001, 0b0000, 0b0110, 0b0000, 0b1100, 0b0000, 0b0000, 0b0001, 0b0000, 0b0000, // backslash - 0b0001, 0b0001, 0b1111, 0b0001, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // ] - 0b0010, 0b0000, 0b0001, 0b0000, 0b0010, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, // ^ - 0b0000, 0b0001, 0b0000, 0b0001, 0b0000, 0b0001, 0b0000, 0b0000, 0b0000, 0b0000 // _ -}; - -char FONT_5X4_WIDTH [] = { - 1, 1, 3, 5, 4, 5, 4, 1, - 2, 2, 3, 5, 2, 3, 1, 4, - 3, 3, 4, 3, 4, 3, 4, 4, - 4, 4, 1, 2, 3, 3, 3, 4, - 5, 4, 3, 4, 3, 3, 3, 4, - 4, 3, 3, 4, 3, 5, 5, 4, - 3, 5, 3, 4, 3, 4, 5, 5, - 3, 3, 4, 2, 4, 2, 3, 3 -}; - diff --git a/Arduino/HT1632/images.h b/Arduino/HT1632/images.h deleted file mode 100644 index 7b4535b..0000000 --- a/Arduino/HT1632/images.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SIMPLE IMAGES FOR RENDERING TO THE LED SCREEN. - * Gaurav Manek, 2011 - */ - -char IMG_MAIL [] = {0b1111, 0b1111, 0b0011, 0b1000, 0b0101, 0b1000, 0b1001, 0b1000, 0b0001, 0b1001, 0b0001, 0b1010, 0b0001, 0b1010, 0b0001, 0b1001, 0b1001, 0b1000, 0b0101, 0b1000, 0b0011, 0b1000, 0b1111, 0b1111}; -#define IMG_MAIL_WIDTH 12 -#define IMG_MAIL_HEIGHT 8 - -char IMG_FB [] = {0b1100, 0b1111, 0b0010, 0b0000, 0b0001, 0b0000, 0b0001, 0b0000, 0b0001, 0b0010, 0b0001, 0b1111, 0b1001, 0b0010, 0b1001, 0b0000}; -#define IMG_FB_WIDTH 8 -#define IMG_FB_HEIGHT 8 - -char IMG_PHONE [] = {0b0000, 0b0100, 0b0000, 0b1110, 0b1111, 0b0111, 0b0011, 0b0000, 0b0011, 0b0000, 0b0011, 0b0010, 0b0011, 0b0111, 0b1111, 0b0011}; -#define IMG_PHONE_WIDTH 8 -#define IMG_PHONE_HEIGHT 8 - -char IMG_MUSIC [] = {0b0000, 0b0100, 0b0000, 0b1110, 0b1111, 0b0111, 0b0011, 0b0000, 0b0011, 0b0000, 0b0011, 0b0010, 0b0011, 0b0111, 0b1111, 0b0011}; -#define IMG_MUSIC_WIDTH 8 -#define IMG_MUSIC_HEIGHT 8 - -char IMG_MUSICNOTE [] = {0b0000, 0b0010, 0b0000, 0b0111, 0b1111, 0b0011, 0b0010, 0b0000}; -#define IMG_MUSICNOTE_WIDTH 4 -#define IMG_MUSICNOTE_HEIGHT 7 - -char IMG_HEART [] = {0b1110, 0b0000, 0b1111, 0b0001, 0b1111, 0b0011, 0b1111, 0b0111, 0b1110, 0b1111, 0b1111, 0b0111, 0b1111, 0b0011, 0b1111, 0b0001, 0b1110, 0b0000}; -#define IMG_HEART_WIDTH 9 -#define IMG_HEART_HEIGHT 8 - - -char IMG_SPEAKER_A [] = {0b1000, 0b0001, 0b1000, 0b0001, 0b1100, 0b0011, 0b0010, 0b0100, 0b0101, 0b1010, 0b1000, 0b0001}; -char IMG_SPEAKER_B [] = {0b1000, 0b0001, 0b1000, 0b0001, 0b1100, 0b0011, 0b0010, 0b0100, 0b1101, 0b1011, 0b0000, 0b0000}; -#define IMG_SPEAKER_WIDTH 6 -#define IMG_SPEAKER_HEIGHT 8 diff --git a/Arduino/Sample/sketch_HT1632_sample_code/sketch_HT1632_sample_code.pde b/Arduino/Sample/sketch_HT1632_sample_code/sketch_HT1632_sample_code.pde deleted file mode 100644 index c4fd53d..0000000 --- a/Arduino/Sample/sketch_HT1632_sample_code/sketch_HT1632_sample_code.pde +++ /dev/null @@ -1,99 +0,0 @@ -#include -#include -#include - -int i = 0; -int wd; - -void setup () { - Serial.begin(9600); - HT1632.begin(12, 13, 10, 9); - - - /* - // Multiple screen control - HT1632.drawTarget(BUFFER_BOARD(1)); - HT1632.drawText("Hello!", 0, 1, FONT_5X4, FONT_5X4_WIDTH, FONT_5X4_HEIGHT, FONT_5X4_STEP_GLYPH); - HT1632.render(); - - HT1632.drawTarget(BUFFER_SECONDARY); - HT1632.drawText("Foo", 0, 1, FONT_5X4, FONT_5X4_WIDTH, FONT_5X4_HEIGHT, FONT_5X4_STEP_GLYPH); - HT1632.render(); - - HT1632.drawTarget(BUFFER_BOARD(2)); - HT1632.drawText("Bar", 0, 1, FONT_5X4, FONT_5X4_WIDTH, FONT_5X4_HEIGHT, FONT_5X4_STEP_GLYPH); - HT1632.render(); - //*/ - - /* - // Buffer swap transition example. - // Fill board buffer with one image - HT1632.drawTarget(BUFFER_BOARD(1)); - HT1632.drawImage(IMG_SPEAKER_A, IMG_SPEAKER_WIDTH, IMG_SPEAKER_HEIGHT, 0, 0); - HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 8, 0); - HT1632.drawImage(IMG_MUSIC, IMG_MUSIC_WIDTH, IMG_MUSIC_HEIGHT, 13, 1); - HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 23, 0); - HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 28, 1); - - // Fill secondary buffer with another image - HT1632.drawTarget(BUFFER_SECONDARY); - HT1632.drawImage(IMG_SPEAKER_B, IMG_SPEAKER_WIDTH, IMG_SPEAKER_HEIGHT, 0, 0); - HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 8, 1); - HT1632.drawImage(IMG_MUSIC, IMG_MUSIC_WIDTH, IMG_MUSIC_HEIGHT, 13, 0); - HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 23, 1); - HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 28, 0); - - HT1632.drawTarget(BUFFER_BOARD(1)); - - HT1632.render(); - - //HT1632.transition(TRANSITION_FADE, 4000); - //*/ - wd = HT1632.getTextWidth("Hello, how are you?", FONT_5X4_WIDTH, FONT_5X4_HEIGHT); -} - -void loop () { - - // Font rendering example - - // HT1632.transition(TRANSITION_BUFFER_SWAP); - // HT1632.render(); - - //* - HT1632.drawTarget(BUFFER_BOARD(1)); - HT1632.clear(); - HT1632.drawText("Hello, how are you?", 2*OUT_SIZE - i, 2, FONT_5X4, FONT_5X4_WIDTH, FONT_5X4_HEIGHT, FONT_5X4_STEP_GLYPH); - HT1632.render(); - - HT1632.drawTarget(BUFFER_BOARD(2)); - HT1632.clear(); - HT1632.drawText("Hello, how are you?", OUT_SIZE - i, 2, FONT_5X4, FONT_5X4_WIDTH, FONT_5X4_HEIGHT, FONT_5X4_STEP_GLYPH); - HT1632.render(); - - - i = (i+1)%(wd + OUT_SIZE * 2); - //*/ - - /* - // Simple rendering example - HT1632.clear(); - HT1632.drawImage(i%2 ? IMG_SPEAKER_A:IMG_SPEAKER_B, IMG_SPEAKER_WIDTH, IMG_SPEAKER_HEIGHT, 0, 0); - HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 8, (i)%2); - HT1632.drawImage(IMG_MUSIC, IMG_MUSIC_WIDTH, IMG_MUSIC_HEIGHT, 13, (i+1)%2); - HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 23, (i)%2); - HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 28, (i+1)%2); - //HT1632.transition(TRANSITION_BUFFER_SWAP); - Serial.write('\n'); - HT1632.render(); - ++i; - //*/ - - /* - // Example of automatic clipping and data preservation. - HT1632.drawImage(IMG_MAIL, IMG_MAIL_WIDTH, IMG_MAIL_HEIGHT, 12, 0); - HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 12, i); - HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 18, -i); - //*/ - - delay(200); -} diff --git a/HT1632.cpp b/HT1632.cpp new file mode 100644 index 0000000..7483f06 --- /dev/null +++ b/HT1632.cpp @@ -0,0 +1,533 @@ +#include "HT1632.h" + +#if PIXELS_PER_BYTE != 8 + #error "The current drawImage, drawText and getTextWidth implementation requires PIXELS_PER_BYTE == 8" +#endif + +/* + * HIGH LEVEL FUNCTIONS + * Functions that perform advanced tasks using lower-level + * functions go here: + */ + +void HT1632Class::drawText(const char text [], int x, int y, const byte font [], int font_end [], uint8_t font_height, uint8_t gutter_space) { + int curr_x = x; + char i = 0; + char currchar; + + // Check if string is within y-bounds + if(y + font_height < 0 || y >= COM_SIZE) + return; + + while(true){ + if(text[i] == '\0') + return; + + currchar = text[i] - 32; + if(currchar >= 65 && currchar <= 90) // If character is lower-case, automatically make it upper-case + currchar -= 32; // Make this character uppercase. + + if(currchar < 0 || currchar >= 64) { // If out of bounds, skip + ++i; + continue; // Skip this character. + } + + // Check to see if character is not too far right. + if(curr_x >= OUT_SIZE) + break; // Stop rendering - all other characters are no longer within the screen + + // Check to see if character is not too far left. + int chr_width = getCharWidth(font_end, font_height, currchar); + if(curr_x + chr_width + gutter_space >= 0){ + drawImage(font, chr_width, font_height, curr_x, y, getCharOffset(font_end, currchar)); + + // Draw the gutter space + for(char j = 0; j < gutter_space; ++j) + drawImage(font, 1, font_height, curr_x + chr_width + j, y, 0); + } + + curr_x += chr_width + gutter_space; + ++i; + } +} + +// Gives you the width, in columns, of a particular string. +int HT1632Class::getTextWidth(const char text [], int font_end [], uint8_t font_height, uint8_t gutter_space) { + int wd = 0; + char i = 0; + char currchar; + + while(true){ + if (text[i] == '\0') { + return wd - gutter_space; + } + + currchar = text[i] - 32; + if (currchar >= 65 && currchar <= 90) { // If character is lower-case, automatically make it upper-case + currchar -= 32; // Make this character uppercase. + } + + if (currchar < 0 || currchar >= 64) { // If out of bounds, skip + ++i; + continue; // Skip this character. + } + + wd += getCharWidth(font_end, font_height, currchar) + gutter_space; + ++i; + } +} + +int HT1632Class::getCharWidth(int font_end [], uint8_t font_height, uint8_t font_index) { + uint8_t bytesPerColumn = (font_height >> 3) + ((font_height & 0b111)?1:0); // Assumes that PIXELS_PER_BYTE is 8 + + if(font_index == 0) { + return font_end[0]; + } + // The width is the difference between the ending index of + // this and the previous characters: + return (font_end[font_index] - font_end[font_index - 1])/bytesPerColumn; +} + +int HT1632Class::getCharOffset(int font_end [], uint8_t font_index) { + if(font_index == 0) { + return 0; + } + // The offset is in the ending index of the previous character: + return font_end[font_index - 1]; +} + +/* + * MID LEVEL FUNCTIONS + * Functions that handle internal memory, initialize the hardware + * and perform the rendering go here: + */ + +void HT1632Class::begin(uint8_t pinCS1, uint8_t pinWR, uint8_t pinDATA) { + _numActivePins = 1; + _pinCS[0] = pinCS1; + initialize(pinWR, pinDATA); +} +void HT1632Class::begin(uint8_t pinCS1, uint8_t pinCS2, uint8_t pinWR, uint8_t pinDATA) { + _numActivePins = 2; + _pinCS[0] = pinCS1; + _pinCS[1] = pinCS2; + initialize(pinWR, pinDATA); +} +void HT1632Class::begin(uint8_t pinCS1, uint8_t pinCS2, uint8_t pinCS3, uint8_t pinWR, uint8_t pinDATA) { + _numActivePins = 3; + _pinCS[0] = pinCS1; + _pinCS[1] = pinCS2; + _pinCS[2] = pinCS3; + initialize(pinWR, pinDATA); +} +void HT1632Class::begin(uint8_t pinCS1, uint8_t pinCS2, uint8_t pinCS3, uint8_t pinCS4, uint8_t pinWR, uint8_t pinDATA) { + _numActivePins = 4; + _pinCS[0] = pinCS1; + _pinCS[1] = pinCS2; + _pinCS[2] = pinCS3; + _pinCS[3] = pinCS4; + initialize(pinWR, pinDATA); +} + +void HT1632Class::initialize(uint8_t pinWR, uint8_t pinDATA) { + _pinWR = pinWR; + _pinDATA = pinDATA; + + for (uint8_t i = 0; i < _numActivePins; ++i){ + pinMode(_pinCS[i], OUTPUT); + } + + pinMode(_pinWR, OUTPUT); + pinMode(_pinDATA, OUTPUT); + + select(); + + for (uint8_t i = 0; i < NUM_CHANNEL; ++i) { + // Allocate new memory for each channel + mem[i] = (byte *)malloc(ADDR_SPACE_SIZE); + } + // Clear all memory + clear(); + + // Send configuration to chip: + // This configuration is from the HT1632 datasheet, with one modification: + // The RC_MASTER_MODE command is not sent to the master. Since acting as + // the RC Master is the default behaviour, this is not needed. Sending + // this command causes problems in HT1632C (note the C at the end) chips. + + // Send Master commands + + select(0b1111); // Assume that board 1 is the master. + writeData(HT1632_ID_CMD, HT1632_ID_LEN); // Command mode + + writeCommand(HT1632_CMD_SYSDIS); // Turn off system oscillator + + // Custom initialization from each: +#if defined TYPE_3208_MONO + writeCommand(HT1632_CMD_COMS00); +#elif defined TYPE_3216_BICOLOR + writeCommand(HT1632_CMD_COMS00); + writeCommand(HT1632_CMD_RCCLK); // Master Mode, external clock +#elif defined TYPE_2416_MONO + writeCommand(HT1632_CMD_COMS01); +#else + writeCommand(HT1632_CMD_COMS00); +#endif + + writeCommand(HT1632_CMD_SYSEN); //Turn on system + writeCommand(HT1632_CMD_LEDON); // Turn on LED duty cycle generator + writeCommand(HT1632_CMD_PWM(16)); // PWM 16/16 duty + + select(); + + // Clear all screens by default: + for(uint8_t i = 0; i < _numActivePins; ++i) { + renderTarget(i); + render(); + } + // Set renderTarget to the first board. + renderTarget(0); +} + +void HT1632Class::selectChannel(uint8_t channel) { + if(channel < NUM_CHANNEL) { + _tgtChannel = channel; + } +} + +void HT1632Class::renderTarget(uint8_t target) { + if(target < _numActivePins) { + _tgtRender = target; + } +} + +void HT1632Class::drawImage(const byte * img, uint8_t width, uint8_t height, int8_t x, int8_t y, int img_offset) { + // Assuming that we are using 8 PIXELS_PER_BYTE, this does the equivalent of Math.ceil(height/PIXELS_PER_BYTE): + uint8_t bytesPerColumn = (height >> 3) + ((height & 0b111)?1:0); + + // Sanity checks + if(y + height < 0 || x + width < 0 || y > COM_SIZE || x > OUT_SIZE) + return; + // After looking at the rest of this function, you may need one. + + // Copying Engine. + + // Current off + int8_t dst_x = x; + int8_t src_x = 0; + // Repeat until each column has been copied. + while (src_x < width) { + if(dst_x < 0) { + // Skip this column if it is too far to the left. + src_x++; + dst_x++; + continue; + } else if (dst_x >= OUT_SIZE) { + // End the copy if it is too far to the right. + break; + } + + int8_t src_y = 0; + int8_t dst_y = y; + while (src_y < height) { + if (dst_y < 0) { + // Skip pixels if the starting point to too far up. + src_y -= dst_y; + dst_y = 0; + continue; + } else if (dst_y >= COM_SIZE) { + // End copying this column if it is too far down + break; + } + + // The use of bitmasking here assumes that PIXELS_PER_BYTE == 8 + + // Find out how many we can copy in the next step: + // as a minimum of the number of bits in the current byte of source + // and destination. + uint8_t copyInNextStep = 8 - max((src_y & 0b111), (dst_y & 0b111)); + + // Limit this by the height of the image: + copyInNextStep = min(copyInNextStep, (height - src_y)); + + // Prepare the bitmask with the number of bits that need to be copied. + uint8_t dst_copyMask = (0b1 << copyInNextStep) - 1; + + // Shift the bitmasks to the correct position. + dst_copyMask <<= (8 - (dst_y & 0b111) - copyInNextStep); + + // Shift the data to the bits of highest significance + uint8_t copyData = pgm_read_byte(&img[img_offset + (bytesPerColumn * src_x) + (src_y >> 3)]) << (src_y & 0b111); + // Shift data to match the destination place value. + copyData >>= (dst_y & 0b111); + + // Perform the copy + mem[_tgtChannel][GET_ADDR_FROM_X_Y(dst_x, dst_y)] = // Put in destination + (mem[_tgtChannel][GET_ADDR_FROM_X_Y(dst_x, dst_y)] & ~dst_copyMask) | // All bits not in the mask from destination + (copyData & dst_copyMask); // All bits in the mask from source + + src_y += copyInNextStep; + dst_y += copyInNextStep; + } + + src_x++; + dst_x++; + } +} + +void HT1632Class::setPixel(uint8_t x, uint8_t y) { + if( x < 0 || x > OUT_SIZE || y < 0 || y > COM_SIZE ) + return; + mem[_tgtChannel][GET_ADDR_FROM_X_Y(x, y)] |= (0b1 << PIXELS_PER_BYTE-1) >> (y % PIXELS_PER_BYTE); +} +void HT1632Class::clearPixel(uint8_t x, uint8_t y) { + if( x < 0 || x > OUT_SIZE || y < 0 || y > COM_SIZE ) + return; + mem[_tgtChannel][GET_ADDR_FROM_X_Y(x, y)] &= ~((0b1 << PIXELS_PER_BYTE-1) >> (y % PIXELS_PER_BYTE)); +} +uint8_t HT1632Class::getPixel(uint8_t x, uint8_t y) { + if( x < 0 || x > OUT_SIZE || y < 0 || y > COM_SIZE ) + return 0; + return mem[_tgtChannel][GET_ADDR_FROM_X_Y(x, y)] & (0b1 << PIXELS_PER_BYTE-1) >> (y % PIXELS_PER_BYTE); +} + +void HT1632Class::setPixel(uint8_t x, uint8_t y, uint8_t channel) { + if( x < 0 || x > OUT_SIZE || y < 0 || y > COM_SIZE ) + return; + mem[channel][GET_ADDR_FROM_X_Y(x, y)] |= GET_BIT_FROM_Y(y); +} +void HT1632Class::clearPixel(uint8_t x, uint8_t y, uint8_t channel) { + if( x < 0 || x > OUT_SIZE || y < 0 || y > COM_SIZE ) + return; + mem[channel][GET_ADDR_FROM_X_Y(x, y)] &= ~(GET_BIT_FROM_Y(y)); +} +uint8_t HT1632Class::getPixel(uint8_t x, uint8_t y, uint8_t channel) { + if( x < 0 || x > OUT_SIZE || y < 0 || y > COM_SIZE ) + return 0; + return mem[channel][GET_ADDR_FROM_X_Y(x, y)] & GET_BIT_FROM_Y(y); +} + +void HT1632Class::fill() { + for(uint8_t i = 0; i < ADDR_SPACE_SIZE; ++i) { + mem[_tgtChannel][i] = 0xFF; + } +} +void HT1632Class::fillAll() { + for(uint8_t c = 0; c < NUM_CHANNEL; ++c) { + for(uint8_t i = 0; i < ADDR_SPACE_SIZE; ++i) { + mem[c][i] = 0xFF; // Needs to be redrawn + } + } +} + +void HT1632Class::clear(){ + for(uint8_t c = 0; c < NUM_CHANNEL; ++c) { + for(uint8_t i = 0; i < ADDR_SPACE_SIZE; ++i) { + mem[c][i] = 0x00; // Needs to be redrawn + } + } +} + +#if defined TYPE_3216_BICOLOR +// Draw the contents of mem +void HT1632Class::render() { + if(_tgtRender >= _numActivePins) { + return; + } + + // Write chip-by-chip: + uint8_t _pinForCS = _pinCS[_tgtRender]; + + for (uint8_t nChip = 0; nChip < NUM_ACTIVE_CHIPS; ++nChip) { + // Select a single sub-chip: + digitalWrite(_pinForCS, HIGH); + for(uint8_t tmp = 0; tmp < NUM_ACTIVE_CHIPS; tmp++){ + if (tmp == nChip) { + digitalWrite(_pinForCS, LOW); + pulseCLK(); + digitalWrite(_pinForCS, HIGH); + } else { + pulseCLK(); + } + } + + // Output data! + writeData(HT1632_ID_WR, HT1632_ID_LEN); + writeData(0, HT1632_ADDR_LEN); // Selecting the memory address + + // Write the channels in order + for(uint8_t c = 0; c < NUM_CHANNEL; ++c) { + //for(uint8_t i = (nChip & 0b1)?0:(ADDR_SPACE_SIZE >> 1); i < (nChip & 0b1)?(ADDR_SPACE_SIZE >> 1):ADDR_SPACE_SIZE; ++i) { + uint8_t i, iMax; + + if(nChip & 0b1) { // If we're writing to the chips on the left + i = 0; // Start from zero + iMax = ADDR_SPACE_SIZE/2; // Stop at the halfway point. + } else { // If we're writing to the chips on the right + i = ADDR_SPACE_SIZE/2; // Start from the halfway point. + iMax = ADDR_SPACE_SIZE; // Stop at the end of the buffer. + } + + // If we are not (top-row chip) + if(!(nChip & 0b10)) { + ++i; // Write only odd-numbered bytes. + } + + for(; i < iMax; i+=2) { // Write every other byte. + // Write the higher bits before the the lower bits. + writeData(mem[c][i] >> HT1632_WORD_LEN, HT1632_WORD_LEN); + writeData(mem[c][i], HT1632_WORD_LEN); + } + } + } +} +#elif defined TYPE_3208_MONO +// Draw the contents of mem +void HT1632Class::render() { + if(_tgtRender >= _numActivePins) { + return; + } + + select(0b0001 << _tgtRender); // Selecting the chip + + writeData(HT1632_ID_WR, HT1632_ID_LEN); + writeData(0, HT1632_ADDR_LEN); // Selecting the memory address + + // Write the channels in order + for(uint8_t c = 0; c < NUM_CHANNEL; ++c) { + for(uint8_t i = 0; i < ADDR_SPACE_SIZE; ++i) { + // Write the higher bits before the the lower bits. + writeData(mem[c][i] >> HT1632_WORD_LEN, HT1632_WORD_LEN); // Write the data in reverse. + writeData(mem[c][i], HT1632_WORD_LEN); // Write the data in reverse. + } + } + + select(); // Close the stream at the end +} +#elif defined TYPE_2416_MONO + // Draw the contents of mem + void HT1632Class::render() { + if (_tgtRender >= _numActivePins) { + return; + } + + select(0b0001 << _tgtRender); // Selecting the chip + + writeData(HT1632_ID_WR, HT1632_ID_LEN); + writeData(0, HT1632_ADDR_LEN); // Selecting the memory address + + // Write the channels in order + for (uint8_t c = 0; c < NUM_CHANNEL; ++c) { + for (uint8_t i = 0; i < ADDR_SPACE_SIZE; ++i) { + // Write the higher bits before the the lower bits. + writeData(mem[c][i] >> HT1632_WORD_LEN, HT1632_WORD_LEN); // Write the data in reverse. + writeData(mem[c][i], HT1632_WORD_LEN); // Write the data in reverse. + } + } + + select(); // Close the stream at the end + } +#endif + +// Set the brightness to an integer level between 1 and 16 (inclusive). +// Uses the PWM feature to set the brightness. +void HT1632Class::setBrightness(char brightness, char selectionmask) { + if(selectionmask == 0b00010000) { + if(_tgtRender < _numActivePins) { + selectionmask = 0b0001 << _tgtRender; + } else { + return; + } + } + + select(selectionmask); + writeData(HT1632_ID_CMD, HT1632_ID_LEN); // Command mode + writeCommand(HT1632_CMD_PWM(brightness)); // Set brightness + select(); +} + + +/* + * LOWER LEVEL FUNCTIONS + * Functions that directly talk to hardware go here: + */ + +void HT1632Class::writeCommand(char data) { + writeData(data, HT1632_CMD_LEN); + writeSingleBit(); +} +// Integer write to display. Used to write commands/addresses. +// PRECONDITION: WR is LOW +void HT1632Class::writeData(byte data, uint8_t len) { + for(int j = len - 1, t = 1 << (len - 1); j >= 0; --j, t >>= 1){ + // Set the DATA pin to the correct state + digitalWrite(_pinDATA, ((data & t) == 0)?LOW:HIGH); + NOP(); // Delay + // Raise the WR momentarily to allow the device to capture the data + digitalWrite(_pinWR, HIGH); + NOP(); // Delay + // Lower it again, in preparation for the next cycle. + digitalWrite(_pinWR, LOW); + } +} + +// Write single bit to display, used as padding between commands. +// PRECONDITION: WR is LOW +void HT1632Class::writeSingleBit() { + // Set the DATA pin to the correct state + digitalWrite(_pinDATA, LOW); + NOP(); // Delay + // Raise the WR momentarily to allow the device to capture the data + digitalWrite(_pinWR, HIGH); + NOP(); // Delay + // Lower it again, in preparation for the next cycle. + digitalWrite(_pinWR, LOW); +} + +void HT1632Class::setCLK(uint8_t pinCLK) { + _pinCLK = pinCLK; + pinMode(_pinCLK, OUTPUT); + digitalWrite(_pinCLK, LOW); +} + +inline void HT1632Class::pulseCLK() { + digitalWrite(_pinCLK, HIGH); + NOP(); + digitalWrite(_pinCLK, LOW); +} + +#if defined TYPE_3216_BICOLOR +// This is used to send initialization commands, and so selects all chips +// in the selected board. +void HT1632Class::select(uint8_t mask) { + for(uint8_t i=0, t=1; i<_numActivePins; ++i, t <<= 1){ + digitalWrite(_pinCS[i], (t & mask)?LOW:HIGH); + } + for (uint8_t tmp = 0; tmp < NUM_ACTIVE_CHIPS; tmp++) { + pulseCLK(); + } +} +#elif defined TYPE_3208_MONO +// Choose a chip. This function sets the correct CS line to LOW, and the rest to HIGH +// Call the function with no arguments to deselect all chips. +// Call the function with a bitmask (0b4321) to select specific chips. 0b1111 selects all. +void HT1632Class::select(uint8_t mask) { + for(uint8_t i=0, t=1; i<_numActivePins; ++i, t <<= 1){ + digitalWrite(_pinCS[i], (t & mask)?LOW:HIGH); + } +} +#elif defined TYPE_2416_MONO +// Choose a chip. This function sets the correct CS line to LOW, and the rest to HIGH +// Call the function with no arguments to deselect all chips. +// Call the function with a bitmask (0b4321) to select specific chips. 0b1111 selects all. +void HT1632Class::select(uint8_t mask) { + for (uint8_t i = 0, t = 1; i<_numActivePins; ++i, t <<= 1) { + digitalWrite(_pinCS[i], (t & mask) ? LOW : HIGH); + } +} +#endif +void HT1632Class::select() { + select(0); +} + +HT1632Class HT1632; diff --git a/HT1632.h b/HT1632.h new file mode 100644 index 0000000..f43c8aa --- /dev/null +++ b/HT1632.h @@ -0,0 +1,192 @@ +/* + HT1632.h - Library for communicating with the popular HT1632/HT1632C + LED controllers. This library provides higher-level access (including + text drawing) for these chips. Currently, the library supports writing + to a single chip at a time, and has been tested with two + Sure Electronics 3208 5mm red board. + + Created by Gaurav Manek, April 8, 2011. + Released into the public domain. +*/ +#ifndef HT1632_h +#define HT1632_h + +#include +#ifdef __AVR__ + #include +#elif defined(ESP8266) + #include +#else + #define PROGMEM +#endif + +// Custom typedefs +typedef unsigned char uint8_t; +typedef unsigned char byte; +// typedef char int8_t; + + +/* + * USER OPTIONS + * Change these options + */ + +// Uncomment the line that matches the board you have, or edit the +// settings in the else block: + +// SureElectronics 32X16 Bicolor LED Dot Matrix Unit Board +#define TYPE_3216_BICOLOR 1 + +// SureElectronics 32X08 Monochrome LED Dot Matrix Unit Board +// #define TYPE_3208_MONO 1 + +// SureElectronics 24x16 Monochrome LED Dot Matrix Unit Board +#define TYPE_2416_MONO 1 + +// SureElectronics 16X08 Bicolor (emulation) +// #define TYPE_1608_DEBUG 1 + +#if defined TYPE_3216_BICOLOR + #define COM_SIZE 16 + #define OUT_SIZE 32 + #define NUM_CHANNEL 2 + #define USE_NMOS 1 + // Number of chips in a single Bicolor board: + #define NUM_ACTIVE_CHIPS 4 +#elif defined TYPE_3208_MONO + #define COM_SIZE 8 + #define OUT_SIZE 32 + #define NUM_CHANNEL 1 + #define USE_NMOS 1 +#elif defined TYPE_2416_MONO + #define COM_SIZE 16 + #define OUT_SIZE 24 + #define NUM_CHANNEL 1 + #define USE_NMOS 1 +#elif defined TYPE_1608_DEBUG + #define COM_SIZE 8 + #define OUT_SIZE 16 + #define NUM_CHANNEL 2 + #define USE_NMOS 1 +#else + // SET YOUR CUSTOM VALUES HERE, AND COMMENT THE NEXT LINE + #error "Pick a board type!" + + // Size of COM and OUT in bits: + #define COM_SIZE 8 + #define OUT_SIZE 32 + // COM_SIZE MUST be either 8 or 16. + + // Number of color channels. The default is a single color channel. + #define NUM_CHANNEL 1 + + // Use N-MOS (if 1) or P-MOS (if 0): + #define USE_NMOS 1 + // There are known issues with this. If the default doesn't work, + // try changing the value. +#endif + +/* + * END USER OPTIONS + * Don't edit anything below unless you know what you are doing! + */ + + + // Pixels in a single byte of the internal image representation: +#define PIXELS_PER_BYTE 8 + +// Address space size (number of 4-bit words in HT1632 memory) +// Exactly equal to the number of 4-bit address spaces available. +#define ADDR_SPACE_SIZE (COM_SIZE * OUT_SIZE / PIXELS_PER_BYTE) +#define GET_ADDR_FROM_X_Y(_x,_y) ((_x)*((COM_SIZE)/(PIXELS_PER_BYTE))+(_y)/(PIXELS_PER_BYTE)) +#define GET_BIT_FROM_Y(_y) ( (0b1 << PIXELS_PER_BYTE-1) >> (y % PIXELS_PER_BYTE) ) + +// NO-OP Definition +#define NOP(); __asm__("nop\n\t"); +// The HT1632 requires at least 50 ns between the change in data and the rising +// edge of the WR signal. On a 16MHz processor, this provides 62.5ns per NOP. + +// Standard command list. +// This list is modified from original code by Bill Westfield + +#define HT1632_ID_CMD 0b100 /* ID = 100 - Commands */ +#define HT1632_ID_RD 0b110 /* ID = 110 - Read RAM */ +#define HT1632_ID_WR 0b101 /* ID = 101 - Write RAM */ +#define HT1632_ID_LEN 3 /* IDs are 3 bits */ + +#define HT1632_CMD_SYSDIS 0x00 /* CMD= 0000-0000-x Turn off oscil */ +#define HT1632_CMD_SYSEN 0x01 /* CMD= 0000-0001-x Enable system oscil */ +#define HT1632_CMD_LEDOFF 0x02 /* CMD= 0000-0010-x LED duty cycle gen off */ +#define HT1632_CMD_LEDON 0x03 /* CMD= 0000-0011-x LEDs ON */ +#define HT1632_CMD_BLOFF 0x08 /* CMD= 0000-1000-x Blink ON */ +#define HT1632_CMD_BLON 0x09 /* CMD= 0000-1001-x Blink Off */ +#define HT1632_CMD_SLVMD 0x10 /* CMD= 0001-00xx-x Slave Mode */ +#define HT1632_CMD_MSTMD 0x14 /* CMD= 0001-01xx-x Master Mode, on-chip clock */ +#define HT1632_CMD_RCCLK 0x18 /* CMD= 0001-10xx-x Master Mode, external clock */ +#define HT1632_CMD_EXTCLK 0x1C /* CMD= 0001-11xx-x Use external clock */ +#define HT1632_CMD_COMS00 0x20 /* CMD= 0010-ABxx-x commons options */ +#define HT1632_CMD_COMS01 0x24 /* CMD= 0010-ABxx-x commons options */ +#define HT1632_CMD_COMS10 0x28 /* CMD= 0010-ABxx-x commons options */ +#define HT1632_CMD_COMS11 0x2C /* CMD= 0010-ABxx-x commons options */ +#define HT1632_CMD_PWM_T 0xA0 /* CMD= 101x-PPPP-x PWM duty cycle - template*/ +#define HT1632_CMD_PWM(lvl) (HT1632_CMD_PWM_T | (lvl-1)) + /* Produces the correct command from the given value of lvl. lvl = [0..15] */ +#define HT1632_CMD_LEN 8 /* Commands are 8 bits long, excluding the trailing bit */ +#define HT1632_ADDR_LEN 7 /* Addresses are 7 bits long */ +#define HT1632_WORD_LEN 4 /* Words are 4 bits long */ + +class HT1632Class +{ + private: + uint8_t _pinCS [4]; + uint8_t _numActivePins; + uint8_t _pinWR; + uint8_t _pinDATA; + uint8_t _pinCLK; + uint8_t _currSelectionMask; + uint8_t _tgtRender; + uint8_t _tgtChannel; + byte * mem [5]; + void writeCommand(char); + void writeData(byte, uint8_t); + void writeDataRev(byte, uint8_t); + void writeSingleBit(); + void initialize(uint8_t, uint8_t); + void select(); + void select(uint8_t mask); + int getCharWidth(int font_end [], uint8_t font_height, uint8_t font_index); + int getCharOffset(int font_end [], uint8_t font_index); + inline void pulseCLK(); + + public: + void begin(uint8_t pinCS1, uint8_t pinWR, uint8_t pinDATA); + void begin(uint8_t pinCS1, uint8_t pinCS2, uint8_t pinWR, uint8_t pinDATA); + void begin(uint8_t pinCS1, uint8_t pinCS2, uint8_t pinCS3, uint8_t pinWR, uint8_t pinDATA); + void begin(uint8_t pinCS1, uint8_t pinCS2, uint8_t pinCS3, uint8_t pinCS4, uint8_t pinWR, uint8_t pinDATA); + void setCLK(uint8_t pinCLK); + void sendCommand(uint8_t command); + void renderTarget(uint8_t targetScreen); + void selectChannel(uint8_t channel); + void render(); + void transition(uint8_t mode, int time = 1000); // Time is in milliseconds. + void clear(); + void drawImage(const byte img [], uint8_t width, uint8_t height, int8_t x, int8_t y, int offset = 0); + void drawText(const char text [], int x, int y, const byte font [], int font_end [], uint8_t font_height, uint8_t gutter_space = 1); + int getTextWidth(const char text [], int font_end [], uint8_t font_height, uint8_t gutter_space = 1); + void setBrightness(char brightness, char selectionmask = 0b00010000); + + void setPixel(uint8_t x, uint8_t y); + void clearPixel(uint8_t x, uint8_t y); + uint8_t getPixel(uint8_t x, uint8_t y); + void setPixel(uint8_t x, uint8_t y, uint8_t channel); + void clearPixel(uint8_t x, uint8_t y, uint8_t channel); + uint8_t getPixel(uint8_t x, uint8_t y, uint8_t channel); + void fill(); + void fillAll(); +}; + +extern HT1632Class HT1632; + +#else +//#error "HT1632.h" already defined! +#endif diff --git a/README.markdown b/README.markdown deleted file mode 100644 index 33e85c6..0000000 --- a/README.markdown +++ /dev/null @@ -1,209 +0,0 @@ -HT1632 for Arduino v1.0 -======================= - -This is a powerful library that allows an Arduino to interface with the popular __Holtek HT1632C__ LED driver. It allows programmers to directly perform advanced drawing of images and text with minimal code, using a similar "state machine" paradigm to OpenGL. - -Do note that the (now depreciated) __Holtek HT1632__ LED driver is *theoretically* compatible with this library, but requires slightly different initialization. - -Quick Start -=========== - -Code ----- - -Here's some sample code to draw a blinking heart on the middle of a single screen. - -```c++ -#include -#include - -void setup () { - HT1632.begin(pinCS1, pinWR, pinDATA); - // Where pinCS1, pinWR and pinDATA are the numbers of the output pins - // that are connected to the appropriate pins on the HT1632. -} - -void loop () { - HT1632.drawImage(IMG_HEART, IMG_HEART_WIDTH, IMG_HEART_HEIGHT, (OUT_SIZE - IMG_HEART_WIDTH)/2, 0); - // The definitions for IMG_HEART and its width and height are available in images.h. - // This step only performs the drawing in internal memory. - HT1632.render(); - // This updates the display on the screen. - - delay(1000); - - HT1632.clear(); - // This zeroes out the internal memory. - HT1632.render(); - // This updates the screen display. - - delay(1000); -} -``` - -Before running the code, go to HT1632.h and change the following definitions, if needed. This needs to be done only __once__. - -```c++ -// Size of COM and OUT in bits: -#define COM_SIZE 8 -#define OUT_SIZE 32 -// COM_SIZE MUST be either 8 or 16. - -// Use N-MOS (if 1) or P-MOS (if 0): -#define USE_NMOS 1 -``` - -The defaults shown here (and in the code) are suitable for the SureElectronics 3208 series display boards. - -Explanation ------------ - -HT1632 is always initialized by calling the begin function, like so: - -```c++ -HT1632.begin(pinCS1 [, pinCS2 [, pinCS3 [, pinCS4]]], pinWR, pinDATA); -``` - -All pins are set to `OUTPUT` and memory is allocated and cleared automatically. The square brackets denote an optional argument. - -The HT1632 class stores an internal copy of the state of each screen used. __All__ drawing and writing functions operate on this internal memory, allowing you to perform complicated compositing. Once the internal memory is ready for display, the `render()` function will efficiently send the updated image to the screen. - -Utilities -========== - -Image Drawing -------------- - -This project includes an image-drawing utility, written in HTML5 (using the canvas tag) and JavaScript. It has been tested on Firefox 3.6.* on OSX. - -The editor provides the data in a ready-to-paste format that allows for quick drawing of fonts and/or images. It can load previously drawn images as well. - -It's use should be self-evident. You can find it in "Utilities/Image drawing/". - -Advanced Use -============ - -Brightness Control ------------------- - -The HT1632C comes with a 15-level PWM control option. You can control the brightness (from 1/16 to 16/16 of the duty cycle) of the current drawing target using the `setBrightness(level)` function, where level is a number from 1 to 16. -__level must never be zero!__ - -If you want to simultaneously set multiple boards to the same brightness level, you can pass a bitmask as an optional second argument, like so: `setBrightness(8, 0b0101)`. The rightmost bit is the first screen, while the fourth bit from the right corresponds to the fourth screen. In the above example, the first and third screen are set to half brightness, while the second and third remain unchanged. - -Multiple HT1632s ----------------- - -This library supports up to 4 chips at a time (though technically more can be run concurrently). To take advantage of this, specify multiple CS pins in the initialization. - -All drawing occurs on the first display by default. The `drawTarget(BUFFER_BOARD(x))` function allows you to choose to write output to the board selected by `pinCSx`. The example below shows how scrolling text can be implemented using this: - -```c++ -#include -#include - -int wd; -int i = 0; - -void setup () { - HT1632.begin(pinCS1, pinCS2, pinWR, pinDATA); - wd = HT1632.getTextWidth("Hello, how are you?", FONT_5X4_WIDTH, FONT_5X4_HEIGHT); -} - -void loop () { - // Select board 1 as the target of subsequent drawing/rendering operations. - HT1632.drawTarget(BUFFER_BOARD(1)); - HT1632.clear(); - - HT1632.drawText("Hello, how are you?", 2*OUT_SIZE - i, 2, - FONT_5X4, FONT_5X4_WIDTH, FONT_5X4_HEIGHT, FONT_5X4_STEP_GLYPH); - - HT1632.render(); // Board 1's contents is updated. - - // Select board 2 as the target of subsequent drawing/rendering operations. - HT1632.drawTarget(BUFFER_BOARD(2)); - HT1632.clear(); - - HT1632.drawText("Hello, how are you?", OUT_SIZE - i, 2, - FONT_5X4, FONT_5X4_WIDTH, FONT_5X4_HEIGHT, FONT_5X4_STEP_GLYPH); - - HT1632.render(); // Board 2's contents is updated. - - i = (i+1)%(wd + OUT_SIZE * 2); // Make it repeating. -} -``` - -Secondary Buffer ----------------- - -In addition to one buffer for each board, one additional buffer (the secondary buffer) is provided. It acts like a drawing target in every way, except that it cannot be rendered. `drawTarget(BUFFER_SECONDARY)` function call allows you to select this buffer. - -*This buffer is currently of limited use. Future expansions plan to use this for transitions.* - -Here's an example showing this buffer being used to render a two-frame animation much more efficiently than redrawing each frame from scratch: - - -```c++ -#include -#include - -void setup () { - HT1632.begin(pinCS1, pinWR, pinDATA); - - // Draw one image on the board buffer. - HT1632.drawTarget(BUFFER_BOARD(1)); // This line is unnecessary, this is the default draw target. - HT1632.drawImage(IMG_SPEAKER_A, IMG_SPEAKER_WIDTH, IMG_SPEAKER_HEIGHT, 0, 0); - HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 8, 0); - HT1632.drawImage(IMG_MUSIC, IMG_MUSIC_WIDTH, IMG_MUSIC_HEIGHT, 13, 1); - HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 23, 0); - HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 28, 1); - - // Draw another image on the secondary buffer. - HT1632.drawTarget(BUFFER_SECONDARY); - HT1632.drawImage(IMG_SPEAKER_B, IMG_SPEAKER_WIDTH, IMG_SPEAKER_HEIGHT, 0, 0); - HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 8, 1); - HT1632.drawImage(IMG_MUSIC, IMG_MUSIC_WIDTH, IMG_MUSIC_HEIGHT, 13, 0); - HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 23, 1); - HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 28, 0); - - HT1632.drawTarget(BUFFER_BOARD(1)); - HT1632.render(); // Render the initial image. -} - -void loop () { - delay(500); - - HT1632.transition(TRANSITION_BUFFER_SWAP); - HT1632.render(); -} -``` -Notice that all the drawing is done in the setup() function? The loop function just shuffles the data around in memory. - -Note: Only three transitions are currently available. - - - - - - - - - - -
`TRANSITION_BUFFER_SWAP`Swap the current buffer and the transition buffer. This is the only transition that preserves the contents of the current buffer.
`TRANSITION_NONE`Simply copy the buffer.
`TRANSITION_FADE`Uses the PWM feature to fade through black. Does not preserve current brightness level.
- -Bugs & Features -=============== - -Known Issues ------------- - -1. Initialization doesn't automatically assign a single HT1632C as the RC Master - some unknown bug prevents this from working. As a result, multiple HT1632Cs only need the power and data pins connected, leaving the OSC and SYNC pins disconnected. - -Future Plans ------------- - -1. Support for direct pixel access and primitive drawing. -2. Support for advanced transitions (moving entire screen contents around with a single command). -3. "Export" feature that transmits the screen contents over Serial, so that animations can be captured in realtime. - diff --git a/README.md b/README.md new file mode 100644 index 0000000..ca4fd65 --- /dev/null +++ b/README.md @@ -0,0 +1,136 @@ +HT1632 for Arduino v2.0 +======================= + +__NOTE:__ This new version of the software changes the underlying data format - upgrading is easy and largely automated. See [upgrade instructions](UPGRADE.md). + +This is a powerful library that allows an Arduino to interface with the popular __Holtek HT1632C__ LED driver. It allows programmers to directly perform advanced drawing of images and text with minimal code. + + +Quick Start +=========== + +Code +---- + +Here's some sample code to draw a blinking heart on the middle of a single screen: + +```c +#include // Include this before or any font. +#include + +void setup () { + HT1632.begin(pinCS1, pinWR, pinDATA); + // Where pinCS1, pinWR and pinDATA are the numbers of the output pins + // that are connected to the appropriate pins on the HT1632. +} + +void loop () { + // The definitions for IMG_HEART and its width and height are available in images.h. + // This step only performs the drawing in internal memory. + HT1632.drawImage(IMG_HEART, IMG_HEART_WIDTH, IMG_HEART_HEIGHT, (OUT_SIZE - IMG_HEART_WIDTH)/2, 0); + + HT1632.render(); // This updates the display on the screen. + + delay(1000); + + HT1632.clear(); // This zeroes out the internal memory. + + HT1632.render(); // This updates the screen display. + + delay(1000); +} +``` + +Before running the code, go to HT1632.h and check the `USER OPTIONS` section and follow the instructions to specify the type of board you are using. + + +Explanation +----------- + +HT1632 is always initialized by calling the begin function, like so: + +```c++ +HT1632.begin(pinCS1 [, pinCS2 [, pinCS3 [, pinCS4]]], pinWR, pinDATA); +``` + +All pins are set to `OUTPUT` and memory is allocated and cleared automatically. The square brackets denote an optional argument. + +The HT1632 class stores an internal copy of the state of each screen used. __All__ drawing and writing functions operate on this internal memory, allowing you to perform complicated compositing. Once the internal memory is ready for display, the `render()` function will efficiently send the updated image to the screen. + +Utilities +========== + +Image Drawing +------------- + +This project includes an image-drawing utility, written in HTML5 (using the canvas tag) and JavaScript. It has been tested on Firefox 3.6.* on OSX. + +The editor provides the data in a ready-to-paste format that allows for quick drawing of fonts and/or images. It can load previously drawn images as well (even those from v1 -- see [upgrading instructions](UPGRADE.md) for more details). + +It's use should be self-evident. You can find it in `Utilities/image_drawing.html`. + +Font Creation +------------- + +Fonts are defined as a series of images of equal height and variable width. (__Note:__ Currently, fonts are only tested to at most one byte per column.) The bytes making up each character, from ASCII char 32 (space) onwards, are appended together without any byte alignment. + +An array, `FONT_8X4_END`, encodes information necessary to extract the width and the offset of the character from the font array. The element at position `i` encodes the first index of character `i + 1`. + +__Generating FONT_NAME_NUM__ + +This array can be generated automatically using `Utilities/font_end_generate.html`. Make sure your font has one character per line (with no trailing newline) and paste it into the tool. + +If you want to skip character `i`, simply set `FONT_NAME_NUM[i] = FONT_NAME_NUM[i - 1]` or `FONT_NAME_NUM[0] = 0` if `i == 0`. Using the `font_end_generate.html` tool, just leave a blank line. + + +Advanced Use +============ + +There are a few examples in `Arduino/HT1632/examples/`. + +Bicolor Displays +---------------- + +This library natively supports Bicolor displays, using the `selectChannel(n)` function to switch to color channel `n` before rendering images. Calls to `clear()` and `render()` automatically operate on all channels. + +An example is available in `HT1632/examples/HT1632_Heart_Bicolor/`. + +__NOTE:__ You need to call `HT1632.setCLK(PIN_NUMBER_CLK);` before calling `begin()`, where `PIN_NUMBER_CLK` is the Arduino pin connected to the `CLK` of your Bicolor board. Refer to the example. + +__NOTE:__ Make sure you have set the board type in `HT1632.h`. If you specify a wrong `NUM_CHANNEL` value, it won't work properly. + +Brightness Control +------------------ + +The HT1632C comes with a 15-level PWM control option. You can control the brightness (from 1/16 to 16/16 of the duty cycle) of the current drawing target using the `setBrightness(level)` function, where level is a number from 1 to 16. __level must never be zero!__ + +If you want to simultaneously set multiple boards to the same brightness level, you can pass a bitmask as an optional second argument, like so: `setBrightness(8, 0b0101)`. The rightmost bit is the first screen, while the fourth bit from the right corresponds to the fourth screen. In the above example, the first and third screen are set to half brightness, while the second and third remain unchanged. + +Multiple HT1632s +---------------- + +This library supports up to 4 chips at a time (though technically more can be run concurrently). To take advantage of this, specify multiple CS pins in the initialization. + +All rendering occurs on the first display by default. A scrolling text example is available in `HT1632/examples/HT1632_Text_8X4_Multidisplay/`. + +Do note that all drawing happens to a single buffer. You need to `clear()` the contents of the buffer if drawing different graphics to different screens. To draw the same image to multiple screens, call `renderTarget()` and `render()` once per target. + +Multiple HT1632s, each with multiple color channels, are supported natively. + + +Bugs & Features +=============== + +Known Issues +------------ + +1. Initialization doesn't automatically assign a single HT1632C as the RC Master - some unknown bug prevents this from working. As a result, multiple HT1632Cs only need the power and data pins connected, leaving the OSC and SYNC pins disconnected. + +2. A single Arduino cannot support both a Mono-color and a Bi-color display. + +Future Plans +------------ + +1. Support for direct pixel access and primitive drawing. +2. Test support for fonts taller than 8px. +3. Allow `FONT_8X4_END` arrays to be either 2-byte `int`s or 1-byte `uint8_t`s diff --git a/UPGRADE.md b/UPGRADE.md new file mode 100644 index 0000000..d778ea0 --- /dev/null +++ b/UPGRADE.md @@ -0,0 +1,60 @@ +Upgrade Instruction from v1.0 +============================= + +Why bother? +----------- + +Because: + - Images, fonts and buffers are smaller, with a minimum 50% reduction in size. + - Drawing is faster, the inner loop of the copying engine has been rewritten. + - Bugfixes, notably the ability to copy images of any arbitrary size. + - Compiled code size. + +For example, the 8x4 font has been compressed from 640 bytes to 237 bytes! + + +How to upgrade +-------------- + +__Structure__ + +A single buffer is used for all compositing operations. The following functions, macros and constants have been removed: + +```c +void HT1632.transition(uint8_t mode, int time = 1000); // Removed + +void HT1632.drawTarget(uint8_t targetBuffer); // Replaced by: +void HT1632.renderTarget(uint8_t targetBuffer); + +BUFFER_BOARD(n) // Just use: +(n - 1) // Board number of pin to use. + +SECONDARY_BUFFER // Removed +``` + +New mechanisms for working with color channels have been added, and are documented in [the README](README.md) + +__Code__ + +1. You need to include `HT1632.h` before `images.h` or any font file. +2. The newer functions require the images/fonts to be updated. +3. All calls to `HT1632.drawText` need to have the `font_glyph_step` argument removed. +4. All references to `FONT_NAME_WIDTH` need to be changed to `FONT_NAME_END`. + +__Images__ + +Your images need to be updated. The upgrade tool is built into the image drawing utility in `Utilities/image_drawing.html`. To use it: + +1. Copy the source array of the image (everything between `{` and `}`). +2. Open `image_drawing.html`. +3. Click `Version 1.0`. +4. Change the width and height values to match your image. +5. Paste the source array. +6. Click `Version 2.0`. +7. Copy the new array and replace the old version in your source code. + +__Fonts__ + +Your fonts need to be updated. The upgrade tool is in `Utilities/font_conv.html`, and should be self-explanatory. Do note that this tool is experimental - if you have trouble converting a particular font file, raise an issue on GitHub. + +The new font format is described in the [README](README.md). diff --git a/Utilities/font_conv.html b/Utilities/font_conv.html new file mode 100644 index 0000000..c99e74f --- /dev/null +++ b/Utilities/font_conv.html @@ -0,0 +1,165 @@ + + +Font Upgrade + + + + + +Font Code: +
+Font-Width array: +
+Font step: Font height:
+
+

+
+
diff --git a/Utilities/font_end_generate.html b/Utilities/font_end_generate.html
new file mode 100644
index 0000000..4502bb0
--- /dev/null
+++ b/Utilities/font_end_generate.html
@@ -0,0 +1,118 @@
+
+
+Font Upgrade
+
+
+
+
+
+Font Code:
+
+
+

+
+
diff --git a/Utilities/Image drawing/LED_image_drawing_utility.html b/Utilities/image_drawing.html
similarity index 68%
rename from Utilities/Image drawing/LED_image_drawing_utility.html
rename to Utilities/image_drawing.html
index 8ae9d86..9770cf0 100644
--- a/Utilities/Image drawing/LED_image_drawing_utility.html	
+++ b/Utilities/image_drawing.html
@@ -2,7 +2,7 @@
 
 
 
-LED Screen Paint
+Image Draw v2