Передача через COM-порт.

vs2007
Offline
Зарегистрирован: 07.07.2013

Всем привет! Проблема такая. Плата Mega 2560. Через Serial1 (115200 бод) поступают данные от устройства A, обрабатываются и передаются через Serial2 (28800 бод) в устройство B через Serial2.write(). Вовремя принять данные из буфера позволяет функция Serial1.available(). Передать данные, так же асинхронно пополнив буфер передачи, средствами языка разработки нельзя, т. к. отсутствует функция проверки опустошения буфера передачи (аналогичная .available()). Применение delay() для создания задержек на передачу съест кучу времени у функций обработки. Уважаемые господа, может подскажете, как проверить буфер передачи на опустошение средствами скетч-языка? 

Snubist
Offline
Зарегистрирован: 18.02.2013

 

vs2007 пишет:

 т. к. отсутствует функция проверки опустошения буфера передачи (аналогичная .available()). 

http://arduino.ru/Reference/Serial/Flush

vs2007
Offline
Зарегистрирован: 07.07.2013

Но там написано:

Serial.flush() ОЖИДАЕТ окончания передачи исходящих данных, т. е. на время ожидания все тормозит?

Snubist
Offline
Зарегистрирован: 18.02.2013

Да, но ведь пока она выполняется,буфер первого сериала будет заполнятся  принятыми данными. так что просто делаешь последовательность, считал, преобразовал, передал. 

Синхронно все делать все равно не получится из за разности скоростей.

vs2007
Offline
Зарегистрирован: 07.07.2013

Программно обработка осуществляется 8-ю связанными конечными автоматами, и один из них выполняет выравнивание потоков данных на входе и выходе, так что, к сожалению, в данном случае поможет не внесение дополнительной задержки, а проверка свободного места в буфере передачи. 

Snubist
Offline
Зарегистрирован: 18.02.2013

 

Ну тогда, разбирай библиотеку serial на составные части. 

как я понял в функции 

void HardwareSerial::flush()
{

  while (transmitting && ! (*_ucsra & _BV(TXC0)));
  transmitting = false;
}

именно регистр TXC0 отвечает за наличие данных в буфере

vs2007
Offline
Зарегистрирован: 07.07.2013

Вообще-то мысль неплохая! А где эта библиотека Serial находится, если не секрет?Попробую дописать в Serial функцию что-то вроде   int txbuffer_is_empty().

maksim
Offline
Зарегистрирован: 12.02.2012

\arduino-1.0\hardware\arduino\cores\arduino\ HardwareSerial.cpp и HardwareSerial.h

Так же некоторые методы наследуются от Stream.

vs2007
Offline
Зарегистрирован: 07.07.2013

Спасибо, буду разбираться & дописывать.

vs2007
Offline
Зарегистрирован: 07.07.2013

P. S.

Так оно и оказалось. Добавил в библиотеку HardwareSerial (файл HardwareSerial.cpp)

функцию bool txempty(void), с Serial.write() вроде работает:



bool HardwareSerial::txempty(void){
	return (!transmitting || (*_ucsra & _BV(TXC0)));
}

здесь надо обязательно использовать флаг transmitting. И в заголовочном файле HardwareSerial.h в объявлении класса, в разделе public соответственно добавить функцию



virtual bool txempty(void);

Теперь можно вызывать из скетча проверку буфера



if(Serial.txempty){
   Serial.write(...);
   ...
}else{
   ...
}

и по ходу дела добавлять данные на передачу. 

Jacks_d
Offline
Зарегистрирован: 31.12.2011

Не используйте Serial.flush() она не всегда нормально работает, точнее не всегда работает, я сам попал на этот глюк, но добрые люди подсказали

if(Serial.available() > 37) // если с СОМ пришло больше 37 символов стираем буфер
   {while(Serial.available()) Serial.read(); }
 if(Serial.available() == 37)// если буфер СОМ = 37 то пишем в массив
   {for(int i=0; i < 37; i++) 
       {inserial[i] = Serial.read() - 48;} 
    while(Serial.available()) Serial.read();//подчищаем все после прочтение(читаем в никуда, тем самым освобождаем буфер)
    }

без такого сброса рано или поздно начнут приходить левые данные

maksim
Offline
Зарегистрирован: 12.02.2012

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

Jacks_d
Offline
Зарегистрирован: 31.12.2011

Хм... таки да, до версии 1.0 она стирала буфер, но как тогда ею пользоваться и в каких случаях? а точнее какой тогда смысл? Всеравно в большенстве случаев данные передаются блоками и читаем с буфера блоками(побатово). Я чисто для самообразования интерисуюсь, т.к. програмер только на уровне библиотек

