#include <LiquidCrystal.h>
#include <util/atomic.h> // For atomic ADC reads
// Pins: RS, EN, D4, D5, D6, D7
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);
// Global variables (faster access)
volatile int adcFmax = 0, adcRmax = 0;
char lcdBuf[2][16] = {"Vf: 0.00", "Vr: 0.00"}; // Pre-formatted
void setup() {
Serial.begin(9600);
// Ultra-fast LCD init (4-bit mode)
lcd.begin(16, 2);
// Pre-write static labels
lcd.print(lcdBuf[0]);
lcd.setCursor(0, 1);
lcd.print(lcdBuf[1]);
// Turbo-charge GPIO (AVR only)
#ifdef __AVR__
DDRB |= 0b00011111; // Pins 8-12 as output (D8-D12)
DDRD |= 0b11100000; // Pins 5-7 as output (D5-D7)
#endif
}
void fastPrint(int row, int value) {
// Atomic update to prevent screen tearing
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
lcd.setCursor(3, row);
lcd.print(value / 100); // Whole number
lcd.write('.');
lcd.print((value / 10) % 10); // Tenths
lcd.print(value % 10); // Hundredths
}
}
void loop() {
unsigned long start = micros();
// 1. Blazing-fast ADC reads (6 samples)
adcFmax = 0; adcRmax = 0;
for (byte i = 0; i < 15; i++) {
adcFmax = max(analogRead(A0), adcFmax);
adcRmax = max(analogRead(A1), adcRmax);
// Minimal delay for ADC settling
__asm__ __volatile__ ("nop\n\t" "nop\n\t" "nop\n\t");
}
// 2. Voltage conversion (integer math)
int voltageFx100 = (adcFmax * 500 + 512) >> 10; // (x*500)/1024 optimized
int voltageRx100 = (adcRmax * 500 + 512) >> 10;
// 3. Update LCD (only if changed)
static int lastVals[2] = {0,0};
if (abs(voltageFx100 - lastVals[0]) > 1) {
fastPrint(0, voltageFx100);
lastVals[0] = voltageFx100;
}
if (abs(voltageRx100 - lastVals[1]) > 1) {
fastPrint(1, voltageRx100);
lastVals[1] = voltageRx100;
}
// Debug (disable for final deployment)
Serial.print("Update time (µs): ");
Serial.println(micros() - start);
delay(50); // 20Hz refresh (adjust as needed)
}
FWD
REF
Slow
Fast
FWD
REF