Почему необработанные байты данных не преобразуются в ASCII, а только в одной части моей программы?

Я пишу программу для одновременного считывания с датчиков Atlas Scientific EZO-HUM, -O2 и -CO2 по протоколу I2C с помощью Arduino Uno. Датчики все работают, но почему-то только данные датчика O2 не конвертируются в текст ASCII. Ниже моя программа:

#include <Ezo_i2c.h>
#include <Ezo_i2c_util.h>
#include <iot_cmd.h>
#include <sequencer1.h>
#include <sequencer2.h>
#include <sequencer3.h>
#include <sequencer4.h>
#include <Wire.h>                //включить I2C.


#define HUM_address 111          //идентификационный номер I2C по умолчанию для датчика влажности EZO.
#define O2_address 108           //идентификационный номер I2C по умолчанию для датчика EZO O2.
#define CO2_address 105          //идентификационный номер I2C по умолчанию для датчика EZO CO2.



//EZO-HUM варс
// | |
// ВВ
char computerdata[32];           // мы создаем 32-байтовый массив символов для хранения входящих данных с ПК / Mac / другого.
byte received_from_computer = 0; //нам нужно знать, сколько символов было получено.
byte serial_event = false;       //флаг, сигнализирующий о получении данных от ПК/макинтош/другого.
byte code = 0;                   //используется для хранения кода ответа I2C.
char Humidity_data[22];          // мы создаем 22-байтовый массив символов для хранения входящих данных с датчика влажности.
byte in_char = 0;                //используется как 1-байтовый буфер для хранения входящих байтов от датчика влажности.
byte i = 0;                      //счетчик, используемый для массива Humidity_data.
int time_ = 1000;                 //используется для установки задержки, необходимой для обработки команды, отправленной датчику влажности EZO.

//переменные EZO-CO2
// | |
// ВВ
//char CO2_computerdata[20]; // мы создаем 20-байтовый массив символов для хранения входящих данных с ПК/макинтош/другого.
byte CO2_received_from_computer = 0; //нам нужно знать, сколько символов было получено.
byte CO2_serial_event = false;       //флаг, сигнализирующий о получении данных от ПК/макинтош/другого.
byte CO2_code = 0;                   //используется для хранения кода ответа I2C.
char CO2_data[20];               // мы создаем 20-байтовый массив символов для хранения входящих данных от датчика СО2.
byte CO2_in_char = 0;                //используется как 1-байтовый буфер для хранения входящих байтов от датчика Co2.
byte CO2_i = 0;                      //счетчик, используемый для массива Co2_data.
//int CO2_time_ = 1000; //используется для установки задержки, необходимой для обработки команды, отправленной на датчик EZO Co2.
int Co2_int;                     //целая переменная, используемая для хранения значения Co2.

//Переменные EZO-O2
// | |
// ВВ
//char O2_computerdata[20]; // мы создаем 20-байтовый массив символов для хранения входящих данных с ПК/макинтош/другого.
byte O2_received_from_computer = 0; //нам нужно знать, сколько символов было получено.
byte O2_serial_event = false;       //флаг, сигнализирующий о получении данных от ПК/макинтош/другого.
byte O2_code = 0;                   //используется для хранения кода ответа I2C.
char O2_data[20];                // мы создаем 20-байтовый массив символов для хранения входящих данных от датчика o2.
byte O2_in_char = 0;                //используется как 1-байтовый буфер для хранения входящих байтов от датчика o2.
byte O2_i = 0;                      //счетчик для массива o2_data.
//целое O2_time_ = 600; //используется для установки задержки, необходимой для обработки команды, отправленной датчику EZO o2.

char *HUM;                       //указатель символа, используемый при разборе строки.
char *TMP;                       //указатель символа, используемый при разборе строки.
char *NUL;                       //указатель на символ, используемый при разборе строки (датчик выводит какой-то текст, который нам не нужен).
char *DEW;                       //указатель символа, используемый при разборе строки.
char *O2_reading;
char *O2_reading_2;

float HUM_float;                 // переменная с плавающей запятой, используемая для хранения значения влажности с плавающей запятой.
float TMP_float;                 // переменная с плавающей запятой, используемая для хранения значения температуры с плавающей запятой.
float DEW_float;                 // переменная с плавающей запятой, используемая для хранения значения с плавающей запятой точки росы.
float O2_float;
float CO2Con_float;



