Using an array to send serial data - any way to simplify this code?

Could I please get a few hints on how to improve my code below.

I am replicating a hardware keypad, which sends out the following for each button press:

11bit constant header & 11bit button data & checksum (checksum is constant header + button data)

e.g.
header 0x14B & button0 0x030 & checksum 0x7B
header 0x14B & button1 0x031 & checksum 0x7C
header 0x14B & button2 0x032 & checksum 0x7D
etc.. for a total 16 buttons.

I have written the code for outputting one button press, which is below.

Do I need a function for each button press? Or can I use some clever trick? Any general pointers are appreciated.

/*
  Arrays
  http://www.arduino.cc/en/Tutorial/Array
*/

int timer = 800;                                         //pulse width of 800microseconds
int headerData[] = { 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1 };  // array for header data - (common to all buttons)
int button0[] = { 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, };    //array for button 0 data
int checksum0[] = { 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1 };   //array for button 0 checksum - (checksum = header & button data)

//NOTE - header is same each time, checksum is header + button data added together


int commsPin = 2;                 //output pin to COMMS connection on panel
int arrayCount = 11;              // the length of each 11-bit word


void setup()
{
  pinMode(commsPin, OUTPUT);
}


void loop ()
{
  button0pressed();
  delay(1000); //just for test purposes
}



void button0pressed()  
{
  //HEADER 
  for (int thisBit = 0; thisBit < arrayCount; thisBit++)
  {
    digitalWrite(commsPin, headerData[thisBit]);
    delayMicroseconds(timer);
  }

  //BUTTON PRESS 
  for (int thisBit = 0; thisBit < arrayCount; thisBit++)
  {
    digitalWrite(commsPin, button0[thisBit]);
    delayMicroseconds(timer);
  }

  //CHECKSUM
  for (int thisBit = 0; thisBit < arrayCount; thisBit++)
  {
    digitalWrite(commsPin, checksum0[thisBit]);
    delayMicroseconds(timer);
  }
}

Example logic trace of the output from pin 2 - matches physical keypad:

do I need a function for each button press?

It looks like there is a consistent pattern there if what you really mean is

0x14B,  0x030, 0x7B for button 0
0x14B,  0x031, 0x7C for button 1
0x14B.  0x032, 0x7D for button 2
and so on

Do I understand correctly what you need to send ?
If so then there a pattern to it which could be programmed into a single function

Hi UKHeliBob,

Yes you are correct, there is a consistent pattern. In total there are 15 keys which follow that pattern up to 0x14B, 0x03E, 0x089. There is only special key which does not follow a pattern..

I will probably use Blynk iOS app virtual buttons, to call each button press individually.
A keypad on my phone if you will.

Or maybe via MQTT using PubSub library.

Yes you are correct

So, given the button number as a byte variable b with a value between 0 and 14 you could send 0x14B, 0x30 + b, 0x7B + b

Yes that would make sense.

At present I am using arrays made up of binary digits, which makes it hard to add the button number.

I tried using the hex value in the array but that did not work.

I’ll keep looking no doubt I can find some solution.

Thanks

You could use an unsigned int (uint16_t) and use a loop to shift out 11 bits to the digital out.

@ToddL1962 that’s sounds interesting, thanks for the tip.

Like this:

void sendBits(unsigned int bitsWord)
{
  byte bitVal;
  for (int thisBit = 0; thisBit < arrayCount; thisBit++, bitsWord <<= 1)
  {
    bitVal = (bitsWord & 0x0400) ? HIGH:LOW;
    digitalWrite(commsPin, bitVal);
    delayMicroseconds(timer);
  }
}

So for a header word you would call it like this:

sendBits(0x14B);

Thanks! I spend 1-2hrs researching this and i didn't get very far.

I just tested the code and it works, only issue is I have to add the '0' start bit and the '1' stop bit to each word sent out, so I guess I need to re-figure out the hex codes...well at least the ones for button0.

I don't understand where the " & 0x0400" bit of the code comes from?

877:
I don't understand where the " & 0x0400" bit of the code comes from?

That masks off the bits we are not interested in. For example, if the word value was 0x0105 then the bit we are interested in (bit 10) is a zero. If we did not mask off the other bits then the line

bitVal = (bitsWord & 0x0400) ? HIGH:LOW;

would evaluate to HIGH instead of LOW.

Thank you, that’s starting to make more sense to me. I will have a good look when I get home from work and let you know :slight_smile:

The below code assumes your keycodes are incremental and start at 0x30.
To make life easier I have altered the sending code to auto add the start and stop bits so you only need the 9 bit serial code.
As the button presses always seem to start with 0x14b and the checksum is just the sum of the first 2 bytes (8 bits only)

const uint16_t timer = 800;                                  // pulse width of 800 microseconds


int commsPin = 2;                                           // output pin to COMMS connection on panel


void setup()
{
  Serial.begin(115200);
  pinMode(commsPin, OUTPUT);
  digitalWrite(commsPin, HIGH);
}


void loop ()
{
  for(uint8_t button = 0; button < 16; button++)
  {
    sendButton(button);
    Serial.println(button);
    delay(10);                                              // just for test purposes
  }
  delay(5000);
}

void sendButton(uint8_t but)  
{
  //HEADER
  sendCode(0x14b);
  //BUTTON PRESS
  sendCode(0x30 + but);
  //CHECKSUM
  sendCode(0x7B + but);
}

void sendCode(uint16_t code)
{
  digitalWrite(commsPin, LOW);                              // Send start bit
  delayMicroseconds(timer);
  for(uint8_t x = 0; x < 9; x++)                            // Send 9 bit serial
  {
    digitalWrite(commsPin, bitRead(code, x));
    delayMicroseconds(timer);
      
  }
  digitalWrite(commsPin, HIGH);                             // Send stop bit
  delayMicroseconds(timer);
}

@Riva thank you! That looks excellent. I'll take a good look and report back :slight_smile:

@Riva I've gone through your code and understand 99% of it, not sure I would have ever come up with that myself! Very impressive. I'd never seem the bitRead command until now. Thank you :slight_smile:

@ToddL1962 also thank you for your help!

I have it hooked up to the Blynk iOS app so I can send keypad data to the esp8266.
It's working, albeit one number at a time for now..