In a loop, where overcurrent on 5 modules must be detected fast (within a few tens of microseconds intervals), a 20x4 I2C display (with PCF8574 addon) must be refreshed every few seconds.
This is using F. Malpartida's LCD library.
However, when this code is omited from the measurement indexing loop,
for (index = 0; index < 5; index++) {
then no output at all comes on the display.
Serial.println(index); // if this line is commentedthen no LCD output
delay(50); // if this line is commented then LCD output on last lines almost illegible
If this last line is omitted, then the LCD displays the last lines virtually illegible.
Also, if the LCD display refresh rate ( slowTimer = 500; ) is increased above 500ms then there is no output on te LCD.
Basically, I need the current measurements to be performed fast, but the LCD updates may be made as slow as every few seconds.
What can be done to get
- fast current measurements
- LCD to display legibly
- LCD refresh rate may made be as slow as several seconds
#include<EEPROM.h>
#include <Wire.h>
#include <LCD.h> // will force using NewLiquidCrystal library
#include <LiquidCrystal_I2C.h>
#include <Auto485.h>
#include <CMRI.h>
#include <SPI.h>
#define CMRI_ADDR 0 // select the CMRI node address
#define DE_PIN 2 // Arduino pin 2 -> MAX485 DE and RE pins
#define pot A7 // calibration pot attached to A7; value is read into calibrationValue
#define rstButton 8 // manual reset button attached to pin DIO8; value is read into rstButtonValue
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // I2C address 0x27 or 0x3F
bool rstButtonValue, ocAlarm, autoRstStatus, manualRstStatus, buttonState, lastButtonState = false; // reset button connected to DIO 8; ocAlarm = flag set when at least one booster is in overcurrent
bool eN1, eN2, eN3, eN4, eN5 = true; // digital outputs to enable booster
uint32_t lastDebounceTime = 0; // max value for analog read
uint32_t previousMillis, currentMillis, currentTotal, manualRstClear, slowTimerVar = 0; // delaying timer variables
float calibrationValue, currentNow, currentAvg, potReading, current1, current2, current3, current4, current5; // variables containing measured currents, and previous values
uint16_t analogReadInterval = 2; // interval in ms between subsequent reads from the same input
uint16_t readRepeat = 10; // number of consecutive repeat current measurements
uint16_t numberOfBooster = 5;
uint16_t index, repeat, i, j, k = 0; // index: currentMeasure array address pointer; repeat: current measurement variable
uint16_t automaticReset = 5; // number of automatic reset attempts
uint16_t autoRstTimer = 2000; // number of miliseconds between automatic reset attempts
uint16_t boosterNumber, x = 0; // array index from 0 to 4
uint16_t debounceDelay = 50; // manual reset button debounce delay
uint16_t manualRstClearDelay = 5000; // time after which manual reset flag is cleared; next short circuit will again be auto reset
uint16_t slowTimer = 500; // refresh time for LCD and reversing check for boosters
float currentMeasure[5] = {current1, current2, current3, current4, current5}; // array with measured currents
// bool stateRev[5] = {revState1, revState2, revState3, revState4, revState5}; // array with status of booster revering
bool enState[5] = {eN1, eN2, eN3, eN4, eN5}; // enable status
uint16_t enablePointer[5] = {3, 4, 5, 6, 7}; // digital output pins for enable
uint16_t analogReadPointer[5] = {0, 1, 2, 3, 6}; // analog pin numbers used for current reading
uint16_t reverserReadPointer[5] = {9, 10, 11, 12, 13}; // DIO output pins for booster reversing, commanded from C/MRI
float maxCurrent = 2.0; // this is the current for which the IBT-2 is set with current sense resistors to give 5V when this current is reached
float version = 1;
static char txt1[4];
static char txt2[4];
static char txt3[4];
static char txt4[4];
static char txt5[4];
void setup() {
Serial.begin (115200);
lcd.begin(20, 4);
lcd.clear();
lcd.backlight();//Power on the back light
Serial.println(" Test started. Version v1");
Serial.println();
for (uint8_t i = 0; i < 5; i++) {
pinMode(enablePointer[i], INPUT_PULLUP); // initialize pin as input wit pullu^p
pinMode(enablePointer[i], OUTPUT); // then convert to output in HIGH state
}
for (i = 0; i < 5; i++) { // set enables states to true
enState[i] = true;
}
for (uint8_t i = 0; i < 5; i++) {
pinMode(reverserReadPointer[i], INPUT_PULLUP); // initialize pin as input wit pullu^p
pinMode(reverserReadPointer[i], OUTPUT); // then convert to output in HIGH state
}
for (auto &i : analogReadPointer) { // auto range based for loops; this is identical to the previous 3 lines.
pinMode(i, INPUT); // currentMeasure are analog inputs; auto range based loop
}
pinMode(rstButton, INPUT_PULLUP);
// pinMode(builtinLed, OUTPUT);
lcd.setCursor(0, 0);
lcd.print(" DCC Booster");
lcd.setCursor(0, 1);
lcd.print(" 16/03/2022");
lcd.setCursor(0, 2);
lcd.print(" version ");
lcd.print(version, 1);
Serial.print(" 16/3/2022 version ");
Serial.println(version, 1);
delay(500);
}
void loop() {
if (millis - slowTimerVar > slowTimer) { // first execution is immediately; execute LCD refresh, and booster reversing inputs check
writeLCD();
reverser();
slowTimerVar = millis();
}
for (index = 0; index < 5; index++) {
// Serial.print("execution of indexing (values 0 to 4), index value = ");
Serial.println(index); // if this line is commentedthen no LCD output
// Serial.println();
delay(50); // if this line is commented then LCD output on last lines almost illegible
currentMeasure[index] = actualMeasure(index); // read value of actualMeasure into array currentMeasure, pointer = index
if (ocAlarm && !manualRstStatus) {
autoRst(index);
}
if (ocAlarm && manualRstStatus) {
manualRst(index);
}
}
if (millis() - manualRstClear > manualRstClearDelay) { // clear manual reset flag, from now again auto reset
manualRstStatus = false;
}
}
float actualMeasure(int i) { // i = value of index:
// function to read measure from index = boosterNumber array address, and return value as float
j = analogReadPointer[i]; // j = value at pointer address in this array
repeat = 0;
float currentMax = 0.0; // min value for analog read
float currentMin = 1000000.0; // min value for analog read
currentTotal = 0.0;
while (repeat < readRepeat) {
currentNow = analogRead(j); // here introduce MIN / MAX algorithm; readRepeat = 10, analogReadInterval = 2ms
currentNow = analogRead(j); // second reading to get stabilised result
if (currentNow < currentMin) currentMin = currentNow;
if (currentNow >= currentMax) currentMax = currentNow;
currentTotal += currentNow;
repeat++;
delayMicroseconds(10);
}
currentTotal -= (currentMin + currentMax);
currentAvg = currentTotal / (readRepeat - 2);
currentAvg = currentAvg / 1023 * maxCurrent; // this is when a voltage of 5V corresponds to maxCurrent A
currentMeasure[i] = currentAvg;
if (currentAvg > maxCurrent) {
enState[i] = false; // disable output to booster i
ocAlarm = true; // set alarm, at least one booster is in overcurrent
digitalWrite (enablePointer[i], LOW); // set low eneable pin
}
return currentAvg;
}
uint16_t autoRst(int pointer) { // returns boolean status of autoreset
for (k = 0; k < automaticReset; k++) { // meerdere (= automaticReset) uitvoeren van pogingen tot automatische reset
currentMillis = millis(); // why use currentMillis as intermediary, and not straight millis() ?
if (currentMillis - previousMillis > autoRstTimer) {
// reset relevant enable outputs to high
enState[pointer] = true; // enable output to booster i
ocAlarm = false; // reset alarm, at least one booster was in overcurrent, now restarted
digitalWrite (enablePointer[i], HIGH); // set high enable pin
// verify if current is ok now
previousMillis = currentMillis;
}
// after automaticReset number of attempts set flag for manual reset, reset flag for autoreset
manualRstStatus = true;
}
}
uint16_t manualRst(int pointer) { // returns boolean status of manual reset
// wait for button press to reset enable outputs
// debounce: wait for status after button release
// read the state of the switch into a local variable:
// !!! RST_BTN goes from high to low when pressed !!! Adapt code below !!! ..done, 16/3/22
rstButtonValue = digitalRead(rstButton);
if (rstButtonValue == LOW && lastButtonState == HIGH) { // indien knop werd ingedrukt EN dit is opgaande flank, start debounce
// reset the debouncing timer
while (lastDebounceTime == 0) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) // uitvoeren na debounce
{
while (buttonState != lastButtonState) // uitvoeren zolang de knop nog ingedrukt is, en dus = 1.
// Wat als de knop niet is/was ingedrukt: dan is buttonstate = lastButtonState en dus LOW, dus vervalt while
{
rstButtonValue = digitalRead (rstButton); // na debounce nogmaals inlezen op voorwaarde dat button nog steeds is ingedrukt
// highState = HIGH;
}
lastButtonState = !rstButtonValue; // lastButtonState wordt 1 zodra knop gelost is; waat als buttonState niet hoog is geweest,
// dus valse lezing? Dan geldt niet meer dat buttonState = HIGH dus if loop lijn 37 wordt niet meer uitgevoerd
}
}
if (rstButtonValue == HIGH && lastButtonState == LOW) // enkel uitvoeren op neergaande flank EN nadat knop gelost werd EN na debounce
{
//hier de code die moet worden uitgevoerd als de reset knop gelost is
manualRstClear = millis();
lastButtonState = rstButtonValue; // alles terug naar begintoestand: 0
lastDebounceTime = 0;
enState[pointer] = true; // enable output to booster i
ocAlarm = false; // reset alarm, at least one booster was in overcurrent, now restarted
digitalWrite (enablePointer[i], HIGH); // set high enable pin
}
}
void writeLCD() {
dtostrf(currentMeasure[0], 3, 1, txt1);
dtostrf(currentMeasure[1], 3, 1, txt2);
dtostrf(currentMeasure[2], 3, 1, txt3);
dtostrf(currentMeasure[3], 3, 1, txt4);
dtostrf(currentMeasure[4], 3, 1, txt5);
lcd.clear();
lcd.backlight();//Power on the back light
lcd.setCursor(0, 0);
lcd.print(F(" B1 B2 B3 B4 B5"));
lcd.setCursor (0, 1); // go to start of 2nd line
// lcd.print("Current (A) :");
// lcd.setCursor (0, 2); // go to start of 2nd line
lcd.print(txt1);
lcd.print(" ");
lcd.print(txt2);
lcd.print(" ");
lcd.print(txt3);
lcd.print(" ");
lcd.print(txt4);
lcd.print(" ");
lcd.print(txt5);
// lcd.print("A");
lcd.setCursor (0, 2);
lcd.print(F("Status : "));
lcd.setCursor (0, 3);
lcd.print(" ");
lcd.print(enState[0]);
lcd.print(" ");
lcd.print(enState[1]);
lcd.print(" ");
lcd.print(enState[2]);
lcd.print(" ");
lcd.print(enState[3]);
lcd.print(" ");
lcd.print(enState[4]);
// delay(10);
}
void reverser() {
}