En este tutorial, veremos cómo dirigir cada relé individualmente con un microcontrolador NodeMCU32S y registros de desplazamiento 74HC595. Al final de este tutorial, también serás capaz de manejar cada relé utilizando el monitor en serie. Este tutorial es una continuación del proyecto Piloto 8 relés utilizando un ESP32 y un registro de desplazamiento.
Este tutorial se puede aplicar a cualquier microcontrolador. Tendrá que tener cuidado de modificar el esquema de conexión y el código para que se ajuste a su uso.
Hardware
- NodeMCU 32S
- Breadboard
- Jumper cable
- Módulo de 8 relés
- Registro de desplazamiento 74hc595
Principio
Hemos visto, en el tutorial anterior, cómo gestionar 8 relés utilizando un registro de desplazamiento. Ahora pasaremos a dirigirnos a cada relé de forma independiente utilizando el monitor de serie de Arduino IDE. Es posible comunicarse con el microcontrolador a través del puerto USB utilizando el puerto serie. Por lo tanto, definiremos una estructura de mensajes para especificar al microcontrolador qué relé debe encender.
Esquema
A modo de recordatorio, este es el diagrama de conexión del proyecto
- GND tierra del circuito integrado
- Pin de alimentación Vdc. Normalmente se conecta a 5V
- SH_CP o RCLK conectado al pin 33
- ST_CP o SRCLK conectado al pin 32
- DS o SER conectado al pin 25
Código
Vamos a tomar el código del tutorial anterior y añadir las funciones para recibir mensajes del monitor serie y recuperar los comandos de control del relé. Para los mensajes de comando, elegimos la forma «YYxZ», con YY, el identificador del relé, un número de 0 a 7; y Z, el estado del relé 0-abierto, 1-cerrado.
La función readSerialPort, recupera los caracteres enviados por el monitor serie en la cadena «msg».
la función convertMsgToCmd traducirá la cadena en un número de identificación relayId y el estado relayState.
void readSerialPort() { while (Serial.available()) { delay(10); if (Serial.available() > 0) { char c = Serial.read(); //gets one byte from serial buffer msg += c; } } } void convertMsgToCmd() { relayId = -1; relayState = -1; if (msg.length() > 0) { Serial.println(msg); sep = msg.indexOf('x'); if (sep > 0) { m1 = msg.substring(0, sep); //get servo id m2 = msg.substring(sep + 1, msg.length()); //get servo pos char carray1[6]; //magic needed to convert string to a number m1.toCharArray(carray1, sizeof(carray1)); relayId = atoi(carray1); char carray2[6]; m2.toCharArray(carray2, sizeof(carray2)); relayState = atoi(carray2); relayState = 1 - relayState; Serial.print(F("Set relay n° ")); Serial.print(relayId); Serial.print(F(" to ")); Serial.println(!relayState ? "HIGH" : "LOW"); } sep = msg.indexOf("reset"); if (sep == 0) { m1 = "reset"; } sep = msg.indexOf("states"); if (sep == 0) { m1 = "states"; } msg = ""; } }
Una vez recuperados los valores relayId y relayState, podemos ponerlos a la entrada de la función setRegisterPin (relayId, relayState); para activar o desactivar el relé. Es posible crear tantos mensajes como quieras. Aquí, por ejemplo, he añadido el comando «reset» para abrir todos los relés y el comando «states» para mostrar los estados de cada relé.
//Constants #define number_of_74hc595s 1 #define numOfRegisterPins number_of_74hc595s * 8 #define SER_Pin 25 #define RCLK_Pin 33 #define SRCLK_Pin 32 //Variables boolean registers[numOfRegisterPins]; String msg, m1, m2; int sep, relayId, relayState; void setup() { delay(100); //Init Serial USB Serial.begin(115200); Serial.println(F("Initialize System")); //Init register pinMode(SER_Pin, OUTPUT); pinMode(RCLK_Pin, OUTPUT); pinMode(SRCLK_Pin, OUTPUT); clearRegisters(); writeRegisters(); delay(500); Serial.println(F("Enter Relay ID ans state (IDxSTATE):")); } void loop() { readSerialPort(); convertMsgToCmd(); if (relayId >= 0 and relayState >= 0) { setRegisterPin(relayId, relayState); writeRegisters(); } if (m1 == "reset") { Serial.println(F("Reset all relays")); clearRegisters(); writeRegisters(); } if (m1 == "states") { Serial.println(F("print relays states")); printRegisters(); } m1 = ""; } void clearRegisters() { /* function clearRegisters */ //// Clear registers variables for (int i = numOfRegisterPins - 1; i >= 0; i--) { registers[i] = HIGH; } printRegisters(); } void writeRegisters() { /* function writeRegisters */ //// Write register after being set digitalWrite(RCLK_Pin, LOW); for (int i = numOfRegisterPins - 1; i >= 0; i--) { digitalWrite(SRCLK_Pin, LOW); digitalWrite(SER_Pin, registers[i]); digitalWrite(SRCLK_Pin, HIGH); } digitalWrite(RCLK_Pin, HIGH); } void setRegisterPin(int index, int value) { /* function setRegisterPin */ ////Set register variable to HIGH or LOW registers[index] = value; } void printRegisters() { /* function clearRegisters */ //// Clear registers variables for (int i = 0; i < numOfRegisterPins; i++) { Serial.print(registers[i]); Serial.print(F(" ,")); } Serial.println(); } void readSerialPort() { while (Serial.available()) { delay(10); if (Serial.available() > 0) { char c = Serial.read(); //gets one byte from serial buffer msg += c; } } } void convertMsgToCmd() { relayId = -1; relayState = -1; if (msg.length() > 0) { Serial.println(msg); sep = msg.indexOf('x'); if (sep > 0) { m1 = msg.substring(0, sep); //get servo id m2 = msg.substring(sep + 1, msg.length()); //get servo pos char carray1[6]; //magic needed to convert string to a number m1.toCharArray(carray1, sizeof(carray1)); relayId = atoi(carray1); char carray2[6]; m2.toCharArray(carray2, sizeof(carray2)); relayState = atoi(carray2); relayState = 1 - relayState; Serial.print(F("Set relay n° ")); Serial.print(relayId); Serial.print(F(" to ")); Serial.println(!relayState ? "HIGH" : "LOW"); } sep = msg.indexOf("reset"); if (sep == 0) { m1 = "reset"; } sep = msg.indexOf("states"); if (sep == 0) { m1 = "states"; } msg = ""; } }
Resultado
Una vez cargado el código en el microcontrolador, abre el monitor de serie. Puede introducir el identificador del relé (0 – 7) y el estado deseado (0-abierto, 1-cerrado). Por ejemplo, para cerrar el relé 2, escriba 2×1 y luego «enter» o «send».
Me gustaría conocer la descripción de algunas lineas del código, donde podría comunicarme con ustedes?
Hola, por supuesto. ¿Qué líneas?
char carray1[6]; //magic needed to convert string to a number
Esta linea
Y para resetear o mostrar el estado de los relays que se tendria que escibir en el monitor serie?
Hola,
como se describe, carray es una variable intermedia, una cadena de 6 caracteres, para convertir una cadena en un número.
para reserear, reset
para mostrar estado, status
char carray1[6]; //magic needed to convert string to a number
Esta linea
Y como escribiría en el puerto serial o que haría para resetear o mostrar los states de los actuadores
La variable sep, y la msg para que sirven?
Hola,
msg para almacenar el mensaje de la comunicación como un String
sep para almacenar el índice del separador (aquí «x») elegido para delimitar dos informaciones (msg=m1xm2)
Hay forma de conectar el serial port con el firebase de google, ya lo enlace pero no me envia los datos, Serian de gran ayuda
no exactamente, es posible leer los datos de firebase para activar los relés. la función readSerialPort debe ser modificada para que los comandos de activación provengan de firebase
si, no tienen algun ejemplo de como sería esa linea de codigo?