├── examples ├── HT1632_Text_From_Serial │ └── HT1632_Text_From_Serial.ino ├── HT1632_Text │ └── HT1632_Text.ino ├── HT1632_Text_8X4 │ └── HT1632_Text_8X4.ino ├── HT1632_Heart │ └── HT1632_Heart.ino ├── HT1632_Sailboat │ └── HT1632_Sailboat.ino ├── HT1632_Text_8X4_Multidisplay │ └── HT1632_Text_8X4_Multidisplay.ino ├── HT1632_Heart_Bicolor │ └── HT1632_Heart_Bicolor.ino ├── HT1632_Animation │ └── HT1632_Animation.ino └── HT1632_Heart_Multiple_Bicolor │ └── HT1632_Heart_Multiple_Bicolor.ino ├── keywords.txt ├── LICENSE ├── images.h ├── UPGRADE.md ├── font_5x4.h ├── font_8x4.h ├── font_8x5.h ├── Utilities ├── font_end_generate.html ├── image_drawing.html └── font_conv.html ├── README.md ├── HT1632.h └── HT1632.cpp /examples/HT1632_Text_From_Serial/HT1632_Text_From_Serial.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | char c [] = "S\0"; 6 | 7 | void setup () { 8 | Serial.begin(9600); 9 | HT1632.begin(12, 10, 9); 10 | } 11 | 12 | void loop () { 13 | while(!Serial.available()); 14 | int ct = Serial.read(); 15 | c[0] = (char) ct; 16 | HT1632.drawTarget(BUFFER_BOARD(1)); 17 | HT1632.clear(); 18 | HT1632.drawText(c, 0, 0, FONT_8X4, FONT_8X4_END, FONT_8X4_HEIGHT); 19 | HT1632.render(); 20 | delay(50); 21 | } 22 | -------------------------------------------------------------------------------- /examples/HT1632_Text/HT1632_Text.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int i = 0; 6 | int wd; 7 | char disp [] = "Hello, how are you?"; 8 | 9 | void setup () { 10 | HT1632.begin(12, 10, 9); 11 | 12 | wd = HT1632.getTextWidth(disp, FONT_5X4_END, FONT_5X4_HEIGHT); 13 | } 14 | 15 | void loop () { 16 | 17 | HT1632.drawTarget(BUFFER_BOARD(1)); 18 | HT1632.clear(); 19 | HT1632.drawText(disp, OUT_SIZE - i, 2, FONT_5X4, FONT_5X4_END, FONT_5X4_HEIGHT); 20 | HT1632.render(); 21 | 22 | i = (i+1)%(wd + OUT_SIZE); 23 | 24 | delay(100); 25 | } 26 | -------------------------------------------------------------------------------- /examples/HT1632_Text_8X4/HT1632_Text_8X4.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int i = 0; 6 | int wd; 7 | char disp [] = "Hello, how are you?"; 8 | 9 | void setup () { 10 | HT1632.begin(12, 10, 9); 11 | 12 | wd = HT1632.getTextWidth(disp, FONT_8X4_END, FONT_8X4_HEIGHT); 13 | } 14 | 15 | void loop () { 16 | 17 | HT1632.drawTarget(BUFFER_BOARD(1)); 18 | HT1632.clear(); 19 | HT1632.drawText(disp, OUT_SIZE - i, 0, FONT_8X4, FONT_8X4_END, FONT_8X4_HEIGHT); 20 | HT1632.render(); 21 | 22 | i = (i+1)%(wd + OUT_SIZE); 23 | 24 | delay(100); 25 | } 26 | -------------------------------------------------------------------------------- /examples/HT1632_Heart/HT1632_Heart.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int i = 0; 6 | 7 | void setup () { 8 | HT1632.begin(12, 10, 9); 9 | } 10 | 11 | void loop () { 12 | // The definitions for IMG_HEART and its width and height are available in images.h. 13 | // This step only performs the drawing in internal memory. 14 | HT1632.drawImage(IMG_HEART, IMG_HEART_WIDTH, IMG_HEART_HEIGHT, (OUT_SIZE - IMG_HEART_WIDTH)/2, 0); 15 | 16 | HT1632.render(); // This updates the display on the screen. 17 | 18 | delay(1000); 19 | 20 | HT1632.clear(); // This zeroes out the internal memory. 21 | 22 | HT1632.render(); // This updates the screen display. 23 | 24 | delay(1000); 25 | } 26 | -------------------------------------------------------------------------------- /examples/HT1632_Sailboat/HT1632_Sailboat.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int i = 0; 6 | int wd; 7 | 8 | void setup () { 9 | HT1632.begin(12, 10, 9); 10 | } 11 | 12 | void loop () { 13 | HT1632.clear(); 14 | // This step only performs the drawing in internal memory. 15 | HT1632.drawImage(IMG_SAILBOAT, IMG_SAILBOAT_WIDTH, IMG_SAILBOAT_HEIGHT, i, 0); 16 | // If the image intersects with the end, 17 | if (i > OUT_SIZE - IMG_SAILBOAT_WIDTH) { 18 | // Draw it wrapping around. 19 | HT1632.drawImage(IMG_SAILBOAT, IMG_SAILBOAT_WIDTH, IMG_SAILBOAT_HEIGHT, i - OUT_SIZE, 0); 20 | } 21 | HT1632.render(); // This updates the display on the screen. 22 | 23 | delay(100); 24 | 25 | i = (i + 1) % (OUT_SIZE); 26 | } 27 | -------------------------------------------------------------------------------- /examples/HT1632_Text_8X4_Multidisplay/HT1632_Text_8X4_Multidisplay.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int i = 0; 6 | int wd; 7 | char disp [] = "Hello, how are you?"; 8 | 9 | void setup () { 10 | HT1632.begin(12, 13, 10, 9); 11 | 12 | wd = HT1632.getTextWidth(disp, FONT_8X4_END, FONT_8X4_HEIGHT); 13 | } 14 | 15 | void loop () { 16 | 17 | HT1632.renderTarget(0); 18 | HT1632.clear(); 19 | HT1632.drawText(disp, OUT_SIZE * 2 - i, 0, FONT_8X4, FONT_8X4_END, FONT_8X4_HEIGHT); 20 | HT1632.render(); 21 | 22 | HT1632.renderTarget(1); 23 | HT1632.clear(); 24 | HT1632.drawText(disp, OUT_SIZE - i, 0, FONT_8X4, FONT_8X4_END, FONT_8X4_HEIGHT); 25 | HT1632.render(); 26 | 27 | i = (i+1)%(wd + OUT_SIZE * 2); 28 | 29 | delay(100); 30 | } 31 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Highlighting for HT1632 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | HT1632 KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | begin KEYWORD2 16 | sendCommand KEYWORD2 17 | renderTarget KEYWORD2 18 | selectChannel KEYWORD2 19 | render KEYWORD2 20 | transition KEYWORD2 21 | clear KEYWORD2 22 | drawImage KEYWORD2 23 | drawText KEYWORD2 24 | getTextWidth KEYWORD2 25 | setBrightness KEYWORD2 26 | setCLK KEYWORD2 27 | 28 | ####################################### 29 | # Constants (LITERAL1) 30 | ####################################### 31 | 32 | COM_SIZE LITERAL1 33 | OUT_SIZE LITERAL1 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Gaurav Manek 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /examples/HT1632_Heart_Bicolor/HT1632_Heart_Bicolor.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int i = 0; 6 | int j = 0; 7 | 8 | void setup () { 9 | // Working with Bicolor displays. 10 | // Make sure that a bicolor display is set in HT1632.h 11 | HT1632.setCLK(13); 12 | HT1632.begin(12, 10, 9); 13 | } 14 | 15 | void loop () { 16 | // Zero all data in all channels: 17 | HT1632.clear(); 18 | 19 | if (~i & 0b01) { // On frames 1 and 3: 20 | HT1632.selectChannel(0); // Select the first channel 21 | // Draw a heart: 22 | HT1632.drawImage(IMG_HEART, IMG_HEART_WIDTH, IMG_HEART_HEIGHT, j - IMG_HEART_WIDTH, 3); 23 | } 24 | 25 | if (~i & 0b10) { // On frames 2 and 3: 26 | HT1632.selectChannel(1); // Select the second channel 27 | // Draw a heart: 28 | HT1632.drawImage(IMG_HEART, IMG_HEART_WIDTH, IMG_HEART_HEIGHT, j - IMG_HEART_WIDTH, 3); 29 | } 30 | 31 | HT1632.render(); // This sends the data in both channels to the screen. 32 | 33 | // Get the next number in the sequence, wrapping from 3 back to 0: 34 | i = (i + 1) % 3; 35 | j = (j + 1) % (OUT_SIZE + IMG_HEART_WIDTH * 2); 36 | 37 | delay(150); 38 | } 39 | -------------------------------------------------------------------------------- /examples/HT1632_Animation/HT1632_Animation.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int i = 0; 6 | 7 | void setup () { 8 | HT1632.begin(12, 10, 9); 9 | } 10 | 11 | void loop () { 12 | // Clear the previous image contents: 13 | HT1632.clear(); 14 | 15 | // Draw a different image based on the frame number: 16 | if(i++ % 2 == 0) { 17 | HT1632.drawImage(IMG_SPEAKER_A, IMG_SPEAKER_WIDTH, IMG_SPEAKER_HEIGHT, 0, 0); 18 | HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 8, 0); 19 | HT1632.drawImage(IMG_MUSIC, IMG_MUSIC_WIDTH, IMG_MUSIC_HEIGHT, 13, 1); 20 | HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 23, 0); 21 | HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 28, 1); 22 | } else { 23 | HT1632.drawImage(IMG_SPEAKER_B, IMG_SPEAKER_WIDTH, IMG_SPEAKER_HEIGHT, 0, 0); 24 | HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 8, 1); 25 | HT1632.drawImage(IMG_MUSIC, IMG_MUSIC_WIDTH, IMG_MUSIC_HEIGHT, 13, 0); 26 | HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 23, 1); 27 | HT1632.drawImage(IMG_MUSICNOTE, IMG_MUSICNOTE_WIDTH, IMG_MUSICNOTE_HEIGHT, 28, 0); 28 | } 29 | 30 | // Perform the drawing: 31 | HT1632.render(); 32 | 33 | delay(200); 34 | } 35 | -------------------------------------------------------------------------------- /examples/HT1632_Heart_Multiple_Bicolor/HT1632_Heart_Multiple_Bicolor.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int j = 0; 6 | 7 | void setup () { 8 | // Working with Bicolor displays. 9 | // Make sure that a bicolor display is set in HT1632.h 10 | HT1632.setCLK(13); 11 | HT1632.begin(12, 6, 10, 9); 12 | } 13 | 14 | void loop () { 15 | // Zero all data in all channels: 16 | HT1632.renderTarget(0); 17 | HT1632.clear(); 18 | 19 | HT1632.selectChannel(0); // Red heart on first screen: 20 | HT1632.drawImage(IMG_HEART, IMG_HEART_WIDTH, IMG_HEART_HEIGHT, j - IMG_HEART_WIDTH, 3); 21 | 22 | HT1632.selectChannel(1); // Green heart on first screen: 23 | HT1632.drawImage(IMG_HEART, IMG_HEART_WIDTH, IMG_HEART_HEIGHT, OUT_SIZE * 2 - j, 3); 24 | 25 | HT1632.render(); // This sends the data in both channels to the screen. 26 | 27 | HT1632.renderTarget(1); 28 | HT1632.clear(); 29 | 30 | HT1632.selectChannel(0); // Red heart on second screen: 31 | HT1632.drawImage(IMG_HEART, IMG_HEART_WIDTH, IMG_HEART_HEIGHT, j - IMG_HEART_WIDTH - OUT_SIZE, 3); 32 | 33 | HT1632.selectChannel(1); // Green heart on second screen: 34 | HT1632.drawImage(IMG_HEART, IMG_HEART_WIDTH, IMG_HEART_HEIGHT, OUT_SIZE - j, 3); 35 | 36 | HT1632.render(); 37 | 38 | // Get the next number in the sequence, wrapping from 3 back to 0: 39 | j = (j + 1) % (OUT_SIZE * 2); 40 | 41 | delay(50); 42 | } 43 | -------------------------------------------------------------------------------- /images.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SIMPLE IMAGES FOR RENDERING TO THE LED SCREEN. 3 | * 8 pixels-per-byte 4 | * Gaurav Manek, 2014 5 | */ 6 | 7 | // 8 | // Online Services: 9 | // 10 | 11 | const byte IMG_MAIL [] PROGMEM = {0b11111111, 0b11000001, 0b10100001, 0b10010001, 0b10001001, 0b10000101, 0b10000101, 0b10001001}; 12 | #define IMG_MAIL_WIDTH 8 13 | #define IMG_MAIL_HEIGHT 8 14 | 15 | const byte IMG_FB [] PROGMEM = {0b00111111, 0b01000000, 0b10000100, 0b10011111, 0b10100100, 0b10100000, 0b10000000, 0b10000000}; 16 | #define IMG_FB_WIDTH 8 17 | #define IMG_FB_HEIGHT 8 18 | 19 | const byte IMG_TWITTER [] PROGMEM = {0b01111110, 0b10000001, 0b10111001, 0b10010101, 0b10010101, 0b10000001, 0b01111110}; 20 | #define IMG_TWITTER_WIDTH 7 21 | #define IMG_TWITTER_HEIGHT 8 22 | 23 | // 24 | // Music: 25 | // 26 | 27 | const byte IMG_MUSIC [] PROGMEM = {0b00000010, 0b00000111, 0b11111110, 0b11000000, 0b11000000, 0b11000100, 0b11001110, 0b11111100}; 28 | #define IMG_MUSIC_WIDTH 8 29 | #define IMG_MUSIC_HEIGHT 8 30 | 31 | const byte IMG_MUSICNOTE [] PROGMEM = {0b00000100, 0b00001110, 0b11111100, 0b01000000}; 32 | #define IMG_MUSICNOTE_WIDTH 4 33 | #define IMG_MUSICNOTE_HEIGHT 7 34 | 35 | const byte IMG_SPEAKER_A [] PROGMEM = {0b00011000, 0b00011000, 0b00111100, 0b01000010, 0b10100101, 0b00011000}; 36 | const byte IMG_SPEAKER_B [] PROGMEM = {0b00011000, 0b00011000, 0b00111100, 0b01000010, 0b10111101, 0b00000000}; 37 | #define IMG_SPEAKER_WIDTH 6 38 | #define IMG_SPEAKER_HEIGHT 8 39 | 40 | // 41 | // Emotions: 42 | // 43 | 44 | const byte IMG_HEART [] PROGMEM = {0b01110000, 0b11111000, 0b11111100, 0b11111110, 0b01111111, 0b11111110, 0b11111100, 0b11111000, 0b01110000}; 45 | #define IMG_HEART_WIDTH 9 46 | #define IMG_HEART_HEIGHT 8 47 | 48 | // 49 | // Things: 50 | // 51 | 52 | const byte IMG_SAILBOAT [] PROGMEM = {0b00000010, 0b00100011, 0b01100011, 0b11111111, 0b01111011, 0b00111011, 0b00011011, 0b00001010}; 53 | #define IMG_SAILBOAT_WIDTH 8 54 | #define IMG_SAILBOAT_HEIGHT 8 55 | -------------------------------------------------------------------------------- /UPGRADE.md: -------------------------------------------------------------------------------- 1 | Upgrade Instruction from v1.0 2 | ============================= 3 | 4 | Why bother? 5 | ----------- 6 | 7 | Because: 8 | - Images, fonts and buffers are smaller, with a minimum 50% reduction in size. 9 | - Drawing is faster, the inner loop of the copying engine has been rewritten. 10 | - Bugfixes, notably the ability to copy images of any arbitrary size. 11 | - Compiled code size. 12 | 13 | For example, the 8x4 font has been compressed from 640 bytes to 237 bytes! 14 | 15 | 16 | How to upgrade 17 | -------------- 18 | 19 | __Structure__ 20 | 21 | A single buffer is used for all compositing operations. The following functions, macros and constants have been removed: 22 | 23 | ```c 24 | void HT1632.transition(uint8_t mode, int time = 1000); // Removed 25 | 26 | void HT1632.drawTarget(uint8_t targetBuffer); // Replaced by: 27 | void HT1632.renderTarget(uint8_t targetBuffer); 28 | 29 | BUFFER_BOARD(n) // Just use: 30 | (n - 1) // Board number of pin to use. 31 | 32 | SECONDARY_BUFFER // Removed 33 | ``` 34 | 35 | New mechanisms for working with color channels have been added, and are documented in [the README](README.md) 36 | 37 | __Code__ 38 | 39 | 1. You need to include `HT1632.h` before `images.h` or any font file. 40 | 2. The newer functions require the images/fonts to be updated. 41 | 3. All calls to `HT1632.drawText` need to have the `font_glyph_step` argument removed. 42 | 4. All references to `FONT_NAME_WIDTH` need to be changed to `FONT_NAME_END`. 43 | 44 | __Images__ 45 | 46 | Your images need to be updated. The upgrade tool is built into the image drawing utility in `Utilities/image_drawing.html`. To use it: 47 | 48 | 1. Copy the source array of the image (everything between `{` and `}`). 49 | 2. Open `image_drawing.html`. 50 | 3. Click `Version 1.0`. 51 | 4. Change the width and height values to match your image. 52 | 5. Paste the source array. 53 | 6. Click `Version 2.0`. 54 | 7. Copy the new array and replace the old version in your source code. 55 | 56 | __Fonts__ 57 | 58 | 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. 59 | 60 | The new font format is described in the [README](README.md). 61 | -------------------------------------------------------------------------------- /font_5x4.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 5-high FONT FOR RENDERING TO THE LED SCREEN. 3 | * Includes kerning support 4 | 5 | * 8 pixels-per-byte, variable width. 6 | * Gaurav Manek, 2011 7 | */ 8 | 9 | #ifndef __FONT5X4_H 10 | #define __FONT5X4_H 11 | 12 | #define FONT_5X4_HEIGHT 5 13 | // Number of bytes per glyph 14 | 15 | const byte FONT_5X4 [] PROGMEM = { 16 | 0b00000000, // 17 | 0b11101000, // ! 18 | 0b11000000, 0b00000000, 0b11000000, // " 19 | 0b01010000, 0b11111000, 0b01010000, 0b11111000, 0b01010000, // # 20 | 0b00000000, 0b00000000, 0b00000000, 0b00000000, // $ 21 | 0b11001000, 0b11010000, 0b00100000, 0b01011000, 0b10011000, // % 22 | 0b01010000, 0b10101000, 0b10011000, 0b01011000, // & 23 | 0b11000000, // ' 24 | 0b01110000, 0b10001000, // ( 25 | 0b10001000, 0b01110000, // ) 26 | 0b10100000, 0b01000000, 0b10100000, // * 27 | 0b00100000, 0b00100000, 0b11111000, 0b00100000, 0b00100000, // + 28 | 0b00001000, 0b00010000, // , 29 | 0b00100000, 0b00100000, 0b00100000, // - 30 | 0b00001000, // . 31 | 0b00001000, 0b00110000, 0b01100000, 0b10000000, // / 32 | 0b01110000, 0b10001000, 0b01110000, // 0 33 | 0b01001000, 0b11111000, 0b00001000, // 1 34 | 0b01001000, 0b10011000, 0b10101000, 0b01001000, // 2 35 | 0b10101000, 0b10101000, 0b01010000, // 3 36 | 0b00110000, 0b01010000, 0b11111000, 0b00010000, // 4 37 | 0b11101000, 0b10101000, 0b10110000, // 5 38 | 0b01110000, 0b10101000, 0b10101000, 0b00010000, // 6 39 | 0b10000000, 0b10111000, 0b10100000, 0b11000000, // 7 40 | 0b01010000, 0b10101000, 0b10101000, 0b01010000, // 8 41 | 0b01000000, 0b10100000, 0b10101000, 0b01110000, // 9 42 | 0b01010000, // : 43 | 0b00001000, 0b01010000, // ; 44 | 0b00100000, 0b01010000, 0b10001000, // < 45 | 0b01010000, 0b01010000, 0b01010000, // = 46 | 0b10001000, 0b01010000, 0b00100000, // > 47 | 0b01000000, 0b10000000, 0b10011000, 0b01100000, // ? 48 | 0b01110000, 0b10000000, 0b10110000, 0b10101000, 0b11110000, // @ 49 | 0b01111000, 0b10100000, 0b10100000, 0b01111000, // A 50 | 0b11111000, 0b10101000, 0b01010000, // B 51 | 0b01110000, 0b10001000, 0b10001000, 0b01010000, // C 52 | 0b11111000, 0b10001000, 0b01110000, // D 53 | 0b11111000, 0b10101000, 0b10001000, // E 54 | 0b11111000, 0b10100000, 0b10100000, // F 55 | 0b01110000, 0b10001000, 0b10011000, 0b01010000, // G 56 | 0b11111000, 0b00100000, 0b00100000, 0b11111000, // H 57 | 0b10001000, 0b11111000, 0b10001000, // I 58 | 0b10010000, 0b10001000, 0b11110000, // J 59 | 0b11111000, 0b00100000, 0b01010000, 0b10001000, // K 60 | 0b11111000, 0b00001000, 0b00001000, // L 61 | 0b11111000, 0b01000000, 0b00100000, 0b01000000, 0b11111000, // M 62 | 0b11111000, 0b01000000, 0b00100000, 0b00010000, 0b11111000, // N 63 | 0b01110000, 0b10001000, 0b10001000, 0b01110000, // O 64 | 0b11111000, 0b10100000, 0b01000000, // P 65 | 0b01110000, 0b10001000, 0b10001000, 0b10010000, 0b01101000, // Q 66 | 0b11111000, 0b10100000, 0b01011000, // R 67 | 0b01001000, 0b10101000, 0b10101000, 0b10010000, // S 68 | 0b10000000, 0b11111000, 0b10000000, // T 69 | 0b11110000, 0b00001000, 0b00001000, 0b11110000, // U 70 | 0b11000000, 0b00110000, 0b00001000, 0b00110000, 0b11000000, // V 71 | 0b11110000, 0b00001000, 0b00110000, 0b00001000, 0b11110000, // W 72 | 0b11011000, 0b00100000, 0b11011000, // X 73 | 0b11000000, 0b00111000, 0b11000000, // Y 74 | 0b10011000, 0b10101000, 0b10101000, 0b11001000, // Z 75 | 0b11111000, 0b10001000, // [ 76 | 0b10000000, 0b01100000, 0b00110000, 0b00001000, // \ 77 | 0b10001000, 0b11111000, // ] 78 | 0b01000000, 0b10000000, 0b01000000, // ^ 79 | 0b00001000, 0b00001000, 0b00001000, // _ 80 | }; 81 | 82 | int FONT_5X4_END [] = { 83 | 1, 2, 5, 10, 14, 19, 23, 24, 84 | 26, 28, 31, 36, 38, 41, 42, 46, 85 | 49, 52, 56, 59, 63, 66, 70, 74, 86 | 78, 82, 83, 85, 88, 91, 94, 98, 87 | 103, 107, 110, 114, 117, 120, 123, 127, 88 | 131, 134, 137, 141, 144, 149, 154, 158, 89 | 161, 166, 169, 173, 176, 180, 185, 190, 90 | 193, 196, 200, 202, 206, 208, 211, 214 91 | }; 92 | 93 | #endif // __FONT5X4_H 94 | -------------------------------------------------------------------------------- /font_8x4.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 8-high FONT FOR RENDERING TO THE LED SCREEN. 3 | * 8 pixels-per-byte, variable width. 4 | * 5 | * By Gaurav Manek, 2014. 6 | * Based loosely on the font by Louis Roy, based on 7x5 by David Soyez, 2013 7 | */ 8 | 9 | #ifndef __FONT8X4_H 10 | #define __FONT8X4_H 11 | 12 | #define FONT_8X4_HEIGHT 8 13 | 14 | const byte FONT_8X4 [] PROGMEM = { 15 | 0b00000000, // SPACE 16 | 0b01110000, 0b11111101, 0b01110000, // ! 17 | 0b11000000, 0b00000000, 0b11000000, // " 18 | 0b00100100, 0b11111111, 0b00100100, 0b11111111, 0b00100100, // # 19 | 0b00100100, 0b01010010, 0b11011011, 0b01001010, 0b00100100, // $ 20 | 0b11000001, 0b11000110, 0b00011000, 0b01100011, 0b10000011, // % 21 | 0b01101110, 0b10010001, 0b10010010, 0b01100101, // & 22 | 0b11000000, // ' 23 | 0b00111100, 0b01000010, 0b10000001, // ( 24 | 0b10000001, 0b01000010, 0b00111100, // ) 25 | 0b10100000, 0b01000000, 0b10100000, // * 26 | 0b00001000, 0b00001000, 0b00111110, 0b00001000, 0b00001000, // + 27 | 0b00000001, 0b00000010, // , 28 | 0b00001000, 0b00001000, 0b00001000, // - 29 | 0b00000001, // . 30 | 0b00000011, 0b00001100, 0b00110000, 0b11000000, // / 31 | 0b01111110, 0b10110001, 0b10001101, 0b01111110, // 0 32 | 0b01000001, 0b11111111, 0b00000001, // 1 33 | 0b01000011, 0b10000101, 0b10001001, 0b01110001, // 2 34 | 0b01000010, 0b10001001, 0b10001001, 0b01110110, // 3 35 | 0b00011100, 0b00100100, 0b01001111, 0b10000100, // 4 36 | 0b11110001, 0b10010001, 0b10010001, 0b10001110, // 5 37 | 0b01111110, 0b10001001, 0b10001001, 0b01000110, // 6 38 | 0b10000000, 0b10000111, 0b10011000, 0b11100000, // 7 39 | 0b01110110, 0b10001001, 0b10001001, 0b01110110, // 8 40 | 0b01110010, 0b10001001, 0b10001001, 0b01111110, // 9 41 | 0b00100010, // : 42 | 0b00000001, 0b00100010, // ; 43 | 0b00011000, 0b00100100, 0b01000010, 0b10000001, // < 44 | 0b00010100, 0b00010100, 0b00010100, 0b00010100, // = 45 | 0b10000001, 0b01000010, 0b00100100, 0b00011000, // > 46 | 0b01000000, 0b10001101, 0b10001000, 0b01110000, // ? 47 | 0b01111110, 0b10000001, 0b10111001, 0b10000101, 0b01111100, // @ 48 | 0b01111111, 0b10001000, 0b10001000, 0b01111111, // A 49 | 0b11111111, 0b10001001, 0b10001001, 0b01110110, // B 50 | 0b01111110, 0b10000001, 0b10000001, 0b01000010, // C 51 | 0b11111111, 0b10000001, 0b10000001, 0b01111110, // D 52 | 0b11111111, 0b10001001, 0b10001001, 0b10000001, // E 53 | 0b11111111, 0b10010000, 0b10010000, 0b10000000, // F 54 | 0b01111110, 0b10000001, 0b10001001, 0b01001110, // G 55 | 0b11111111, 0b00001000, 0b00001000, 0b11111111, // H 56 | 0b10000001, 0b11111111, 0b10000001, // I 57 | 0b10000110, 0b10000001, 0b10000001, 0b11111110, // J 58 | 0b11111111, 0b00010000, 0b00101000, 0b11000111, // K 59 | 0b11111111, 0b00000001, 0b00000001, 0b00000001, // L 60 | 0b01111111, 0b11000000, 0b00110000, 0b11000000, 0b01111111, // M 61 | 0b11111111, 0b01100000, 0b00011000, 0b00000110, 0b11111111, // N 62 | 0b01111110, 0b10000001, 0b10000001, 0b01111110, // O 63 | 0b11111111, 0b10001000, 0b10001000, 0b01110000, // P 64 | 0b01111110, 0b10000001, 0b10000101, 0b10000010, 0b01111101, // Q 65 | 0b11111111, 0b10001000, 0b10001100, 0b01110011, // R 66 | 0b01100010, 0b10010001, 0b10001001, 0b01000110, // S 67 | 0b10000000, 0b11111111, 0b10000000, // T 68 | 0b11111110, 0b00000001, 0b00000001, 0b11111110, // U 69 | 0b11111110, 0b00000001, 0b00000110, 0b11111000, // V 70 | 0b11111100, 0b00000011, 0b00011100, 0b00000011, 0b11111100, // W 71 | 0b10000001, 0b01100110, 0b00011000, 0b01100110, 0b10000001, // X 72 | 0b11000000, 0b00110000, 0b00001111, 0b00110000, 0b11000000, // Y 73 | 0b10000011, 0b10001101, 0b10110001, 0b11000001, // Z 74 | 0b11111111, 0b10000001, // [ 75 | 0b11000000, 0b00110000, 0b00001100, 0b00000011, // \ 76 | 0b10000001, 0b11111111, // ] 77 | 0b01000000, 0b10000000, 0b01000000, // ^ 78 | 0b00000001, 0b00000001, 0b00000001, 0b00000001, // _ 79 | }; 80 | 81 | int FONT_8X4_END [] = { 82 | 1, 4, 7, 12, 17, 22, 26, 27, 83 | 30, 33, 36, 41, 43, 46, 47, 51, 84 | 55, 58, 62, 66, 70, 74, 78, 82, 85 | 86, 90, 91, 93, 97, 101, 105, 109, 86 | 114, 118, 122, 126, 130, 134, 138, 142, 87 | 146, 149, 153, 157, 161, 166, 171, 175, 88 | 179, 184, 188, 192, 195, 199, 203, 208, 89 | 213, 218, 222, 224, 228, 230, 233, 237 90 | }; 91 | 92 | #endif // __FONT8X4_H 93 | -------------------------------------------------------------------------------- /font_8x5.h: -------------------------------------------------------------------------------- 1 | /* 2 | * A nice 8-Height font with variable width up to 5 pixels. 3 | * Most characters are in the top 7 pixels, and the bottom pixel is used sparingly. 4 | * This makes an attractive vertical spacing for two-line displays. 5 | * 6 | * The font is the work of Pawel A Hernik, from fonts.h in: 7 | * "MAX7219 functions by Pawel A. Hernik" 8 | * Found in hareeshmu's ESP Matrix Pixel Clock project here: 9 | * https://github.com/hareeshmu/ESP-Matrix-Pixel-Clock/blob/master/max7219.h 10 | * 11 | * Reformatted and inverted for use with HT1632 by Steve Haehnichen 2018-06-27 12 | */ 13 | #ifndef __FONT8X5_H 14 | #define __FONT8X5_H 15 | 16 | #define FONT_8X5_HEIGHT 8 17 | 18 | const byte FONT_8X5 [] PROGMEM = { 19 | 0b00000000, // space 20 | 0b11111010, // ! 21 | 0b11000000, 0b00000000, 0b11000000, // " 22 | 0b00101000, 0b01111100, 0b00101000, 0b01111100, 0b00101000, // # 23 | 0b00100100, 0b01010110, 0b11010100, 0b01001000, // $ 24 | 0b11000110, 0b11001000, 0b00010000, 0b00100110, 0b11000110, // % 25 | 0b01101100, 0b10010010, 0b01101010, 0b00000100, 0b00001010, // & 26 | 0b11000000, // ' 27 | 28 | 0b00111000, 0b01000100, 0b10000010, // ( 29 | 0b10000010, 0b01000100, 0b00111000, // ) 30 | 0b00010100, 0b00011000, 0b01110000, 0b00011000, 0b00010100, // * 31 | 0b00010000, 0b00010000, 0b01111100, 0b00010000, 0b00010000, // + 32 | 0b00001101, 0b00001110, // , 33 | 0b00010000, 0b00010000, 0b00010000, 0b00010000, // - 34 | 0b00000010, // . 35 | 0b00000110, 0b00111000, 0b11000000, // / 36 | 37 | 0b01111100, 0b10000010, 0b10000010, 0b01111100, // 0 38 | 0b01000010, 0b11111110, 0b00000010, // 1 39 | 0b01000110, 0b10001010, 0b10010010, 0b01100010, // 2 40 | 0b01000100, 0b10000010, 0b10010010, 0b01101100, // 3 41 | 0b00011000, 0b00101000, 0b01001000, 0b11111110, // 4 42 | 0b11100100, 0b10100010, 0b10100010, 0b10011100, // 5 43 | 0b01111100, 0b10010010, 0b10010010, 0b01001100, // 6 44 | 0b10000110, 0b10001000, 0b10010000, 0b11100000, // 7 45 | 46 | 0b01101100, 0b10010010, 0b10010010, 0b01101100, // 8 47 | 0b01100100, 0b10010010, 0b10010010, 0b01111100, // 9 48 | 0b00100010, // : 49 | 0b00000001, 0b00001010, // ; 50 | 0b00001000, 0b00010100, 0b00100010, // < 51 | 0b00101000, 0b00101000, 0b00101000, // = 52 | 0b00100010, 0b00010100, 0b00001000, // > 53 | 0b01000000, 0b10011010, 0b10010000, 0b01100000, // ? 54 | 55 | 0b01111100, 0b10010010, 0b10101010, 0b10111010, 0b01110000, // @ 56 | 0b01111110, 0b10001000, 0b10001000, 0b01111110, // A 57 | 0b11111110, 0b10010010, 0b10010010, 0b01101100, // B 58 | 0b01111100, 0b10000010, 0b10000010, 0b01000100, // C 59 | 0b11111110, 0b10000010, 0b10000010, 0b01111100, // D 60 | 0b11111110, 0b10010010, 0b10010010, 0b10000010, // E 61 | 0b11111110, 0b10010000, 0b10010000, 0b10000000, // F 62 | 0b01111100, 0b10000010, 0b10010010, 0b01011110, // G 63 | 64 | 0b11111110, 0b00010000, 0b00010000, 0b11111110, // H 65 | 0b10000010, 0b11111110, 0b10000010, // I 66 | 0b00001100, 0b00000010, 0b10000010, 0b11111100, // J 67 | 0b11111110, 0b00010000, 0b00101000, 0b11000110, // K 68 | 0b11111110, 0b00000010, 0b00000010, 0b00000010, // L 69 | 0b11111110, 0b01000000, 0b00110000, 0b01000000, 0b11111110, // M 70 | 0b11111110, 0b00100000, 0b00010000, 0b00001000, 0b11111110, // N 71 | 0b01111100, 0b10000010, 0b10000010, 0b01111100, // O 72 | 73 | 0b11111110, 0b10010000, 0b10010000, 0b01100000, // P 74 | 0b01111100, 0b10000010, 0b10000010, 0b01111101, // Q 75 | 0b11111110, 0b10010000, 0b10010000, 0b01101110, // R 76 | 0b01100100, 0b10010010, 0b10010010, 0b01001100, // S 77 | 0b10000000, 0b10000000, 0b11111110, 0b10000000, 0b10000000, // T 78 | 0b11111100, 0b00000010, 0b00000010, 0b11111100, // U 79 | 0b11110000, 0b00001100, 0b00000010, 0b00001100, 0b11110000, // V 80 | 0b11111100, 0b00000010, 0b00011100, 0b00000010, 0b11111100, // W 81 | 82 | 0b11000110, 0b00101000, 0b00010000, 0b00101000, 0b11000110, // X 83 | 0b11100000, 0b00010000, 0b00001110, 0b00010000, 0b11100000, // Y 84 | 0b10000110, 0b10001010, 0b10010010, 0b11100010, // Z 85 | 0b11111110, 0b10000010, // [ 86 | 0b10000000, 0b01100000, 0b00011000, 0b00000110, // \ 87 | 0b10000010, 0b11111110, // ] 88 | 0b01000000, 0b10000000, 0b01000000, // ^ 89 | 0b00000010, 0b00000010, 0b00000010, 0b00000010, // _ 90 | }; 91 | 92 | // Offsets generated by font_end_generate.html 93 | int FONT_8X5_END [] = 94 | { 95 | 1, 2, 5, 10, 14, 19, 24, 25, 96 | 28, 31, 36, 41, 43, 47, 48, 51, 97 | 55, 58, 62, 66, 70, 74, 78, 82, 98 | 86, 90, 91, 93, 96, 99, 102, 106, 99 | 111, 115, 119, 123, 127, 131, 135, 139, 100 | 143, 146, 150, 154, 158, 163, 168, 172, 101 | 176, 180, 184, 188, 193, 197, 202, 207, 102 | 212, 217, 221, 223, 227, 229, 232, 236 103 | }; 104 | #endif // __FONT8X5_H 105 | 106 | /* 107 | Character widths: 108 | 1, 1, 3, 5, 4, 5, 5, 1, 109 | 3, 3, 5, 5, 2, 4, 1, 3, 110 | 4, 3, 4, 4, 4, 4, 4, 4, 111 | 4, 4, 1, 2, 3, 3, 3, 4, 112 | 5, 4, 4, 4, 4, 4, 4, 4, 113 | 4, 3, 4, 4, 4, 5, 5, 4, 114 | 4, 4, 4, 4, 5, 4, 5, 5, 115 | 5, 5, 4, 2, 4, 2, 3, 4 116 | */ 117 | -------------------------------------------------------------------------------- /Utilities/font_end_generate.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | Font Upgrade 6 | 11 | 45 | 46 | 47 | 48 | Font Code: 49 |
115 |
116 |

117 | 
118 | 
119 | 


--------------------------------------------------------------------------------
/Utilities/image_drawing.html:
--------------------------------------------------------------------------------
  1 | 
  2 | 
  3 | 
  4 | 
  5 | Image Draw v2
  6 | 
 22 | 
215 | 
216 | 
217 | 
218 | 

219 |
220 | Width: Height: Use Circle
221 | Pixels per Byte: Reverse Pixel Order
222 |
223 |
224 | 225 | 226 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | HT1632 for Arduino v2.0 2 | ======================= 3 | 4 | __NOTE:__ This new version of the software changes the underlying data format - upgrading is easy and largely automated. See [upgrade instructions](UPGRADE.md). 5 | 6 | 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. 7 | 8 | 9 | Quick Start 10 | =========== 11 | 12 | Code 13 | ---- 14 | 15 | Here's some sample code to draw a blinking heart on the middle of a single screen: 16 | 17 | ```c 18 | #include // Include this before or any font. 19 | #include 20 | 21 | void setup () { 22 | HT1632.begin(pinCS1, pinWR, pinDATA); 23 | // Where pinCS1, pinWR and pinDATA are the numbers of the output pins 24 | // that are connected to the appropriate pins on the HT1632. 25 | } 26 | 27 | void loop () { 28 | // The definitions for IMG_HEART and its width and height are available in images.h. 29 | // This step only performs the drawing in internal memory. 30 | HT1632.drawImage(IMG_HEART, IMG_HEART_WIDTH, IMG_HEART_HEIGHT, (OUT_SIZE - IMG_HEART_WIDTH)/2, 0); 31 | 32 | HT1632.render(); // This updates the display on the screen. 33 | 34 | delay(1000); 35 | 36 | HT1632.clear(); // This zeroes out the internal memory. 37 | 38 | HT1632.render(); // This updates the screen display. 39 | 40 | delay(1000); 41 | } 42 | ``` 43 | 44 | 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. 45 | 46 | 47 | Explanation 48 | ----------- 49 | 50 | HT1632 is always initialized by calling the begin function, like so: 51 | 52 | ```c++ 53 | HT1632.begin(pinCS1 [, pinCS2 [, pinCS3 [, pinCS4]]], pinWR, pinDATA); 54 | ``` 55 | 56 | All pins are set to `OUTPUT` and memory is allocated and cleared automatically. The square brackets denote an optional argument. 57 | 58 | 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. 59 | 60 | Utilities 61 | ========== 62 | 63 | Image Drawing 64 | ------------- 65 | 66 | 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. 67 | 68 | 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). 69 | 70 | It's use should be self-evident. You can find it in `Utilities/image_drawing.html`. 71 | 72 | Font Creation 73 | ------------- 74 | 75 | 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. 76 | 77 | 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`. 78 | 79 | __Generating FONT_NAME_NUM__ 80 | 81 | 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. 82 | 83 | 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. 84 | 85 | 86 | Advanced Use 87 | ============ 88 | 89 | There are a few examples in `Arduino/HT1632/examples/`. 90 | 91 | Bicolor Displays 92 | ---------------- 93 | 94 | 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. 95 | 96 | An example is available in `HT1632/examples/HT1632_Heart_Bicolor/`. 97 | 98 | __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. 99 | 100 | __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. 101 | 102 | Brightness Control 103 | ------------------ 104 | 105 | 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!__ 106 | 107 | 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. 108 | 109 | Multiple HT1632s 110 | ---------------- 111 | 112 | 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. 113 | 114 | All rendering occurs on the first display by default. A scrolling text example is available in `HT1632/examples/HT1632_Text_8X4_Multidisplay/`. 115 | 116 | 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. 117 | 118 | Multiple HT1632s, each with multiple color channels, are supported natively. 119 | 120 | 121 | Bugs & Features 122 | =============== 123 | 124 | Known Issues 125 | ------------ 126 | 127 | 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. 128 | 129 | 2. A single Arduino cannot support both a Mono-color and a Bi-color display. 130 | 131 | Future Plans 132 | ------------ 133 | 134 | 1. Support for direct pixel access and primitive drawing. 135 | 2. Test support for fonts taller than 8px. 136 | 3. Allow `FONT_8X4_END` arrays to be either 2-byte `int`s or 1-byte `uint8_t`s 137 | -------------------------------------------------------------------------------- /HT1632.h: -------------------------------------------------------------------------------- 1 | /* 2 | HT1632.h - Library for communicating with the popular HT1632/HT1632C 3 | LED controllers. This library provides higher-level access (including 4 | text drawing) for these chips. Currently, the library supports writing 5 | to a single chip at a time, and has been tested with two 6 | Sure Electronics 3208 5mm red board. 7 | 8 | Created by Gaurav Manek, April 8, 2011. 9 | Released into the public domain. 10 | */ 11 | #ifndef HT1632_h 12 | #define HT1632_h 13 | 14 | #include 15 | #ifdef __AVR__ 16 | #include 17 | #elif defined(ESP8266) 18 | #include 19 | #else 20 | #define PROGMEM 21 | #endif 22 | 23 | // Custom typedefs 24 | typedef unsigned char uint8_t; 25 | typedef unsigned char byte; 26 | // typedef char int8_t; 27 | 28 | 29 | /* 30 | * USER OPTIONS 31 | * Change these options 32 | */ 33 | 34 | // Uncomment the line that matches the board you have, or edit the 35 | // settings in the else block: 36 | 37 | // SureElectronics 32X16 Bicolor LED Dot Matrix Unit Board 38 | #define TYPE_3216_BICOLOR 1 39 | 40 | // SureElectronics 32X08 Monochrome LED Dot Matrix Unit Board 41 | // #define TYPE_3208_MONO 1 42 | 43 | // SureElectronics 24x16 Monochrome LED Dot Matrix Unit Board 44 | #define TYPE_2416_MONO 1 45 | 46 | // SureElectronics 16X08 Bicolor (emulation) 47 | // #define TYPE_1608_DEBUG 1 48 | 49 | #if defined TYPE_3216_BICOLOR 50 | #define COM_SIZE 16 51 | #define OUT_SIZE 32 52 | #define NUM_CHANNEL 2 53 | #define USE_NMOS 1 54 | // Number of chips in a single Bicolor board: 55 | #define NUM_ACTIVE_CHIPS 4 56 | #elif defined TYPE_3208_MONO 57 | #define COM_SIZE 8 58 | #define OUT_SIZE 32 59 | #define NUM_CHANNEL 1 60 | #define USE_NMOS 1 61 | #elif defined TYPE_2416_MONO 62 | #define COM_SIZE 16 63 | #define OUT_SIZE 24 64 | #define NUM_CHANNEL 1 65 | #define USE_NMOS 1 66 | #elif defined TYPE_1608_DEBUG 67 | #define COM_SIZE 8 68 | #define OUT_SIZE 16 69 | #define NUM_CHANNEL 2 70 | #define USE_NMOS 1 71 | #else 72 | // SET YOUR CUSTOM VALUES HERE, AND COMMENT THE NEXT LINE 73 | #error "Pick a board type!" 74 | 75 | // Size of COM and OUT in bits: 76 | #define COM_SIZE 8 77 | #define OUT_SIZE 32 78 | // COM_SIZE MUST be either 8 or 16. 79 | 80 | // Number of color channels. The default is a single color channel. 81 | #define NUM_CHANNEL 1 82 | 83 | // Use N-MOS (if 1) or P-MOS (if 0): 84 | #define USE_NMOS 1 85 | // There are known issues with this. If the default doesn't work, 86 | // try changing the value. 87 | #endif 88 | 89 | /* 90 | * END USER OPTIONS 91 | * Don't edit anything below unless you know what you are doing! 92 | */ 93 | 94 | 95 | // Pixels in a single byte of the internal image representation: 96 | #define PIXELS_PER_BYTE 8 97 | 98 | // Address space size (number of 4-bit words in HT1632 memory) 99 | // Exactly equal to the number of 4-bit address spaces available. 100 | #define ADDR_SPACE_SIZE (COM_SIZE * OUT_SIZE / PIXELS_PER_BYTE) 101 | #define GET_ADDR_FROM_X_Y(_x,_y) ((_x)*((COM_SIZE)/(PIXELS_PER_BYTE))+(_y)/(PIXELS_PER_BYTE)) 102 | #define GET_BIT_FROM_Y(_y) ( (0b1 << PIXELS_PER_BYTE-1) >> (y % PIXELS_PER_BYTE) ) 103 | 104 | // NO-OP Definition 105 | #define NOP(); __asm__("nop\n\t"); 106 | // The HT1632 requires at least 50 ns between the change in data and the rising 107 | // edge of the WR signal. On a 16MHz processor, this provides 62.5ns per NOP. 108 | 109 | // Standard command list. 110 | // This list is modified from original code by Bill Westfield 111 | 112 | #define HT1632_ID_CMD 0b100 /* ID = 100 - Commands */ 113 | #define HT1632_ID_RD 0b110 /* ID = 110 - Read RAM */ 114 | #define HT1632_ID_WR 0b101 /* ID = 101 - Write RAM */ 115 | #define HT1632_ID_LEN 3 /* IDs are 3 bits */ 116 | 117 | #define HT1632_CMD_SYSDIS 0x00 /* CMD= 0000-0000-x Turn off oscil */ 118 | #define HT1632_CMD_SYSEN 0x01 /* CMD= 0000-0001-x Enable system oscil */ 119 | #define HT1632_CMD_LEDOFF 0x02 /* CMD= 0000-0010-x LED duty cycle gen off */ 120 | #define HT1632_CMD_LEDON 0x03 /* CMD= 0000-0011-x LEDs ON */ 121 | #define HT1632_CMD_BLOFF 0x08 /* CMD= 0000-1000-x Blink ON */ 122 | #define HT1632_CMD_BLON 0x09 /* CMD= 0000-1001-x Blink Off */ 123 | #define HT1632_CMD_SLVMD 0x10 /* CMD= 0001-00xx-x Slave Mode */ 124 | #define HT1632_CMD_MSTMD 0x14 /* CMD= 0001-01xx-x Master Mode, on-chip clock */ 125 | #define HT1632_CMD_RCCLK 0x18 /* CMD= 0001-10xx-x Master Mode, external clock */ 126 | #define HT1632_CMD_EXTCLK 0x1C /* CMD= 0001-11xx-x Use external clock */ 127 | #define HT1632_CMD_COMS00 0x20 /* CMD= 0010-ABxx-x commons options */ 128 | #define HT1632_CMD_COMS01 0x24 /* CMD= 0010-ABxx-x commons options */ 129 | #define HT1632_CMD_COMS10 0x28 /* CMD= 0010-ABxx-x commons options */ 130 | #define HT1632_CMD_COMS11 0x2C /* CMD= 0010-ABxx-x commons options */ 131 | #define HT1632_CMD_PWM_T 0xA0 /* CMD= 101x-PPPP-x PWM duty cycle - template*/ 132 | #define HT1632_CMD_PWM(lvl) (HT1632_CMD_PWM_T | (lvl-1)) 133 | /* Produces the correct command from the given value of lvl. lvl = [0..15] */ 134 | #define HT1632_CMD_LEN 8 /* Commands are 8 bits long, excluding the trailing bit */ 135 | #define HT1632_ADDR_LEN 7 /* Addresses are 7 bits long */ 136 | #define HT1632_WORD_LEN 4 /* Words are 4 bits long */ 137 | 138 | class HT1632Class 139 | { 140 | private: 141 | uint8_t _pinCS [4]; 142 | uint8_t _numActivePins; 143 | uint8_t _pinWR; 144 | uint8_t _pinDATA; 145 | uint8_t _pinCLK; 146 | uint8_t _currSelectionMask; 147 | uint8_t _tgtRender; 148 | uint8_t _tgtChannel; 149 | byte * mem [5]; 150 | void writeCommand(char); 151 | void writeData(byte, uint8_t); 152 | void writeDataRev(byte, uint8_t); 153 | void writeSingleBit(); 154 | void initialize(uint8_t, uint8_t); 155 | void select(); 156 | void select(uint8_t mask); 157 | int getCharWidth(int font_end [], uint8_t font_height, uint8_t font_index); 158 | int getCharOffset(int font_end [], uint8_t font_index); 159 | inline void pulseCLK(); 160 | 161 | public: 162 | void begin(uint8_t pinCS1, uint8_t pinWR, uint8_t pinDATA); 163 | void begin(uint8_t pinCS1, uint8_t pinCS2, uint8_t pinWR, uint8_t pinDATA); 164 | void begin(uint8_t pinCS1, uint8_t pinCS2, uint8_t pinCS3, uint8_t pinWR, uint8_t pinDATA); 165 | void begin(uint8_t pinCS1, uint8_t pinCS2, uint8_t pinCS3, uint8_t pinCS4, uint8_t pinWR, uint8_t pinDATA); 166 | void setCLK(uint8_t pinCLK); 167 | void sendCommand(uint8_t command); 168 | void renderTarget(uint8_t targetScreen); 169 | void selectChannel(uint8_t channel); 170 | void render(); 171 | void transition(uint8_t mode, int time = 1000); // Time is in milliseconds. 172 | void clear(); 173 | void drawImage(const byte img [], uint8_t width, uint8_t height, int8_t x, int8_t y, int offset = 0); 174 | void drawText(const char text [], int x, int y, const byte font [], int font_end [], uint8_t font_height, uint8_t gutter_space = 1); 175 | int getTextWidth(const char text [], int font_end [], uint8_t font_height, uint8_t gutter_space = 1); 176 | void setBrightness(char brightness, char selectionmask = 0b00010000); 177 | 178 | void setPixel(uint8_t x, uint8_t y); 179 | void clearPixel(uint8_t x, uint8_t y); 180 | uint8_t getPixel(uint8_t x, uint8_t y); 181 | void setPixel(uint8_t x, uint8_t y, uint8_t channel); 182 | void clearPixel(uint8_t x, uint8_t y, uint8_t channel); 183 | uint8_t getPixel(uint8_t x, uint8_t y, uint8_t channel); 184 | void fill(); 185 | void fillAll(); 186 | }; 187 | 188 | extern HT1632Class HT1632; 189 | 190 | #else 191 | //#error "HT1632.h" already defined! 192 | #endif 193 | -------------------------------------------------------------------------------- /Utilities/font_conv.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | Font Upgrade 6 | 11 | 73 | 74 | 75 | 76 | Font Code: 77 |
150 | Font-Width array: 151 |
161 | Font step: Font height:
162 |
163 |

164 | 
165 | 
166 | 


--------------------------------------------------------------------------------
/HT1632.cpp:
--------------------------------------------------------------------------------
  1 | #include "HT1632.h"
  2 | 
  3 | #if PIXELS_PER_BYTE != 8
  4 | 	#error "The current drawImage, drawText and getTextWidth implementation requires PIXELS_PER_BYTE == 8"
  5 | #endif
  6 | 
  7 | /*
  8 |  * HIGH LEVEL FUNCTIONS
  9 |  * Functions that perform advanced tasks using lower-level
 10 |  * functions go here:
 11 |  */
 12 | 
 13 | void HT1632Class::drawText(const char text [], int x, int y, const byte font [], int font_end [], uint8_t font_height, uint8_t gutter_space) {
 14 | 	int curr_x = x;
 15 | 	char i = 0;
 16 | 	char currchar;
 17 | 	
 18 | 	// Check if string is within y-bounds
 19 | 	if(y + font_height < 0 || y >= COM_SIZE)
 20 | 	return;
 21 | 	
 22 | 	while(true){  
 23 | 		if(text[i] == '\0')
 24 | 			return;
 25 | 		
 26 | 		currchar = text[i] - 32;
 27 | 		if(currchar >= 65 && currchar <= 90) // If character is lower-case, automatically make it upper-case
 28 | 			currchar -= 32; // Make this character uppercase.
 29 | 
 30 | 		if(currchar < 0 || currchar >= 64) { // If out of bounds, skip
 31 | 			++i;
 32 | 			continue; // Skip this character.
 33 | 		}
 34 | 
 35 | 		// Check to see if character is not too far right.
 36 | 		if(curr_x >= OUT_SIZE)
 37 | 			break; // Stop rendering - all other characters are no longer within the screen 
 38 | 		
 39 | 		// Check to see if character is not too far left.
 40 | 		int chr_width = getCharWidth(font_end, font_height, currchar);
 41 | 		if(curr_x + chr_width + gutter_space >= 0){
 42 | 			drawImage(font, chr_width, font_height, curr_x, y,  getCharOffset(font_end, currchar));
 43 | 			
 44 | 			// Draw the gutter space
 45 | 			for(char j = 0; j < gutter_space; ++j)
 46 | 			drawImage(font, 1, font_height, curr_x + chr_width + j, y, 0);
 47 | 		}
 48 | 		
 49 | 		curr_x += chr_width + gutter_space;
 50 | 		++i;
 51 | 	}
 52 | }
 53 | 
 54 | // Gives you the width, in columns, of a particular string.
 55 | int HT1632Class::getTextWidth(const char text [], int font_end [], uint8_t font_height, uint8_t gutter_space) {
 56 | 	int wd = 0;
 57 | 	char i = 0;
 58 | 	char currchar;
 59 | 	
 60 | 	while(true){  
 61 | 		if (text[i] == '\0') {
 62 | 			return wd - gutter_space;
 63 | 		}
 64 | 			
 65 | 		currchar = text[i] - 32;
 66 | 		if (currchar >= 65 && currchar <= 90) { // If character is lower-case, automatically make it upper-case
 67 | 			currchar -= 32;                     // Make this character uppercase.
 68 | 		}
 69 | 
 70 | 		if (currchar < 0 || currchar >= 64) {   // If out of bounds, skip
 71 | 			++i;
 72 | 			continue; // Skip this character.
 73 | 		}
 74 | 
 75 | 		wd += getCharWidth(font_end, font_height, currchar) + gutter_space;
 76 | 		++i;
 77 | 	}
 78 | }
 79 | 
 80 | int HT1632Class::getCharWidth(int font_end [], uint8_t font_height, uint8_t font_index) {
 81 | 	uint8_t bytesPerColumn = (font_height >> 3) + ((font_height & 0b111)?1:0); // Assumes that PIXELS_PER_BYTE is 8
 82 | 
 83 | 	if(font_index == 0) {
 84 | 		return font_end[0];
 85 | 	}
 86 | 	// The width is the difference between the ending index of
 87 | 	//  this and the previous characters:
 88 | 	return (font_end[font_index] - font_end[font_index - 1])/bytesPerColumn;
 89 | }
 90 | 
 91 | int HT1632Class::getCharOffset(int font_end [], uint8_t font_index) {
 92 | 	if(font_index == 0) {
 93 | 		return 0;
 94 | 	}
 95 | 	// The offset is in the ending index of the previous character:
 96 | 	return font_end[font_index - 1];
 97 | }
 98 | 
 99 | /*
100 |  * MID LEVEL FUNCTIONS
101 |  * Functions that handle internal memory, initialize the hardware
102 |  * and perform the rendering go here:
103 |  */
104 | 
105 | void HT1632Class::begin(uint8_t pinCS1, uint8_t pinWR, uint8_t pinDATA) {
106 | 	_numActivePins = 1;
107 | 	_pinCS[0] = pinCS1;
108 | 	initialize(pinWR, pinDATA);
109 | }
110 | void HT1632Class::begin(uint8_t pinCS1, uint8_t pinCS2, uint8_t pinWR,   uint8_t pinDATA) {
111 | 	_numActivePins = 2;
112 | 	_pinCS[0] = pinCS1;
113 | 	_pinCS[1] = pinCS2;
114 | 	initialize(pinWR, pinDATA);
115 | }
116 | void HT1632Class::begin(uint8_t pinCS1, uint8_t pinCS2, uint8_t pinCS3,  uint8_t pinWR,   uint8_t pinDATA) {
117 | 	_numActivePins = 3;
118 | 	_pinCS[0] = pinCS1;
119 | 	_pinCS[1] = pinCS2;
120 | 	_pinCS[2] = pinCS3;
121 | 	initialize(pinWR, pinDATA);
122 | }
123 | void HT1632Class::begin(uint8_t pinCS1, uint8_t pinCS2, uint8_t pinCS3,  uint8_t pinCS4,  uint8_t pinWR,   uint8_t pinDATA) {
124 | 	_numActivePins = 4;
125 | 	_pinCS[0] = pinCS1;
126 | 	_pinCS[1] = pinCS2;
127 | 	_pinCS[2] = pinCS3;
128 | 	_pinCS[3] = pinCS4;
129 | 	initialize(pinWR, pinDATA);
130 | }
131 | 
132 | void HT1632Class::initialize(uint8_t pinWR, uint8_t pinDATA) {
133 | 	_pinWR = pinWR;
134 | 	_pinDATA = pinDATA;
135 | 	
136 | 	for (uint8_t i = 0; i < _numActivePins; ++i){
137 | 		pinMode(_pinCS[i], OUTPUT);
138 | 	}
139 | 
140 | 	pinMode(_pinWR, OUTPUT);
141 | 	pinMode(_pinDATA, OUTPUT);
142 | 	
143 | 	select();
144 | 	
145 | 	for (uint8_t i = 0; i < NUM_CHANNEL; ++i) {
146 | 		// Allocate new memory for each channel
147 | 		mem[i] = (byte *)malloc(ADDR_SPACE_SIZE);
148 | 	}
149 | 	// Clear all memory
150 | 	clear();
151 | 
152 | 	// Send configuration to chip:
153 | 	// This configuration is from the HT1632 datasheet, with one modification:
154 | 	//   The RC_MASTER_MODE command is not sent to the master. Since acting as
155 | 	//   the RC Master is the default behaviour, this is not needed. Sending
156 | 	//   this command causes problems in HT1632C (note the C at the end) chips. 
157 | 	
158 | 	// Send Master commands
159 | 	
160 | 	select(0b1111); // Assume that board 1 is the master.
161 | 	writeData(HT1632_ID_CMD, HT1632_ID_LEN);    // Command mode
162 | 	
163 | 	writeCommand(HT1632_CMD_SYSDIS); // Turn off system oscillator
164 | 	
165 | 	// Custom initialization from each:
166 | #if defined TYPE_3208_MONO
167 | 	writeCommand(HT1632_CMD_COMS00);
168 | #elif defined TYPE_3216_BICOLOR
169 | 	writeCommand(HT1632_CMD_COMS00);
170 | 	writeCommand(HT1632_CMD_RCCLK);  // Master Mode, external clock
171 | #elif defined TYPE_2416_MONO
172 | 	writeCommand(HT1632_CMD_COMS01);
173 | #else
174 | 	writeCommand(HT1632_CMD_COMS00);
175 | #endif
176 | 
177 | 	writeCommand(HT1632_CMD_SYSEN); //Turn on system
178 | 	writeCommand(HT1632_CMD_LEDON); // Turn on LED duty cycle generator
179 | 	writeCommand(HT1632_CMD_PWM(16)); // PWM 16/16 duty
180 | 	
181 | 	select();
182 | 	
183 | 	// Clear all screens by default:
184 | 	for(uint8_t i = 0; i < _numActivePins; ++i) {
185 | 		renderTarget(i);
186 | 		render();
187 | 	}
188 | 	// Set renderTarget to the first board.
189 | 	renderTarget(0);
190 | }
191 | 
192 | void HT1632Class::selectChannel(uint8_t channel) {
193 | 	if(channel < NUM_CHANNEL) {
194 | 		_tgtChannel = channel;
195 | 	}
196 | }
197 | 
198 | void HT1632Class::renderTarget(uint8_t target) {
199 | 	if(target < _numActivePins) {
200 | 		_tgtRender = target;
201 | 	}
202 | }
203 | 
204 | void HT1632Class::drawImage(const byte * img, uint8_t width, uint8_t height, int8_t x, int8_t y, int img_offset) {
205 | 	// Assuming that we are using 8 PIXELS_PER_BYTE, this does the equivalent of Math.ceil(height/PIXELS_PER_BYTE):
206 | 	uint8_t bytesPerColumn = (height >> 3) + ((height & 0b111)?1:0);
207 | 
208 | 	// Sanity checks
209 | 	if(y + height < 0 || x + width < 0 || y > COM_SIZE || x > OUT_SIZE)
210 | 		return;
211 | 	// After looking at the rest of this function, you may need one.
212 | 	
213 | 	// Copying Engine.
214 | 
215 | 	// Current off
216 | 	int8_t dst_x = x;
217 | 	int8_t src_x = 0;
218 | 	// Repeat until each column has been copied.
219 | 	while (src_x < width) {
220 | 		if(dst_x < 0) {
221 | 			// Skip this column if it is too far to the left.
222 | 			src_x++;
223 | 			dst_x++;
224 | 			continue;
225 | 		} else if (dst_x >= OUT_SIZE) {
226 | 			// End the copy if it is too far to the right.
227 | 			break;
228 | 		}
229 | 
230 | 		int8_t src_y = 0;
231 | 		int8_t dst_y = y;
232 | 		while (src_y < height) {
233 | 			if (dst_y < 0) {
234 | 				// Skip pixels if the starting point to too far up.
235 | 				src_y -= dst_y;
236 | 				dst_y = 0;
237 | 				continue;
238 | 			} else if (dst_y >= COM_SIZE) {
239 | 				// End copying this column if it is too far down
240 | 				break;
241 | 			}
242 | 
243 | 			// The use of bitmasking here assumes that PIXELS_PER_BYTE == 8
244 | 
245 | 			// Find out how many we can copy in the next step:
246 | 			//  as a minimum of the number of bits in the current byte of source
247 | 			//  and destination.
248 | 			uint8_t copyInNextStep = 8 - max((src_y & 0b111), (dst_y & 0b111));
249 | 
250 | 			// Limit this by the height of the image:
251 | 			copyInNextStep = min(copyInNextStep, (height - src_y));
252 | 
253 | 			// Prepare the bitmask with the number of bits that need to be copied.
254 | 			uint8_t dst_copyMask = (0b1 << copyInNextStep) - 1;
255 | 			
256 | 			// Shift the bitmasks to the correct position.
257 | 			dst_copyMask <<= (8 - (dst_y & 0b111) - copyInNextStep);
258 | 
259 | 			// Shift the data to the bits of highest significance
260 | 			uint8_t copyData = pgm_read_byte(&img[img_offset + (bytesPerColumn * src_x) + (src_y >> 3)]) << (src_y & 0b111);
261 | 			// Shift data to match the destination place value.
262 | 			copyData >>= (dst_y & 0b111);
263 | 
264 | 			// Perform the copy
265 | 			mem[_tgtChannel][GET_ADDR_FROM_X_Y(dst_x, dst_y)] =  // Put in destination
266 | 				(mem[_tgtChannel][GET_ADDR_FROM_X_Y(dst_x, dst_y)] & ~dst_copyMask) | // All bits not in the mask from destination
267 | 				(copyData & dst_copyMask); // All bits in the mask from source
268 | 
269 | 			src_y += copyInNextStep;
270 | 			dst_y += copyInNextStep;
271 | 		}
272 | 
273 | 		src_x++;
274 | 		dst_x++;
275 | 	}
276 | }
277 | 
278 | void HT1632Class::setPixel(uint8_t x, uint8_t y) {
279 | 	if( x < 0 || x > OUT_SIZE || y < 0 || y > COM_SIZE )
280 | 		return;
281 | 	mem[_tgtChannel][GET_ADDR_FROM_X_Y(x, y)] |= (0b1 << PIXELS_PER_BYTE-1) >> (y % PIXELS_PER_BYTE);
282 | }
283 | void HT1632Class::clearPixel(uint8_t x, uint8_t y) {
284 | 	if( x < 0 || x > OUT_SIZE || y < 0 || y > COM_SIZE )
285 | 		return;
286 | 	mem[_tgtChannel][GET_ADDR_FROM_X_Y(x, y)] &= ~((0b1 << PIXELS_PER_BYTE-1) >> (y % PIXELS_PER_BYTE));
287 | }
288 | uint8_t HT1632Class::getPixel(uint8_t x, uint8_t y) {
289 | 	if( x < 0 || x > OUT_SIZE || y < 0 || y > COM_SIZE )
290 | 		return 0;
291 | 	return mem[_tgtChannel][GET_ADDR_FROM_X_Y(x, y)] & (0b1 << PIXELS_PER_BYTE-1) >> (y % PIXELS_PER_BYTE);
292 | }
293 | 
294 | void HT1632Class::setPixel(uint8_t x, uint8_t y, uint8_t channel) {
295 | 	if( x < 0 || x > OUT_SIZE || y < 0 || y > COM_SIZE )
296 | 		return;
297 | 	mem[channel][GET_ADDR_FROM_X_Y(x, y)] |= GET_BIT_FROM_Y(y);
298 | }
299 | void HT1632Class::clearPixel(uint8_t x, uint8_t y, uint8_t channel) {
300 | 	if( x < 0 || x > OUT_SIZE || y < 0 || y > COM_SIZE )
301 | 		return;
302 | 	mem[channel][GET_ADDR_FROM_X_Y(x, y)] &= ~(GET_BIT_FROM_Y(y));
303 | }
304 | uint8_t HT1632Class::getPixel(uint8_t x, uint8_t y, uint8_t channel) {
305 | 	if( x < 0 || x > OUT_SIZE || y < 0 || y > COM_SIZE )
306 | 		return 0;
307 | 	return mem[channel][GET_ADDR_FROM_X_Y(x, y)] & GET_BIT_FROM_Y(y);
308 | }
309 | 
310 | void HT1632Class::fill() {
311 | 	for(uint8_t i = 0; i < ADDR_SPACE_SIZE; ++i) {
312 | 		mem[_tgtChannel][i] = 0xFF;
313 | 	}
314 | }
315 | void HT1632Class::fillAll() {
316 | 	for(uint8_t c = 0; c < NUM_CHANNEL; ++c) {
317 | 		for(uint8_t i = 0; i < ADDR_SPACE_SIZE; ++i) {
318 | 			mem[c][i] = 0xFF; // Needs to be redrawn
319 | 		}
320 | 	}
321 | }
322 | 
323 | void HT1632Class::clear(){
324 | 	for(uint8_t c = 0; c < NUM_CHANNEL; ++c) {
325 | 		for(uint8_t i = 0; i < ADDR_SPACE_SIZE; ++i) {
326 | 			mem[c][i] = 0x00; // Needs to be redrawn
327 | 		}
328 | 	}
329 | }
330 | 
331 | #if defined TYPE_3216_BICOLOR
332 | // Draw the contents of mem
333 | void HT1632Class::render() {
334 | 	if(_tgtRender >= _numActivePins) {
335 | 		return;
336 | 	}
337 | 
338 | 	// Write chip-by-chip:
339 | 	uint8_t _pinForCS = _pinCS[_tgtRender];
340 | 	
341 | 	for (uint8_t nChip = 0; nChip < NUM_ACTIVE_CHIPS; ++nChip) {
342 | 		// Select a single sub-chip:
343 | 		digitalWrite(_pinForCS, HIGH);
344 | 		for(uint8_t tmp = 0; tmp < NUM_ACTIVE_CHIPS; tmp++){
345 | 			if (tmp == nChip) {
346 | 				digitalWrite(_pinForCS, LOW);
347 | 				pulseCLK();
348 | 				digitalWrite(_pinForCS, HIGH);
349 | 			} else {
350 | 				pulseCLK();
351 | 			}
352 | 		}
353 | 		
354 | 		// Output data!
355 | 		writeData(HT1632_ID_WR, HT1632_ID_LEN);
356 | 		writeData(0, HT1632_ADDR_LEN); // Selecting the memory address
357 | 
358 | 		// Write the channels in order
359 | 		for(uint8_t c = 0; c < NUM_CHANNEL; ++c) {
360 | 			//for(uint8_t i = (nChip & 0b1)?0:(ADDR_SPACE_SIZE >> 1); i < (nChip & 0b1)?(ADDR_SPACE_SIZE >> 1):ADDR_SPACE_SIZE; ++i) {
361 | 			uint8_t i, iMax;
362 | 
363 | 			if(nChip & 0b1) { // If we're writing to the chips on the left
364 | 				i = 0; // Start from zero
365 | 				iMax = ADDR_SPACE_SIZE/2; // Stop at the halfway point.
366 | 			} else { // If we're writing to the chips on the right
367 | 				i = ADDR_SPACE_SIZE/2; // Start from the halfway point.
368 | 				iMax = ADDR_SPACE_SIZE; // Stop at the end of the buffer.
369 | 			}
370 | 
371 | 			// If we are not (top-row chip)
372 | 			if(!(nChip & 0b10)) {
373 | 				++i; // Write only odd-numbered bytes.
374 | 			}
375 | 
376 | 			for(; i < iMax; i+=2) { // Write every other byte.
377 | 				// Write the higher bits before the the lower bits.
378 | 				writeData(mem[c][i] >> HT1632_WORD_LEN, HT1632_WORD_LEN);
379 | 				writeData(mem[c][i], HT1632_WORD_LEN);
380 | 			}
381 | 		}
382 | 	}
383 | }
384 | #elif defined TYPE_3208_MONO
385 | // Draw the contents of mem
386 | void HT1632Class::render() {
387 | 	if(_tgtRender >= _numActivePins) {
388 | 		return;
389 | 	}
390 | 	
391 | 	select(0b0001 << _tgtRender); // Selecting the chip
392 | 	
393 | 	writeData(HT1632_ID_WR, HT1632_ID_LEN);
394 | 	writeData(0, HT1632_ADDR_LEN); // Selecting the memory address
395 | 
396 | 	// Write the channels in order
397 | 	for(uint8_t c = 0; c < NUM_CHANNEL; ++c) {
398 | 		for(uint8_t i = 0; i < ADDR_SPACE_SIZE; ++i) {
399 | 			// Write the higher bits before the the lower bits.
400 | 			writeData(mem[c][i] >> HT1632_WORD_LEN, HT1632_WORD_LEN); // Write the data in reverse.
401 | 			writeData(mem[c][i], HT1632_WORD_LEN); // Write the data in reverse.
402 | 		}
403 | 	}
404 | 
405 | 	select(); // Close the stream at the end
406 | }
407 | #elif defined TYPE_2416_MONO
408 | 	// Draw the contents of mem
409 | 	void HT1632Class::render() {
410 | 		if (_tgtRender >= _numActivePins) {
411 | 			return;
412 | 		}
413 | 
414 | 		select(0b0001 << _tgtRender); // Selecting the chip
415 | 
416 | 		writeData(HT1632_ID_WR, HT1632_ID_LEN);
417 | 		writeData(0, HT1632_ADDR_LEN); // Selecting the memory address
418 | 
419 | 									   // Write the channels in order
420 | 		for (uint8_t c = 0; c < NUM_CHANNEL; ++c) {
421 | 			for (uint8_t i = 0; i < ADDR_SPACE_SIZE; ++i) {
422 | 				// Write the higher bits before the the lower bits.
423 | 				writeData(mem[c][i] >> HT1632_WORD_LEN, HT1632_WORD_LEN); // Write the data in reverse.
424 | 				writeData(mem[c][i], HT1632_WORD_LEN); // Write the data in reverse.
425 | 			}
426 | 		}
427 | 
428 | 		select(); // Close the stream at the end
429 | 	}
430 | #endif
431 | 
432 | // Set the brightness to an integer level between 1 and 16 (inclusive).
433 | // Uses the PWM feature to set the brightness.
434 | void HT1632Class::setBrightness(char brightness, char selectionmask) {
435 | 	if(selectionmask == 0b00010000) {
436 | 		if(_tgtRender < _numActivePins) {
437 | 			selectionmask = 0b0001 << _tgtRender;
438 | 		} else {
439 | 			return;
440 | 		}
441 | 	}
442 | 	
443 | 	select(selectionmask); 
444 | 	writeData(HT1632_ID_CMD, HT1632_ID_LEN);    // Command mode
445 | 	writeCommand(HT1632_CMD_PWM(brightness));   // Set brightness
446 | 	select();
447 | }
448 | 
449 | 
450 | /*
451 |  * LOWER LEVEL FUNCTIONS
452 |  * Functions that directly talk to hardware go here:
453 |  */
454 |  
455 | void HT1632Class::writeCommand(char data) {
456 | 	writeData(data, HT1632_CMD_LEN);
457 | 	writeSingleBit();
458 | } 
459 | // Integer write to display. Used to write commands/addresses.
460 | // PRECONDITION: WR is LOW
461 | void HT1632Class::writeData(byte data, uint8_t len) {
462 | 	for(int j = len - 1, t = 1 << (len - 1); j >= 0; --j, t >>= 1){
463 | 		// Set the DATA pin to the correct state
464 | 		digitalWrite(_pinDATA, ((data & t) == 0)?LOW:HIGH);
465 | 		NOP(); // Delay 
466 | 		// Raise the WR momentarily to allow the device to capture the data
467 | 		digitalWrite(_pinWR, HIGH);
468 | 		NOP(); // Delay
469 | 		// Lower it again, in preparation for the next cycle.
470 | 		digitalWrite(_pinWR, LOW);
471 | 	}
472 | }
473 | 
474 | // Write single bit to display, used as padding between commands.
475 | // PRECONDITION: WR is LOW
476 | void HT1632Class::writeSingleBit() {
477 | 	// Set the DATA pin to the correct state
478 | 	digitalWrite(_pinDATA, LOW);
479 | 	NOP(); // Delay
480 | 	// Raise the WR momentarily to allow the device to capture the data
481 | 	digitalWrite(_pinWR, HIGH);
482 | 	NOP(); // Delay
483 | 	// Lower it again, in preparation for the next cycle.
484 | 	digitalWrite(_pinWR, LOW);
485 | }
486 | 
487 | void HT1632Class::setCLK(uint8_t pinCLK) {
488 | 	_pinCLK = pinCLK;
489 | 	pinMode(_pinCLK, OUTPUT);
490 | 	digitalWrite(_pinCLK, LOW);
491 | }
492 | 
493 | inline void HT1632Class::pulseCLK() {
494 | 	digitalWrite(_pinCLK, HIGH);
495 | 	NOP();
496 | 	digitalWrite(_pinCLK, LOW);
497 | }
498 | 
499 | #if defined TYPE_3216_BICOLOR
500 | // This is used to send initialization commands, and so selects all chips
501 | // in the selected board.
502 | void HT1632Class::select(uint8_t mask) {
503 | 	for(uint8_t i=0, t=1; i<_numActivePins; ++i, t <<= 1){
504 | 		digitalWrite(_pinCS[i], (t & mask)?LOW:HIGH);
505 | 	}
506 | 	for (uint8_t tmp = 0; tmp < NUM_ACTIVE_CHIPS; tmp++) {
507 | 		pulseCLK();
508 | 	}
509 | }
510 | #elif defined TYPE_3208_MONO
511 | // Choose a chip. This function sets the correct CS line to LOW, and the rest to HIGH
512 | // Call the function with no arguments to deselect all chips.
513 | // Call the function with a bitmask (0b4321) to select specific chips. 0b1111 selects all. 
514 | void HT1632Class::select(uint8_t mask) {
515 | 	for(uint8_t i=0, t=1; i<_numActivePins; ++i, t <<= 1){
516 | 		digitalWrite(_pinCS[i], (t & mask)?LOW:HIGH);
517 | 	}
518 | }
519 | #elif defined TYPE_2416_MONO
520 | // Choose a chip. This function sets the correct CS line to LOW, and the rest to HIGH
521 | // Call the function with no arguments to deselect all chips.
522 | // Call the function with a bitmask (0b4321) to select specific chips. 0b1111 selects all. 
523 | void HT1632Class::select(uint8_t mask) {
524 | 	for (uint8_t i = 0, t = 1; i<_numActivePins; ++i, t <<= 1) {
525 | 		digitalWrite(_pinCS[i], (t & mask) ? LOW : HIGH);
526 | 	}
527 | }
528 | #endif
529 | void HT1632Class::select() {
530 | 	select(0);
531 | }
532 | 
533 | HT1632Class HT1632;
534 | 


--------------------------------------------------------------------------------