void setup()                    // аппаратная инициализация.
{
  Serial.begin(9600);           //включить последовательный порт.
  Wire.begin();                 //включить порт I2C.
  while(!Serial);            //ждем открытия последовательного монитора
}


void serialEvent() {                                                              // это прерывание сработает, когда будут получены данные, поступающие от последовательного монитора (ПК/mac/другое).
  received_from_computer = Serial.readBytesUntil(13, computerdata, 22);           // мы читаем данные, отправленные с последовательного монитора (ПК/макинтош/другое), пока не увидим <CR>. Мы также считаем, сколько символов было получено.
  computerdata[received_from_computer] = 0;                                       // остановить буфер от передачи остатков или мусора.
  serial_event = true;                                                            // устанавливаем флаг последовательного события.
}


void loop() {                                                                     //основной цикл.
  if (serial_event == true) {                                                     //если на устройство EZO была отправлена команда.
    for (i = 0; i <= received_from_computer; i++) {                               // установить для всех символов нижний регистр, это просто для того, чтобы этот точный пример кода мог распознать "sleep" команда.
      computerdata[i] = tolower(computerdata[i]);                                 //"Сон" ≠ "спать"
    }
    i=0;                                                                          //сбрасываем i, он нам понадобится позже
   
 //------------------------------------------------ --------- Датчик EZO-HUM-------------------------------------- -------------------------------------------------------//
    Wire.beginTransmission(HUM_address);                                              //вызываем схему по ее идентификационному номеру.
    Wire.write(computerdata);                                                     //передаем команду, которая была отправлена через последовательный порт.
    Wire.endTransmission();                                                       //завершить передачу данных I2C.

    

// Нужно поговорить с каждым датчиком отдельно. Поскольку все они являются датчиками Atlas Scientific EZO, все они реагируют на одни и те же команды.
 
    if (strcmp(computerdata, "sleep") != 0) {                                     //если отправленная команда НЕ является командой sleep, подождите необходимое время и запросите данные.
                                                                                  //если это команда sleep, ничего не делаем. Выдача команды перехода в спящий режим и последующий запрос данных активируют датчик влажности.

      delay(time_);                                                               // ждем нужное количество времени, пока схема завершит свою инструкцию.
       
      Wire.requestFrom(HUM_address, 22, 1);                                           //вызываем схему и запрашиваем 22 байта.
      code = Wire.read();                                                         //первый байт это код ответа, это читаем отдельно.

      switch (code) {                       //переключить регистр в зависимости от кода ответа.
        case 1:                             // десятичный 1.
          Serial.println("HUM Success");        //означает, что команда выполнена успешно.
          break;                            //выходим из регистра switch.

        case 2:                             //десятичный 2.
          Serial.println("HUM Failed");         //означает, что команда не удалась.
          break;                            //выходим из регистра switch.

        case 254:                           // десятичный 254.
          Serial.println("HUM Pending");        //означает, что команда еще не завершила расчет.
          break;                            //выходим из регистра switch.

        case 255:                           // десятичный 255.
          Serial.println("HUM No Data");        //означает, что больше нет данных для отправки.
          break;                            //выходим из регистра switch.
    }



    while (Wire.available()) {              //есть ли байты для получения.
      in_char = Wire.read();                // получаем байт.
      Humidity_data[i] = in_char;           // загружаем этот байт в наш массив.
      //Serial.println((int)in_char);
      i += 1;                               //возьмем на себя счетчик для элемента массива.
      if (in_char == 0) {                   //если видим, что нам прислали нулевую команду.
        i = 0;                              // сбрасываем счетчик i в 0.
        break;                              //выходим из цикла.
      }
    }
    if (computerdata[0] == 'r') string_pars();    // раскомментируйте эту функцию, если хотите разбить строку, разделенную запятыми, на отдельные части.
  }

 //------------------------------------------------ --------- Датчик EZO-O2------------------------------------- -------------------------------------------------------//
  
    Wire.beginTransmission(O2_address);                                           //вызываем схему по ее идентификационному номеру.
    Wire.write(computerdata);                                                     //передаем команду, которая была отправлена через последовательный порт.
    Wire.endTransmission();                                                       //завершить передачу данных I2C.
    
    if (strcmp(computerdata, "sleep") != 0) {                                     //если отправленная команда НЕ является командой sleep, подождите необходимое время и запросите данные.
                                                                                  //если это команда sleep, ничего не делаем. Выдача команды перехода в спящий режим и последующий запрос данных активируют датчик влажности.

      delay(time_);                                                               // ждем нужное количество времени, пока схема завершит свою инструкцию.
       
      Wire.requestFrom(O2_address, 22, 1);                                           //вызываем схему и запрашиваем 22 байта.
      O2_code = Wire.read();                                                         //первый байт это код ответа, это читаем отдельно.

      switch (O2_code) {                       //переключить регистр в зависимости от кода ответа.
        case 1:                             // десятичный 1.
          Serial.println("O2 Sensor Success");        //означает, что команда выполнена успешно.
          break;                            //выходим из регистра switch.

        case 2:                             //десятичный 2.
          Serial.println("O2 Sensor Failed");         //означает, что команда не удалась.
          break;                            //выходим из регистра switch.

        case 254:                           // десятичный 254.
          Serial.println("O2 Sensor Pending");        //означает, что команда еще не завершила расчет.
          break;                            //выходим из регистра switch.

        case 255:                           // десятичный 255.
          Serial.println("O2 Sensor No Data");        //означает, что больше нет данных для отправки.
          break;                            //выходим из регистра switch.
    }



    while (Wire.available()) {              //есть ли байты для получения.
      O2_in_char = Wire.read();                // получаем байт.
      O2_data[i] = O2_in_char;           // загружаем этот байт в наш массив.
      Serial.println((int)O2_in_char);
      Serial.println(O2_data);
      i += 1;                               //возьмем на себя счетчик для элемента массива.
      if (O2_in_char == 0) {                   //если видим, что нам прислали нулевую команду.
        i = 0;                              // сбрасываем счетчик i в 0.
        break;                              //выходим из цикла.
      }
    }
// Serial.print("Концентрация O2:"); //Этот код не выводит никакой информации, хотя программа получает байты, которые отображаются в цикле while.
// Serial.println(O2_data);
// Serial.println();

    if (computerdata[0] == 'r') O2_string_pars();             //Этот код также не выводит никакой информации.
  }
  
 //------------------------------------------------ ---------Датчик EZO-CO2------------------------------------- -------------------------------------------------------//
 
    Wire.beginTransmission(CO2_address);                                          //вызываем схему по ее идентификационному номеру.
    Wire.write(computerdata);                                                     //передаем команду, которая была отправлена через последовательный порт.
    Wire.endTransmission();                                                       //завершить передачу данных I2C.
    
    if (strcmp(computerdata, "sleep") != 0) {                                     //если отправленная команда НЕ является командой sleep, подождите необходимое время и запросите данные.
                                                                                  //если это команда sleep, ничего не делаем. Выдача команды перехода в спящий режим и последующий запрос данных активируют датчик влажности.

      delay(time_);                                                               // ждем нужное количество времени, пока схема завершит свою инструкцию.
       
      Wire.requestFrom(CO2_address, 22, 1);                                           //вызываем схему и запрашиваем 22 байта.
      CO2_code = Wire.read();                                                         //первый байт это код ответа, это читаем отдельно.

      switch (CO2_code) {                       //переключение регистра в зависимости от кода ответа.
        case 1:                             // десятичный 1.
          Serial.println("CO2 Sensor Success");        //означает, что команда выполнена успешно.
          break;                            //выходим из регистра switch.

        case 2:                             //десятичный 2.
          Serial.println("CO2 Sensor Failed");         //означает, что команда не удалась.
          break;                            //выходим из регистра switch.

        case 254:                           // десятичный 254.
          Serial.println("CO2 Sensor Pending");        //означает, что команда еще не завершила расчет.
          break;                            //выходим из регистра switch.

        case 255:                           // десятичный 255.
          Serial.println("CO2 Sensor No Data");        //означает, что больше нет данных для отправки.
          break;                            //выходим из регистра switch.
    }



    while (Wire.available()) {              //есть ли байты для получения.
      CO2_in_char = Wire.read();                // получаем байт.
      CO2_data[i] = CO2_in_char;           // загружаем этот байт в наш массив.
      //Serial.println((int)CO2_in_char);
      i += 1;                               //возьмем на себя счетчик для элемента массива.
      if (CO2_in_char == 0) {                   //если видим, что нам прислали нулевую команду.
        i = 0;                              // сбрасываем счетчик i в 0.
        break;                              //выходим из цикла.
      }
    }  
    Serial.print("CO2 Concentration:");                      
    Serial.println(CO2_data);                       
  }

  serial_event = false;                     // сбрасываем флаг последовательного события

// if (computerdata[0] == 'r') string_pars(); // раскомментируйте эту функцию, если хотите разбить строку, разделенную запятыми, на отдельные части.
}
   }
  
