Hello,
as part of my ongoing Arduino trip computer project, I have been toying with the idea of implementing a "nightttime" design of the screen. At the moment, all the numbers on the 1.44'' Adafruit TFT screen are displayed in black on white, about like this:
The numbers - and all the icons - are all stored as const uint16_t arrays in PROGMEM, like this:
const uint16_t s1[192] PROGMEM = {
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffdf,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xbdf7, 0xb5b6,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xdefb, 0x1082, 0xce59,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x39c7, 0x0000, 0xdefb,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0861, 0x0000, 0xf79e,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffdf, 0x0000, 0x0020, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffdf, 0x2945, 0x18e3, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xdefb, 0xc638, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xd6ba, 0xd6ba, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xd6ba, 0x1082, 0x52aa, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x94b2, 0x0000, 0x632c, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x0000, 0x7bcf, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8430, 0x0000, 0x8c71, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xf79e, 0x18e3, 0xa534, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xbdd7, 0xbdd7, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffdf, 0xffff
};
To put the numbers on the screen, I use the following functions:
//------------- Image and Text Drawing Functions
void drawProgmemIcon(const uint16_t* icon, int16_t x, int16_t y, uint8_t width, uint8_t height) {
uint16_t count = 0;
// Set up a window the right size to stream pixels into
tft.setAddrWindow(x, y, x + width - 1, y + height - 1);
for (uint16_t i = 0; i < height; i++) {
for (uint16_t j = 0; j < width; j++) {
tft.pushColor(pgm_read_word(&icon[count++]));
}
}
}
void plotFloat(float value, int poX, int poY, uint16_t font)
{
if (value < -20) return; // Temperature sensors only support temperatures of -20°C
if (value > 149.9) return; // This function handles values in range 0.0 - 149.9
char str[13];
byte index = 0;
byte digit = 0;
byte bmpWidth = 0;
byte bmpHeight = 0;
// Convert value to a string of length 4 with 1 decimal place
if (font == "large") dtostrf(value, 4, 1, str);
else if (font == "small") dtostrf(value, 5, 1, str);
while (str[index]) {
if ( str[index] == ' ') // Is it a 'space' character
{
if (font == "large") {
bmpWidth = pgm_read_byte( &cWidths[0]);
bmpHeight = pgm_read_byte( &cHeights[0]);
}
else if (font == "small") {
bmpWidth = pgm_read_byte( &sWidths[0]);
bmpHeight = pgm_read_byte( &sHeights[0]);
}
// Use fill rectangle as there is no 'space' character in the bitmap set
tft.fillRect(poX, poY, bmpWidth, bmpHeight, ST7735_WHITE); // Draw a 'space'
// drawIcon(aBMPmap[0], poX, poY, bmpWidth, bmpHeight); // Leading zero instead of space (alternative to above line)
poX += bmpWidth; // Width of a space same as 0 digit to over-write previous numbers
}
else
{
digit = str[index]; // Fetch ascii code
if (digit == '.') digit = 10; // Check for decimal point, set to bitmap 10
else if (digit == '-') digit = 11; // allow for negative values
else digit -= '0'; // Shift to range 0-9
if (font == "large") {
bmpWidth = pgm_read_byte( &cWidths[digit]);
bmpHeight = pgm_read_byte( &cHeights[digit]);
// Draw the bitmap
drawProgmemIcon(cBMPmap[digit], poX, poY, bmpWidth, bmpHeight);
}
else if (font == "small") {
bmpWidth = pgm_read_byte( &sWidths[digit]);
bmpHeight = pgm_read_byte( &sHeights[digit]);
// Draw the bitmap
drawProgmemIcon(sBMPmap[digit], poX, poY, bmpWidth, bmpHeight);
}
// Move x coord plot position
poX += bmpWidth;
}
index++; // Increment pointer to next character
}
}
void plotInteger(long value, int poX, int poY, uint16_t font)
{
char str[12];
byte index = 0; // Array index
byte digit = 0;
byte bmpWidth = 0;
byte bmpHeight = 0;
// Convert value to a string
ltoa(value, str, 10);
// While character pointed to is not a null (strings are zero terminated)
while (str[index]) {
digit = str[index++] - '0'; // Fetch ascii code, shift to range 0-9 and increment index
if (digit == '-') digit = 11; // allow for negative values
bmpWidth = pgm_read_byte( &cWidths[digit]); // Get width
bmpHeight = pgm_read_byte( &cHeights[digit]); //Get height
// Draw the bitmap
drawProgmemIcon(cBMPmap[digit], poX, poY, bmpWidth, bmpHeight);
// Move x coord plot position
poX += bmpWidth;
}
}
My Atmega1284P which will power the display is already brimming with PROGMEM icons by now, as all you can see in the above picture comes from PROGMEM.
To implement some sort of "nighttime" display, which will be easier on the eyes in the dark, I've had the idea of just swapping out black and white pixels against each other and drawing them on a black background, because again, the Atmega1284P is "full" and won't take up another complete set of "nighttime" icons and numbers.
The main reason why I chose the Atmega1284P to power the display was its huge memory and that I will be able to have near-unnoticeable refresh latencies compared to loading all the icons and digits from SD, and that my trip computer display will remain fully operational if there is a SD card read failure. But what remains of the Atmega's memory now, I will need for my actual program code.
One thing I've already tried was to alter the drawProgmemIcon function like this:
for (uint16_t i = 0; i < height; i++) {
for (uint16_t j = 0; j < width; j++) {
uint16_t currentColor = pgm_read_word(&icon[count++]);
String currentColorString = String(currentColor);
currentColorString.replace("ffff", "0000");
uint16_t currentColorShow = currentColorString.toInt();
tft.pushColor(currentColorShow);
}
}
This did not work, the display looks the same, and all it does is slow down the screen refresh time considerably.
Is there any way that my "pixel swap" idea could work as part of this code?