Связь Arduino и ESP8266 SoftwareSerial
У меня есть Arduino Uno и ESP8266, подключенные через последовательный порт. ESP8266 контакт GPIO_2 (который установлен как RX через espsoftwareserial) и 11 на Uno (который установлен как TX через SoftwareSerial). Я пытаюсь отправить данные (пока что просто случайные числа от 0 до 1000) с Arduino Uno на ESP8266. Но ESP8266 показывает беспорядочные символы.
Я использую:
Код Arduino UNO:
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX
int randnum;
void setup() {
// установить скорость передачи данных для порта SoftwareSerial
mySerial.begin(9600);
Serial.begin(115200);
}
void loop() { // запускать снова и снова
randnum = random(0,1000);
mySerial.write(randnum);
Serial.println(randnum);
delay(2000);
}
Код ESP8266: (программируется с помощью Arduino IDE)
#include <ESP8266WiFi.h>
#include <SoftwareSerial.h>
SoftwareSerial ARD_ESP(2, SW_SERIAL_UNUSED_PIN); // RX, TX |||| RX = ESP8266 = GPIO_2
const char* ssid = "myssid";
const char* password = "mypassword";
const char* host = "www.myweb.com";
const char* value2 = "986.458";
const char* value1 = "150.0589";
long previousMillis = 0;
char indata;
String incomingData_from_ARD = "";
int i=0;
void setup() {
Serial.begin(115200);
ARD_ESP.begin(9600);
delay(10);
// Начнем с подключения к сети WiFi
Serial.println();
Serial.println();
Serial.print("connecting to wifi: ");
Serial.print(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
//целое значение = 0;
void loop() {
//задержка(1000);
//++значение;
if (ARD_ESP.available() > 0) {
Serial.write(ARD_ESP.read());
indata = ARD_ESP.read();
incomingData_from_ARD += String(indata);
}
if ((millis() - previousMillis) > 10000) {
Serial.println("---------------------------------------------------------------------------------------");
Serial.print("Requesting URL: ");
Serial.println(host);
Serial.println("-------------------------------");
// Используйте класс WiFiClient для создания TCP-соединений
WiFiClient client;
const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println("Request failed");
return;
}
// Теперь создаем URI для запроса
String url = "/testesp.php";
url += "?sensor_1_total_volume=";
url += incomingData_from_ARD;
url += "&sensor_2_total_volume=";
url += value2;
Serial.println("Sending data to URL: ");
Serial.println(url);
Serial.println("-------------------------------");
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println(">>> Server Timeout!");
client.stop();
return;
}
}
while(client.available()) {
String line = client.readStringUntil('\r');
Serial.print(line);
}
Serial.println();
Serial.println("Closing connection with web");
Serial.println("-----------------------------------------------------------------------------------");
previousMillis = millis();
incomingData_from_ARD = "";
}
}
И вот текст, который я получаю на Serial (на ПК):
-----------------------------------------------------------------------------------
›¸Ąě*Ű
---------------------------------------------------------------------------------------
Requesting URL: www.myweb.com
-------------------------------
Sending data to URL:
/testesp.php?sensor_1_total_volume=Ĺ˙˙˙˙˙&sensor_2_total_volume=986.458
-------------------------------
HTTP/1.1 200 OK
Server: nginx
Date: Tue, 13 Dec 2016 23:28:58 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: close
X-Powered-By: PHP/7.0.10
354
<div style=" background-color:#; font-size: px;"><div class="oznamy"><div class="eq"><i>„Čas si vymysleli lidé, aby věděli, od kdy do kdy a co za to.“ </i>Jan Werich</div></div></div><!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="description" content="TEST_ESP">
<meta name="author" content="Vasekdvor">
<meta name="robots" content="noindex">
<title>TEST ESP 8266 POST A GET</title>
0
Closing connection with web
-----------------------------------------------------------------------------------
Эти беспорядочные символы в начале — случайные числа, которые отправляет Arduino Uno:
›¸Ąě*Ű
Но Arduino отправляет реальные числа, только ESP8266 интерпретирует их именно так.
Помогите мне это исправить? Как мне получать номера?
Спасибо.
РЕДАКТИРОВАТЬ:
Поэтому я внес некоторые изменения, основываясь на рекомендациях chupo_cro
Теперь это Arduino:
void loop() { // запускать снова и снова
randnum = random(0,1000);
mySerial.write((byte*)&randnum, sizeof(randnum));
Serial.println(randnum);
delay(2000);
}
И ESP8266:
long previousMillis = millis();
char indata;
String incomingData_from_ARD = "";
int i=0;
void setup() {
.................................
void loop() {
//delay(1000);
//++value;
if (ARD_ESP.available() > 0) {
//Serial.write(ARD_ESP.read());
indata = ARD_ESP.read();
incomingData_from_ARD += indata;
}
Serial.println(incomingData_from_ARD);
if ((millis() - previousMillis) > 10000) {
Он все еще не работает.
@Vasekdvor, 👍0
2 ответа
Лучший ответ:
В вашем коде есть несколько проблем.
Во-первых, у вас есть if (ARD_ESP.available() > 0)
для проверки, поступили ли данные, но что произойдет, если данные все еще не поступили? Вместо того, чтобы ждать поступления данных, программа продолжит цикл и будет отправлять запрос каждые 10 секунд, даже если данных нет.
Во-вторых, вы инициализировали previousMillis
нулем. Вам следует инициализировать его как millis()
, чтобы вы могли считать с настоящего момента времени.
В-третьих, в цикле, где вы считываете входные данные:
if (ARD_ESP.available() > 0) {
Serial.write(ARD_ESP.read()); // <-- 1-е чтение
indata = ARD_ESP.read(); // <-- 2-е чтение
incomingData_from_ARD += String(indata);
}
когда что-то приходит, вы читаете это дважды, поэтому второе чтение indata = ARD_ESP.read();
возвращает -1
(нет доступных данных), когда в буфере меньше двух символов. Даже если вы отправили больше одного символа, новые данные не успевают поступить в буфер, и даже если есть больше одного символа, вы пропускаете каждый второй из-за первого чтения.
В-четвертых, вы не можете отправить число больше 255 (один байт) с помощью mySerial.write(randnum);
, потому что write()
отправляет только один байт. И даже если бы вы могли таким образом отправить больше одного байта, вы не смогли бы отобразить эти байты как строку, представляющую число. Вы могли бы отправить все байты с помощью:
mySerial.write((byte*)&randnum, sizeof(randnum));
но, как я уже сказал, эти байты не являются строкой, представляющей число, содержащееся в переменной. Например, если randnum = 1000
, то есть 0xe8, 0x03
, а "1000"
— это 0x31, 0x30, 0x30, 0x30
. 0x31
— это ASCII для 1
, а 0x30
— это ASCII для 0
.
Итак, вам есть что улучшить.
РЕДАКТИРОВАТЬ:
Попробуйте это, у меня нет времени проверять код, но это должно работать:
int length = 4;
char to_send[length];
itoa(randnum, to_send, 10);
mySerial.write((byte*)&to_send, sizeof(to_send));
Serial.println(to_send);
РЕДАКТИРОВАТЬ:
К сожалению, у меня нет Arduino (даже никогда не было :-)), так что вам придется попробовать код и сообщить, работает ли он. У меня есть несколько ESP8266, но все они в данный момент регистрируют какие-то данные.
Теперь код ESP8266:
У вас есть как минимум два варианта выбора при выборе способа чтения данных. Первый вариант — «ваш путь», что-то вроде:
void loop() {
char input;
if(ARD_ESP.available()) {
input = (char)ARD_ESP.read(); // можно попробовать даже без (char)
Serial.print(input); // отправить символ на терминал
incomingData_from_ARD += input; // объединяем новый символ
}
if ((millis() - previousMillis) > 10000) {
// если что-то было получено до сих пор
if(incomingData_from_ARD.length()) {
// ...
incomingData_from_ARD = "";
}
previousMillis = millis();
}
// ...
}
Второй способ может быть таким:
void loop() {
char input;
// ждем данные
while(!ARD_ESP.available())
yield(); // чтобы предотвратить сброс WDT
// прочитать все, что было отправлено
while(ARD_ESP.available()) {
input = (char)ARD_ESP.read();
Serial.print(input);
incomingData_from_ARD += input;
delay(120); // 100 или немного больше для 9600 Бод
}
// удалить 'if' для немедленной отправки
if ((millis() - previousMillis) > 10000) {
// ...
previousMillis = millis();
}
// ...
}
Между этими двумя способами чтения входящих данных есть существенная разница. При чтении данных, как в первом примере, при каждом проходе по циклу вы либо читаете, либо не читаете ровно один байт. Поскольку существует вероятность, что пройдет 10 секунд, прежде чем мы получим какие-то данные, должна быть проверка, поступили ли данные за это время или нет. Если бы были какие-то данные, то каждые 10 секунд все, что было получено до этого момента, отправлялось бы - даже если бы это было в середине строки. Вы, вероятно, не хотите отправлять на сервер только одну часть строки.
Во втором примере есть цикл while
, ожидающий данные из последовательного порта. Когда данные приходят, есть еще один цикл while
, который считывает все байты один за другим. Без delay
цикл закончился бы до получения второго и всех последующих байтов, поэтому полученная строка была бы разрезана на 1-символьные куски. Теперь, когда получена вся строка, нам не нужно проверять, пришло ли что-то, потому что мы уже знаем, что это произошло.
Я оставил задержку в 10 секунд между отправкой запросов GET, но вы должны решить, действительно ли это то, что вы действительно хотите. Вы должны знать, что если следующие данные поступят между отправкой запросов GET, следующая строка (число) будет объединена с предыдущей, а вы не хотите, чтобы это произошло, потому что такие данные не будут иметь смысла. Чтобы избежать объединения новых данных со старыми, вам нужно удалить if
, который проверяет millis()
для немедленной отправки полученных данных.
Примечание: Как я уже сказал, я не могу протестировать код, поэтому не могу гарантировать, что он на 100% свободен от ошибок, но вы можете проверить его работоспособность, чтобы я мог исправить ошибки, если таковые имеются.
Проверьте библиотеку Softwareserial, она не от Arduino, а от парня по имени Питер Леруп. Я протестировал две платы Uno Softwareserial, и они работают отлично. Но затем, когда я использую плату Wifi-uno-look-alike, я не получаю никакого последовательного сигнала.
- Проблемы при использовании SoftwareSerial
- AT-команда не отвечает на последовательный монитор
- Последовательная связь между ESP8266 и Arduino Uno
- Как связаться с ESP8266 ESP01, отправив данные через программный сериал на Arduino Uno?
- Последовательная связь от Arduino до ESP8266 NodeMCU работает, но от NodeMCU до Arduino не работает
- Arduino считывает состояние подключения устройства hc-05
- HLW8032 UART отправляет случайные данные (регистры часто переполняются)
- Как связаться с GPS SIM900a без serial monitor