// ======= ACS712 (Current Measurement) ========
// NeoPixel Library
#include <Adafruit_NeoPixel.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Wire.h>
#include "logo.h" // Include logo file
#include <Adafruit_INA219.h>
Adafruit_INA219 ina219;
#define LED_PIN 6
#define NUM_LEDS 100 // Max number of led's \
// Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800); // In start initilize led strip with 10 leds
// Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800); // In start initilize led strip with 10 leds
//LED strip variables
// Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// ACS-712
#define ACS712_PIN A0
const float ACS712_SENSITIVITY = 66.0; // Sensibilité du capteur ACS712 en mV/A
const int numReadings = 10; // Nombre de lectures pour la moyenne
float readings[numReadings]; // Tableau pour stocker les lectures
int index = 0; // Index pour parcourir le tableau
float total = 0; // Variable pour stocker la somme des lectures
void displayLogo() {
// Affiche le logo sur l'écran OLED pendant 3 secondes
display.clearDisplay();
display.drawBitmap(5, 0, epd_bitmap_logo_mmw_128x64, 128, 64, 1);
display.display();
// delay(3000);
}
// =========== Encoder Pins =============
#define ENCODER_CLK 2
#define ENCODER_DT 3
#define ENCODER_SW 4
int counter = 0;
float averageCurrent = 0;
float loadvoltage = 0;
// Menu and other Variables
byte page = 1; // variable to hold page number
byte ledNumber = 1; // Number of leds' to be tested
byte brightness = 10; // LED Brightness
bool automatic = true; // Selection test Mode automatic/manual
bool startTest = false; // flag to star the test
bool startFinalTest = false; // flag to start the led color tests
byte testNumber = 1; // test Number
byte prevPage = 0; // Variable to hold previous page number
bool ledInitialize = false;
unsigned long timeOut = 10 * 1000; // time for timeout in milliseconds for manual mode if user doesn't press button
bool timeOutFlag = false; // flag to turn on when timeout occur
unsigned long mainTimeOut = 30 * 1000; // main display timeout
unsigned long lastActivity = millis(); // variable to store last activity
bool mainTimeOutFlag = false; // flag to check if we are in main timeout
bool forceExit = false; // flag to exit forcefully
unsigned long lastEncoderInterruptTime = millis();
uint8_t wr, wb, wg;
void readEncoder() {
mainTimeOutFlag = false;
lastActivity = millis(); // note activity time
// This function will read encoder
int dtValue = digitalRead(ENCODER_DT);
if ((millis() - lastEncoderInterruptTime) > 90) {
if (dtValue == HIGH) {
if (page == 2) {
counter += 10; // increment counter with 10
counter = (counter > 100) ? 100 : counter;
} else
counter++; // Clockwise
if (page == 3)
automatic = false; // select manual mode
}
if (dtValue == LOW) {
if (page == 2) {
counter -= 10; // increment counter with 10
counter = (counter < 10) ? 10 : counter; // if counter get's below 0 set it to 0
} else {
counter--; // Counterclockwise
counter = (counter < 0) ? 0 : counter; // if counter get's below 0 set it to 0
}
if (page == 3)
automatic = true; // select automatic mode
}
}
}
// Get the counter value, disabling interrupts.
// This make sure readEncoder() doesn't change the value
// while we're reading it.
int getCounter() {
int result;
noInterrupts();
result = counter;
interrupts();
return result;
}
void resetCounter() {
noInterrupts();
counter = 0;
interrupts();
}
void customDelay(unsigned long waitTime);
void about() { // show about
display.clearDisplay();
display.setCursor(32, 10);
display.drawRoundRect(28, 6, 73, 15, 2, WHITE);
display.println("MM-WORKSHOP");
display.setCursor(20, 35);
display.print("www.mmwork.shop");
display.setCursor(25, 50);
display.print("v1.0 - 2023");
display.display();
}
void setup() {
// Serial.begin(9600); // Initialize Serial communication at 115200 baud rate
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Initialize LCD
display.setTextColor(WHITE, BLACK); //Sets the font display color
display.clearDisplay(); //cls
// Initialize encoder pins
pinMode(ENCODER_CLK, INPUT); // Set clock pin as input
pinMode(ENCODER_DT, INPUT); // Set data pin as input
pinMode(ENCODER_SW, INPUT_PULLUP); // Set enconder button pin as input with pullup
attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), readEncoder, FALLING); // Attach falling interrupt to clock pin
displayLogo(); // Display logo on OLED
delay(3000);
about(); // show about
delay(3000); // Wait for 3 seconds
// Try to initialize the INA219
ina219.begin();
}
void showMenu() {
display.clearDisplay();
page = 1; // set page number to 1
// Display main menu
display.setCursor(40, 0);
display.println("Main Menu");
display.setCursor(0, 14);
display.print("> # LED's: ");
display.setCursor(90, 14);
display.print(ledNumber);
display.setCursor(0, 27);
display.println(" Brightness: ");
display.setCursor(90, 27);
display.print(String(brightness) + " %");
display.setCursor(0, 40);
display.print(" Mode: ");
display.setCursor(90, 40);
if (automatic)
display.print("Auto");
else if (!automatic)
display.print("Manual");
display.setCursor(0, 55);
display.print("Press Button to Next");
display.display();
counter = 1; // set counter to 1
}
void loop() {
if (prevPage == 0) {
showMenu(); // display menu
// resetCounter(); // reset counter value
prevPage = 1;
page = 1;
}
updateDisplay();
if (digitalRead(ENCODER_SW) == LOW) {
lastActivity = millis(); // note current activity time
// check if encoder button was pressed
page += 1;
if (page == 2) {
resetCounter(); // reset counter value
counter = 10; // changer coutner to 10 for brightness
display.setCursor(0, 14);
display.print(" ");
display.setCursor(0, 27);
display.print(">");
} else if (page == 3) {
resetCounter(); // reset counter value
display.setCursor(0, 27);
display.print(" ");
display.setCursor(0, 40);
display.print(">");
display.setCursor(0, 55);
display.print("Press Button to Start");
} else {
startTest = true; // set the start test flag
}
display.display();
customDelay(500); // avoid double press
}
if (startTest) {
// Serial.println("Start Tests");
display.clearDisplay(); // clear display
display.setCursor(30, 24);
display.print("Initializing");
display.display();
chaseLEDs();
// flashFirstLED();
display.clearDisplay(); // clear display
display.setCursor(18, 18);
display.print("Initialized test");
display.setCursor(55, 35);
display.print("phases");
display.display();
customDelay(1000);
startTest = false;
}
if (startFinalTest) {
startColorTests();
prevPage = 0;
}
if (timeOutFlag || forceExit) {
if (timeOutFlag) {
display.clearDisplay();
display.setCursor(40, 22);
display.print("TimeOUT"); // Test 2 Green
display.display();
timeOutFlag = false;
} else if (forceExit) {
display.clearDisplay();
display.setCursor(40, 22);
display.print("Aborted"); // Test 2 Green
display.display();
forceExit = false;
}
startFinalTest = false;
prevPage = 0;
customDelay(2000);
}
if ((millis() - lastActivity) > mainTimeOut) { // in case of inactivity show logo and about screen
mainTimeOutFlag = true;
bool changeDisplay = false; // flag to chagne display
unsigned long cTime = millis(); // note current time
while (mainTimeOutFlag) {
if ((millis() - cTime) > 10000) { // if 10 seconds has passed switch display between logo and abouts
if (changeDisplay) {
displayLogo();
changeDisplay = false;
} else if (!changeDisplay) {
changeDisplay = true;
about();
}
cTime = millis();
}
}
prevPage = 0;
mainTimeOutFlag = false;
}
}
void updateDisplay() {
if (page == 1) {
ledNumber = getCounter();
display.setCursor(90, 14);
display.print(ledNumber);
display.print(" ");
} else if (page == 2) {
brightness = getCounter();
display.setCursor(90, 27);
display.print(brightness);
display.print(" % ");
display.display();
} else if (page == 3) {
display.setCursor(90, 40);
if (automatic)
display.print("Auto ");
else if (!automatic)
display.print("Manual");
}
display.display(); // update display
}
void customDelay(unsigned long waitTime) {
unsigned long cTime = millis();
while ((millis() - cTime) < waitTime) {
if (!digitalRead(ENCODER_SW)) { // check if user pressed button
while (!digitalRead(ENCODER_SW)) { ; } // wait for button release
if ((millis() - cTime) > 2000) // if button press time is two second activate force exit
forceExit = true; // set force exit flag
}
}
}
void chaseLEDs() {
// Serial.println("Chase LED");
Adafruit_NeoPixel strip = Adafruit_NeoPixel(10, LED_PIN, NEO_GRB + NEO_KHZ800);
strip.begin();
strip.show();
// Serial.println(brightness);
strip.setBrightness(map(brightness, 10, 100, 25, 255)); // 255 is the max brightness
customDelay(1000);
unsigned long startMillis = millis();
while (millis() - startMillis < 3000) {
for (int i = 0; i < 10; i++) {
strip.setPixelColor(i, 255, 0, 0); // RED color for chasing
strip.show();
customDelay(100);
// strip.setPixelColor(i, strip.Color(0, 0, 0)); // Turn off LED
}
for (int i = 9; i >= 0; i--) {
strip.setPixelColor(i, 0, 0, 0);
strip.show();
customDelay(100);
// strip.setPixelColor(i, strip.Color(0, 0, 0));
}
}
strip.clear();
strip.show();
// Serial.println("Flash LED");
for (byte i = 0; i < 3; i++) {
strip.setPixelColor(0, 0, 255, 0); // GREEN color
strip.show();
customDelay(500);
strip.setPixelColor(0, 0, 0, 0); // Turn off LED
strip.show();
customDelay(500);
}
strip.clear();
strip.show();
startFinalTest = true;
// flashFirstLED();
}
void startColorTests() {
// Serial.println("Starting final tests");
waitForNext(); // call the function to update display
if (timeOutFlag || forceExit)
return;
// display.clearDisplay(); // clear display
// display.display();
display.setCursor(40, 22);
display.print("RED Test"); // Test 1 Red
display.display(); // update display
colorTest(255, 0, 0, false); // Red
waitForNext(); // call the function to update display
if (timeOutFlag || forceExit)
return;
// display.clearDisplay(); // clear display
display.setCursor(35, 22);
display.print("Green Test"); // Test 2 Green
display.display(); // update display
colorTest(0, 255, 0, false); // Green
waitForNext(); // call the function to update display
if (timeOutFlag || forceExit)
return;
// display.clearDisplay(); // clear display
display.setCursor(38, 22);
display.print("Blue Test"); // Test 2 Green
display.display(); // update display
colorTest(0, 0, 255, false); // Blue
waitForNext(); // call the function to update display
if (timeOutFlag || forceExit)
return;
// display.clearDisplay(); // clear display
display.setCursor(35, 22);
display.print("White Test"); // Test 2 Green
display.display(); // update display
colorTest(255, 255, 255, false); // White
waitForNext(); // call the function to update display
if (timeOutFlag || forceExit)
return;
// display.clearDisplay(); // clear display
display.setCursor(32, 22);
display.print("Purple Test"); // Test 2 Green
display.display(); // update display
colorTest(128, 0, 128, false); // Purple
waitForNext(); // call the function to update display
if (timeOutFlag || forceExit)
return;
// display.clearDisplay(); // clear display
display.setCursor(30, 22);
display.print("Rainbow Test"); // Test 2 Green
display.display(); // update display
colorTest(128, 0, 128, true); // rainbow test
startFinalTest = false;
}
void waitForNext() {
// bool timeOutFlag = false; // flag to turn on when timeout occur
// bool = false; // flag to exit forcefully
unsigned long cTime = millis();
// in case of manual mode program has to wait for button press
display.clearDisplay(); // clear display
if ((testNumber == 1) && (!automatic)) {
display.setCursor(14, 22);
display.print("Validate to launch");
display.setCursor(38, 36);
display.print("the Tests");
display.display();
// while (digitalRead(ENCODER_SW)) { ; } // wait for button press
testNumber = 2; // change test number not to show same message
} else if (!automatic) {
display.setCursor(14, 24);
display.print("Validate for Next");
display.setCursor(52, 38);
display.print("Test");
display.display();
}
if (!automatic) { // in case of manual mode
while (digitalRead(ENCODER_SW)) { // wait for button press
if ((millis() - cTime) > timeOut) {
customDelay(10);
timeOutFlag = true; // set timeout flat
break; // break loop
}
// customDelay(1);
}
}
display.clearDisplay(); // clear display
display.setCursor(5, 52);
display.print("LEDs:");
display.print(ledNumber); // Display selectd number of leds
display.setCursor(66, 52);
display.print("Brigth:");
display.print(brightness); // Display selected brightness
display.setCursor(0, 0);
display.print("Voltage");
display.setCursor(85, 0);
display.print("Current");
display.setCursor(0, 52);
display.display();
lastActivity = millis();
}
void colorTest(byte r, byte g, byte b, bool rainbow) {
Adafruit_NeoPixel strip = Adafruit_NeoPixel(ledNumber, LED_PIN, NEO_GRB + NEO_KHZ800);
strip.begin();
strip.show();
strip.setBrightness(map(brightness, 10, 100, 25, 255)); // 255 is the max brightness
if (!rainbow) {
int ledDelay = 5000 / ledNumber;
displayVoltageCurrent(); // get voltage and current
for (int i = 0; i < ledNumber; i++) {
strip.setPixelColor(i, r, g, b);
strip.show();
customDelay(ledDelay);
if (forceExit) break;
}
displayVoltageCurrent(); // get voltage and current
customDelay(1000); // Pause for 5 seconds
// // Turn off LEDs in reverse order quickly
for (int i = ledNumber - 1; i >= 0; i--) {
strip.setPixelColor(i, 0);
strip.show();
customDelay(50); // Quick turn off
}
displayVoltageCurrent(); // get voltage and current
}
if (rainbow) {
strip.begin();
strip.show();
strip.setBrightness(map(brightness, 10, 100, 25, 255)); // 255 is the max brightness
uint16_t i, j;
for (j = 0; j < 256 * 3; j++) { // 3 cycles of all colors on wheel
for (i = 0; i < strip.numPixels(); i++) {
Wheel(((i * 256 / strip.numPixels()) + j) & 255);
strip.setPixelColor(i, wr, wg, wb);
}
strip.show();
customDelay(20);
if (forceExit) break;
}
// // Turn off LEDs in reverse order quickly
for (int i = ledNumber - 1; i >= 0; i--) {
strip.setPixelColor(i, 0);
strip.show();
customDelay(50); // Quick turn off
}
}
display.setCursor(40, 36);
display.print("Finished");
display.display();
customDelay(2000); // wait for 2 second
}
// Function to generate rainbow colors
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 - WheelPos;
if (WheelPos < 85) {
wr = 255 - WheelPos * 3;
wg = 0;
wb = WheelPos * 3;
}
if (WheelPos < 170) {
WheelPos -= 85;
wr = 0;
wg = WheelPos * 3;
wb = 255 - WheelPos * 3;
}
WheelPos -= 170;
wr = WheelPos * 3;
wg = 255 - WheelPos * 3;
wb = 0;
}
void measureVoltage(){
float shuntvoltage = 0;
float busvoltage = 0;
shuntvoltage = ina219.getShuntVoltage_mV();
busvoltage = ina219.getBusVoltage_V();
loadvoltage = busvoltage + (shuntvoltage / 1000);
}
void measureCurrent(){
// Lis la valeur analogique du capteur ACS712
int rawValueACS712 = analogRead(ACS712_PIN);
// Convertit la valeur analogique en tension en utilisant la référence de tension de l'Arduino (5V)
float voltageACS712 = (rawValueACS712 / 1023.0) * 5.0;
// Calcule le courant en A en utilisant la sensibilité du capteur ACS712
float currentACS712 = voltageACS712 / ACS712_SENSITIVITY;
// Ajoute la nouvelle lecture à la somme totale en soustrayant la lecture la plus ancienne du tableau
total = total - readings[index];
readings[index] = currentACS712;
total = total + readings[index];
// Incrémente l'index pour la prochaine lecture
index = (index + 1) % numReadings;
// Calcule la moyenne des lectures
averageCurrent = total / numReadings;
}
void displayVoltageCurrent(){
measureVoltage(); // measure voltage
measureCurrent(); // Measure Current
display.setCursor(7, 12);
display.print(loadvoltage, 2);
display.setCursor(97, 12);
display.print(averageCurrent, 2);
display.display();
}