Проблемы с печатью Arduino UNO, повторяющейся "double" на последовательном мониторе
Происходит странное, я не могу понять, почему. Сначала у меня была проблема со связью с SIM800L. Поэтому я попытался проверить оборудование USART, чтобы увидеть, что UNO отправляет на SIM800, используя небольшую часть, прикрепленную ниже. Скетч состоит в том, чтобы сравнить то, что я отправляю с последовательного монитора, со строками «Hello», «heLLo» и т. д. и "Здравствуйте" Ожидается, что будет найдено... или совпадение не найдено. каждую строку строки, которую я отправляю, последовательный монитор печатает дважды ПОЧЕМУ?, Первый говорит, что не найден, а второй говорит, что Получено == ........ ПОЧЕМУ?
**См. вывод последовательного терминала когда я набрал "Привет" с кавычками.
12:03:46.536 -> Buffer Received= " No match found
12:03:46.569 ->
12:03:46.569 -> Buffer Received= Hello"
12:03:46.603 -> Found Hello
when i typed "HELLO" with quotes.
12:03:55.855 -> Buffer Received= " No match found
12:03:55.888 ->
12:03:55.888 -> Buffer Received= HELLO"
12:03:55.921 -> Found HELLO**
****когда я набрал "привет" с кавычками.
12:04:04.016 -> Buffer Received= " No match found
12:04:04.049 ->
12:04:04.049 -> Buffer Received= heLLo"
12:04:04.082 -> Found heLLo
12:04:04.115 ->****
Когда я печатаю без кавычек, все, что я получаю, не найдено совпадений
char buffer[100];
uint8_t index=0;
void setup()
{
Serial.begin(9600);
_delay_ms(4000);
}
void loop()
{
if(Serial.available()>0)
{
index=0;
while(Serial.available())
{
buffer[index++]=Serial.read();
}
buffer[index]='\0';
Serial.println(' ');
Serial.print("Buffer Received");
Serial.print(buffer);
Serial.print('\t');
if(strstr(buffer, "Hello")!=NULL) Serial.println("Found Hello");
else if(strstr(buffer, "HELLO")!=NULL) Serial.println("Found HELLO");
else if(strstr(buffer, "heLLo")!=NULL) Serial.println("Found heLLo");
else Serial.println("No match found");
Serial.flush();
}
}
Примечание. Подозревая аппаратное обеспечение и последовательный драйвер моего ПК,
поэтому я попробовал это в своем Ubuntu 20.04 и окне 10, установленном с Arduino IDE 1.8.13.
подозревая, что это может быть кристалл, я попробовал две разные платы и даже использовал ядро Atmega328P.
Я также подозревал, что моя клавиатура "ENTER" ключ, поэтому я попробовал серийный монитор "отправить" кнопка.
без разницы.
Кажется, мне не хватает идей, поэтому я публикую их в сообществе. Позвольте мне тоже поделиться вашим советом и опытом.
Спасибо.
@Avong, 👍1
Обсуждение1 ответ
Как уже заявили Majenko и DataFiddler в комментариях, вы неправильно читаете интерфейс Serial, потому что вы, кажется, неправильно понимаете конкретный момент, связанный с интерфейсом.
Последовательный (UART) интерфейс знает только об отдельных байтах, которые асинхронно отправляются по линиям. Он не имеет никакого контекста полного пакета или сообщения. Когда вы вводите некоторые данные в Serial Monitor, а затем нажимаете «Отправить», данные будут отправлены, но не как один большой набор данных. Отдельные байты задерживаются.
Первая задержка связана с характером самого интерфейса, поскольку вы отправляете данные с ограниченной скоростью передачи данных. Со скоростью 9600 бод Arduino работает намного быстрее, чем могут поступать байты. Таким образом, когда вы впервые получаете результат больше нуля от Serial.available()
, остальная часть сообщения еще не получена. Таким образом, с вашим текущим кодом вы обработаете только первую часть сообщения.
Вторая задержка связана с тем, что вы и программа Serial на вашем ПК не можете контролировать, когда именно отправляется каждый байт. Это делает водитель. Так что может случиться так, что где-то в вашем сообщении есть небольшой пробел между 2 байтами. Вы не можете смягчить это, не написав свой собственный драйвер, и вы не можете это предсказать.
Итак, что теперь делать? Вы должны считать данные, когда они доступны, и поместить их в буфер. И только, когда было получено полное сообщение, следует обрабатывать данные. Теперь вам нужно знать, где находится конец сообщения. В основном используется символ-разделитель (например, символ новой строки \n
) в конце сообщения. Таким образом, вы читаете, если доступно, и обрабатываете сообщение только тогда, когда вы прочитали символ-разделитель. Что-то вроде этого:
unsigned int buffer_pos = 0;
char buffer[50]="";
void loop(){
if(Serial.available()){
char c = Serial.read();
if(c == '\n'){
buffer[buffer_pos] = '\0'; // Завершить сообщение как строку C нулевым символом
// обрабатываем сообщение здесь
buffer_pos = 0;
} else {
buffer[buffer_pos] = c;
buffer_pos++;
}
}
}
buffer
содержит сообщение. buffer_pos
— текущая позиция в буфере. Мы завершаем сообщение нулевым символом, чтобы получить допустимую строку C в буфере. После обработки сообщения мы устанавливаем позицию обратно в ноль, чтобы получить следующее сообщение. Когда вы отправляете данные со своего ПК, вам необходимо убедиться, что сообщение заканчивается символом новой строки.
Теперь вы не зависите от того, когда именно отправляются данные.
DataFiddler заявил в комментариях, что без символа-разделителя вы можете просто задержаться на достаточное время, чтобы у данных было достаточно времени для поступления. Он также заявил, что это некрасиво. Это плохой стиль кодирования. Длительная задержка повлияет на скорость отклика вашей программы, а короткая задержка может вызвать проблемы с более длинными сообщениями. Поэтому я предлагаю вам использовать правильный способ чтения последовательного интерфейса. Тогда у вас нет таких подводных камней.
Дорогой Крис! вы молодцы! СПАСИБО БОЛЬШОЕ. сначала разрешил это из предложения DataFiddler, а затем из предложения Majenko. Ваши объяснения откровенны. Я наслаждаюсь всем вашим вкладом. ТОЛЬКО то, что я был немного неосторожен в обращении с этим. Как ни смешно это прозвучит. Я сражаюсь с этим около 22 часов. Как я уже говорил ранее, я буду более осторожен, чтобы избежать такого предотвратимого стресса., @Avong
@Avong, пожалуйста, проголосуйте за хорошие ответы и отметьте лучший ответ как правильный, так как это лучший способ поблагодарить людей за то, что они нашли время написать хорошие ответы. Кнопка «за» — это маленькая стрелка вверх в левом верхнем углу ответа., @Gabriel Staples
- Как использовать SPI на Arduino?
- Как решить проблему «avrdude: stk500_recv(): programmer is not responding»?
- Как создать несколько запущенных потоков?
- Как подключиться к Arduino с помощью WiFi?
- avrdude ser_open() can't set com-state
- Как узнать частоту дискретизации?
- Что такое Serial.begin(9600)?
- Я закирпичил свой Arduino Uno? Проблемы с загрузкой скетчей на плату
У вас фундаментальное непонимание того, как работает последовательная связь. Вы не можете просто прочитать «пока доступен», потому что это не будет правдой. Вам нужно «прочитать, если доступно, и до завершающего символа»., @Majenko
9600 бод означает 1 мс на символ. Если нет завершающего символа, на который можно положиться, простое ожидание в течение нескольких мс с помощью
delay(10);
после первогоSerial.available()> 0
в этом случае является уродливой, но выполнимой альтернативой., @DataFiddlerЗдравствуйте, DataFiddler, Вы молодец, ваше предложение работает. это был просто случай задержки, который проигнорировали. На самом деле я добавил задержку (10) между чтениями символов. и больше никакого дублирования печати. НО ЗАЧЕМ это нужно? в eclipse я не думаю, что у меня есть такой опыт. НА ЭТО СТОИТ ИСПОЛЬЗОВАТЬ ПРИ ИСПОЛЬЗОВАНИИ ARDUINO IDE!, @Avong
Неважно, какую IDE вы используете для написания кода, код один и тот же. Проблема в том, что последовательные данные не приходят сразу. Вы получаете один символ и читаете его, а затем, прежде чем появится следующий символ, доступный снова равен 0, и вы уходите, чтобы сравнить свой один прочитанный символ. Пока вы это делаете, приходит остальная часть строки. Когда вы вернетесь, у вас будет вся струна. С задержкой вы даете строке время для завершения прибытия по одному письму на порт., @Delta_G
Нет необходимости иметь задержку, если вы пишете правильный код для обработки последовательных данных. Пусть он ищет конечный маркер, прежде чем он сделает сравнение. Или подождите, пока available вернет полную длину строки, прежде чем вы начнете ее читать., @Delta_G
Уважаемый Delta_G Хорошо, я принимаю к сведению все предложения. Ваше здоровье!, @Avong
@Delta_G: «Неважно, какую IDE вы используете для написания кода» — но может иметь значение, если вы используете встроенный эмулятор терминала., @JRobert