Here is another example, it is again designed to be used between two arduino boards, one transmitting the other receiving. This code does away with all the “clever” stuff, no structures, no inter byte timeouts, simple ASCII protocol. The message sends the same data as before, two 16 bit analog values, two 8 bit digital values, the ASCII message looks like this.
M:0000,1111,22,33:
The message starts with two characters, “M:”
next analog value 0 is sent as a 4 digit hex number, next analog 1 as a 4 digit hex number, digital 0 is next then digital 1. The message terminates with another colon. Lets say analog 0 is 100, analog 2 is 200, everything else is 0 the message would be.
M:0064,00C8,00,00:
lets break down the code.
#include <SoftwareSerial.h>
// Uncomment to compile for the transmitter
//#define TRANSMITTER 1
#define DEBUG 1
#define BUFFER_SIZE 32
// Storage for the vex communications data
char TxBuffer BUFFER_SIZE ];
char RxBuffer BUFFER_SIZE ];
// use softwareSerial for receive
SoftwareSerial mySerial(6, 7); // RX, TX
/*-----------------------------------------------------------------------------*/
/* */
/* Arduino setup function */
/* */
/*-----------------------------------------------------------------------------*/
void setup()
{
int i;
// initialize the digital pin 13 as an output.
pinMode(13, OUTPUT);
// Clear buffers
for(i=0;i<BUFFER_SIZE;i++)
TxBuffer i ] = 0;
for(i=0;i<BUFFER_SIZE;i++)
RxBuffer i ] = 0;
// Open the software serial port, luckily it defaults to 8bit, 1 stop, no parity
// as this is not easily changed
// This is used for receive data so we can use the concole for debug
mySerial.begin( 38400 );
// console and transmit data
Serial.begin( 38400 );
// Software alive
Serial.print(F("\r\nSerial demo code"));
}
The setup function, the transmit and receive buffers are now simple arrays. I’m using the console serial port for transmit and the software serial for receive.
/*-----------------------------------------------------------------------------*/
/* */
/* Arduino main loop */
/* */
/*-----------------------------------------------------------------------------*/
void loop()
{
static uint32_t timer = 0;
int analogValue0;
int analogValue1;
unsigned char digitalValue0;
unsigned char digitalValue1;
#ifndef TRANSMITTER
// Run the receive task often
serialRxTask();
#endif
// Run every 50mS
if(millis() - timer < 50)
return;
timer = millis();
#ifdef TRANSMITTER
// Read Analog channel 0
analogValue0 = analogRead(A0);
// Read Analog channel 1
analogValue1 = analogRead(A1);
// Clear digital data
digitalValue0 = 0;
digitalValue1 = 0;
// Read some digital pins
if( digitalRead(8) )
digitalValue0 |= 0x01;
if( digitalRead(9) )
digitalValue0 |= 0x02;
if( digitalRead(10) )
digitalValue0 |= 0x04;
if( digitalRead(11) )
digitalValue0 |= 0x08;
// Create message
sprintf( TxBuffer,"M:%04X,%04X,%02X,%02X:\n", analogValue0, analogValue1, digitalValue0, digitalValue1 );
// Transmit data
Serial.write( TxBuffer );
#endif
}
The main loop. For the receiver keep calling the serialRxTask() function. For the transmitter use sprintf to create the transmit data. Send new data every 50mS (20 messages a second).
/*-----------------------------------------------------------------------------*/
/* */
/* Message receive task */
/* */
/*-----------------------------------------------------------------------------*/
void
serialRxTask()
{
static int serialRxState = 0;
static int serialDataReceived = 0;
int c;
// check for a received character
if( ! mySerial.available() )
return;
// Read char
c = mySerial.read();
// A new character has been received so process it.
// Where are we in the message parsing process ?
switch( serialRxState )
{
case 0:
// look for first header byte
if( c == 'M' )
{
serialDataReceived = 0;
RxBuffer serialDataReceived++ ] = c;
serialRxState++;
}
break;
case 1:
// look for second header byte
if( c == ':' )
{
// Header found
RxBuffer serialDataReceived++ ] = c;
serialRxState++;
}
else
{
// Bad message
serialRxState = 0;
}
break;
case 2:
// store the data
RxBuffer serialDataReceived ] = c;
// check for buffer overflow
if( ++serialDataReceived >= BUFFER_SIZE )
{
// Error
serialRxState = 0;
}
// look for end of message
if( c == ':' )
{
// Terminate rx buffer with a NULL
RxBuffer serialDataReceived ] = 0;
// Decode message
serialRxDecode();
// done
serialRxState = 0;
}
break;
default:
serialRxState = 0;
break;
}
}
The receive task. A bit long but not really complex. Look for another receive character, check for the header in two parts, first the “M” and then the “:”, keep receiving data until either the buffer overflows (an error) or the terminating character is found “:”. Decode the receive buffer.
/*-----------------------------------------------------------------------------*/
/* */
/* Message decoding */
/* */
/*-----------------------------------------------------------------------------*/
void
serialRxDecode()
{
char str[32];
long analog0;
long analog1;
char *p;
// Show buffer for DEBUG
Serial.write( RxBuffer );
Serial.write("\n");
// an example, get the first two analog values
p = &(RxBuffer[2]);
analog0 = strtol( p, &p, 16 );
p++; // skip comma
analog1 = strtol( p, &p, 16 );
// DEBUG - show the value of A0 and A1
sprintf(str,"A0 %ld, A1 %ld\n", analog0, analog1 );
Serial.write( str );
}
Decode the message, here all I’m doing as it’s a demo is printing the message to the console and using strtol to get the first two analog values. Code is attached.
Enjoy.
serialDemo2.zip (2.52 KB)