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

, 👍1

Обсуждение

Какие данные вы получаете от Serial? Ваша проблема во многом зависит от этих данных, поэтому, пожалуйста, включите их., @chrisl


1 ответ


2

При проверке значения 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

,