Hi everyone ,
Please, I need your insights on two issues in this bidirectional communication project:
-
RELAY GETS STUCK IN CLOSED POSITION WHEN A 12V/400mA PUMP IS CONNECTED:
(See diagrams images) While Buttons are pressed on the TX, Pumps on the RX are activated via relays. Releasing the button stops the Pumps.
Problem: If a button is held for more than 6 seconds when a mini pump is connected, the relay remains closed, preventing the pump from shutting down until the program is reset. (This does not occur when no pump is connected.) -
MESSAGE 2 RETURNS INCOMPLETE
(See "Code Logic" image) TX sends Message 1 with buttons states, RX controls actuators, then generates Message 2 accordingly the action taken, printing and sending it back to the TX.
Problem: (See "Serial Monitors" image) Despite proper display by the RX, the TX sometimes skips action messages.
Thank you!
//TRANSMITTER TX
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
//PINS------------------------------------------------------------------------------------------------------------------------
// NRF24L01 Pins
RF24 radio(9, 8); // CE, CSN
const byte address[][10] = {"00001","00002"};//addresses that receives and transfer data
// Pump Pins
const int Button1 = 7; //Controls Pump1
const int Button2 = 6; //Controls Pump2
// DS18B20 Pin
const int Button3 = 5; //Controls DS18B20
// DC Pins
int vry = A1; // Potentiometer VRY (Y-AXIS)in the Joystick KY023
//VARIABLES------------------------------------------------------------------------------------------------------------------------
// NRF24L01 Variables
int Message1[4];
char Message2[50];
//MAIN------------------------------------------------------------------------------------------------------------------------
void setup() {
pinMode(Button1, INPUT_PULLUP); // Pump1 - Enable internal pull-up resistor for button
pinMode(Button2, INPUT_PULLUP); // Pump2 - Enable internal pull-up resistor for button
pinMode(Button3, INPUT_PULLUP); // DS18B20
Serial.begin(9600);
radio.begin();
radio.openWritingPipe(address[0]);//address of transmitter
radio.openReadingPipe(1, address[1]);//address of receiver - specify the ch-freq in which receives
radio.setPALevel(RF24_PA_MAX);//set power amplifier level (minimum since NRFs are close)
delay(10);
}
void loop() {
delay(10);
radio.stopListening(); //transmit
Message1[0] = digitalRead(Button1); // Pump1 button current state
Message1[1] = digitalRead(Button2); // Pump2 button current state
Message1[2] = digitalRead(Button3); // DS18B20
Message1[3] = analogRead(vry)*(437.0/1023.0); //Joystick DC - Scale: 0-437rpm
radio.write(Message1, sizeof(Message1));
radio.startListening(); //receive
if (radio.available())
{
// Read data into the Message2 array
radio.read(&Message2, sizeof(Message2)); // Correct usage for arrays
Serial.println(Message2);
}
}
//RECEIVER RX
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include "BTS7960.h"
//PINS----------------------------------------------------------------------------------------------------------------------------
// NFR24L01 Pins
RF24 radio(7, 8); // CE, CSN
const byte address[][10] = {"00001","00002"};//addresses that receives and transfer data
// Pump Pins
const int Relay1 = 9;
const int Relay2 = 10;
// DC Pins
int pinA = 2; // Channel A in the DC Motor Encoder
int pinB = 3; // Channel B in the DC Motor Encoder
int RPWM = 4; // RPWM on the BTS7960
int LPWM = 5; // LPWM on the BTS7960
int EN = 6; // L_EN and R_EN on the BTS7960
const int PushTop = 32; //end of stroke 1 (top)
const int PushEnd = 34; //end of stroke 2 (end)
//VARIABLES------------------------------------------------------------------------------------------------------------------------
// NRF24L01 Variables
int Message1[4];
char Message2[50];
// Pump Variables
bool previousButtonState1 = HIGH; // Variable to store the previous state of the button. Initially high (not pressed)
bool previousButtonState2 = HIGH; // Variable to store the previous state of the button. Initially high (not pressed)
bool printedState = false; // Flag to control the printing of the state
enum State1 {OFF1,ON1}; // States of Pump1
enum State2 {OFF2,ON2}; // States of Pump2
State1 state1 = OFF1;
State2 state2 = OFF2;
State1 previousState1 = OFF1;
State2 previousState2 = OFF2;
// DS18B20 Variables
enum State3 {OFF3, ON3};
State3 state3 = OFF3;
unsigned long lastDebounceTime = 0; // millisecond timestamp for last button press
const unsigned long debounceDelay = 1000; // milliseconds
int buttonState3; //button for temperature sensor DS18B20
// DC Variables
int speed = 0; //Speed for soft start
float sp; // Set point
float pv; // From encoder
volatile int contador = 0;
unsigned long previousMillis = 0;
long interval = 100; //100
enum State {OFF,UP,DOWN}; // States of DC
State state = OFF; // Current state of DC
State previousState = OFF; // Previous state of DC
//FUNCTIONS---------------------------------------------------------------------------------------------------------------------
// Pump Functions
void turnonPump1();
void turnoffPump1();
void turnonPump2();
void turnoffPump2();
// DS18B20 Functions
void readtemperature();
// DC Functions
void interrupcion();
void stopmotor();
void upmotor();
void downmotor();
//OBJECTS------------------------------------------------------------------------------------------------------------------------
// DS18B20 Objects
OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices
DallasTemperature sensors(&oneWire); // Pass our oneWire reference to Dallas Temperature.
//DC Objects
BTS7960 motorController(EN, LPWM, RPWM); //Initialize the motor controller
//MAIN------------------------------------------------------------------------------------------------------------------------
void setup() {
pinMode(Relay1, OUTPUT); // Initialize relay pin as output
pinMode(Relay2, OUTPUT); // Initialize relay pin as output
pinMode(pinA, INPUT); //DC
pinMode(pinB, INPUT); //DC
pinMode(RPWM, OUTPUT); //DC
pinMode(LPWM, OUTPUT); //DC
pinMode(EN, OUTPUT); //DC
pinMode(PushTop, INPUT_PULLUP); //DC
pinMode(PushEnd, INPUT_PULLUP); //DC
digitalWrite(RPWM, LOW); //DC
digitalWrite(LPWM, LOW); //DC
digitalWrite(EN, HIGH); //DC - Enable "Right" and "Left" movement on the HBridge
turnoffPump1();// Pump1 initially off
turnoffPump2();// Pump2 initially off
stopmotor(); //DC off
Serial.begin(9600);
radio.begin();
radio.openWritingPipe(address[1]);//address of transmitter
radio.openReadingPipe(1, address[0]);//address of receiver - specify the ch-freq in which receives
radio.setPALevel(RF24_PA_MAX);//set power amplifier level (minimum since NRFs are close)
sensors.begin(); // DS18B20
attachInterrupt(0, interrupcion, RISING); //DC - Rising edge on PIN 2 (Channel A in the DC Motor Encoder)
}
void loop() {
delay(10);
radio.startListening(); //receive
int buttonTop = digitalRead(PushTop); //DC
int buttonEnd = digitalRead(PushEnd); //DC
motorController.Enable(); //DC - Activate motor controller
unsigned long currentMillis = millis();//DC
if ((currentMillis - previousMillis)>= interval) //DC - si es mayor que el intervalo (1seg) hace lo que esta adentro
{
previousMillis = currentMillis;
pv = 10*contador*(60.0/211.2); //RPM del eje principal
contador = 0;
}
if (radio.available())
{
radio.read(Message1, sizeof(Message1));
int buttonState1 = Message1[0]; // Pump1 button current state
int buttonState2 = Message1[1]; // Pump2 button current state
int buttonState3 = Message1[2]; // DS18B20 button current state
sp = Message1[3]; //Joystick DC
// Relay1 + Pump1 Control
if (buttonState1 != previousButtonState1) { //Compare previous and current states of the button1
if (buttonState1 == LOW) { //keep the button1 activated
turnonPump1(); // Turn on Pump1
state1 = ON1;
} else {
turnoffPump1(); // Turn off Pump1
state1 = OFF1;
}
previousButtonState1 = buttonState1; // Update previous button state for button 1
}
delay(5);// Wait to avoid button bounces
// Relay2 + Pump2 Control
if (buttonState2 != previousButtonState2) { //Compare previous and current states of the button2
if (buttonState2 == LOW) { //keep the button2 activated
turnonPump2(); // Turn on Pump2
state2 = ON2;
} else {
turnoffPump2(); // Turn off Pump2
state2 = OFF2;
}
previousButtonState2 = buttonState2; // Update previous button state for button 2
}
delay(5);// Wait to avoid button bounces
// DS18B20 Control
if ((millis() - lastDebounceTime) > debounceDelay && buttonState3 == LOW) {
readtemperature(); //Read temperatures from DS18B20 sensors
state3 = ON3;
lastDebounceTime = millis(); // Update debounce timer
} else {
state3 = OFF3;
}
delay(5);// Wait to avoid button bounces
// DC Control
if (sp > 224.0 && sp < 227.0){
stopmotor();
state = OFF;
}
delay(5);// Wait to avoid button bounces
if (sp > 227.0){
if (buttonTop == HIGH) {
upmotor();
state = UP;
} else {
stopmotor();
state = OFF;
}
}
delay(5);// Wait to avoid button bounces
if (sp < 224.0) {
if (buttonEnd == HIGH) {
downmotor();
state = DOWN;
} else {
stopmotor();
state = OFF;
}
}
delay(5);// Wait to avoid button bounces
}
delay(10);
radio.stopListening(); //transmit
if (state1 != previousState1) { //Compare previous and current states of the button1
switch (state1) {
case OFF1:
strcpy(Message2, "PUMP 1 OFF");
radio.write(&Message2, sizeof(Message2));
Serial.println(Message2); //TEST
break;
case ON1:
strcpy(Message2, "PUMP 1 ON");
radio.write(&Message2, sizeof(Message2));
Serial.println(Message2); //TEST
break;
}
previousState1 = state1; //update state1
}
if (state2 != previousState2) { //Compare previous and current states of the button2
switch (state2) {
case OFF2:
strcpy(Message2, "PUMP 2 OFF");
radio.write(&Message2, sizeof(Message2));
Serial.println(Message2); //TEST
break;
case ON2:
strcpy(Message2, "PUMP 2 ON");
radio.write(&Message2, sizeof(Message2));
Serial.println(Message2); //TEST
break;
}
previousState2 = state2; //update state2
}
if (state3 == ON3) { //Compare previous and current states of the button3
//Read temperatures
float temp1 = sensors.getTempCByIndex(0);
float temp2 = sensors.getTempCByIndex(1);
// Crear cadenas para las temperaturas
char tempStr1[20];
char tempStr2[20];
// Formatear temperaturas en cadenas
dtostrf(temp1, 4, 2, tempStr1);
dtostrf(temp2, 4, 2, tempStr2);
// Construir el mensaje
sprintf(Message2, "T1: %s°C\nT2: %s°C", tempStr1, tempStr2);
radio.write(&Message2, sizeof(Message2));
Serial.println(Message2);//TEST
}
if (state != previousState) {
switch (state) {
case OFF:
strcpy(Message2, "DC OFF");
radio.write(&Message2, sizeof(Message2));
Serial.println(Message2); //TEST
break;
case UP:
strcpy(Message2, "DC UP");
radio.write(&Message2, sizeof(Message2));
Serial.println(Message2); //TEST
break;
case DOWN:
strcpy(Message2, "DC DOWN");
radio.write(&Message2, sizeof(Message2));
Serial.println(Message2); //TEST
break;
}
previousState = state; // update previousState
}
delay(10);
}
//FUNCTIONS------------------------------------------------------------------------------------------------------------------------
void turnonPump1() {
digitalWrite(Relay1, LOW);
}
void turnoffPump1() {
digitalWrite(Relay1, HIGH);
}
void turnonPump2() {
digitalWrite(Relay2, LOW);
}
void turnoffPump2() {
digitalWrite(Relay2, HIGH);
}
void readtemperature(){
sensors.requestTemperatures(); // Send the command to get temperatures
}
void interrupcion(){
contador++; //Count rising edges
}
void stopmotor(){
motorController.Stop();
motorController.Disable();
}
void upmotor(){
motorController.TurnRight(sp-227.0); //analog outputs doesn't give more than 255
}
void downmotor(){
motorController.TurnLeft(224.0-sp);
}