Search code examples
databasevariablesarduinolora

variable data keep switching on receiving


i am using 2 UART lora one transmit and the other receive using arduino for both data sent for LDR was around 350 and accelerometer was 605 i have 2 variable to send the transmitting:

#include <SoftwareSerial.h>

SoftwareSerial mySerial(6, 7); // RX, TX

int LDR_Pin = A0; //analog pin 0
int y=A1;         //y axis variable

int pirPin = 5;    //the digital pin connected to the PIR sensor's output

void setup(){
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
mySerial.begin(9600); 
}

void loop(){
int vert = analogRead(y);
int LDRReading = analogRead(LDR_Pin);
int result = LDRReading/4;
mySerial.write(result);
Serial.print("LDR : "); 
Serial.print(LDRReading);
delay(1000);
mySerial.flush();
int acc = vert/4;
mySerial.write(acc);
Serial.print(" acc: ");
Serial.println(vert);
mySerial.flush();
delay(1000);

 }

to receive

#include <SPI.h>
#include <Client.h>
#include <Ethernet.h>
#include <Server.h>
#include <Udp.h>
#include <SoftwareSerial.h>

SoftwareSerial mySerial(6, 7); // RX, TX

int LDR_Pin = A0; //analog pin 0
int y=A1;         //y axis variable 

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = {};      // ip in lan
byte gateway[] = {};      // internet access via router
byte subnet[] = {};                   //subnet mask

EthernetServer server(80);   //server port

void setup() {
  // initialize serial communication:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
    }
    mySerial.begin(9600);

  Ethernet.begin(mac, ip, gateway, subnet);

}

void loop(){ 

int vert = mySerial.read();
int acc =vert*4;
Serial.println(acc);
mySerial.flush();
delay(1000);

mySerial.flush();
int LDRReading = mySerial.read();
int result = LDRReading*4;
Serial.println(result);
mySerial.flush();
delay(1000);

EthernetClient client = server.available();    

   if (client) {

      Serial.println("Connected");
      client.println("<!DOCYTYPE html>");
      client.println("<html>");
      client.println("<title>Sensor Hub</title>");        
      client.println("<head> <meta http-equiv='refresh' content='1;http://' /> </head>");
      client.println("<body bgcolor='#FFFFFF'>");
      client.println("<center><h1>this is sensor webpage indicator.</h1></center>");          
      client.println("<script src='https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'></script>");
      client.println("<script type='text/javascript'>");
      client.println("$.ajax({");
      client.println("type: 'POST',");
      client.println("url: 'http:// /fyp/write.php',");           
      client.print("data: { LDRReading: '");
      client.print(result);   
      client.print("', acc:'");
      client.print(acc);
      client.print("'}");
      client.println("");       
      client.println("});"); 
      client.println("</script>");            
      client.println("</body></html>");     
      client.stop();

    }
    }               

but when i am checking my database i find my accelerometer data in my LDR database column and vice versa sometimes

i am unsure on how to fix the problem and is it possible to give an ID to the variable data to prevent data switching?


