Считать одно значение из непрерывного потока данных с более низкой частотой
Я работаю над выпускным проектом университета и столкнулся с проблемой программирования Arduino после 3-летнего перерыва. У меня есть датчик давления, который отправляет данные о давлении с частотой 10 Гц. Я успешно запрограммировал свой Arduino Pro Micro на считывание данных по мере их поступления. Я использую библиотеку SoftwareSerial для установки цифровых контактов 8 и 9 на RX и TX соответственно. Поскольку датчик давления непрерывно передает значения данных, я считываю каждый символ, сохраняю их в массиве и вывожу на последовательный монитор. Я использую начальный и конечный маркеры для распознавания каждого входящего символа и помещения их в массив. Необработанные выходные данные от датчика имеют вид:
*000114.2927
*000114.2926
*000114.2927
И это код, который я использую.
#include <SoftwareSerial.h>
#define paroRX 8
#define paroTX 9
SoftwareSerial paroSerial(paroRX, paroTX);
const byte numChars = 16;
char paroChars[numChars]; //массив для хранения полученных данных
char paroToSend[numChars]; //массив для передачи
boolean newParoData = false;
void setup(){
Serial.begin(9600); //с радиопередатчиком
paroSerial.begin(9600);
}
void loop(){
paroSerial.listen();
readParo(); //прочитать из Paro и сохранить значения в paroChars
if(newParoData == true){
for(int i=0; i<16; i++){
paroToSend[i] = paroChars[i];
}
Serial.print(paroToSend); Serial.print('\n'); //передача данных Paro с новой строкой для каждого значения
newParoData = false;
}
}
void readParo(){
static boolean receiveInProgress = false;
static byte index = 0;
char startMarker = '*';
char endMarker = '\n';
char pd;
while(paroSerial.available() && newParoData == false){
pd = paroSerial.read();
if(receiveInProgress == true){
if(pd != endMarker){
paroChars[index] = pd;
index++;
if(index >= numChars){
index = numChars - 1;
}
}else{
paroChars[index] = '\0'; //завершить строку
receiveInProgress = false;
index = 0;
newParoData = true;
}
}else if(pd == startMarker){
receiveInProgress = true;
}
}
}
И вот что я получаю на выходе, и это правильно. Мне вообще не нужна эта * впереди.
000114.2927
000114.2928
000114.2927
000114.2929
Но все это происходит на частоте 10 Гц, что означает, что я получаю постоянный поток показаний на последовательном мониторе. Я хочу замедлить это до 1 Гц, или всего одного показания в секунду. Очевидным решением, которое пришло мне в голову, было добавить задержку в цикл. Поэтому я попытался реализовать это с помощью delay(1000) и также с помощью функции millis(), но я получаю странные показания, например:
000114.2927
***000114
**2928
***.000114
000114.2928
Как мне считывать данные с частотой 1 Гц из потока данных с частотой 10 Гц? Я хочу просто сохранять одно значение данных из потока в секунду в виде 000114.2927, а затем игнорировать остальное, пока Arduino делает что-то еще.
Спасибо!
@bf109k4, 👍1
3 ответа
Лучший ответ:
Вы думаете в обратном порядке. Вы не хотите читать медленнее (что и делает задержка), вы хотите отправлять только каждую 10-ю запись.
То есть, считайте строки по мере их поступления. Когда вы достигнете 10, вы печатаете одну и сбрасываете счет.
Другими словами:
static int count = 0;
if(newParoData == true){
count ++;
if (count == 10) {
count = 0;
// (Зачем копировать строку только для того, чтобы отправить копию...?)
for(int i=0; i<16; i++){
paroToSend[i] = paroChars[i];
}
Serial.print(paroToSend); Serial.print('\n'); //передача данных Paro с новой строкой для каждого значения
}
newParoData = false;
}
Я бы использовал функции времени класса Stream. Serial — это реализация Stream. Свойство timeout
(setTimeout
) устанавливает, как долго функции блокировки будут ждать следующий байт/символ. Значение timeuot по умолчанию составляет 1000 мс.
Временные функции потока: find
, parseInt
, parseFloat
, readBytes
, readBytesUntil
, readString
и readStringUntil
. (Неблокирующие функции чтения: read
и peek
.)
Ответ Маженко точен: вам просто нужно посчитать предложения, которые вы
читать и повторять одно из десяти предложений. И вам не нужно две копии
предложения, которое вы читаете: одного достаточно. Но я бы добавил, что вы
даже не нужна ни одна копия: вы можете просто повторить символы, которые вы
читать, не сохраняя их, пока не нажмете '*'
:
void loop()
{
static uint8_t sentence_count;
if (paroSerial.available()) {
char c = paroSerial.read();
if (c == '*') {
// Увеличиваем количество предложений по модулю 10.
if (++sentence_count == 10)
sentence_count = 0;
} else if (sentence_count == 0) {
// Это одно предложение, которое нам придется повторить.
Serial.write(c);
}
}
}
Кстати, если ваша программа не считывает входные данные с компьютера,
и если он ничего не посылает на преобразователь, то вы можете рассмотреть
избавляемся от SoftwareSerial
и используем только аппаратный последовательный порт:
- приемная часть порта для считывания данных с преобразователя
- часть-эмиттер для отправки данных на компьютер.
Да, совершенно нормально использовать приемник и передатчик для разные ссылки. Единственное предостережение в том, что вам придется использовать те же самые конфигурация порта с обеих сторон: если преобразователь говорит на 9600 бит/с, то весь порт должен будет работать на скорости 9600 бит/с.
- Ошибка 'Serial' was not declared in this scope
- Serial.availableForWrite против Serial.flush
- Arduino считывает состояние подключения устройства hc-05
- Повреждение данных SoftwareSerial - поиск предложений
- Какой лучший способ объявить Serial при создании библиотеки Arduino?
- Последовательная связь между двумя Arduino не работает при отправке строки в программе с большим количеством функций.
- Термопринтер Adafruit печатает слабо
- Последовательная связь, если инструкция не работает