Имеем Arduini Nano со скетчем:
int val;
void setup() {
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
int8_t i;
if (Serial.available()) {
val = Serial.read();
if (val == '1') {
for (i=0; i<5 ; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
}
}
Это упрощенная, для дебага, версия скетча эмулирующего пульт ДУ, просто вместо отправки пакетов на ИК светодиод он моргает встроенным. В исходном виде код работает аналогично, пульт эмулируется.
Если для отправки команд использовать программы
picocom,
minicom,
монитор порта ардуино и любые другие терминалы всё работает. Но если просто плюнуть в порт командой:
echo "1" > /dev/ttyUSB0
Ничего не произойдет. Ардуинка его получает, начинает исполнять, но исполнение срывается. Команда начинает работать только в том случае если открыть на блокирующее чтение фал COM-порта ардуинки, любой командой способной это делать
cat,
grep и т.д.
cat > /dev/ttyUSB0
При этом на осциллограмме всегда одни и те же данные, щупы подключены непосредственно к выводам UART.
RigolDS14.png
Первый байт - это 49 , ascii код символа "1" в десятичной системе. Второй - это 10, код символа LF (line feed), он подставляется автоматически.
Т.е. данные до процессора доходят всегда и всегда одинаковые, каких то изменений мне отловить не удалось. Но в одном случае код срабатывает, а в другом срывается. С повторяемостью 100% на 2-х разных платках Nano и разных ПК.
Кто-нибудь имеет представление, чем обусловлено такое поведение?
Под спойлером видео представление правильной и не правильной работы, для лучшего понимания. Оно короткое, посмотрите пожалуйста
Видео работы
Смотрел только порт приёма. А порт отправки не смотрел?
Либо я чего-то не понимаю либо вы
Я подключился вот сюда
electrical_shema_arduino_nano.png
На скрине RX желтая TX синяя (подписаны)
При прошивке пакеты по ним видно, при работе устройство ничего не отправляет да и не должно.
Или вы про что-то другое?
Я про то, что если используемые библиотеки ничего не отсылают, они ничего и не должны ждать. А если отсылают - затык может быть на стороне приёма (сигналы управления портом).
Из описания я понял, что при приёме байта из одной программы ардуина что-то делает, а при приёме точно такого же (вплоть до бита) из другой программы, не делает. По факту это мистика и нужно выявлять побочный неявный функционал.
зы: а ты уверен, что любой терминал точно всегда добавляет 0Ah после? Не в этом ли собака порылась? Потому что Echo точно довабляет конец строки/перевод, а вот терминал... ? Не зависает ли ардуиновский алгоритм по приходу этого 0Ah вследствие "неожиданного" прихода при отсутствии обработки этого прихода (не прописано прерывание и т.п.), а в это время у тебя там Delay Delay?
Думаю что не в этом дело. 0Ah не влияет на работу поскольку команда Serial.read(); читает только первый приходящий байт, и что там на конце ей фиолетово. Пробовал через монитор порта изменять конец строки всё работает одинаково правильно.
Да и у echo есть параметр не вносить 0Ah
echo -n "1" > /dev/ttyUSB0
А осциллограмма вот так
RigolDS15.png
С командой echo начинает работать только тогда когда файл /dev/ttyUSB0 открыт на бесконечное считывание какой-нибудь программой.
И да одиночное моргание светодиодом L скорее всего означает перезагрузку атмеги (по крайней мере при перезагрузке она так же моргает). Но почему это происходит при приёме команды.
Я пробовал подключать логический анализатор, но ни при открытом на чтение файле /dev/ttyUSB0, ни при использовании терминала, ни просnо при отправке echo каких-то еще данных кроме вышеуказанных не передаётся.
Мне не обоснованно кажется, что проблема может крыться в настройке COM порта, но я пока не могу разобраться как работает команда stty
У COM порта вон ажно сколько параметров
stty -F /dev/ttyUSB0 -a
speed 9600 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 hupcl -cstopb cread clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
-iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
echoctl echoke -flusho -extproc
Всё что я научился ей делать это менять скорости.
Ради интереса пробовал в тупую заинитить UART в ардуине кодом на СИ
#include <IRremote.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#define FOSC 16000000
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD-1
IRsend irsend;
int val;
uint8_t rx_buf;
uint8_t rx_end = 0;
uint8_t temp = 0b00110001;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
//Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
}
void USART_Init( unsigned int ubrr)
{
/*установка битрейта */
UBRR0H = (unsigned char)(ubrr >> 8);
UBRR0L = (unsigned char)ubrr;
UCSR0A = 0; //Режим двойной скорости выключен:
UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0); // Установка параметров: включение портов ввода и вывода, разрешение прерывание по окончанию приёма
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); // Установка формата фрейма: 8data, 1stop bit
}
// the loop function runs over and over again forever
ISR (USART_RX_vect)
{
rx_buf = UDR0;
rx_end = 1;
}
void loop() {
USART_Init(MYUBRR);
sei(); //разрешаем глобальные прерывания
int8_t i;
/*while(!(UCSR0A&(1<<UDRE0)));
UDR0 = temp;*/
if (rx_end == 1) {
val = rx_buf; // переменная val равна полученной команде
rx_end = 0;
if (val == 49) {
for (i = 0; i < 5 ; i++) {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(500); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(500);
}
}
}
Но в таком виде он почему-то не обрабатывает прерывания хотя отправка идёт отлично.
терминал по-дефолту открывает порт и на чтение и на запись.
Цикл так-то закрыть надо, он не оформлен (заначка есть, но что-то пошло не так). По окончании прохода прога вываливается в никуда.
Переменным RX_xxx надо бы свойство Volatile сделать, чтобы явно указать, что компилятору их оптимизировать не надо.