Solution

  • Apart from what gre_gor said in a comment (so for reading and writing an integer you need to send and receive two bytes) you need a stronger way to send and receive the bytes (simply waiting and praying for them to be synchronized is not an option).

    There are tons of way to make a suitable protocol. In your ideal protocol you need a way to determine the start and/or end of the data, and a way to determine WHAT data is being transmitted.

    If you use ascii representation (i.e. with print and printlns) you can use a non-printable character or a space or a new line to set this. Since you are using the write, however, I'm going towards a more "byte saver" technique.

    In a byte oriented transmission I usually found two ways of dealing with this.

    The first one is to use a set of reserved bytes and an "escape" one. Whenever you get one reserved byte you put an escape and then modify the byte in order to set it non-reserved. For instance, if you define 7D and 7E as reserved, and define 7E as escape byte (and for instance 7D is the end of transmission, and you make a reserved into a non-reserved by changing the 7 in a 8) if your byte array is 01 34 7D 66 7E then you transform the 7D in 7E 8D (escape + non reserved=, the 7E in 7E 8E, and append a 7D. This way you send 01 34 7E 8D 66 7E 8E 7D. The parser waits for the 7D, and knows that whenever it receives the 7E it discards that byte and changes the following 8x into 7x.

    This is an easy way to make a more robust protocol, but has a drawback that the output has a variable length. The alternative I often use when I need to send data which is shorter that 8 bits (or a multiple) is to reserve a bit for indicating if the byte is a data or a command, then use the other 7 bits to store the actual data. I'm using this approach in your case, assuming that the two variables you are sending are signed and with a range 16383 - -16384.

    So, the protocol is simple. if the first bit of the received byte is a 1, then this is a command. Valid commands are:

    0x80 Accelerometer data
    0x81 LDR data
    (you can add your own ones, but all of them should start with a 1 bit)
    

    All the commands should be followed by two data bytes, and each data byte starts with a 0 bit. The composition is

    bit position  7   6   5   4   3   2   1   0
    1st byte     '0' b13 b12 b11 b10 b09 b08 b07
    2nd byte     '0' b06 b05 b04 b03 b02 b01 b00
    

    Where '0' is a 0 bit, and bxx is the xx-th bit of the data being transmitted.

    Now, sending the data is simple. This simple code can do it:

    #define SEND_ACCEL_DATA 0x80
    #define SEND_LDR_DATA   0x81
    
    void sendData(uint8_t type, int value)
    {
        mySerial.write(type);
        mySerial.write((value >> 7) & 0x7F); // Upper 7 bytes
        mySerial.write(value & 0x7F); // Lower 7 bytes
        // Never needed to call flush, but if you need it put it here
    }
    
    usage:
    sendData(SEND_LDR_DATA, ldr_value);
    sendData(SEND_ACCEL_DATA, accelerom_value);
    

    As you can see you are just sending the type followed by the values.

    The receive code is simple too:

    #define SEND_ACCEL_DATA 0x80
    #define SEND_LDR_DATA   0x81
    
    if (mySerial.available() >= 3)
    {
        switch (mySerial.read())
        {
        case SEND_ACCEL_DATA:
            {
                int acceleration = mySerial.read() & 0x7F;
                acceleration = (acceleration << 7) | (mySerial.read() & 0x7F);
                if (acceleration & 0x2000) acceleration |= 0xC000; // This is the sign extension
    
                // now you can use acceleration (and store it in the database)
            }
            break;
        case SEND_LDR_DATA:
            {
                int ldr = mySerial.read() & 0x7F;
                ldr = (ldr << 7) | (mySerial.read() & 0x7F);
                if (ldr & 0x2000) ldr |= 0xC000; // This is the sign extension
    
                // now you can use ldr (and store it in the database)
            }
            break;
        }
    }
    

    If you want, you can embed this in a function too:

    #define SEND_NONE       0x00
    #define SEND_ACCEL_DATA 0x80
    #define SEND_LDR_DATA   0x81
    
    int getDataFromSerial(uint8_t *p_type)
    {
        int result = 0;
        *p_type = SEND_NONE;
    
        if (mySerial.available() >= 3)
        {
            switch (*p_type = mySerial.read())
            {
            case SEND_ACCEL_DATA:
            case SEND_LDR_DATA:
                int result = mySerial.read() & 0x7F;
                result = (result << 7) | (mySerial.read() & 0x7F);
                if (result & 0x2000) result |= 0xC000; // This is the sign extension
    
                break;
            default:
                *p_type = SEND_NONE;
                break;
            }
        }
    
        return result;
    }
    
    // Usage
    
    uint8_t type;
    int result = getDataFromSerial(&type);
    switch (type)
    {
    case SEND_ACCEL_DATA:
        // result is the acceleration
        break;
    case SEND_LDR_DATA:
        // result is the ldr
        break;
    }
    

    Just beware that you WON'T receive both data at the same time, but one after the other. If you need the data to arrive at the same time, ask and I'll upload a modified version to send and receive both data at the same time.

    EDIT: as asked, here is the version with the data travelling together.

    Now, if you group the two data together the type of packet is just one. So there is no need for a byte stating what type of byte it is. So you can modify the protocol to just report if the byte is the starting one or not. The protocol now just has one type of packet, which is 4 bytes long:

    bit position  7   6   5   4   3   2   1   0
    1st byte     '1' l13 l12 l11 l10 l09 l08 l07
    2nd byte     '0' l06 l05 l04 l03 l02 l01 l00
    3rd byte     '0' a13 a12 a11 a10 a09 a08 a07
    4th byte     '0' a06 a05 a04 a03 a02 a01 a00
    

    where l13-l00 are the fourteen bits of the LDR value, and a13-a00 are the ones for the acceleration.

    The sending is modified, but is simple once you know what to send:

    void sendData(int ldr, int accel)
    {
        mySerial.write(((ldr >> 7) & 0x7F) | 0x80); // Upper 7 bytes and first bit
        mySerial.write(ldr & 0x7F); // Lower 7 bytes
        mySerial.write((accel >> 7) & 0x7F); // Upper 7 bytes
        mySerial.write(accel & 0x7F); // Lower 7 bytes
    }
    
    usage:
    sendData(ldr_value, accel_value);
    

    The only thing worth noting is that the first byte has the highest bit set, while the other bytes haven't.

    The receiving code simply has to wait for all the four bytes to arrive, checking that the first one actually starts with a 1, and then recover the two values exactly like the previous way:

    while (mySerial.available() >= 4)
    {
        if (!(mySerial.peek() & 0x80))
        { // If the first byte in the buffer is not a valid start, discard it
            mySerial.read();
            continue;
        }
    
        int ldr = mySerial.read() & 0x7F;
        ldr = (ldr << 7) | (mySerial.read() & 0x7F);
        if (ldr & 0x2000) ldr |= 0xC000; // This is the sign extension
    
        int acceleration = mySerial.read() & 0x7F;
        acceleration = (acceleration << 7) | (mySerial.read() & 0x7F);
        if (acceleration & 0x2000) acceleration |= 0xC000; // This is the sign extension
    
        // now you can use acceleration and ldr (and store them in the database)
        }
    }
    

    If you prefer a function, you can implement it this way:

    boolean getDataFromSerial(int *p_ldr, int *p_accel)
    {
        boolean foundData = false;
    
        while ((!foundData) && (mySerial.available() >= 4))
        {
            if (!(mySerial.peek() & 0x80))
            { // If the first byte in the buffer is not a valid start, discard it
                mySerial.read();
                continue;
            }
    
            *p_ldr = mySerial.read() & 0x7F;
            *p_ldr = ((*p_ldr) << 7) | (mySerial.read() & 0x7F);
            if ((*p_ldr) & 0x2000) (*p_ldr) |= 0xC000; // This is the sign extension
    
            *p_accel = mySerial.read() & 0x7F;
            *p_accel = ((*p_accel) << 7) | (mySerial.read() & 0x7F);
            if ((*p_accel) & 0x2000) (*p_accel) |= 0xC000; // This is the sign extension
    
            foundData = true;
            }
        }
        return foundData;
    }
    
    usage:
    int accel, ldr;
    if (getDataFromSerial(&ldr, &accel))
    {
        // use accel and ldr
    }
    

    In this case the two variables always go together, while in the other you can send them separately. Which is better? It depends on what you need. This is easier and more effective, the other is more flexible.

    EDIT 2: Complete example:

    I designed a complete example of two arduinos communicating with the latest protocol (2 data together). The one on the left generates the two values starting from two potentiometers, the other prints them.

    Here you can find it: https://circuits.io/circuits/3690285-software-serial-binary-transmission

    Connections:

    Connections

    Sender code:

    #include <SoftwareSerial.h>
    SoftwareSerial mySerial(10, 11);
    
    void sendData(int ldr, int accel)
    {
        mySerial.write(((ldr >> 7) & 0x7F) | 0x80); // Upper 7 bytes and first bit
        mySerial.write(ldr & 0x7F); // Lower 7 bytes
        mySerial.write((accel >> 7) & 0x7F); // Upper 7 bytes
        mySerial.write(accel & 0x7F); // Lower 7 bytes
    }
    
    // the setup routine runs once when you press reset:
    void setup() {
      Serial.begin(9600);
      mySerial.begin(2400);
    }
    
    // the loop routine runs over and over again forever:
    void loop() {
      int ldr_value = analogRead(A0);
      int accel_value = analogRead(A1);
    
      sendData(ldr_value, accel_value);
    
      // Print it on the serial interface for debug
      Serial.print("TX LDR: ");
      Serial.print(ldr_value);
      Serial.print(" - ACC: ");
      Serial.println(accel_value);
    
      delay(1000);
    }
    

    Receiver code:

    #include <SoftwareSerial.h>
    SoftwareSerial mySerial(10, 11);
    
    boolean getDataFromSerial(int *p_ldr, int *p_accel)
    {
        boolean foundData = false;
    
        while ((!foundData) && (mySerial.available() >= 4))
        {
            if (!(mySerial.peek() & 0x80))
            { // If the first byte in the buffer is not a valid start, discard it
                mySerial.read();
                continue;
            }
    
            *p_ldr = mySerial.read() & 0x7F;
            *p_ldr = ((*p_ldr) << 7) | (mySerial.read() & 0x7F);
            if ((*p_ldr) & 0x2000) (*p_ldr) |= 0xC000; // This is the sign extension
    
            *p_accel = mySerial.read() & 0x7F;
            *p_accel = ((*p_accel) << 7) | (mySerial.read() & 0x7F);
            if ((*p_accel) & 0x2000) (*p_accel) |= 0xC000; // This is the sign extension
    
            foundData = true;
        }
        return foundData;
    }
    
    // the setup routine runs once when you press reset:
    void setup() {
      Serial.begin(9600);
      mySerial.begin(2400);
    }
    
    // the loop routine runs over and over again forever:
    void loop() {
      int accel, ldr;
      if (getDataFromSerial(&ldr, &accel))
      {
          // Print it on the serial interface for debug
        Serial.print("RX LDR: ");
        Serial.print(ldr);
        Serial.print(" - ACC: ");
        Serial.println(accel);
      }
    }