Датчик газа Arduino Due & Spec — как выбрать конкретную информацию из потока входящих байтов для сохранения
Я пытаюсь собрать датчик загрязнения воздуха для студенческого проекта, используя Arduino Due и несколько цифровых газоанализаторов Spec Sensors. Однако у меня возникли некоторые трудности с настройкой первого из них (угарного газа, https://www.spec-sensors.com/product/digital-co-sensor/), прежде чем я смогу запустить несколько. Поскольку все они имеют одинаковую конфигурацию датчиков, но для разных газов, как только я заработаю с первым, остальные должны легко подтянуться.
Код очень прост, так как он использует собственную систему команд Spec: отправка буквы «c» датчику заставляет его снимать одно показание в секунду, пока датчик подключен к сети, а затем последовательный монитор отображает то, что возвращается:
void setup() {
// датчик работает через Serial1
Serial.begin(9600);
Serial1.begin(9600);
Serial1.print("c");
}
void loop() {
if(Serial1.available()!=0)
{
Serial.write(Serial1.read());
}
}
Проблема связана с возвращаемыми данными. Показания концентрации газа присутствуют, но также присутствует много лишней информации, которая мне не нужна. Согласно технической документации датчика, возвращаемая информация следующая: серийный номер, показания (ppb), температура, влажность, исходные значения напряжения и время работы датчика. В последовательном мониторе это выглядит так:

Сейчас мне нужны только показания в ppb (второе значение), либо как единственные поступающие данные, либо как сохраняемые, чтобы их можно было использовать в расчётах, например, для усреднения показаний в час. Проблема в том, что эта информация, по всей видимости, поступает потоком отдельных байтов, и в этом формате мне сложно придумать эффективный способ указать, какую информацию я хочу сохранить, а какую проигнорировать. Я пытался, например, придумать способ указать, что первые 14 байтов (серийный номер, запятая, пробел — так как эта длина всегда будет одинаковой) следует игнорировать, а затем следующую серию (до следующей запятой — так как это показание может состоять из 4-6 цифр) хранить как int или что-то в этом роде, но, несмотря на все мои попытки, я ничего не могу добиться. Есть ли у кого-нибудь предложения?
@Gala Pagois, 👍0
Обсуждение2 ответа
Лучшее решение — отправлять только необходимые данные. Если датчик не поддерживает такую функцию, попробуйте следующий код:
char str[] = "102617010933, 8486, 22, 35, 13464, 25716, 21962, 00, 00, 20, 06";
unsigned long ppb = 0;
void setup(){
Serial.begin(9600);
int counter = 0;
char * pch = strtok(str, " ,");
while(pch != NULL){
if(counter == 1){
ppb = atol(pch);
break;
}
pch = strtok(NULL, " ,");
counter += 1;
}
Serial.println(ppb);
}
void loop(){
}
Поскольку длина каждого типа данных различается, извлекать данные следует с помощью разделителя, например запятой в потоке.
Сначала получите одну строку данных с датчика. Считывайте строку до появления символа «Перевод строки (LF)» или «Возврат каретки (CR)». Эти два символа, расположенные в конце строки (EOL), разделяют строки, меняя строку. Без этих двух символов поток данных на мониторе отображается следующим образом (без смены строки).
102617010933, 8486, 22, 35, 13464, 25716, 21962, 00, 00, 20, 06102617010933, 87216, 22, 35, 13576, 25223, 21442, 00, 00, 20, 07
Итак, вы видите символы CR и LF в конце строки. Используйте CR или LF в качестве терминатора функции ReadStringUntil(). https://www.arduino.cc/en/Serial/ReadStringUntil
Во-вторых, процесс анализа. Этот процесс извлекает нужные данные из функции strtok(). Функция strtok() из языка C. Она разделяет строку по символам-разделителям.
https://stackoverflow.com/questions/3889992/how-does-strtok-split-the-string-into-tokens-in-c?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
Наконец, используйте данные и повторяйте каждый раз, когда датчик отправляет данные.
Я не эксперт в программировании. Я не тестировал приведённый ниже код. Но он может быть полезен.
int data[12];
int isDataReceived = false;
void setup(){
Serial.begin(9600);
Serial1.begin(9600);
Serial1.write('c');
}
void loop(){
while(Serial1.available()>0) {
String inString = Serial1.readStringUntil('\n');
char * pch = strtok(inString, ","); //Серийный номер будет проигнорирован
for(int i=0; pch != NULL; i++) { //следующие данные хранятся в строке data[12]
pch = strtok(NULL, ",");
data[i] = atoi(pch);
}
isDataReceived=true;
}
if(isDataReceived) {
Serial.print("Data:");
Serial.println(data[0]); //Это просто пример кода. Вы можете увидеть ppb на последовательном мониторе.
isDataReceived=false;
}
}
- Как получить ненулевой выход из HX711 и ячейки загрузки?
- Serial.availableForWrite против Serial.flush
- Как получить данные о весе с датчиков стеклянных электронных весов для ванной?
- Построение графика на Python с использованием Tkinter Canvas
- Отправка последовательных данных в прерывании
- Почему люди используют 115200 вместо 9600?
- Как связаться с датчиком через порты RX/TX Arduino?
- Ошибка 'Serial' was not declared in this scope
примечание: непрерывное чтение в течение 1 секунды, похоже, не документировано, @jsotola