adds666's: Multi channel - 4 bit binary - Radio Frequency controller

Evening all,

I'm an electrical engineer by trade - hardware only. Starting to venture in to the world of microcontrollers.

Layman's description of aim:

"I'm looking to build a control panel where I can flick 4 toggle switches (dip switches) hi or low to form a binary code, press a trigger button and that code is sent via RF to be received on a separate box (Separate thread - will link to it here in the future).
Multiply the above by 5 so I essentially have 5 channels of 4 bit binary code I can trigger and send each of the channels individually.
Plus a number of 'single shot' momentary press buttons that send their own, individually identifiable code, via RF to the other box.
Codes are sent continually whilst a single shot or trigger button is pressed - until release.
If multiple trigger buttons or 'single shot' buttons are pressed at the same time, codes are sent one after the other, continually (1, 2, 3, 1, 2, 3, 1, 2, 3...)"

The purpose of this thread is not for you to tell me what to do, what to code, but simply to point me in the right direction of resources. And if I should be thinking of the approach in a different way - with my limited knowledge and googling...!

All switches / buttons have their own input pin with internal pullups on a mega.
HC 12 uses just TX and RX pins

My thinking:

  • RF communication will be done using HC-12 modules - which I'm led to believe is like a simple Serial Print - See linkhttps://howtomechatronics.com/tutorials/arduino/arduino-and-hc-12-long-range-wireless-communication-module/

  • 4 'Bit' switches are polled constantly and update a state machine to determine their 'on' / 'off' state (Any good resources and examples of the above are appreciated

  • Trigger buttons are an interrupt and then digital write a code with syntax such as CA (for Channel A) 0001 (The 4 bits as per the switches) to the HC 12 module (Unsure of how to read the button states and put in print

  • Code is written so that

  • Binary switch states are updated

  • Trigger buttons are looked at in order

  • single shot buttons are looked at

  • repeat

I understand the importance of not using delay()

I was pointed towards This example of DIP switches however Think my setup will be substantially different and only need the

for(i=0; i<=3; i++){
 j = (j << 1) | digitalRead(dipPins[i]);   // read each input pin
 }
 return j; //return address

Section? (Whats return?)

What else should I be aware of / is my approach logical?

Many thanks in advance

Adam

UPDATE: Circuit design Lighting TX Controller | Tinkercad

  • Tinkercad with simulated dip switches and buttons

Trigger buttons are an interrupt

Why?

for(i=0; i < 4; i++){is more natural, no?

AWOL:
Why?

The entire system is to control a lighting rig that plays a pre-recorded pattern (programmed as a function) when it receives the associated channel binary option.

The one shots should be sent as soon as possible to "turn them all white" or "illuminate all lights at once"

I'm guessing youre asking the question because this sketch wont be long and so shouldnt need an interrupt?

Right, I've made a start and are in a point where I am reading the 4 dip switches correctly and am wanting to include the result in a string to be Printed (Sent via RF)

I am getting an error when trying to concatenate 3 separate pieces of information

  • CH1 - Channel one
  • CH1Add - The binary switches I've read in 0s and 1s
  • ON - because the trigger is being pressed

Can anyone assist?

/*
  Code to build a control box to send strings of data via the HC 12 RF module

  Control board consists of 5 channels of 4 bit (Latching switches similar to DIP switches) and a final Trigger switch.
  When triggered, the channel looks at the 4 bit code and sends a message with syntax:
  'CHX0001ON'
  CH1 0001 ON

  Code is sent constatly whilst trigger switch is HIGH

  Once Trigger goes LOW send same code with OFF at end.

  https://forum.arduino.cc/index.php?topic=566702.0
  - Forum with me asking for guidance and help

  https://www.tinkercad.com/things/4LNWSpp3Fjl
  - Tinkercad with simulated dip switches and buttons
*/

void setup() {
  //  start serial connection
  Serial.begin(9600);
  //c onfigure pins as an input and enable the internal pull-up resistor
  pinMode(2, INPUT_PULLUP);// Bit 0 of channel 1's 4 bit DIP switches
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);// Channel 1 Trigger button
  //  configure pin 13 as output (internal LED for debugging)
  pinMode(13, OUTPUT);

}

void loop() {
  //  read the pushbutton values into a variable
  int CH1B0 = digitalRead(2);
  int CH1B1 = digitalRead(3);
  int CH1B2 = digitalRead(4);
  int CH1B3 = digitalRead(5);
  int CH1TR = digitalRead(8);
  
  //  Collect all of the button reads and put in to binary form
  //  char CH1Add[5];  // 4 bits + 1 char for the termination character binary address (removed so can add "ON" at end of final string CH1AddON
  char CH1Add[4];  // 4 bits + 1 char for the termination character binary address
  CH1Add[0] = CH1B0 == HIGH ? '0' : '1';
  CH1Add[1] = CH1B1 == HIGH ? '0' : '1';
  CH1Add[2] = CH1B2 == HIGH ? '0' : '1';
  CH1Add[3] = CH1B3 == HIGH ? '0' : '1';
  //  CH1Add[4] = '\0';  // add NUL termination (removed so can add "ON" at the end of final string CH1AddON
  //  Keep in mind the pullup means the button logic is reversed

  //Trying to concatenate for the final address
  String CH1AddON = "CH1" + CH1Add + "ON";

  // Keep in mind the pullup means the pushbutton's
  // logic is inverted. It goes HIGH when it's open,
  // and LOW when it's pressed. 
  if (CH1TR == LOW) {
    digitalWrite(13, HIGH);
    Serial.println(CH1AddON);
  } else {
    digitalWrite(13, LOW);
  }
}

I am getting an error when trying to concatenate 3 separate pieces of information

And the error is . . ?

I've got an error on line 53 (where I attempt to concatenate information together:

"Invalid Operands
In function 'void loop()':
Binary_reading_switches:53: error: invalid operands of types 'const char [4]' and 'char [4]' to binary 'operator+'
String CH1AddON = "CH1" + CH1Add + "ON";
^
exit status 1
invalid operands of types 'const char [4]' and 'char [4]' to binary 'operator+'"

SOLVED: By ensuring "CH1" is a String rather than a string (notice lower case)
String CH1AddON = (String("CH1") + CH1Add + "ON";

I took your code, and rewrote it without Strings.
It ends up a lot shorter, and uses less RAM (not a lot) and flash (better than 1600 bytes fewer).

const int nChannelPins = 4;
const byte channelPins [nChannelPins] = {2, 3, 4, 5}; // re-order to suit schematic
const byte selectSwitch = 8; // whatever you want to call it.

void setup()
{
  Serial.begin(9600);
  for (int i = 0; i < nChannelPins; i++) {
    pinMode(channelPins [i], INPUT_PULLUP);
  }
  pinMode(selectSwitch, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite (LED_BUILTIN, LOW);
}

void loop()
{
  if (digitalRead(selectSwitch) == LOW) { // do you really want to send this all the time the switch is closed?
    digitalWrite(LED_BUILTIN, HIGH);
    Serial.print ("CH1");
    for (int i = 0; i < nChannelPins; i++) {
      Serial.print (digitalRead(channelPins [i]) == HIGH ? '0' : '1');
    }
    Serial.println ("ON");
  } else {
    digitalWrite(LED_BUILTIN, LOW);
  }
}

You, sir, are a scholar and a Gentlemen,

I managed to get to the below, and built essentially two sending types:

  • Constantly whilst button is pressed
  • Single shot of on / off when button is pressed / released
/*
  Code to build a control box to send strings of data via the HC 12 RF module

  Control board consists of 5 channels of 4 bit (Latching switches similar to DIP switches) and a final Trigger switch.
  When triggered, the channel looks at the 4 bit code and sends a message with syntax:
  'CHX0001ON'
  CH1 0001 ON

  Code is sent constatly whilst trigger switch is HIGH

  Once Trigger goes LOW send same code with OFF at end.

  https://forum.arduino.cc/index.php?topic=566702.0
  - Forum with me asking for guidance and help

  https://www.tinkercad.com/things/4LNWSpp3Fjl
  - Tinkercad with simulated dip switches and buttons
*/
  //  Setup the pushbutton values for Channel 1 into a variable
  const int CH1B0 = 2;
  const int CH1B1 = 3;
  const int CH1B2 = 4;
  const int CH1B3 = 5;
  const int CH1TR = 8;
  // Plus two states to detect button states - used in button state detection
  int CH1TRState = 0;
  int LastCH1TRState = 0;
  

void setup() {
  //  start serial connection
  Serial.begin(9600);
  //  configure pins as an input and enable the internal pull-up resistor
  pinMode(2, INPUT_PULLUP);// Bit 0 of channel 1's 4 bit DIP switches
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);// Channel 1 Trigger button
  
  //  configure pin 13 as output (internal LED for debugging)
  pinMode(13, OUTPUT);

}

void loop() {
  //  read the pushbutton values into a variable
  const int CH1B0 = digitalRead(2);
  const int CH1B1 = digitalRead(3);
  const int CH1B2 = digitalRead(4);
  const int CH1B3 = digitalRead(5);
  const int CH1TR = digitalRead(8);
 
  //  Collect all of the button reads and put in to binary form
  //  char CH1Add[5];  // 4 bits + 1 char for the termination character binary address (removed so can add "ON" at end of final string CH1AddON
  char CH1Add[4];  // 4 bits + 1 char for the termination character binary address
  CH1Add[0] = CH1B0 == HIGH ? '0' : '1';
  CH1Add[1] = CH1B1 == HIGH ? '0' : '1';
  CH1Add[2] = CH1B2 == HIGH ? '0' : '1';
  CH1Add[3] = CH1B3 == HIGH ? '0' : '1';
  //  CH1Add[4] = '\0';  // add NUL termination (removed so can add "ON" at the end of final string CH1AddON
  //  Keep in mind the pullup means the button logic is reversed

  // concatenate for the final address
  String CH1AddON = String("CH1") + CH1Add + "ON";
  String CH1AddOFF = String("CH1") + CH1Add + "OFF";
  
  // Keep in mind the pullup means the pushbutton's
  // logic is inverted. It goes HIGH when it's open,
  // and LOW when it's pressed. 
  
/////////////// If button is pressed continually sends command
  if (CH1TR == LOW){
    Serial.println(CH1AddON);
  }
  else  {
      Serial.println(CH1AddOFF);
    }
  }

//////////////ButtonState change detection - sends one command once button pressed
  //A different command once button released
  
  //CH1TRState = digitalRead(8);
  //if (CH1TRState != LastCH1TRState){
  //  if (CH1TRState == LOW){
  //   Serial.println(CH1AddON);
  //   }
  //    else  {
  //      Serial.println(CH1AddOFF);
  //   }
  //  delay(50);
  //}
  //LastCH1TRState = CH1TRState; 
//}

I will be editing now to structure the code like your edit. Thank you.

I guess the question of which sending type I choose will depend on how quick my receiver can react to serial.println inputs.

On the receiving side, does every single serial.printin entry get read and actioned upon?

Again, thank you.

I guess the question of which sending type I choose will depend on how quick my receiver can react to serial.println inputs.

A lot faster than   Serial.begin(9600);

I've got everything setup - 7 channels of 4 bit dip switches with a select switch.

Sketch looks at each and sends data to serial if called for, once on button press and once on button release - with ON and OFF depending on press or release.

I've also got 5 'interrupt' (interrupt in the practical sense of the word, not the arduino sense) which are basically 5 more channels without any binary coding behind them - simple.

Now I need to figure out whether (according to linked HC12 tutorial below-

  • I can change all references to serial.print and serial.println to HC12.print as in example 2
  • I simply pipe all serial data to HC12 with HC12.write(Serial.read) as in example 1

Code is linked on codeshare as too long for forum posting

https://codeshare.io/5RyEg4

May build this in hardware, and build a simple receiver and see in practice?