/*
* VERTICAL SCROLLING GRAPHS ON LCD DISPLAY
*
*/
#include "Arduino.h"
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4); // 20 x 4 lcd
uint8_t scanGraphNumber = 2; // 1, 2 or max 4
uint8_t scanGraphWidth = 20 / scanGraphNumber;
int freqDiffGraph = 0;
uint8_t scanGraphArray[4][4] = {}; // array to remember old graphs for scrolling
uint8_t scanGraphArrayPos = 0; // index within array
int scanGraphScreenRow = 0; // screen row
uint8_t scanGraphCharacter[8][8] PROGMEM = {
{B10000, B10000, B10000, B10000, B10000, B10000, B10000, B10000}, // char 0x00: 1 bar
{B11000, B11000, B11000, B11000, B11000, B11000, B11000, B11000}, // char 0x01: 2 bar
{B11100, B11100, B11100, B11100, B11100, B11100, B11100, B11100}, // char 0x02: 3 bar
{B11110, B11110, B11110, B11110, B11110, B11110, B11110, B11110}, // char 0x03: 4 bar
{B11111, B11011, B10011, B11011, B11011, B11011, B10001, B11111}, // char 0x04: reverse 1 (white on black)
{B11111, B10001, B10101, B11101, B11011, B10111, B10001, B11111}, // char 0x05: reverse 2
{B11111, B10001, B11101, B11001, B11101, B10101, B10001, B11111}, // char 0x06: reverse 3
{B11111, B10101, B10101, B10101, B10001, B11101, B11101, B11111} // char 0x07: reverse 4
};
void setup()
{
Serial.begin(115200);
lcd.init();
createScanGraphCharacter();
screenScanSetup();
}
void createScanGraphCharacter()
{
for (uint8_t i = 0; i < 8; i ++) {
lcd.createChar(i, scanGraphCharacter[i]); // create characters 0 to 7
}
}
void screenScanSetup()
{
for (uint8_t i = 0; i < scanGraphNumber; i ++) {
for (uint8_t j = 0; j < 4; j ++) {
lcd.setCursor(i * scanGraphWidth, j);
lcd.write(0xFF); // fill first columns with blocks
lcd.setCursor(i * scanGraphWidth, 0);
lcd.write(i + 4); // add reverse numbers
}
}
}
void loop()
{
delay(1000);
freqDiffGraph = random(1, 10);
screenScanGraph();
}
void screenScanGraph() // create custom characters - use log2, logn or log10?
{
// log2(freqDiff): 1 = 0, 2 = 1, 4 = 2, 8 = 3, 16 = 4, 32 = 5, 64 = 6, 128 = 7, 256 = 8, 512 = 9, 1024 = 10, 2048 = 11, 4096 = 12, 8192 = 13, 16384 = 14, 32768 = 15, etc
// logn(freqDiff): 1 = 0, 10 = 1, 100 = 2, 1000 = 3, 10000 = 4, 100000 = 5, 1000000 = 6, 10000000 = 7, etc
// log10(freqDiff): 1 = 1, 10 = 2, 100 = 3, 1000 = 4, 10000 = 5, 100000 = 6, 1000000 = 7, etc
for (uint8_t i = 0; i < scanGraphNumber; i ++) { // erase previous graphs
for (uint8_t j = 0; j < 4; j ++) {
lcd.setCursor((i * scanGraphWidth) + 1, j);
for (uint8_t k = 0; k < (scanGraphWidth - 1); k ++) {
lcd.write(0xFE);
}
}
}
freqDiffGraph = abs(freqDiffGraph); // only use positive values
freqDiffGraph = constrain(freqDiffGraph, 1, 10000); // constrain between log(1) = 0 and log(10000) = 4, log(0) is not possible
uint16_t freqDiffGraphLog = (log2(freqDiffGraph)) * 10; // logn of freqDiffGraph, * 10 to preserve decimal point during map()
uint16_t scanGraphXColumn = (scanGraphWidth - 1) * 5; // number of pixel columns available to draw each graph
uint16_t scanGraphValue = map(freqDiffGraphLog, 0, 120, 0, scanGraphXColumn);
scanGraphArray[0][scanGraphArrayPos]= scanGraphValue;
for (uint8_t i = 0; i < scanGraphNumber; i ++) {
scanGraphScreenRow = scanGraphArrayPos; // latest value
for (uint8_t j = 0; j < 4; j ++) {
uint16_t scanGraphXBlock = scanGraphArray[0][scanGraphScreenRow] / 5; // calculate number of block to fill
uint16_t scanGraphXPixel = scanGraphArray[0][scanGraphScreenRow] % 5; // calculate extra pixels
lcd.setCursor((i * scanGraphWidth) + 1, j);
for (uint8_t i = 0; i < scanGraphXBlock; i ++) {
lcd.write(0xFF);
}
if (scanGraphXPixel == 0) {
lcd.write(0xFE);
} else {
lcd.write(scanGraphXPixel - 1);
}
scanGraphScreenRow --;
if (scanGraphScreenRow == -1) {
scanGraphScreenRow = 3;
}
}
}
scanGraphArrayPos ++;
if (scanGraphArrayPos > 3) {
scanGraphArrayPos = 0;
}
}