484 lines
15 KiB
C++
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]);
|
|
} |