我使用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以防止数据切换?
答案 0 :(得分:1)
除了gre_gor在注释中所说的内容(因此,读取和写入需要发送和接收两个字节的整数),您需要一种更强大的方式来发送和接收字节(只需等待并祈祷它们被同步即可不是一种选择)。
有很多方法可以制定合适的协议。在理想的协议中,您需要一种方法来确定数据的开始和/或结束,以及确定传输什么数据的方法。
如果您使用ascii表示(即使用print
和println
),您可以使用不可打印的字符或空格或新行来设置它。但是,由于您使用的是write
,因此我会使用更多的字节保护程序&#34;技术
在面向字节的传输中,我通常会找到两种方法来解决这个问题。
第一个是使用一组保留字节和一个&#34;转义&#34;一。每当你得到一个保留字节时,你就放一个转义然后修改字节以便将它设置为非保留字节。例如,如果将7D和7E定义为保留,并将7E定义为转义字节(例如,7D是传输结束,如果您的字节通过更改8中的7,则将保留为非保留)数组是01 34 7D 66 7E然后你转换7E 8D中的7D(转义+非保留=,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
其中&#39; 0&#39;是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);
}
}