Files
Library-ES32A08/src/ES32A08.cpp
2025-02-05 20:28:29 -05:00

484 lines
15 KiB
C++

#include "ES32A08.h"
/**
* @brief Initializes the ES32A08 module.
*
* This function sets up the necessary pin modes and initial states for the
* 74HC595D shift register (used for Relay and 7-Segment display), the power
* LED, and the digital input shift register. It also configures the button
* pins as input with pull-up resistors. Finally, it creates a task to update
* the registers periodically.
*
* Pin configurations:
* - DATA_PIN: Output for shift register data
* - LATCH_PIN: Output for shift register latch
* - CLOCK_PIN: Output for shift register clock
* - OE_PIN: Output for shift register output enable
* - PWR_LED_PIN: Output for power LED
* - buttonPins[0-3]: Input with pull-up for buttons
* - LOAD165_PIN: Output for digital input shift register load
* - CLK165_PIN: Output for digital input shift register clock
* - DATA165_PIN: Input for digital input shift register data
*
* The function also calls the reset() method to initialize the module state
* and creates a FreeRTOS task to handle register updates.
*/
void ES32A08::begin() {
// 74HC595D shift register config (Relay + 7-Seg disp.)
pinMode(DATA_PIN, OUTPUT);
pinMode(LATCH_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
pinMode(OE_PIN, OUTPUT);
digitalWrite(DATA_PIN, LOW);
digitalWrite(LATCH_PIN, LOW);
digitalWrite(CLOCK_PIN, LOW);
digitalWrite(OE_PIN, LOW);
pinMode(PWR_LED_PIN, OUTPUT); // "PWR" board Led
pinMode(buttonPins[0], INPUT_PULLUP);
pinMode(buttonPins[1], INPUT_PULLUP);
pinMode(buttonPins[2], INPUT_PULLUP);
pinMode(buttonPins[3], INPUT_PULLUP);
// Digital inputs shift register config
pinMode(LOAD165_PIN, OUTPUT);
pinMode(CLK165_PIN, OUTPUT);
pinMode(DATA165_PIN, INPUT);
digitalWrite(LOAD165_PIN, HIGH);
reset();
xTaskCreatePinnedToCore(ES32A08::updateRegisters, "Update Registers",
2048, // Stack size
this, // Parameter
1, // Priority
NULL, // Task handle
1 // Core on which the task will run
);
}
/**
* @brief Resets the ES32A08 device to its initial state.
*
* This function performs the following actions:
* - Turns on the power LED to indicate a reset state.
* - Sets the current relay states to either all on or all off based on the RESET_RELAY_ON flag.
* - Clears the display, which also triggers sending data to the shift register.
*/
void ES32A08::reset() {
setPWRLED(RESET_LED_ON);
currentRelays = RESET_RELAY_ON ? 0b11111111 : 0b00000000;
clearDisplay(); // it also calls sendToShiftRegister()
}
/**
* @brief Sends the current state of relays, digits, and segments to the shift registers.
*
* This function updates the shift registers with the current state of the relays, digits,
* and segments by shifting out the data bits and latching the output. It controls three
* shift registers, each handling 8 bits, for a total of 24 bits.
*
* @details
* - The function first sets the latch pin to LOW to prepare for data transmission.
* - It then shifts out the bits for the relays, digits, and segments in MSB first order.
* - After shifting out the data, it sets the latch pin to HIGH to update the output.
* - Finally, it introduces a small delay to ensure the data is properly latched.
*
* @note The delay is specified in microseconds and is defined by the DIGIT_PERS constant.
*/
void ES32A08::sendToShiftRegister() {
digitalWrite(LATCH_PIN, LOW);
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, currentRelays);
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, currentDigits);
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, currentSegments);
digitalWrite(LATCH_PIN, HIGH);
delayMicroseconds(DIGIT_PERS);
} // There are 3 shift registers for a total of 24 bits
/**
* @brief Clears the display buffer.
*
* This function sets all elements of the display buffer to zero, effectively
* clearing the display.
*/
void ES32A08::clearDisplay() {
memset(displayBuffer, 0, sizeof(displayBuffer));
}
/**
* @brief Updates the display registers continuously.
*
* This function runs an infinite loop that updates the display registers.
* It iterates through the display buffer and updates the current digits and segments,
* then sends the data to the shift register.
*
* @param instance A pointer to an instance of the ES32A08 class.
*/
void ES32A08::updateRegisters(void *instance) {
ES32A08 *self = static_cast<ES32A08 *>(instance); // Cast del puntatore
for (;;) {
for (uint8_t pos = 0; pos < 4; pos++) {
self->currentDigits = self->digitNumber[1 + pos];
self->currentSegments = self->displayBuffer[pos];
self->sendToShiftRegister();
}
}
}
/**
* @brief Converts a character to its corresponding 7-segment display encoding.
*
* This function takes a character as input and returns the corresponding
* 8-bit binary encoding for a 7-segment display. The encoding is based on
* the common cathode 7-segment display configuration.
*
* @param c The character to be converted. Supported characters include:
* '0'-'9', 'A'-'Z', 'a'-'z', ' ', '.', '-', '_'.
* @return uint8_t The 8-bit binary encoding for the 7-segment display.
* If the character is not recognized, it returns 0b00000000 (blank).
*/
uint8_t ES32A08::charToSegments(char c) {
switch (c) {
case '0':
return 0b00111111; // 0
case '1':
return 0b00000110; // 1
case '2':
return 0b01011011; // 2
case '3':
return 0b01001111; // 3
case '4':
return 0b01100110; // 4
case '5':
return 0b01101101; // 5
case '6':
return 0b01111101; // 6
case '7':
return 0b00000111; // 7
case '8':
return 0b01111111; // 8
case '9':
return 0b01101111; // 9
case ' ':
return 0b00000000; // white space
case '.':
return 0b10000000; // decimal point
case '-':
return 0b01000000; // score
case '_':
return 0b00001000; // underscore
case 'A':
return 0b01110111; // A
case 'a':
return 0b01011111; // a
case 'B':
case 'b':
return 0b01111100; // B-b
case 'C':
return 0b00111001; // C
case 'c':
return 0b01011000; // c
case 'D':
case 'd':
return 0b01011110; // D-d
case 'E':
return 0b01111001; // E
case 'e':
return 0b01111011; // e
case 'F':
case 'f':
return 0b01110001; // F-f
case 'G':
case 'g':
return 0b01101111; // G-g
case 'H':
return 0b01110110; // H
case 'h':
return 0b01110100; // h
case 'I':
return 0b00000110; // I
case 'i':
return 0b00010000; // i
case 'J':
case 'j':
return 0b00011110; // J-j
case 'L':
return 0b00111000; // L
case 'l':
return 0b00011000; // l
case 'M':
case 'm':
return 0b00110111; // M-m
case 'N':
case 'n':
return 0b01010100; // N-n
case 'O':
case 'o':
return 0b01011100; // O-o
case 'P':
case 'p':
return 0b01110011; // P-p
case 'Q':
case 'q':
return 0b01100111; // Q-q
case 'R':
case 'r':
return 0b01010000; // R-r
case 'S':
case 's':
return 0b01101101; // S-s
case 'T':
case 't':
return 0b01111000; // T-t
case 'U':
return 0b00111110; // U
case 'u':
return 0b00011100; // u
case 'Y':
case 'y':
return 0b01100110; // Y-y
case 'Z':
case 'z':
return 0b01011011; // Z-z
default:
return 0b00000000; // Blank if not found
}
}
/**
* @brief Displays a message on the ES32A08 display.
*
* This function clears the display buffer and then converts each character
* in the provided message to its corresponding segment representation,
* storing it in the display buffer. The message is truncated to a maximum
* of 4 characters.
*
* @param message The message to be displayed. It should be a null-terminated
* string with a maximum length of 4 characters.
*/
void ES32A08::display(const char *message) {
memset(displayBuffer, 0, sizeof(displayBuffer));
for (int pos = 0; message[pos] != '\0' && pos < 4; pos++)
displayBuffer[pos] = charToSegments(message[pos]);
}
/**
* @brief Displays a given integer number on a 4-digit 7-segment display.
*
* This function takes an integer number and displays it on a 4-digit 7-segment display.
* If the number is outside the range of -999 to 9999, it displays " -- ".
* Otherwise, it formats the number to fit within 4 characters and updates the display buffer.
*
* @param number The integer number to be displayed. Valid range is -999 to 9999.
*/
void ES32A08::display(int number) {
if (number > 9999 || number < -999)
display(" -- ");
else {
char buffer[5]; // Chars buffer + endl ('\0')
snprintf(buffer, sizeof(buffer), "%4d", number);
for (int i = 0; i < 4; i++)
displayBuffer[i] = charToSegments(buffer[i]);
}
}
/**
* @brief Displays a floating-point number on a 7-segment display.
*
* This function takes a floating-point number and converts it into a format
* suitable for displaying on a 7-segment display. The number is formatted to
* two decimal places. If the number is outside the range of -999 to 9999,
* it displays " -- " to indicate an out-of-range value.
*
* @param number The floating-point number to be displayed.
*/
void ES32A08::display(float number) {
memset(displayBuffer, 0, sizeof(displayBuffer));
if (number > 9999 || number < -999)
display(" -- ");
else {
char buffer[6]; // Chars buffer + endl ('\0')
snprintf(buffer, sizeof(buffer), "%.2f", number);
int i;
for (i = 0; i < 4 && buffer[i] != '.'; i++) {
displayBuffer[i] = charToSegments(buffer[i]);
}
if (i == 4)
return; // No decimal point found
if (buffer[i] == '.') {
displayBuffer[i - 1] |= 0b10000000; // Decimal point
for (i; i < 5; i++) {
displayBuffer[i] = charToSegments(buffer[i + 1]);
}
}
}
}
/**
* @brief Reads the analog current in milliamps from the specified channel.
*
* This function reads the analog value from the specified channel, converts it
* to a current value in milliamps, and returns the result. The conversion is
* based on a 12-bit ADC (Analog-to-Digital Converter) with a range of 0 to 4095.
*
* @param channel The analog input channel to read from. Valid values are 0 to 3.
* @return The current in milliamps. If the channel is out of range, the function returns 0.
*/
float ES32A08::readAnalogmA(int channel) {
if (channel < 0 || channel > 3)
return 0;
int adcValue = analogRead(mAInputPins[channel]);
float current = ((adcValue / 4095.0) * (20.0 - 4.0)) * 2.0692;
return current;
}
/**
* @brief Reads the analog voltage from a specified channel.
*
* This function reads the analog value from the specified channel, converts it
* to a voltage, and returns the result. The conversion assumes a 12-bit ADC
* with a reference voltage of 10V and applies a scaling factor.
*
* @param channel The analog input channel to read from (valid values are 0 to 3).
* @return The converted voltage value. Returns 0 if the channel is out of range.
*/
float ES32A08::readAnalogVoltage(int channel) {
if (channel < 0 || channel > 3)
return 0;
int adcValue = analogRead(voltageInputPins[channel]);
float voltage = ((adcValue / 4095.0) * 10.0) * 2.0692;
return voltage;
}
/**
* @brief Reads the raw analog voltage from the specified channel.
*
* This function reads the analog voltage from one of the predefined input pins
* corresponding to the given channel. The channel must be between 0 and 3 inclusive.
* If the channel is out of this range, the function returns 0.
*
* @param channel The analog input channel to read from (0-3).
* @return The raw analog voltage value read from the specified channel, or 0 if the channel is invalid.
*/
int ES32A08::rawReadAnalogVoltage(int channel) {
if (channel < 0 || channel > 3)
return 0;
return analogRead(voltageInputPins[channel]);
}
/**
* @brief Sets the state of a specified relay.
*
* This function sets the state (on or off) of the relay specified by the
* relay parameter. It updates the currentRelays variable and sends the
* updated state to the shift register.
*
* @param relay The relay number to set (0-based index).
* @param state The desired state of the relay (true for on, false for off).
*/
void ES32A08::setRelay(int relay, bool state) {
bitWrite(currentRelays, relay, state);
sendToShiftRegister();
}
// Set all relays (0b00000000 - 0b11111111)
/**
* @brief Sets the state of the relays.
*
* This function updates the current state of the relays and sends the new state
* to the shift register.
*
* @param relayStates An unsigned long representing the desired state of the relays.
*/
void ES32A08::setRelays(unsigned long relayStates) {
currentRelays = relayStates;
sendToShiftRegister();
}
// Read all digital inputs
/**
* @brief Reads the digital inputs from a shift register.
*
* This function reads 8 digital inputs from a shift register connected to the
* microcontroller. It first loads the inputs by toggling the LOAD165_PIN, then
* reads each bit by toggling the CLK165_PIN and reading the DATA165_PIN.
*
* @return uint8_t A byte representing the state of the 8 digital inputs.
*/
uint8_t ES32A08::readDigitalInputs() {
uint8_t inputs = 0;
digitalWrite(LOAD165_PIN, LOW);
delayMicroseconds(5);
digitalWrite(LOAD165_PIN, HIGH);
// delayMicroseconds(5);
for (int i = 0; i < 8; i++) {
digitalWrite(CLK165_PIN, LOW); // Init clock cycle
delayMicroseconds(5);
bitWrite(inputs, 7 - i, digitalRead(DATA165_PIN));
digitalWrite(CLK165_PIN, HIGH);
// delayMicroseconds(5);
}
return inputs;
}
// Read single digital input
/**
* @brief Reads the state of a specified digital input.
*
* This function checks the state of a digital input specified by the input number.
* The input number must be between 1 and 8, inclusive. If the input number is out
* of this range, the function returns false.
*
* @param inputNumber The number of the digital input to read (1-8).
* @return true if the specified digital input is high, false if it is low or if the input number is out of range.
*/
bool ES32A08::readDigitalInput(int inputNumber) {
if (inputNumber < 1 || inputNumber > 8)
return false;
uint8_t digitalInputs = readDigitalInputs();
return digitalInputs & (1 << (inputNumber - 1));
}
// Set "PWR" onboard LED
/**
* @brief Sets the state of the power LED.
*
* This function controls the power LED by setting its state to the specified value.
*
* @param state The desired state of the power LED.
* - `true` to turn the LED off.
* - `false` to turn the LED on.
*/
void ES32A08::setPWRLED(bool state) { digitalWrite(PWR_LED_PIN, !state); }
// Read single button state
/**
* @brief Reads the state of a specified button.
*
* This function reads the digital state of a button specified by its number.
* It returns `true` if the button is pressed and `false` otherwise.
*
* @param buttonNumber The number of the button to read (1-based index).
* @return `true` if the button is pressed, `false` otherwise.
*/
bool ES32A08::readButton(int buttonNumber) {
return !digitalRead(buttonPins[buttonNumber - 1]);
}