Почему необработанные байты данных не преобразуются в 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
@czar1249, 👍1
Обсуждение1 ответ
Лучший ответ:
Вы полагаетесь на полученный байт NULL для сброса переменной указателя i
. Если этот NULL по какой-либо причине никогда не приходит, вы не будете записывать свои новые данные в начало следующего массива.
Вы должны всегда сбрасывать счетчик перед получением новых данных, независимо от того, что вы только что получили.
- Отправка и получение различных типов данных через I2C в Arduino
- Как работают функции вне цикла void?
- Как отображать переменные на 0,96-дюймовом OLED-дисплее с библиотекой u8glib?
- OVF в последовательном мониторе вместо данных
- ЖК-дисплей I2C отображает странные символы
- Соединение I2C зависает Ведущий если ведомый отключается
- Экран LCD 16*02 I2C показывает только первый напечатанный символ
- Отключение внутренних подтягивающих резисторов i2c
Потому что в вашем коде вы специально печатаете целые числа?, @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