Serial.read(); и конечный автомат для AT-команд
У меня возникла странная проблема: индекс массива не увеличивается, и когда я печатаю значение из serialdata[pointingfinger], он просто выдает пустое место. Это машина состояний (я полагаю), которая должна проверять, какой символ в данный момент записывается в массив, и его позицию, чтобы избежать поиска по нему позже. Когда у нас есть законченная строка, она переключает большую машину состояний в другой режим (который проверяет, есть ли команда на четыре символа дальше), когда обработка завершена, она должна вернуться к получению следующей строки.
Это Arduino Leonardo, Serial — это USB, а Serial1 — это то место, где я отправляю и получаю AT-команды.
const long interval = 1000;
static long currentMillis;
char plussignpoint = 0; //Чтобы определить, где находится + в +CCLK в массиве символов
char serialdata[256] = ""; //Массив для хранения символов перед анализом
int rdpos = 0;
int pointingfinger = 0;
char timeen = 0;
byte stat0 = 0;
char futstat0 = 0;
char searchcharpos = 0;
char enabled = 0;
char searchchartype = 0;
char smsvalid = 0;
void setup()
{
Serial.begin(9600);
Serial1.begin(9600);
Serial1.write("ATE0\r");
}
void loop() {
if (millis() - currentMillis >= interval)
{
Serial1.print("AT+CCLK?\r"); //спросить время
enabled = 1;
currentMillis = millis();
}
if (enabled == 1) {
if (stat0 == 0) {
if (Serial1.available () > 0) {
pointingfinger++;
serialdata[pointingfinger] = Serial1.read();
if (serialdata[pointingfinger] == '+') {
searchcharpos = pointingfinger;
searchchartype = 1;
futstat0 = 1;
}
else if (serialdata[pointingfinger] == '$') {
if (smsvalid = 1) {
searchcharpos = pointingfinger;
searchchartype = 2;
futstat0 = 2;
}
if (smsvalid = 0) {
stat0 = futstat0;
pointingfinger = 0;
}
}
else if (serialdata[pointingfinger] == '\n') {
stat0 = futstat0;
pointingfinger = 0;
enabled = 0;
}
else if (serialdata[pointingfinger] == '\r') {
stat0 = futstat0;
pointingfinger = 0;
enabled = 0;
}
else {
stat0 = 0;
pointingfinger = 0;
}
}
if (pointingfinger == 255) {
pointingfinger = 0;
enabled = 0;
}
}
}
}
ПРАВКА: Я забыл указать, какие AT-команды он должен анализировать:
Arduino: AT+CCLK?
SIM800H: +CCLK: "04/01/01,01:35:31+00"
OK
@A. Somov, 👍1
Обсуждение1 ответ
При проверке значения smsvalid
вы используете оператор присваивания =
вместо оператора сравнения ==
.
else if (serialdata[pointingfinger] == '$') {
if (smsvalid == 1) {
searchcharpos = pointingfinger;
searchchartype = 2;
futstat0 = 2;
}
if (smsvalid == 0) {
stat0 = futstat0;
pointingfinger = 0;
}
}
И также вы увеличиваете pointingfinget
перед записью в буфер serialdata
. Это означает, что первый символ будет записан в индексе 1. Таким образом, первый символ serialdata будет равен нулю, что означает пустую строку.
pointingfinger++;
serialdata[pointingfinger] = Serial1.read();
В вашем коде много проблем. Я вставил ваш код в онлайн-компилятор gdb c++, чтобы вы могли поиграться с ним и посмотреть, что происходит.
Эти AT-машины нелегко настроить на Arduino. Я потратил много времени на отладку похожего кода и обнаружил, что лучший способ — это модульное тестирование всех возможных ситуаций в Visual Studio или Xcode. Arduino — это просто C++, и если вы скопируете/вставите некоторые части вашего кода в C++ IDE, после реализации нескольких функций или классов он должен работать. Например, чтобы ваш код работал в XCode, мне пришлось реализовать некий фиктивный класс Serial1 и упростить код цикла:
class _Serial1
{
std::string buffer{"OK\r\n"};
public:
int available()
{
return (int)buffer.size();
}
char read()
{
char c = buffer[0];
buffer.erase(0, 1);
return c;
}
} Serial1;
void loop() {
if (enabled == 1) {
if (stat0 == 0) {
if (Serial1.available () > 0) {
pointingfinger++;
serialdata[pointingfinger] = Serial1.read();
if (serialdata[pointingfinger] == '+') {
searchcharpos = pointingfinger;
searchchartype = 1;
futstat0 = 1;
}
else if (serialdata[pointingfinger] == '$') {
if (smsvalid == 1) { // ==
searchcharpos = pointingfinger;
searchchartype = 2;
futstat0 = 2;
}
if (smsvalid == 0) { // ==
stat0 = futstat0;
pointingfinger = 0;
}
}
else if (serialdata[pointingfinger] == '\n') {
stat0 = futstat0;
pointingfinger = 0;
enabled = 0;
}
else if (serialdata[pointingfinger] == '\r') {
stat0 = futstat0;
pointingfinger = 0;
enabled = 0;
}
else {
stat0 = 0;
pointingfinger = 0;
}
}
if (pointingfinger == 255) {
pointingfinger = 0;
enabled = 0;
}
}
}
}
И компилятор сразу же указал мне на неверные назначения, а также я смог отладить код шаг за шагом и посмотреть, что происходит внутри.
В моей ситуации я подключал модуль SIMCOM900 gprs и создал конечный автомат, который позволяет мне писать такой код:
virtual void Program()
{
switch (Pc())
{
case 0: _ASSERT(strlen(mApn)>0);
Stream() << "AT+CSTT=\"" << mApn << "\",\"\",\"\"\r\n";
break;
case 1: Expect("OK\r\n");
if (Expect("+CME ERROR")) { Error("CME Error when attaching apn"); Return(false);}
if (Timeout(25000)) Return(false);
break;
case 2: Stream() << "AT+CIICR\r\n"; break;
case 3: Expect("OK\r\n");
if (Timeout(15000)) Next(); break;
case 4: Stream() << "AT+CIFSR\r\n"; break;
case 5: if (ReadIpAddress()) Next();
if (Timeout(2000)) Return(false); break; // дольше?
default: Return(true);
}
}
Вот немного более старая версия: https://gist.github.com/gabonator/88b80d9c6b16d699d6f4234ebc3a2587
- Как разделить входящую строку?
- Как вывести несколько переменных в строке?
- В чем разница между Serial.write и Serial.print? И когда они используются?
- Загрузка Arduino Nano дает ошибку: avrdude: stk500_recv(): programmer is not responding
- Программы построения последовательных данных
- Как узнать частоту дискретизации?
- Что такое Serial.begin(9600)?
- Очистить существующий массив при получении новой последовательной команды
Какие данные вы получаете от Serial? Ваша проблема во многом зависит от этих данных, поэтому, пожалуйста, включите их., @chrisl