可变数据不断切换接收

variable data keep switching on receiving

我正在使用 2 个 UART lora,一个发送,另一个使用 arduino 接收 为 LDR 发送的数据约为 350,加速度计为 605 我有 2 个变量要发送 传送:

#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);

 }

接收

#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();

    }
    }               

但是当我检查我的数据库时,我有时会在我的 LDR 数据库列中找到我的加速度计数据,反之亦然

我不确定如何解决这个问题,是否可以为变量数据提供一个 ID 以防止数据切换?

除了gre_gor在评论中所说的(所以为了读取和写入一个整数,你需要发送和接收两个字节)你需要一个更强大的方式来发送和接收字节(简单地等待和祈祷让他们同步不是一个选项)。

有很多方法可以制定合适的协议。在您理想的协议中,您需要一种方法来确定数据的开始 and/or 结束,以及一种方法来确定正在传输什么数据。

如果您使用 ascii 表示(即使用 printprintlns),您可以使用不可打印的字符或 space 或换行来设置它。但是,由于您使用的是 write,我将采用更 "byte saver" 的技术。

在面向字节的传输中,我通常找到两种处理方法。

第一个是使用一组保留字节和一个 "escape"。每当您获得一个保留字节时,您都会进行一次转义,然后修改该字节以将其设置为非保留字节。例如,如果您将 7D 和 7E 定义为保留字节,并将 7E 定义为转义字节(例如 7D 是传输结束,并且通过将 7 更改为 8 将保留字节变为非保留字节)如果您的字节数组是 01 34 7D 66 7E 然后你将 7D 转换为 7E 8D(转义 + 非保留 =,7E 8E 中的 7E,并附加一个 7D。这样你发送 01 34 7E 8D 66 7E 8E 7D。解析器等待7D,并且知道每当它收到 7E 时,它就会丢弃该字节并将后面的 8x 更改为 7x。

这是制作更健壮协议的简单方法,但缺点是输出的长度可变。当我需要发送短于 8 位(或多位)的数据时,我经常使用的替代方法是保留一个位来指示该字节是数据还是命令,然后使用其他 7 位来存储实际数据.我在你的情况下使用这种方法,假设你发送的两个变量是有符号的并且范围是 16383 - -16384.

所以,协议很简单。如果接收到的字节的第一位是 1,那么这是一条命令。有效命令是:

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

所有的命令后面都要跟两个数据字节,每个数据字节都以0位开始。组成是

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

其中“0”是 0 位,bxx 是正在传输的数据的第 xx 位。

现在,发送数据很简单。这个简单的代码可以做到:

#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);

如您所见,您只是在发送类型后跟值。

接收码也很简单:

#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;
    }
}

如果需要,您也可以将其嵌入函数中:

#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;
}

请注意,您不会同时收到两个数据,而是一个接一个地收到。如果您需要数据同时到达,请询问,我会上传修改版本以同时发送和接收两个数据。

编辑:如问,这里是数据一起走的版本。

现在,如果将两个数据组合在一起,则数据包类型只有一种。所以不需要一个字节来说明它是什么类型的字节。因此,您可以修改协议以仅报告字节是否为起始字节。该协议现在只有一种类型的数据包,长度为 4 个字节:

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

其中l13-l00为LDR值的14位,a13-a00为加速度。

发送已修改,但一旦您知道要发送什么就很简单:

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);

唯一值得注意的是第一个字节设置了最高位,而其他字节没有。

接收代码只需要等待所有四个字节都到达,检查第一个字节是否确实以 1 开头,然后像以前的方式一样恢复两个值:

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)
    }
}

如果你更喜欢一个函数,你可以这样实现它:

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
}

在这种情况下,两个变量总是一起发送,而在另一种情况下,您可以将它们分开发送。哪个更好?这取决于你需要什么。这个更简单有效,另一个更灵活。

编辑 2: 完整示例:

我设计了一个完整的例子,两个arduinos用最新的协议通信(2个数据在一起)。左边的一个从两个电位器开始生成两个值,另一个打印它们。

在这里你可以找到它:https://circuits.io/circuits/3690285-software-serial-binary-transmission

连接:

发件人代码:

#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);
}

收件人代码:

#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);
  }
}