Если тебе удалось обмануть человека, то это не значит, что он дурак. Это лишь значит, что тебе доверяли больше, чем ты того заслуживаешь.

Меню навигации для мобильных

Непонятная работа Arduino Nano с COM в Linux

Автор Shaman, 12 Июнь, 2023, 17:12

« предыдущая - следующая »

Shaman

Имеем 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 и разных ПК.

Кто-нибудь имеет представление, чем обусловлено такое поведение?

Под спойлером видео представление правильной и не правильной работы, для лучшего понимания. Оно короткое, посмотрите пожалуйста
Видео работы
[свернуть]

Slabovik

Смотрел только порт приёма. А порт отправки не смотрел?
Общением на форуме подпитываю свою эгоистичную, склонную к самолюбованию сущность.

Shaman

Либо я чего-то не понимаю либо вы

Я подключился вот сюда
electrical_shema_arduino_nano.png

На скрине RX желтая TX синяя  (подписаны)

При прошивке пакеты по ним видно, при работе устройство ничего не отправляет да и не должно.

Или вы про что-то другое?

Slabovik

#3
Я про то, что если используемые библиотеки ничего не отсылают, они ничего и не должны ждать. А если отсылают - затык может быть на стороне приёма (сигналы управления портом).

Из описания я понял, что при приёме байта из одной программы ардуина что-то делает, а при приёме точно такого же (вплоть до бита) из другой программы, не делает. По факту это мистика и нужно выявлять побочный неявный функционал.

зы: а ты уверен, что любой терминал точно всегда добавляет 0Ah после? Не в этом ли собака порылась? Потому что Echo точно довабляет конец строки/перевод, а вот терминал... ? Не зависает ли ардуиновский алгоритм по приходу этого 0Ah вследствие "неожиданного" прихода при отсутствии обработки этого прихода (не прописано прерывание и т.п.), а в это время у тебя там Delay Delay?
Общением на форуме подпитываю свою эгоистичную, склонную к самолюбованию сущность.

Shaman

Думаю что не в этом дело. 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);
      }
}
}

Но в таком виде он почему-то не обрабатывает прерывания хотя отправка идёт отлично.

Slabovik

терминал по-дефолту открывает порт и на чтение и на запись.
Цикл так-то закрыть надо, он не оформлен (заначка есть, но что-то пошло не так). По окончании прохода прога вываливается в никуда.
Переменным RX_xxx надо бы свойство Volatile сделать, чтобы явно указать, что компилятору их оптимизировать не надо.
Общением на форуме подпитываю свою эгоистичную, склонную к самолюбованию сущность.