diff --git a/examples/Example10_DefineChar/Example10_DefineChar.ino b/examples/Example10_DefineChar/Example10_DefineChar.ino new file mode 100644 index 0000000..6c34c5a --- /dev/null +++ b/examples/Example10_DefineChar/Example10_DefineChar.ino @@ -0,0 +1,65 @@ +/************************************************************************************** + * This example redefines some characters of an alphanumeric display. + * + * Written by Gaston Williams + * April 30, 2020 + * + * Based on code written by + * Priyanka Makin @ SparkFun Electronics + * Original Creation Date: February 26, 2020 + * + * SparkFun labored with love to create this code. Feel like supporting open source hardware? + * Buy a board from SparkFun! https://www.sparkfun.com/products/16426 + * + * This code is beerware; if you see me (or any other SparkFun employee) at the + * local, and you've found our code helpful, please buy us a round! + * + * Hardware Connections: + * Attach Red Board to computer using micro-B USB cable. + * Attach Qwiic Alphanumeric board to Red Board using Qwiic cable. + * Don't close any of the address jumpers so that it defaults to address 0x70. + * + * Distributed as-is; no warranty is given. + *****************************************************************************************/ +#include +HT16K33 display; + +void setup() { + Serial.begin(115200); + Serial.println("Qwiic Alphanumeric examples"); + Wire.begin(); //Join I2C bus + + //check if display will acknowledge + if (display.begin() == false) + { + Serial.println("Device did not acknowledge! Freezing."); + while(1); + } + Serial.println("Display acknowledged."); + + //Just for demo purposes, show original characters before change + display.print("cafe"); + delay(500); + display.print("size"); + + + //Update a, e, f, s and z to new characters + //This change is not permanent, and lasts only for this program. + + //Define 14 segment bits: nmlkjihgfedcba + display.defineChar('a', 0b01000001011000); + display.defineChar('e', 0b10000001011000); + display.defineChar('f', 0b01010101000000); + //Also can use constants SEG_A - SEG_N to define characters + display.defineChar('s', SEG_L | SEG_I | SEG_D); // 0b00100100001000 + display.defineChar('z', SEG_N | SEG_G | SEG_D); // 0b10000001001000 +} + +void loop() +{ + //Show the new characters + delay(500); + display.print("cafe"); + delay(500); + display.print("size"); +} diff --git a/examples/Example7_unkownChar/Example7_unkownChar.ino b/examples/Example7_unkownChar/Example7_unkownChar.ino index 77918ed..0d74022 100644 --- a/examples/Example7_unkownChar/Example7_unkownChar.ino +++ b/examples/Example7_unkownChar/Example7_unkownChar.ino @@ -3,6 +3,7 @@ * * Priyanka Makin @ SparkFun Electronics * Original Creation Date: March 13, 2020 + * Updated April 30, 2020 by Gaston Williams - changed exclamation to tab character * * SparkFun labored with love to create this code. Feel like supporting open source hardware? * Buy a board from SparkFun! https://www.sparkfun.com/products/16391 @@ -34,7 +35,7 @@ void setup() { } Serial.println("Display acknowledged."); - display.print("!!!!"); + display.print("\t\t\t\t"); //tabs are not printable characters } void loop() diff --git a/library.properties b/library.properties index 3b6f24b..1b4bcc1 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SparkFun Qwiic Alphanumeric Display Arduino Library -version=v1.0.1 +version=v1.1.1 author=SparkFun Electronics maintainer=SparkFun Electronics sentence=A library to drive the Holtek HT16K33 LED Driver with an Alphanumeric Display. diff --git a/src/SparkFun_Alphanumeric_Display.cpp b/src/SparkFun_Alphanumeric_Display.cpp index ea319a4..b92ce28 100644 --- a/src/SparkFun_Alphanumeric_Display.cpp +++ b/src/SparkFun_Alphanumeric_Display.cpp @@ -5,6 +5,8 @@ Priyanka Makin @ SparkFun Electronics Original Creation Date: February 25, 2020 https://github.com/sparkfun/SparkFun_Alphanumeric_Display_Arduino_Library +Updated May 2, 2020 by Gaston Williams to add defineChar function + Pickup a board here: https://sparkle.sparkfun.com/sparkle/storefront_products/16391 This file implements all functions of the HT16K33 class. Functions here range @@ -12,8 +14,8 @@ from printing to one or more Alphanumeric Displays, changing the display setting reading the RAM of the HT16K33. The Holtek HT16K33 seems to be susceptible to address changes intra-sketch. The ADR pins -are muxed with the ROW and COM drivers so as semgents are turned on/off that affect -the ADR1/ADR0 pins the address has been seen to change. The best way around this is +are muxed with the ROW and COM drivers so as semgents are turned on/off that affect +the ADR1/ADR0 pins the address has been seen to change. The best way around this is to do a isConnected check before updateRAM() is sent to the driver IC. Development environment specifics: @@ -27,8 +29,113 @@ local, and you've found our code helpful, please buy us a round! Distributed as-is; no warranty is given. ******************************************************************************/ +#include #include +/*--------------------------- Character Map ----------------------------------*/ +#define SFE_ALPHANUM_UNKNOWN_CHAR 95 + +//This is the lookup table of segments for various characters +static const uint16_t PROGMEM alphanumeric_segs[96]{ + //nmlkjihgfedcba + 0b00000000000000, //' ' (space) + 0b00001000001000, //'!' - added to map + 0b00001000000010, //'"' - added to map + 0b1001101001110, //'#' + 0b1001101101101, //'$' + 0b10010000100100, //'%' + 0b110011011001, //'&' + 0b1000000000, //''' + 0b111001, //'(' + 0b1111, //')' + 0b11111010000000, //'*' + 0b1001101000000, //'+' + 0b10000000000000, //',' + 0b101000000, //'-' + 0b00000000000000, //'.' - changed to blank + 0b10010000000000, //'/' + 0b111111, //'0' + 0b10000000110, //'1' + 0b101011011, //'2' + 0b101001111, //'3' + 0b101100110, //'4' + 0b101101101, //'5' + 0b101111101, //'6' + 0b1010000000001, //'7' + 0b101111111, //'8' + 0b101100111, //'9' + 0b00000000000000, //':' - changed to blank + 0b10001000000000, //';' + 0b110000000000, //'<' + 0b101001000, //'=' + 0b01000010000000, //'>' + 0b01000100000011, //'?' - Added to map + 0b00001100111011, //'@' - Added to map + 0b101110111, //'A' + 0b1001100001111, //'B' + 0b111001, //'C' + 0b1001000001111, //'D' + 0b101111001, //'E' + 0b101110001, //'F' + 0b100111101, //'G' + 0b101110110, //'H' + 0b1001000001001, //'I' + 0b11110, //'J' + 0b110001110000, //'K' + 0b111000, //'L' + 0b10010110110, //'M' + 0b100010110110, //'N' + 0b111111, //'O' + 0b101110011, //'P' + 0b100000111111, //'Q' + 0b100101110011, //'R' + 0b110001101, //'S' + 0b1001000000001, //'T' + 0b111110, //'U' + 0b10010000110000, //'V' + 0b10100000110110, //'W' + 0b10110010000000, //'X' + 0b1010010000000, //'Y' + 0b10010000001001, //'Z' + 0b111001, //'[' + 0b100010000000, //'\' + 0b1111, //']' + 0b10100000000000, //'^' - Added to map + 0b1000, //'_' + 0b10000000, //'`' + 0b101011111, //'a' + 0b100001111000, //'b' + 0b101011000, //'c' + 0b10000100001110, //'d' + 0b1111001, //'e' + 0b1110001, //'f' + 0b110001111, //'g' + 0b101110100, //'h' + 0b1000000000000, //'i' + 0b1110, //'j' + 0b1111000000000, //'k' + 0b1001000000000, //'l' + 0b1000101010100, //'m' + 0b100001010000, //'n' + 0b101011100, //'o' + 0b10001110001, //'p' + 0b100101100011, //'q' + 0b1010000, //'r' + 0b110001101, //'s' + 0b1111000, //'t' + 0b11100, //'u' + 0b10000000010000, //'v' + 0b10100000010100, //'w' + 0b10110010000000, //'x' + 0b1100001110, //'y' + 0b10010000001001, //'z' + 0b10000011001001, //'{' + 0b1001000000000, //'|' + 0b110100001001, //'}' + 0b00000101010010, //'~' - Added to map + 0b11111111111111, //Unknown character (DEL or RUBOUT) +}; + /*--------------------------- Device Status----------------------------------*/ bool HT16K33::begin(uint8_t addressLeft, uint8_t addressLeftCenter, uint8_t addressRightCenter, uint8_t addressRight, TwoWire &wirePort) @@ -392,7 +499,7 @@ bool HT16K33::decimalOn() status = false; } - Serial.println(status); + //Serial.println(status); return status; } @@ -457,7 +564,7 @@ bool HT16K33::colonOn() bool HT16K33::colonOff() { bool status = true; - + colonOnOff = ALPHA_COLON_OFF; for (uint8_t i = 0; i < numberOfDisplays; i++) @@ -527,135 +634,26 @@ void HT16K33::illuminateChar(uint16_t segmentsToTurnOn, uint8_t digit) } } -#define SFE_ALPHANUM_UNKNOWN_CHAR 89 - -//This is the lookup table of segments for various characters +//Show a character on display void HT16K33::printChar(uint8_t displayChar, uint8_t digit) { - - static uint16_t alphanumeric_segs[90]{ - 0b00000000000000, //' ' (space) - - 0b1001101001110, //'#' - 0b1001101101101, //'$' - 0b10010000100100, //'%' - 0b110011011001, //'&' - 0b1000000000, //''' - 0b111001, //'(' - 0b1111, //')' - 0b11111010000000, //'*' - 0b1001101000000, //'+' - 0b10000000000000, //',' - 0b101000000, //'-' - 0b10, //'.' - DEBUG: need to test - 0b10010000000000, //'/' - 0b111111, //'0' - 0b10000000110, //'1' - 0b101011011, //'2' - 0b101001111, //'3' - 0b101100110, //'4' - 0b101101101, //'5' - 0b101111101, //'6' - 0b1010000000001, //'7' - 0b101111111, //'8' - 0b101100111, //'9' - 0b1, //':' - DEBUG: need to test - 0b10001000000000, //';' - 0b110000000000, //'<' - 0b101001000, //'=' - 0b10000010000000, //'>' - - 0b101110111, //'A' - 0b1001100001111, //'B' - 0b111001, //'C' - 0b1001000001111, //'D' - 0b101111001, //'E' - 0b101110001, //'F' - 0b100111101, //'G' - 0b101110110, //'H' - 0b1001000001001, //'I' - 0b11110, //'J' - 0b110001110000, //'K' - 0b111000, //'L' - 0b10010110110, //'M' - 0b100010110110, //'N' - 0b111111, //'O' - 0b101110011, //'P' - 0b100000111111, //'Q' - 0b100101110011, //'R' - 0b110001101, //'S' - 0b1001000000001, //'T' - 0b111110, //'U' - 0b10010000110000, //'V' - 0b10100000110110, //'W' - 0b10110010000000, //'X' - 0b1010010000000, //'Y' - 0b10010000001001, //'Z' - 0b111001, //'[' - 0b100010000000, //'\' - 0b1111, //']' - - 0b1000, //'_' - 0b10000000, //'`' - 0b101011111, //'a' - 0b100001111000, //'b' - 0b101011000, //'c' - 0b10000100001110, //'d' - 0b1111001, //'e' - 0b1110001, //'f' - 0b110001111, //'g' - 0b101110100, //'h' - 0b1000000000000, //'i' - 0b1110, //'j' - 0b1111000000000, //'k' - 0b1001000000000, //'l' - 0b1000101010100, //'m' - 0b100001010000, //'n' - 0b101011100, //'o' - 0b10001110001, //'p' - 0b100101100011, //'q' - 0b1010000, //'r' - 0b110001101, //'s' - 0b1111000, //'t' - 0b11100, //'u' - 0b10000000010000, //'v' - 0b10100000010100, //'w' - 0b10110010000000, //'x' - 0b1100001110, //'y' - 0b10010000001001, //'z' - 0b10000011001001, //'{' - 0b1001000000000, //'|' - 0b110100001001, //'}' - - 0b11111111111111, //Unknown character - }; - + //moved alphanumeric_segs array to PROGMEM uint16_t characterPosition = 65532; //space if (displayChar == ' ') characterPosition = 0; - //Symbols - else if (displayChar >= '#' && displayChar <= '>') - { - characterPosition = displayChar - '#' + 1; - } - //Upper case letters + symbols - else if (displayChar >= 'A' && displayChar <= ']') - { - characterPosition = displayChar - 'A' + 1 + 28; - } - //Symbols + lower case letters - else + //Printable Symbols + else if (displayChar >= '!' && displayChar <= '~') { - characterPosition = displayChar - '_' + 1 + 28 + 29; + characterPosition = displayChar - '!' + 1; } uint8_t dispNum = digitPosition / 4; //Take care of special characters - if (characterPosition == 12) //'.' + if (characterPosition == 14) //'.' decimalOnSingle(dispNum); - if (characterPosition == 24) //':' + if (characterPosition == 26) //':' colonOnSingle(dispNum); if (characterPosition == 65532) //unknown character characterPosition = SFE_ALPHANUM_UNKNOWN_CHAR; @@ -664,7 +662,79 @@ void HT16K33::printChar(uint8_t displayChar, uint8_t digit) // if (characterPosition > sizeof(alphanumeric_segs)) // characterPosition = sizeof(alphanumeric_segs) - 1; //Unknown char - illuminateChar(alphanumeric_segs[characterPosition], digit); + uint16_t segmentsToTurnOn = getSegmentsToTurnOn(characterPosition); + + illuminateChar(segmentsToTurnOn, digit); +} + +//Update the list to define a new segments display for a particular character +bool HT16K33::defineChar(uint8_t displayChar, uint16_t segmentsToTurnOn) +{ + bool result = false; + + //Check to see if character is within range of displayable ASCII characters + if (displayChar >= '!' && displayChar <= '~') + { + //Get the index of character in table and update its 14-bit segment value + uint16_t characterPosition = displayChar - '!' + 1; + + //Create a new character definition + struct CharDef * pNewCharDef = calloc(1, sizeof(CharDef)); + + //Set the position to the table index + pNewCharDef -> position = characterPosition; + //Mask the segment value to 14 bits only + pNewCharDef -> segments = segmentsToTurnOn & 0x3FFF; + //New definition always goes at the end of the list + pNewCharDef -> next = NULL; + + //If list is empty set it to the new item + if (pCharDefList == NULL) + { + pCharDefList = pNewCharDef; + } + else + { + //Otherwise go to the end of the list and add it there + struct CharDef * pTail = pCharDefList; + + while(pTail->next != NULL) + { + pTail = pTail->next; + } + + pTail->next = pNewCharDef; + } + //We added the definition so we're all good + result = true; + } + return result; +} + +//Get the character map from the definition list or default table +uint16_t HT16K33::getSegmentsToTurnOn(uint8_t charPos) +{ + uint16_t segments = 0; + //pointer to a defined character in list + struct CharDef * pDefChar = pCharDefList; + + //Search the chacters list for a match + while(pDefChar && (pDefChar->position != charPos)) + { + pDefChar = pDefChar -> next; + } + + //If we found a match return that value + if (pDefChar != NULL) + { + segments = pDefChar -> segments; + } + //Otherwise get the value from the table + else + { + segments = pgm_read_word_near(alphanumeric_segs + charPos); + } + return segments; } /* diff --git a/src/SparkFun_Alphanumeric_Display.h b/src/SparkFun_Alphanumeric_Display.h index 117f6c6..e20d71b 100644 --- a/src/SparkFun_Alphanumeric_Display.h +++ b/src/SparkFun_Alphanumeric_Display.h @@ -5,6 +5,8 @@ Priyanka Makin @ SparkFun Electronics Original Creation Date: July 25, 2019 https://github.com/sparkfun/SparkFun_Alphanumeric_Display_Arduino_Library +Updated April 30, 2020 by Gaston Williams to add defineChar function + Pickup a board here: https://sparkle.sparkfun.com/sparkle/storefront_products/16391 This file prototypes the HT16K33 class, implemented in SparkFun_Alphanumeric_Display.cpp. @@ -29,6 +31,23 @@ Distributed as-is; no warranty is given. // #define DEV_ID 0x12 //Device ID that I just made up #define DEFAULT_NOTHING_ATTACHED 0xFF +//Define constants for segment bits +#define SEG_A 0x0001 +#define SEG_B 0x0002 +#define SEG_C 0x0004 +#define SEG_D 0x0008 +#define SEG_E 0x0010 +#define SEG_F 0x0020 +#define SEG_G 0x0040 +#define SEG_H 0x0080 +#define SEG_I 0x0100 +#define SEG_J 0x0200 +#define SEG_K 0x0400 +#define SEG_L 0x0800 +#define SEG_M 0x1000 +#define SEG_N 0x2000 + + typedef enum { ALPHA_BLINK_RATE_NOBLINK = 0b00, @@ -62,6 +81,13 @@ typedef enum ALPHA_CMD_DIMMING_SETUP = 0b11100000, } alpha_command_t; +//Structure for defining new character displays +struct CharDef { + uint8_t position; + int16_t segments; + struct CharDef * next; +}; + // class HT16K33 class HT16K33 : public Print { @@ -82,6 +108,9 @@ class HT16K33 : public Print uint8_t displayRAM[16 * 4]; char displayContent[4 * 4 + 1] = ""; + //Linked List of character definitions + struct CharDef * pCharDefList = NULL; + public: //Device status bool begin(uint8_t addressLeft = DEFAULT_ADDRESS, @@ -119,6 +148,10 @@ class HT16K33 : public Print void printChar(uint8_t displayChar, uint8_t digit); bool updateDisplay(); + //Define Character Segment Map + bool defineChar(uint8_t displayChar, uint16_t segmentsToTurnOn); + uint16_t getSegmentsToTurnOn (uint8_t charPos); + //Colon and decimal bool decimalOn(); bool decimalOff();