HT16K33 backpack - cpp to spin
rogersyd
Posts: 223
Hi all.
I am working on a clock project and decided to leverage the adafruit HT16K33 backpack to drive the 4 digit 7 seg display.
http://www.adafruit.com/datasheets/ht16K33v110.pdf
http://www.adafruit.com/products/878
Here is a slightly modified version of the HT16K33 driver found in the OBX (Thanks to topher_cantrell for the object). This particular driver was written for a 8x8 bi-color version of the backpack, and the methods i need are excluded. I am struggling with converting the CPP code (also below) to write a 4 digit number to the backpack. I am communicating with the backpack ok, as demonstrated via the "dimming" repeat loop, but i just cant figure out who to send the data located in the buffer to the display. CPP may as well be greek to me, although i am getting better at deciphering it. Does anyone have any experience with the HT16K33 chip that could provide some guidance here? Thanks for any advice.
CPP code from ADAFRUIT
I am working on a clock project and decided to leverage the adafruit HT16K33 backpack to drive the 4 digit 7 seg display.
http://www.adafruit.com/datasheets/ht16K33v110.pdf
http://www.adafruit.com/products/878
Here is a slightly modified version of the HT16K33 driver found in the OBX (Thanks to topher_cantrell for the object). This particular driver was written for a 8x8 bi-color version of the backpack, and the methods i need are excluded. I am struggling with converting the CPP code (also below) to write a 4 digit number to the backpack. I am communicating with the backpack ok, as demonstrated via the "dimming" repeat loop, but i just cant figure out who to send the data located in the buffer to the display. CPP may as well be greek to me, although i am getting better at deciphering it. Does anyone have any experience with the HT16K33 chip that could provide some guidance here? Thanks for any advice.
con led = 0 var byte ADDR ' Backpack I2C address byte PIN_SCL ' I/O pin connected to SCL (SDA is very next pin) ' 8x8 bicolor specific byte raster[16] ' Raster buffer for (x,y) graphics OBJ i2c : "Basic_I2C_Driver_1" pub start|delaytime,br dira[led]:=1 init($70,3) writeDisplay($0,16,@buffer)'(register,count,data) repeat outa[led]:=1 repeat br from %0000 to %0011 !outa[Led] ' toggle the pin state setBrightness(br) ' Max brightness waitcnt(clkfreq/5 + cnt) ' wait repeat br from %0010 to %0001 !outa[Led] ' toggle the pin state setBrightness(br) ' Max brightness waitcnt(clkfreq/5 + cnt) PUB init(i2cAddress,pinSCL) '' Initialize the object with the given I2C-address and hardware pins. '' The driver I am using requires SDA to be the next pin after SCL. ' ADDR := i2cAddress PIN_SCL := pinSCL i2c.Initialize(PIN_SCL) setOscillator(1) ' Start the oscillator setBlink(1,0) ' Power on, no blinking setBrightness(%0000) ' Max brightness PUB setOscillator(on) | address '' Turn the oscillator on (or off) ' ' 0010_xxx_p ' address := ADDR << 1 ' # R/-W bit = 0 (write) on := on & 1 on := on | $20 i2c.Start(PIN_SCL) i2c.Write(PIN_SCL,address) i2c.Write(PIN_SCL,on) i2c.Stop(PIN_SCL) PUB setBlink(power,rate) | address '' Set the display power and blink rate '' rate = 00 = Off '' 01 = 2Hz '' 10 = 1Hz '' 11 = 0.5Hz ' ' 1000_x_rr_p ' address := ADDR << 1 ' # R/-W bit = 0 (write) rate := rate & 3 rate := rate << 1 power := power & 1 rate := rate | power rate := rate | $80 i2c.Start(PIN_SCL) i2c.Write(PIN_SCL,address) i2c.Write(PIN_SCL,rate) i2c.Stop(PIN_SCL) PUB setBrightness(level) | address '' Set the display brightness '' level: 0000=minimum, 1111=maximum ' ' 1110_vvvv ' address := ADDR << 1 ' # R/-W bit = 0 (write) level := level & 15 level := level | $E0 i2c.Start(PIN_SCL) i2c.Write(PIN_SCL,address) i2c.Write(PIN_SCL,level) i2c.Stop(PIN_SCL) pub writeDigitRaw(bitmask) {writeDigitRaw(uint8_t d, uint8_t bitmask) if (d > 4) return; displaybuffer[d] = bitmask} PUB writeDisplay(register,count,data) | address '' Write a number of data values beginning with the '' given register. address := ADDR << 1 ' # R/-W bit = 0 (write) i2c.Start(PIN_SCL) i2c.Write(PIN_SCL,address) i2c.Write(PIN_SCL,register) repeat while count>0 i2c.Write(PIN_SCL,byte[data]) data := data +1 count := count -1 i2c.Stop(PIN_SCL) { writeDisplay(void) Wire.beginTransmission(i2c_addr); Wire.write((uint8_t)0x00); // start at address $00 for (uint8_t i=0; i<8; i++) Wire.write(displaybuffer[i] & 0xFF); Wire.write(displaybuffer[i] >> 8); Wire.endTransmission(); } ' ' Specific to the adafruit 8x8 bicolor backpack. ' Leave them out or tweak them. ' '' The 8x8 bicolor matrix is wired as follows: '' register 0: Row 0/green (LSB is left pixel, MSB is right pixel) '' register 1: Row 0/red (LSB is left pixel, MSB is right pixel) '' register 2: Row 1/green (LSB is left pixel, MSB is right pixel) '' etc '' '' Turn both red and green on to make orange PUB clearRaster | ix repeat ix from 0 to 15 raster[ix] := 0 PUB drawRaster writeDisplay(0,16,@raster) DAT Buffer byte "1234",0 one byte "1",0
CPP code from ADAFRUIT
/*************************************************** This is a library for our I2C LED Backpacks Designed specifically to work with the Adafruit LED Matrix backpacks ----> http://www.adafruit.com/products/ ----> http://www.adafruit.com/products/ These displays use I2C to communicate, 2 pins are required to interface. There are multiple selectable I2C addresses. For backpacks with 2 Address Select pins: 0x70, 0x71, 0x72 or 0x73. For backpacks with 3 Address Select pins: 0x70 thru 0x77 Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! Written by Limor Fried/Ladyada for Adafruit Industries. BSD license, all text above must be included in any redistribution ****************************************************/ #ifdef __AVR_ATtiny85__ #include <TinyWireM.h> #define Wire TinyWireM #else #include <Wire.h> #endif #include "Adafruit_LEDBackpack.h" #include "Adafruit_GFX.h" #ifndef _BV #define _BV(bit) (1<<(bit)) #endif static const uint8_t numbertable[] = { 0x3F, /* 0 */ 0x06, /* 1 */ 0x5B, /* 2 */ 0x4F, /* 3 */ 0x66, /* 4 */ 0x6D, /* 5 */ 0x7D, /* 6 */ 0x07, /* 7 */ 0x7F, /* 8 */ 0x6F, /* 9 */ 0x77, /* a */ 0x7C, /* b */ 0x39, /* C */ 0x5E, /* d */ 0x79, /* E */ 0x71, /* F */ }; static const uint16_t alphafonttable[] PROGMEM = { 0b0000000000000001, 0b0000000000000010, 0b0000000000000100, 0b0000000000001000, 0b0000000000010000, 0b0000000000100000, 0b0000000001000000, 0b0000000010000000, 0b0000000100000000, 0b0000001000000000, 0b0000010000000000, 0b0000100000000000, 0b0001000000000000, 0b0010000000000000, 0b0100000000000000, 0b1000000000000000, 0b0000000000000000, 0b0000000000000000, 0b0000000000000000, 0b0000000000000000, 0b0000000000000000, 0b0000000000000000, 0b0000000000000000, 0b0000000000000000, 0b0001001011001001, 0b0001010111000000, 0b0001001011111001, 0b0000000011100011, 0b0000010100110000, 0b0001001011001000, 0b0011101000000000, 0b0001011100000000, 0b0000000000000000, // 0b0000000000000110, // ! 0b0000001000100000, // " 0b0001001011001110, // # 0b0001001011101101, // $ 0b0000110000100100, // % 0b0010001101011101, // & 0b0000010000000000, // ' 0b0010010000000000, // ( 0b0000100100000000, // ) 0b0011111111000000, // * 0b0001001011000000, // + 0b0000100000000000, // , 0b0000000011000000, // - 0b0000000000000000, // . 0b0000110000000000, // / 0b0000110000111111, // 0 0b0000000000000110, // 1 0b0000000011011011, // 2 0b0000000010001111, // 3 0b0000000011100110, // 4 0b0010000001101001, // 5 0b0000000011111101, // 6 0b0000000000000111, // 7 0b0000000011111111, // 8 0b0000000011101111, // 9 0b0001001000000000, // : 0b0000101000000000, // ; 0b0010010000000000, // < 0b0000000011001000, // = 0b0000100100000000, // > 0b0001000010000011, // ? 0b0000001010111011, // @ 0b0000000011110111, // A 0b0001001010001111, // B 0b0000000000111001, // C 0b0001001000001111, // D 0b0000000011111001, // E 0b0000000001110001, // F 0b0000000010111101, // G 0b0000000011110110, // H 0b0001001000000000, // I 0b0000000000011110, // J 0b0010010001110000, // K 0b0000000000111000, // L 0b0000010100110110, // M 0b0010000100110110, // N 0b0000000000111111, // O 0b0000000011110011, // P 0b0010000000111111, // Q 0b0010000011110011, // R 0b0000000011101101, // S 0b0001001000000001, // T 0b0000000000111110, // U 0b0000110000110000, // V 0b0010100000110110, // W 0b0010110100000000, // X 0b0001010100000000, // Y 0b0000110000001001, // Z 0b0000000000111001, // [ 0b0010000100000000, // 0b0000000000001111, // ] 0b0000110000000011, // ^ 0b0000000000001000, // _ 0b0000000100000000, // ` 0b0001000001011000, // a 0b0010000001111000, // b 0b0000000011011000, // c 0b0000100010001110, // d 0b0000100001011000, // e 0b0000000001110001, // f 0b0000010010001110, // g 0b0001000001110000, // h 0b0001000000000000, // i 0b0000000000001110, // j 0b0011011000000000, // k 0b0000000000110000, // l 0b0001000011010100, // m 0b0001000001010000, // n 0b0000000011011100, // o 0b0000000101110000, // p 0b0000010010000110, // q 0b0000000001010000, // r 0b0010000010001000, // s 0b0000000001111000, // t 0b0000000000011100, // u 0b0010000000000100, // v 0b0010100000010100, // w 0b0010100011000000, // x 0b0010000000001100, // y 0b0000100001001000, // z 0b0000100101001001, // { 0b0001001000000000, // | 0b0010010010001001, // } 0b0000010100100000, // ~ 0b0011111111111111, }; void Adafruit_LEDBackpack::setBrightness(uint8_t b) { if (b > 15) b = 15; Wire.beginTransmission(i2c_addr); Wire.write(HT16K33_CMD_BRIGHTNESS | b); Wire.endTransmission(); } void Adafruit_LEDBackpack::blinkRate(uint8_t b) { Wire.beginTransmission(i2c_addr); if (b > 3) b = 0; // turn off if not sure Wire.write(HT16K33_BLINK_CMD | HT16K33_BLINK_DISPLAYON | (b << 1)); Wire.endTransmission(); } Adafruit_LEDBackpack::Adafruit_LEDBackpack(void) { } void Adafruit_LEDBackpack::begin(uint8_t _addr = 0x70) { i2c_addr = _addr; Wire.begin(); Wire.beginTransmission(i2c_addr); Wire.write(0x21); // turn on oscillator Wire.endTransmission(); blinkRate(HT16K33_BLINK_OFF); setBrightness(15); // max brightness } void Adafruit_LEDBackpack::writeDisplay(void) { Wire.beginTransmission(i2c_addr); Wire.write((uint8_t)0x00); // start at address $00 for (uint8_t i=0; i<8; i++) { Wire.write(displaybuffer[i] & 0xFF); Wire.write(displaybuffer[i] >> 8); } Wire.endTransmission(); } void Adafruit_LEDBackpack::clear(void) { for (uint8_t i=0; i<8; i++) { displaybuffer[i] = 0; } } /******************************* QUAD ALPHANUM OBJECT */ Adafruit_AlphaNum4::Adafruit_AlphaNum4(void) { } void Adafruit_AlphaNum4::writeDigitRaw(uint8_t n, uint16_t bitmask) { displaybuffer[n] = bitmask; } void Adafruit_AlphaNum4::writeDigitAscii(uint8_t n, uint8_t a, boolean d) { uint16_t font = pgm_read_word(alphafonttable+a); displaybuffer[n] = font; /* Serial.print(a, DEC); Serial.print(" / '"); Serial.write(a); Serial.print("' = 0x"); Serial.println(font, HEX); */ if (d) displaybuffer[n] |= (1<<15); } /******************************* 24 BARGRAPH OBJECT */ Adafruit_24bargraph::Adafruit_24bargraph(void) { } void Adafruit_24bargraph::setBar(uint8_t bar, uint8_t color) { uint16_t a, c; if (bar < 12) c = bar / 4; else c = (bar - 12) / 4; a = bar % 4; if (bar >= 12) a += 4; //Serial.print("Ano = "); Serial.print(a); Serial.print(" Cath = "); Serial.println(c); if (color == LED_RED) { // Turn on red LED. displaybuffer[c] |= _BV(a); // Turn off green LED. displaybuffer[c] &= ~_BV(a+8); } else if (color == LED_YELLOW) { // Turn on red and green LED. displaybuffer[c] |= _BV(a) | _BV(a+8); } else if (color == LED_OFF) { // Turn off red and green LED. displaybuffer[c] &= ~_BV(a) & ~_BV(a+8); } else if (color == LED_GREEN) { // Turn on green LED. displaybuffer[c] |= _BV(a+8); // Turn off red LED. displaybuffer[c] &= ~_BV(a); } } /******************************* 8x8 MATRIX OBJECT */ Adafruit_8x8matrix::Adafruit_8x8matrix(void) : Adafruit_GFX(8, 8) { } void Adafruit_8x8matrix::drawPixel(int16_t x, int16_t y, uint16_t color) { if ((y < 0) || (y >= 8)) return; if ((x < 0) || (x >= 8)) return; // check rotation, move pixel around if necessary switch (getRotation()) { case 1: swap(x, y); x = 8 - x - 1; break; case 2: x = 8 - x - 1; y = 8 - y - 1; break; case 3: swap(x, y); y = 8 - y - 1; break; } // wrap around the x x += 7; x %= 8; if (color) { displaybuffer[y] |= 1 << x; } else { displaybuffer[y] &= ~(1 << x); } } /******************************* 8x8 BICOLOR MATRIX OBJECT */ Adafruit_BicolorMatrix::Adafruit_BicolorMatrix(void) : Adafruit_GFX(8, 8) { } void Adafruit_BicolorMatrix::drawPixel(int16_t x, int16_t y, uint16_t color) { if ((y < 0) || (y >= 8)) return; if ((x < 0) || (x >= 8)) return; switch (getRotation()) { case 1: swap(x, y); x = 8 - x - 1; break; case 2: x = 8 - x - 1; y = 8 - y - 1; break; case 3: swap(x, y); y = 8 - y - 1; break; } if (color == LED_GREEN) { // Turn on green LED. displaybuffer[y] |= 1 << x; // Turn off red LED. displaybuffer[y] &= ~(1 << (x+8)); } else if (color == LED_RED) { // Turn on red LED. displaybuffer[y] |= 1 << (x+8); // Turn off green LED. displaybuffer[y] &= ~(1 << x); } else if (color == LED_YELLOW) { // Turn on green and red LED. displaybuffer[y] |= (1 << (x+8)) | (1 << x); } else if (color == LED_OFF) { // Turn off green and red LED. displaybuffer[y] &= ~(1 << x) & ~(1 << (x+8)); } } /******************************* 7 SEGMENT OBJECT */ Adafruit_7segment::Adafruit_7segment(void) { position = 0; } void Adafruit_7segment::print(unsigned long n, int base) { if (base == 0) write(n); else printNumber(n, base); } void Adafruit_7segment::print(char c, int base) { print((long) c, base); } void Adafruit_7segment::print(unsigned char b, int base) { print((unsigned long) b, base); } void Adafruit_7segment::print(int n, int base) { print((long) n, base); } void Adafruit_7segment::print(unsigned int n, int base) { print((unsigned long) n, base); } void Adafruit_7segment::println(void) { position = 0; } void Adafruit_7segment::println(char c, int base) { print(c, base); println(); } void Adafruit_7segment::println(unsigned char b, int base) { print(b, base); println(); } void Adafruit_7segment::println(int n, int base) { print(n, base); println(); } void Adafruit_7segment::println(unsigned int n, int base) { print(n, base); println(); } void Adafruit_7segment::println(long n, int base) { print(n, base); println(); } void Adafruit_7segment::println(unsigned long n, int base) { print(n, base); println(); } void Adafruit_7segment::println(double n, int digits) { print(n, digits); println(); } void Adafruit_7segment::print(double n, int digits) { printFloat(n, digits); } size_t Adafruit_7segment::write(uint8_t c) { uint8_t r = 0; if (c == '\n') position = 0; if (c == '\r') position = 0; if ((c >= '0') && (c <= '9')) { writeDigitNum(position, c-'0'); r = 1; } position++; if (position == 2) position++; return r; } void Adafruit_7segment::writeDigitRaw(uint8_t d, uint8_t bitmask) { if (d > 4) return; displaybuffer[d] = bitmask; } void Adafruit_7segment::drawColon(boolean state) { if (state) displaybuffer[2] = 0x2; else displaybuffer[2] = 0; } void Adafruit_7segment::writeColon(void) { Wire.beginTransmission(i2c_addr); Wire.write((uint8_t)0x04); // start at address $02 Wire.write(displaybuffer[2] & 0xFF); Wire.write(displaybuffer[2] >> 8); Wire.endTransmission(); } void Adafruit_7segment::writeDigitNum(uint8_t d, uint8_t num, boolean dot) { if (d > 4) return; writeDigitRaw(d, numbertable[num] | (dot << 7)); } void Adafruit_7segment::print(long n, int base) { printNumber(n, base); } void Adafruit_7segment::printNumber(long n, uint8_t base) { printFloat(n, 0, base); } void Adafruit_7segment::printFloat(double n, uint8_t fracDigits, uint8_t base) { uint8_t numericDigits = 4; // available digits on display boolean isNegative = false; // true if the number is negative // is the number negative? if(n < 0) { isNegative = true; // need to draw sign later --numericDigits; // the sign will take up one digit n *= -1; // pretend the number is positive } // calculate the factor required to shift all fractional digits // into the integer part of the number double toIntFactor = 1.0; for(int i = 0; i < fracDigits; ++i) toIntFactor *= base; // create integer containing digits to display by applying // shifting factor and rounding adjustment uint32_t displayNumber = n * toIntFactor + 0.5; // calculate upper bound on displayNumber given // available digits on display uint32_t tooBig = 1; for(int i = 0; i < numericDigits; ++i) tooBig *= base; // if displayNumber is too large, try fewer fractional digits while(displayNumber >= tooBig) { --fracDigits; toIntFactor /= base; displayNumber = n * toIntFactor + 0.5; } // did toIntFactor shift the decimal off the display? if (toIntFactor < 1) { printError(); } else { // otherwise, display the number int8_t displayPos = 4; if (displayNumber) //if displayNumber is not 0 { for(uint8_t i = 0; displayNumber || i <= fracDigits; ++i) { boolean displayDecimal = (fracDigits != 0 && i == fracDigits); writeDigitNum(displayPos--, displayNumber % base, displayDecimal); if(displayPos == 2) writeDigitRaw(displayPos--, 0x00); displayNumber /= base; } } else { writeDigitNum(displayPos--, 0, false); } // display negative sign if negative if(isNegative) writeDigitRaw(displayPos--, 0x40); // clear remaining display positions while(displayPos >= 0) writeDigitRaw(displayPos--, 0x00); } } void Adafruit_7segment::printError(void) { for(uint8_t i = 0; i < SEVENSEG_DIGITS; ++i) { writeDigitRaw(i, (i == 2 ? 0x00 : 0x40)); } }
Comments
Here is the code if it helps anyone else using this device:
EDIT: Found a small error in the alpha_bits() method -- please use the updated object file.
Helpful?!?!
It would have taken me weeks to write and debug all those methods - and it would be a mess.
I think just about every project I build uses one of your objects, and I learn a lot by studying them. So once again, THANK YOU sir for your fine contributions to the community!
I've been trying to get my 7 segment display (HT16K33) working with your code but I think I'm misusing it somehow. I am calling it like this:
I haven't soldered any of the jumpers on the back and I assume that means %000 is correct although I tried "000" and other combinations of values with no luck. Everything looks wired up ok and it has 5VDC on the power input.
Can you (or anyone else) tell what I'm doing wrong?
Thanks,
Brian
These calls are me just trying anything to get an LED on. It looks like "bits" in the write command were supposed to come from the maps given by the "digit" method. Also I turned the display on.... Still I have nothing showing up.
Thanks,
Brian