123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923 |
- /******************************************************************************
- SparkFun_Alphanumeric_Display.cpp
- SparkFun Alphanumeric Display Library Source File
- 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
- from printing to one or more Alphanumeric Displays, changing the display settings, and writing/
- 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
- to do a isConnected check before updateRAM() is sent to the driver IC.
- Development environment specifics:
- IDE: Arduino 1.8.9
- Hardware Platform: Arduino Uno
- Alphanumeric Display Breakout Version: 1.0.0
- 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!
- Distributed as-is; no warranty is given.
- ******************************************************************************/
- #include <SparkFun_Alphanumeric_Display.h>
- /*--------------------------- Character Map ----------------------------------*/
- #define SFE_ALPHANUM_UNKNOWN_CHAR 95
- //This is the lookup table of segments for various characters
- //For AVR architecture, use PROGMEM
- #if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)
- #include <avr/pgmspace.h>
- static const uint16_t PROGMEM alphanumeric_segs[96]{
- #else
- static const uint16_t alphanumeric_segs[96]{
- #endif
- // nmlkjihgfedcba
- 0b00000000000000, // ' ' (space)
- 0b00001000001000, // '!'
- 0b00001000000010, // '"'
- 0b01001101001110, // '#'
- 0b01001101101101, // '$'
- 0b10010000100100, // '%'
- 0b00110011011001, // '&'
- 0b00001000000000, // '''
- 0b00000000111001, // '('
- 0b00000000001111, // ')'
- 0b11111010000000, // '*'
- 0b01001101000000, // '+'
- 0b10000000000000, // ','
- 0b00000101000000, // '-'
- 0b00000000000000, // '.'
- 0b10010000000000, // '/'
- 0b00000000111111, // '0'
- 0b00010000000110, // '1'
- 0b00000101011011, // '2'
- 0b00000101001111, // '3'
- 0b00000101100110, // '4'
- 0b00000101101101, // '5'
- 0b00000101111101, // '6'
- 0b01010000000001, // '7'
- 0b00000101111111, // '8'
- 0b00000101100111, // '9'
- 0b00000000000000, // ':'
- 0b10001000000000, // ';'
- 0b00110000000000, // '<'
- 0b00000101001000, // '='
- 0b01000010000000, // '>'
- 0b01000100000011, // '?'
- 0b00001100111011, // '@'
- 0b00000101110111, // 'A'
- 0b01001100001111, // 'B'
- 0b00000000111001, // 'C'
- 0b01001000001111, // 'D'
- 0b00000101111001, // 'E'
- 0b00000101110001, // 'F'
- 0b00000100111101, // 'G'
- 0b00000101110110, // 'H'
- 0b01001000001001, // 'I'
- 0b00000000011110, // 'J'
- 0b00110001110000, // 'K'
- 0b00000000111000, // 'L'
- 0b00010010110110, // 'M'
- 0b00100010110110, // 'N'
- 0b00000000111111, // 'O'
- 0b00000101110011, // 'P'
- 0b00100000111111, // 'Q'
- 0b00100101110011, // 'R'
- 0b00000110001101, // 'S'
- 0b01001000000001, // 'T'
- 0b00000000111110, // 'U'
- 0b10010000110000, // 'V'
- 0b10100000110110, // 'W'
- 0b10110010000000, // 'X'
- 0b01010010000000, // 'Y'
- 0b10010000001001, // 'Z'
- 0b00000000111001, // '['
- 0b00100010000000, // '\'
- 0b00000000001111, // ']'
- 0b10100000000000, // '^'
- 0b00000000001000, // '_'
- 0b00000010000000, // '`'
- 0b00000101011111, // 'a'
- 0b00100001111000, // 'b'
- 0b00000101011000, // 'c'
- 0b10000100001110, // 'd'
- 0b00000001111001, // 'e'
- 0b00000001110001, // 'f'
- 0b00000110001111, // 'g'
- 0b00000101110100, // 'h'
- 0b01000000000000, // 'i'
- 0b00000000001110, // 'j'
- 0b01111000000000, // 'k'
- 0b01001000000000, // 'l'
- 0b01000101010100, // 'm'
- 0b00100001010000, // 'n'
- 0b00000101011100, // 'o'
- 0b00010001110001, // 'p'
- 0b00100101100011, // 'q'
- 0b00000001010000, // 'r'
- 0b00000110001101, // 's'
- 0b00000001111000, // 't'
- 0b00000000011100, // 'u'
- 0b10000000010000, // 'v'
- 0b10100000010100, // 'w'
- 0b10110010000000, // 'x'
- 0b00001100001110, // 'y'
- 0b10010000001001, // 'z'
- 0b10000011001001, // '{'
- 0b01001000000000, // '|'
- 0b00110100001001, // '}'
- 0b00000101010010, // '~'
- 0b11111111111111, // Unknown character (DEL or RUBOUT)
- };
- /*--------------------------- Device Status----------------------------------*/
- bool HT16K33::begin(uint8_t addressDisplayOne, uint8_t addressDisplayTwo, uint8_t addressDisplayThree, uint8_t addressDisplayFour, TwoWire &wirePort)
- {
- _deviceAddressDisplayOne = addressDisplayOne; // grab the address of the alphanumeric
- _deviceAddressDisplayTwo = addressDisplayTwo;
- _deviceAddressDisplayThree = addressDisplayThree;
- _deviceAddressDisplayFour = addressDisplayFour;
- if (_deviceAddressDisplayFour != DEFAULT_NOTHING_ATTACHED)
- numberOfDisplays = 4;
- else if (_deviceAddressDisplayThree != DEFAULT_NOTHING_ATTACHED)
- numberOfDisplays = 3;
- else if (_deviceAddressDisplayTwo != DEFAULT_NOTHING_ATTACHED)
- numberOfDisplays = 2;
- else
- numberOfDisplays = 1;
- //TODO: malloc more displayRAM
- _i2cPort = &wirePort; // Remember the user's setting
- for (uint8_t i = 1; i <= numberOfDisplays; i++)
- {
-
- if (isConnected(i) == false)
- {
- return false;
- }
- // if (checkDeviceID(i) == false)
- // {
- // Serial.println(i);
- // Serial.println("Hello, I've failed checkDeviceID()");
- // return false;
- // }
- delay(100);
- }
- if (initialize() == false)
- {
- return false;
- }
- if (clear() == false) // Clear all displays
- {
- return false;
- }
- displayContent[4 * 4] = '\0'; // Terminate the array because we are doing direct prints
- return true;
- }
- // Check that the display is responding on the I2C bus
- // The Holtek IC sometimes fails to respond. This attempts multiple times before giving up.
- bool HT16K33::isConnected(uint8_t displayNumber)
- {
- uint8_t triesBeforeGiveup = 5;
- for (uint8_t x = 0; x < triesBeforeGiveup; x++)
- {
-
- _i2cPort->beginTransmission(lookUpDisplayAddress(displayNumber));
- if (_i2cPort->endTransmission() == 0)
- {
- return true;
- }
- delay(100);
- }
- return false;
- }
- // Run through initialization procedure for each display connected on the bus
- bool HT16K33::initialize()
- {
- // Turn on system clock of all displays
- if (enableSystemClock() == false)
- {
- return false;
- }
- // Set brightness of all displays to full brightness
- if (setBrightness(15) == false)
- {
- return false;
- }
- // Turn blinking off for all displays
- if (setBlinkRate(ALPHA_BLINK_RATE_NOBLINK) == false)
- {
- return false;
- }
- // Turn on all displays
- if (displayOn() == false)
- {
- return false;
- }
- return true;
- }
- // Turn on the system oscillator for all displays on the I2C bus
- bool HT16K33::enableSystemClock()
- {
- bool status = true;
- for (uint8_t i = 1; i <= numberOfDisplays; i++)
- {
- if (enableSystemClockSingle(i) == false)
- status = false;
- }
- return status;
- }
- // Turn off the system oscillator for all displays on the bus
- bool HT16K33::disableSystemClock()
- {
- bool status = true;
- for (uint8_t i = 1; i <= numberOfDisplays; i++)
- {
- if (disableSystemClockSingle(i) == false)
- status = false;
- }
- return status;
- }
- // Turn on the system oscillator for normal operation mode
- bool HT16K33::enableSystemClockSingle(uint8_t displayNumber)
- {
- uint8_t dataToWrite = ALPHA_CMD_SYSTEM_SETUP | 1; // Enable system clock
- bool status = writeRAM(lookUpDisplayAddress(displayNumber), dataToWrite);
- delay(1); // Allow display to start
- return (status);
- }
- // Turn off the system oscillator for standby mode
- bool HT16K33::disableSystemClockSingle(uint8_t displayNumber)
- {
- uint8_t dataToWrite = ALPHA_CMD_SYSTEM_SETUP | 0; // Standby mode
- return (writeRAM(lookUpDisplayAddress(displayNumber), dataToWrite));
- }
- // This function connects the display number to its coressponding address
- uint8_t HT16K33::lookUpDisplayAddress(uint8_t displayNumber)
- {
- switch (displayNumber)
- {
- case 1:
- return _deviceAddressDisplayOne;
- break;
- case 2:
- return _deviceAddressDisplayTwo;
- break;
- case 3:
- return _deviceAddressDisplayThree;
- break;
- case 4:
- return _deviceAddressDisplayFour;
- break;
- }
- return 0; // We shouldn't get here
- }
- /*-------------------------- Display configuration functions ---------------------------*/
- // Turn off all segments of all displays connected to bus
- bool HT16K33::clear()
- {
- // Clear the displayRAM array
- for (uint8_t i = 0; i < 16 * numberOfDisplays; i++)
- displayRAM[i] = 0;
- digitPosition = 0;
- return (updateDisplay());
- }
- // This function sets the brightness of all displays on the bus.
- // Duty cycle valid between 0 (1/16 brightness) and 15 (full brightness)
- bool HT16K33::setBrightness(uint8_t duty)
- {
- bool status = true;
- for (uint8_t i = 1; i <= numberOfDisplays; i++)
- {
- if (setBrightnessSingle(i, duty) == false)
- status = false;
- }
- return status;
- }
- // Set the brightness of a single display
- // Duty cycle valid between 0 (1/16 brightness) and 15 (full brightness)
- bool HT16K33::setBrightnessSingle(uint8_t displayNumber, uint8_t duty)
- {
- if (duty > 15) // Error check
- duty = 15;
- uint8_t dataToWrite = ALPHA_CMD_DIMMING_SETUP | duty;
- return (writeRAM(lookUpDisplayAddress(displayNumber), dataToWrite));
- }
- // Set the blink rate of all displays on the bus
- // Parameter "rate" in Hz
- // Valid options for "rate" are defined by datasheet: 2.0, 1.0, or 0.5 Hz
- // Any other input to this function will result in steady alphanumeric display
- bool HT16K33::setBlinkRate(float rate)
- {
- bool status = true;
- for (uint8_t i = 1; i <= numberOfDisplays; i++)
- {
- if (setBlinkRateSingle(i, rate) == false)
- status = false;
- }
- return status;
- }
- // Set the blink rate of a single display on the bus
- // Parameter "rate" is in Hz
- // Valid options for "rate" are defined by datasheet: 2.0, 1.0, or 0.5 Hz
- // Any other input to this function will result in steady alphanumeric display
- bool HT16K33::setBlinkRateSingle(uint8_t displayNumber, float rate)
- {
- if (rate == 2.0)
- {
- blinkRate = ALPHA_BLINK_RATE_2HZ;
- }
- else if (rate == 1.0)
- {
- blinkRate = ALPHA_BLINK_RATE_1HZ;
- }
- else if (rate == 0.5)
- {
- blinkRate = ALPHA_BLINK_RATE_0_5HZ;
- }
- //default to no blink
- else
- {
- blinkRate = ALPHA_BLINK_RATE_NOBLINK;
- }
- uint8_t dataToWrite = ALPHA_CMD_DISPLAY_SETUP | (blinkRate << 1) | displayOnOff;
- return (writeRAM(lookUpDisplayAddress(displayNumber), dataToWrite));
- }
- // Turn a single alphanumeric display on
- bool HT16K33::displayOnSingle(uint8_t displayNumber)
- {
- return setDisplayOnOff(displayNumber, true);
- }
- // Turn a single alphanumeric display off
- bool HT16K33::displayOffSingle(uint8_t displayNumber)
- {
- return setDisplayOnOff(displayNumber, false);
- }
- // Set or clear the display on/off bit of a given display number
- bool HT16K33::setDisplayOnOff(uint8_t displayNumber, bool turnOnDisplay)
- {
- if (turnOnDisplay) {
- displayOnOff = ALPHA_DISPLAY_ON;
- }
- else {
- displayOnOff = ALPHA_DISPLAY_OFF;
- }
- uint8_t dataToWrite = ALPHA_CMD_DISPLAY_SETUP | (blinkRate << 1) | displayOnOff;
- return (writeRAM(lookUpDisplayAddress(displayNumber), dataToWrite));
- }
- // Turn on all displays on the I2C bus
- bool HT16K33::displayOn()
- {
- bool status = true;
- displayOnOff = ALPHA_DISPLAY_ON;
- for (uint8_t i = 1; i <= numberOfDisplays; i++)
- {
- if (displayOnSingle(i) == false)
- status = false;
- }
- return status;
- }
- // Turn off all displays on the I2C bus
- bool HT16K33::displayOff()
- {
- bool status = true;
- displayOnOff = ALPHA_DISPLAY_OFF;
- for (uint8_t i = 1; i <= numberOfDisplays; i++)
- {
- if (displayOffSingle(i) == false)
- status = false;
- }
- return status;
- }
- // Turn the decimal point on for a single display
- bool HT16K33::decimalOnSingle(uint8_t displayNumber, bool updateNow)
- {
- return setDecimalOnOff(displayNumber, true, updateNow);
- }
- // Turn the decimal point off for a single display
- bool HT16K33::decimalOffSingle(uint8_t displayNumber, bool updateNow)
- {
- return setDecimalOnOff(displayNumber, false, updateNow);
- }
- // Set or clear the decimal on/off bit
- bool HT16K33::setDecimalOnOff(uint8_t displayNumber, bool turnOnDecimal, bool updateNow)
- {
- uint8_t adr = 0x03;
- uint8_t dat;
- if (turnOnDecimal == true)
- {
- decimalOnOff = ALPHA_DECIMAL_ON;
- dat = 0x01;
- }
- else
- {
- decimalOnOff = ALPHA_DECIMAL_OFF;
- dat = 0x00;
- }
- displayRAM[adr + (displayNumber - 1) * 16] = displayRAM[adr + (displayNumber - 1) * 16] | dat;
- if(updateNow)
- {
- return updateDisplay();
- }
- else
- {
- return true;
- }
- }
- // Turn the decimal on for all displays on bus
- bool HT16K33::decimalOn()
- {
- bool status = true;
- decimalOnOff = ALPHA_DECIMAL_ON;
- for (uint8_t i = 1; i <= numberOfDisplays; i++)
- {
- if (decimalOnSingle(i) == false)
- status = false;
- }
- return status;
- }
- // Turn the decimal point off for all displays on bus
- bool HT16K33::decimalOff()
- {
- bool status = true;
- decimalOnOff = ALPHA_DECIMAL_OFF;
- for (uint8_t i = 1; i <= numberOfDisplays; i++)
- {
- if (decimalOffSingle(i) == false)
- status = false;
- }
- return status;
- }
- // Turn the colon on for a single display
- bool HT16K33::colonOnSingle(uint8_t displayNumber, bool updateNow)
- {
- return setColonOnOff(displayNumber, true, updateNow);
- }
- // Turn the colon off for a single display
- bool HT16K33::colonOffSingle(uint8_t displayNumber, bool updateNow)
- {
- return setColonOnOff(displayNumber, false, updateNow);
- }
- // Set or clear the colon on/off bit
- bool HT16K33::setColonOnOff(uint8_t displayNumber, bool turnOnColon, bool updateNow)
- {
- uint8_t adr = 0x01;
- uint8_t dat;
- if (turnOnColon == true)
- {
- colonOnOff = ALPHA_COLON_ON;
- dat = 0x01;
- }
- else
- {
- colonOnOff = ALPHA_COLON_OFF;
- dat = 0x00;
- }
- displayRAM[adr + (displayNumber - 1) * 16] = displayRAM[adr + (displayNumber - 1) * 16] | dat;
- if(updateNow)
- {
- return updateDisplay();
- }
- else
- {
- return true;
- }
- }
- // Turn the colon on for all displays on the bus
- bool HT16K33::colonOn()
- {
- bool status = true;
- colonOnOff = ALPHA_COLON_ON;
- for (uint8_t i = 1; i <= numberOfDisplays; i++)
- {
- if (colonOnSingle(i) == false)
- status = false;
- }
- return status;
- }
- // Turn the colon off for all displays on the bus
- bool HT16K33::colonOff()
- {
- bool status = true;
- colonOnOff = ALPHA_COLON_OFF;
- for (uint8_t i = 1; i <= numberOfDisplays; i++)
- {
- if (colonOffSingle(i) == false)
- status = false;
- }
- return status;
- }
- /*---------------------------- Light up functions ---------------------------------*/
- // Given a segment and a digit, set the matching bit within the RAM of the Holtek RAM set
- void HT16K33::illuminateSegment(uint8_t segment, uint8_t digit)
- {
- uint8_t com;
- uint8_t row;
- com = segment - 'A'; // Convert the segment letter back to a number
- if (com > 6)
- com -= 7;
- if (segment == 'I')
- com = 0;
- if (segment == 'H')
- com = 1;
- row = digit % 4; // Convert digit (1 to 16) back to a relative position on a given digit on display
- if (segment > 'G')
- row += 4;
- uint8_t offset = digit / 4 * 16;
- uint8_t adr = com * 2 + offset;
- // Determine the address
- if (row > 7)
- adr++;
- // Determine the data bit
- if (row > 7)
- row -= 8;
- uint8_t dat = 1 << row;
- displayRAM[adr] = displayRAM[adr] | dat;
- }
- // Given a binary set of segments and a digit, store this data into the RAM array
- void HT16K33::illuminateChar(uint16_t segmentsToTurnOn, uint8_t digit)
- {
- for (uint8_t i = 0; i < 14; i++) // There are 14 segments on this display
- {
- if ((segmentsToTurnOn >> i) & 0b1)
- illuminateSegment('A' + i, digit); // Convert the segment number to a letter
- }
- }
- // Print a character, for a given digit, on display
- void HT16K33::printChar(uint8_t displayChar, uint8_t digit)
- {
- // moved alphanumeric_segs array to PROGMEM
- uint16_t characterPosition = 65532;
- // space
- if (displayChar == ' ')
- characterPosition = 0;
- // Printable Symbols -- Between first character ! and last character ~
- else if (displayChar >= '!' && displayChar <= '~')
- {
- characterPosition = displayChar - '!' + 1;
- }
- uint8_t dispNum = digitPosition / 4;
- // Take care of special characters by turning correct segment on
- if (characterPosition == 14) // '.'
- decimalOnSingle(dispNum+1, false);
- if (characterPosition == 26) // ':'
- colonOnSingle(dispNum+1, false);
- if (characterPosition == 65532) // unknown character
- characterPosition = SFE_ALPHANUM_UNKNOWN_CHAR;
- 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 = (CharDef *)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;
- }
- /*
- * Write a byte to the display.
- * Required for overloading the Print function.
- */
- size_t HT16K33::write(uint8_t b)
- {
- // If user wants to print '.' or ':', don't increment the digitPosition!
- if (b == '.' || b == ':')
- printChar(b, 0);
- else
- {
- printChar(b, digitPosition++);
- digitPosition %= (numberOfDisplays * 4); // Convert displays to number of digits
- }
- return (updateDisplay()); // Send RAM buffer over I2C bus
- }
- /*
- * Write a character buffer to the display.
- * Required for overloading the Print function.
- */
- size_t HT16K33::write(const uint8_t *buffer, size_t size)
- {
- size_t n = size;
- uint8_t buff;
- // Clear the displayRAM array
- for (uint8_t i = 0; i < 16 * numberOfDisplays; i++)
- displayRAM[i] = 0;
- digitPosition = 0;
- while (size--)
- {
- buff = *buffer++;
- // For special characters like '.' or ':', do not increment the digitPosition
- if (buff == '.')
- printChar('.', 0);
- else if (buff == ':')
- printChar(':', 0);
- else
- {
- printChar(buff, digitPosition);
- displayContent[digitPosition] = buff; // Record to internal array
- digitPosition++;
- digitPosition %= (numberOfDisplays * 4);
- }
- }
- updateDisplay(); // Send RAM buffer over I2C bus
- return n;
- }
- /*
- * Write a string to the display.
- * Required for overloading the Print function.
- */
- size_t HT16K33::write(const char *str)
- {
- if (str == NULL)
- return 0;
- return write((const uint8_t *)str, strlen(str));
- }
- // Push the contents of displayRAM out to the various displays in 16 byte chunks
- bool HT16K33::updateDisplay()
- {
- bool status = true;
- for (uint8_t i = 1; i <= numberOfDisplays; i++)
- {
- if (writeRAM(lookUpDisplayAddress(i), 0, (uint8_t *)(displayRAM + ((i-1) * 16)), 16) == false)
- {
- //Serial.print("updateDisplay fail at display 0x");
- //Serial.println(lookUpDisplayAddress(i), HEX);
- status = false;
- }
- }
- return status;
- }
- // Shift the display content to the right one digit
- bool HT16K33::shiftRight(uint8_t shiftAmt)
- {
- for (uint8_t x = (4 * numberOfDisplays) - shiftAmt; x >= shiftAmt; x--)
- {
- displayContent[x] = displayContent[x - shiftAmt];
- }
- // Clear the leading characters
- for (uint8_t x = 0; x < shiftAmt; x++)
- {
- if (x + shiftAmt > (4 * numberOfDisplays))
- break; // Error check
- displayContent[0 + x] = ' ';
- }
- return (print(displayContent));
- }
- // Shift the display content to the left one digit
- bool HT16K33::shiftLeft(uint8_t shiftAmt)
- {
- for (int x = 0; x < 4 * numberOfDisplays; x++)
- {
- if (x + shiftAmt > (4 * numberOfDisplays))
- break; // Error check
- displayContent[x] = displayContent[x + shiftAmt];
- }
- // Clear the trailing characters
- for (int x = 0; x < shiftAmt; x++)
- {
- if (4 * numberOfDisplays - 1 - x < 0)
- break; //Error check
- displayContent[4 * numberOfDisplays - 1 - x] = ' ';
- }
- return (print(displayContent));
- }
- /*----------------------- Internal I2C Abstraction -----------------------------*/
- bool HT16K33::readRAM(uint8_t address, uint8_t reg, uint8_t *buff, uint8_t buffSize)
- {
- uint8_t displayNum = 1;
- if (address == _deviceAddressDisplayTwo)
- displayNum = 2;
- else if (address == _deviceAddressDisplayThree)
- displayNum = 3;
- else if (address == _deviceAddressDisplayFour)
- displayNum = 4;
- isConnected(displayNum); // Wait until display is ready
- _i2cPort->beginTransmission(address);
- _i2cPort->write(reg);
- _i2cPort->endTransmission(false);
- if (_i2cPort->requestFrom(address, buffSize) > 0)
- {
- for (uint8_t i = 0; i < buffSize; i++)
- buff[i] = _i2cPort->read();
- return true;
- }
- return false;
- }
- // Write the contents of the RAM array out to the Holtek IC
- bool HT16K33::writeRAM(uint8_t address, uint8_t reg, uint8_t *buff, uint8_t buffSize)
- {
- uint8_t displayNum = 1;
- if (address == _deviceAddressDisplayTwo)
- displayNum = 2;
- else if (address == _deviceAddressDisplayThree)
- displayNum = 3;
- else if (address == _deviceAddressDisplayFour)
- displayNum = 4;
- isConnected(displayNum); //Wait until display is ready
- _i2cPort->beginTransmission(address);
- _i2cPort->write(reg);
- for (uint8_t i = 0; i < buffSize; i++)
- _i2cPort->write(buff[i]);
- if (_i2cPort->endTransmission() == 0)
- return true;
- return false;
- }
- // Write a single byte to the display. This is often a command byte.
- // The address of the data to write is contained in the first four bits of dataToWrite
- bool HT16K33::writeRAM(uint8_t address, uint8_t dataToWrite)
- {
- uint8_t temp = 0;
- return (writeRAM(address, dataToWrite, (uint8_t *)&temp, 0));
- }
|