I would like to display a float on the Adafruit 0.54" alphanumeric 14 segment display (2 displays with 7 segments). This seems to be much more difficult than I anticipated. I am used to digging through the source codes of the libraries that I use to find the answer but this is far beyond my comfort zone when it comes to Arduino libraries as the programming language is fairly new to me.
I am using the Adafruit_LEDBackpack library. The example isn't very useful.
Looking on GitHub I did find that the Adafruit_7segment class has a printFloat method. It accepts a double. Let's assume the temperature is 20.51 at the moment. I thought this method would solve it, but unfortunately it didn't. It does accept the double but not all segments light up. If the temperature is 20.51 the display says it's 20 6 (no dot, no 'leading' zero). And the segments of the 2 and 6 are incomplete.
When I pass the numbers individually with the Adafruit_AlphaNum4 class method writeDigitAscii all segments do light up, so these are definitely not broken.
I could probably make some logic to come up with a poor workaround in the Arduino (converting things to a string and using charAt) but I'd rather not. It does work when I do this but in that case I can't get the dot to light up (this is with the Adafruit_AlphaNum4 class).
What is the recommend way to display a float on this display?
Sorry about missing some of the guidelines. The product I am using is:
I thought about the sharing the code but as it would only include class references decided not to. I have tried:
#include <Wire.h>
#include <Adafruit_GFX.h>
#include "Adafruit_LEDBackpack.h"
Adafruit_AlphaNum4 alpha4 = Adafruit_AlphaNum4();
Adafruit_7segment 7segment = Adafruit_7segment();
void setup() {
alpha4.begin(0x70);
alpha4.clear();
float number = 0.21;
// Note that this is an example of how
// it COULD work, this doesn't take the
// the float and obviously would need a
// method to parse and display it.
//
// The below is just an example.
Display.writeDigitAscii(0, '2');
Display.writeDigitAscii(1, '3');
Display.writeDigitAscii(2, '4');
Display.writeDigitAscii(3, '5');
alpha4.writeDisplay();
delay(1000);
7segment.begin(0x70);
7segment.print(number);
7segment.writeDisplay();
delay(1000);
7segment.printFloat(number);
7segment.writeDisplay();
}
void loop() {
}
This combines multiple things I've tried. While further expanding on this issue I do realise that using the 7segment makes no sense.
@noiasca that looks very promising. I don't have the Arduino with me where I am at the moment but I will 100% give it go tomorrow morning.
Thanks for all of your help so far, I appreciate it.
Have not connected any hardware currently, but that might work:
#include "NoiascaHt16k33.h" // include the noiasca HT16K33 library - download from http://http://werner.rothschopf.net/
Noiasca_ht16k33_hw_14_4 display = Noiasca_ht16k33_hw_14_4(); // object for 14 segments - 4 digits
const uint8_t i2cAdress = 0x71; // the I2C Address of the first module
const uint8_t numOfDevices = 1; // how many modules have you installed on the I2C Bus
void setup() {
// put your setup code here, to run once:
Wire.begin();
display.begin(i2cAdress, numOfDevices); // I2C address of first display, total number of devices
display.clear();
float number = 0.21;
display.print(number);
}
void loop() {
// put your main code here, to run repeatedly:
}
Have you followed this Adafruit tutorial to get the display wired up and running, displaying ASCII characters?
If so, just format the temperature yourself using fixed point arithmetic, and handle the decimal point separately using the very limited HT16K33 library. You could also consider using the function dtostrf() (float to ASCII).
For a single decimal place, multiply the (floating point) temperature in Celsius by 10, and convert to an integer to get the three useful digits.
void writeDigitRaw(uint8_t n, uint16_t bitmask);
void writeDigitAscii(uint8_t n, uint8_t ascii, boolean dot = false);
I think you will need to use the second one to display each digit and put the optional decimal point where you want it. Are you passing it ascii characters? The writeDigitscii() function doesn't bother checking to see if you are passing valid printable ASCII or not. If you don't, it will just display whatever garbage it fetches from PROGMEM off the ends of the table.
Maybe you can adapt the 7segment::printFloat code to calculate the digits for you.
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);
}
}