Кстати ТС мог бы и написать как именно передаются данные, возможно упростило бы понимание что именно нужно сделать, я в своем проекте передаю необходимые данные в 37ми символах, в 10й системе, первые четыре цифры - адрес и комада, остальное данные этой команды. 

А ТС можно порыться в либе от GPS там думаю ему будит много полезного, ИМХО конечно

maksim
Offline
Зарегистрирован: 12.02.2012

Пользоваться как раз в таких случаях как у ТС, то есть когда нужно дождаться окончания передачи данных.

Jacks_d
Offline
Зарегистрирован: 31.12.2011

Да но если как у ТС и входящие данные идут неприрывно, то все рано или поздно упрется в буфер, как по мне то лучше в его случае ждать заполнения буфера например 10 байтами, сразу читать далее отправлять, а пока отправляются на меньшей скорости то буфер заполнится еще каким то количевством данны, и мы не будим ждать пока закончится передача кажется так лучше, т.е. как то так:

if(Serial.available() == 10)
   {for(int i=0; i < 10; i++) 
       {inserial[i] = Serial.read();}
for(int i=0; i < 10; i++) 
   {Serial2.write(inserial[i]);}

Или я не правельно понимаю как работает буфер? 

допустим данные идут неприрывно, мы считали первые 10 байт, и после это например данные из ечейчи 11 и 12 которые заполнились во время чтения переносятся в ячейку памяти 1 и 2 соответственно, тоесть сжвиг данных получается по адресу.

Или происходит по другому?

Jacks_d
Offline
Зарегистрирован: 31.12.2011

А как тогда собирать принятые данные? писать то будим в масив? но как узнать количевство принятых данных? т.к. если например в стринг собирать чтобы проще было то стринг забъется в конце нулями в зависимости от длинны массива, или как то по другому можне?тогда получается

int i = 0;
byte inserial[];
void setup()  
{Serial.begin(115200);
 Serial2.begin(28800);
}
void loop() 
{
 Serial.flush()
 while(Serial.available()){inserial[i] = Serial.read(); i++;}
 for(int b=0; b< i+1; b++)
     {Serial2.write(inserial[b]);
      if(b==i){ i = 0;}      
      }

}

Наверно как то так тогда получается и нужно учесть что буфер максимум 128 байт http://arduino.ru/Reference/Serial/Available

vs2007
Offline
Зарегистрирован: 07.07.2013

Всем привет! Только что вернулся из командировки, где успешно установил свое устройство на Mega 2560 (раньше Arduino не пользовался, программировал контроллеры на C и ASM). 

Вкратце сутью проекта было построение конвертора протоколов из разновидности modbus (115200 бод, с байтами-разделителями, адресами, кодами операций, данными, пустыми байтами и CRC8, переменная длина кадра) в специфический протокол ввода в PC (28800 бод). Цель - подключить внешнее устройство к Soft-у на PC, изначально для работы с этим устройством не предназначенному (т. е. эмулировать одно устройство с помощью другого, аналогичного по функциям).

Прием. Из вариантов: 1)прием по прерываниям, 2)прием в бесконечном цикле в отдельном потоке, 3)прием в общем бесконечном цикле, для Arduino подошел последний вариант №3 в цикле loop{}. Для большей равномерности и исключения всяческих зависаний оптимален ПОБАЙТОВЫЙ прием и обработка со СРЕДНЕЙ скоростью 115200 бод, и честно говоря, большой необходимости в программном буфере я здесь не наблюдаю.  Передача. Здесь, наоборот, оказалось удобнее формировать и класть в программный буфер передачи с помощью Serial.write() порции байтов (в моем случае по 24 байта), проверяя его на пустоту по Serial.txempty() (POST #9) опять же в общем бесконечном цикле.

Проверенный надежный способ реализации нескольких задач в бесконечном цикле - представление их в виде конечных автоматов (КА) по известной switch-технологии (управление состоянием КА по switch-case). Единственное ограничение - функции КА не должны вносить больших задержек, чтобы обеспечивать СРЕДНИЕ скорости приема и передачи.

 

toc
Offline
Зарегистрирован: 09.02.2013

vs2007,

вероятно, возможно развитие ...

1. узнать размер буфера отправки

2. в цикле: если программе есть что отправить и если в буфере отправки есть N свободных байт, вызвать Serial.write ...

vs2007
Offline
Зарегистрирован: 07.07.2013

Да, конечно. Кстати, полный размер программного буфера отправки 64 байта, но его можно изменить в библиотеке.