void string_pars() {                        //эта функция разбивает строку CSV на 3 отдельные части. ГУМ|ТМД|РОСА.
                                            // это делается с помощью команды C «strtok».

  HUM = strtok(Humidity_data, ",");         //давайте проанализируем строку до каждой запятой.
  TMP = strtok(NULL, ",");                  //давайте проанализируем строку до каждой запятой.
  NUL = strtok(NULL, ",");                  //разбираем строку по каждой запятой (датчик выдает в строке слово "РОСА", оно нам не нужно.
  DEW = strtok(NULL, ",");                  //давайте проанализируем строку до каждой запятой.

  Serial.println();                          // это просто облегчает чтение вывода, добавляя дополнительную пустую строку.
 
  Serial.print("HUM:");                      // теперь мы печатаем каждое проанализированное значение отдельно.
  Serial.println(HUM);                       //это значение влажности.

  Serial.print("Air TMP:");                  // теперь мы печатаем каждое проанализированное значение отдельно.
  Serial.println(TMP);                       //это значение температуры воздуха.

  Serial.print("DEW:");                      // теперь мы печатаем каждое проанализированное значение отдельно.
  Serial.println(DEW);                       // это точка росы.
  Serial.println();




  
  // раскомментируйте этот раздел, если вы хотите взять значения и преобразовать их в числа с плавающей запятой.
  /*
    HUM_float=atof(HUM);
    TMP_float=atof(TMP);
    DEW_float=atof(DEW);
  */
}  

