// Concepto: mide la tensión de bobinado constantemente y acciona el servo para aumentar o disminuír
// la tensión usando un control PID.
//
// Un botón (latch) determina si el control de tensión está activado. Si no, se mide la tensión, pero no se activa el servo para corregirla.
// Si la tensión está dentro del rango establecido como seguro, el LED tensión se mantiene encendido continuamente.
// Si la tensión está fuera de ese rango, el LED tensión titila cada vez con menos frecuencia a medida que se aleja del valor central.
// Lee la tensión de alimentación del Arduino.
// Avisa encendiendo un LED cuándo cae por debajo de un valor umbral.
// La ideal para 4 pilas recarganles es de 4,8 V (y se supone que se mantiene mucho tiempo así).
// Si cae por debajo de 4,4, el LED comienza a titilar, 1 vez cada tantos segundos como decimales haya:
// 4,4 V: 1 vez cada 4 segundos.
// 4,3 V: 1 vez cada 3 segundos.
// 4,2 V: 1 vez cada 2 segundos.
// 4,1 V: 1 vez cada 1 segundo.
// Por debajo de 4 V, se mantiene encendido.
// Si el switch del bluetooth está activado, envía los valores de tensión con una frecuenia determinada.
// Made by Juan 03/2025
#include <arduino-timer.h>
// https://deepbluembedded.com/arduino-timer-library/#google_vignette
// https://github.com/contrem/arduino-timer
#include "HX711.h"
// https://github.com/RobTillaart/HX711
HX711 scale;
Timer<1, millis> TimnerManageBatteryVoltage;
Timer<2, millis> TimerLowBatteryLED; // 2 concurrent tasks, one to turn the LED on and the other to turn it off.
Timer<2, millis> TimerTensionLED;
Timer<1, millis> TimerBTSendData; // 1 concurrent task, using millis as resolution.
// Global variables - Stert
float measured_tension = 0;
constexpr float target_tension = 1; // Determined by a calibration.
constexpr float tension_safe_range_width = 0.1; // Determined by a calibration.
long manage_battery_voltaje_delay = 600000L; // Check every 10 minutes.
long low_battery_LED_delay = 1000L; // Send data every ... ms.
long tension_LED_delay = 1000L; // Send data every ... ms.
constexpr int BT_sendData_delay = 1000; // Send data every ... ms.
constexpr int LED_blink_on_duration = 100; // Amount of time the LED stays on (in ms).
constexpr byte low_battery_LED_pin = 2;
constexpr byte tension_LED_pin = 3;
constexpr byte active_tension_pin = 4;
constexpr byte active_BT_pin = 5;
constexpr byte LOADCELL_DOUT_PIN = A0;
constexpr byte LOADCELL_SCK_PIN = A1;
bool low_battery_LED_state = false;
bool isTimerLowBatteryLEDRunning = false;
bool tension_LED_state = false;
//bool active_tension_state = 0;
//bool active_BT_state = 0;
// Global variables - End
void setup() {
pinMode(low_battery_LED_pin, OUTPUT);
pinMode(tension_LED_pin, OUTPUT);
pinMode(active_tension_pin, OUTPUT);
pinMode(active_BT_pin, OUTPUT);
TimnerManageBatteryVoltage.in(1, Manage_Battery_Voltage); // Check the battery level when the program starts.
TimerLowBatteryLED.every(low_battery_LED_delay, Blink_Low_Battery_LED);
TimerTensionLED.every(tension_LED_delay, Set_tension_LED);
TimerBTSendData.every(BT_sendData_delay, BT_send_data);
scale.begin(dataPin, clockPin);
scale.set_scale(0.420); // load cell factor (comes from calibration)
scale.tare(); // reset the scale to zero = 0
}
void loop() {
TimnerManageBatteryVoltage.tick();
TimerLowBatteryLED.tick();
TimerTensionLED.tick();
TimerBTSendData.tick();
}
bool Set_tension_LED(void *)
// en proceso....
{
if (low_battery_LED_state) {
digitalWrite(tension_LED_pin, LOW);
} else {
digitalWrite(tension_LED_pin, HIGH);
}
return true; // true: repeat the action, false: to stop the task.
}
bool BT_send_data(void *)
// en proceso....
{
return true; // true: repeat the action, false: to stop the task.
}
bool Manage_Battery_Voltage(void *)
// Measures the battery voltage and resets the TimerLowBatteryLED (so it will always show the latest data).
{
TimerLowBatteryLED.cancel(); // Cancel all tasks in TimerLowBatteryLED.
TimnerManageBatteryVoltage.cancel(); // Cancel all tasks in TimnerManageBatteryVoltage.
int Vcc = getVcc();
if (Vcc <= 4450) { // Low battery level:
manage_battery_voltaje_delay = 60000L; // Check every minute.
if (Vcc > 4350) low_battery_LED_delay = 4000;
else if (Vcc <= 4350 && Vcc > 4250) low_battery_LED_delay = 3000;
else if (Vcc <= 4250 && Vcc > 4150) low_battery_LED_delay = 2000;
else if (Vcc <= 4150 && Vcc > 4000) low_battery_LED_delay = 1000;
else low_battery_LED_delay = 2.5 * LED_blink_on_duration;
TimerLowBatteryLED.every(low_battery_LED_delay, Blink_Low_Battery_LED); // Only sets low_battery_LED if Vcc <= 4450.
} else manage_battery_voltaje_delay = 600000L; // Check every 10 minutes.
TimnerManageBatteryVoltage.every(manage_battery_voltaje_delay, Manage_Battery_Voltage); // Read battery voltage every 10 minutes and set the blinking frecuency.
return true; // true: repeat the action, false: to stop the task.
}
bool Blink_Low_Battery_LED(void *)
{
digitalWrite(low_battery_LED_pin, HIGH);
TimerLowBatteryLED.in(LED_blink_on_duration, Turn_off_Low_Battery_LED);
return true; // true: repeat the action, false: to stop the task.
}
bool Turn_off_Low_Battery_LED(void *)
{
digitalWrite(low_battery_LED_pin, LOW);
return false; // true: repeat the action, false: to stop the task.
}
int getVcc()
// Returns the Vcc voltage (in mV).
{
constexpr long InternalReferenceVoltage = 1056L; // Adjust this value to your boards specific internal BG voltage in mV.
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// For mega boards
// REFS1 REFS0 --> 0 1, AVcc internal ref. -Selects AVcc reference
// MUX4 MUX3 MUX2 MUX1 MUX0 --> 11110 1.1V (VBG) -Selects channel 30, bandgap voltage, to measure
ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR)| (0<<MUX5) | (1<<MUX4) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
#else
// For 168/328 boards
// REFS1 REFS0 --> 0 1, AVcc internal ref. -Selects AVcc external reference
// MUX3 MUX2 MUX1 MUX0 --> 1110 1.1V (VBG) -Selects channel 14, bandgap voltage, to measure
ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
#endif
delay(50); // Let mux settle a little to get a more stable A/D conversion
// Start a conversion
ADCSRA |= _BV( ADSC );
// Wait for it to complete
while( ( (ADCSRA & (1<<ADSC)) != 0 ) );
int result = ((InternalReferenceVoltage * 1024L) / ADC) + 5L; // calculates for straight line value.
return result;
}