void O2_string_pars() {                        //эта функция разбивает строку CSV
                                            // это делается с помощью команды C «strtok».

  O2_reading = strtok(O2_data, ",");         //давайте проанализируем строку до каждой запятой.
// O2_reading_2 = strtok(NULL, ",");

  Serial.println();                          // это просто облегчает чтение вывода, добавляя дополнительную пустую строку.
 
  Serial.print("O2 Concentration: ");                   
  Serial.println(O2_reading);
// Serial.println("Дополнительная информация O2: ");
// Serial.print(O2_reading_2);




  

}

Вот что выводит программа:

Успех HUM

ХУМ: 45,39

ТМД воздуха: 23,61

РОСА: 11,16

Датчик O2 успешно выполнен

50

48

46

56

53

0

Концентрация O2:

Датчик CO2 успешно выполнен

Концентрация CO2: 599

, 👍1

Обсуждение

Потому что в вашем коде вы специально печатаете целые числа?, @Majenko

Если вы читали программу, я печатаю массив, содержащий байты в строке ниже команды для печати отдельных байтов по мере их ввода в O2_data. Эти распечатки выводят пустые строки. Я попытался воспроизвести функцию string_pars() EZO-HUM для выходов EZO-O2, которая также выводит пробелы. У меня нет этой проблемы ни с одним из двух других датчиков., @czar1249

Что такое «i» в начале вашего цикла приема?, @Majenko

Если вы имеете в виду начало раздела «Датчик EZO-O2», он был сброшен на 0 после получения команды NULL от датчика EZO-HUM в конце соответствующего раздела этого датчика. По крайней мере, я так читаю., @czar1249

Вы *уверены* в этом? Напечатайте, что такое i, чтобы убедиться., @Majenko

Я напечатал i во всех трех сегментах — HUM, O2 и CO2. Счетчик _не_ сбрасывался после сегмента HUM, но сбрасывался после сегмента O2. Это было связано с тем, как был написан код примера EZO-HUM. Он запросил у датчика 22-байтовый символ, сбрасывая счетчик массива при получении «0» байта. Короче говоря, 22 байта отсекают команду NULL, отправленную датчиком, и изменение «Wire.requestFrom(HUM_address, 22, 1);» на «Wire.requestFrom (HUM_address, 23, 1);» починил это. Спасибо, @Маженко!, @czar1249

примечание: используйте имя computer_data, чтобы иметь согласованное соглашение об именах во всей вашей программе., @jsotola


1 ответ


Лучший ответ:

2

Вы полагаетесь на полученный байт NULL для сброса переменной указателя i. Если этот NULL по какой-либо причине никогда не приходит, вы не будете записывать свои новые данные в начало следующего массива.

Вы должны всегда сбрасывать счетчик перед получением новых данных, независимо от того, что вы только что получили.

,