Что делает надежную схему последовательной связи RS232 на встроенном устройстве? - PullRequest
3 голосов
/ 28 января 2011

Итак, у меня начинает возникать повторяющаяся проблема с написанием схем последовательной связи, и, похоже, это связано с синхронизацией.Моя встроенная платформа - это Rabbit Semiconductor BL2600, и в данном случае она разговаривает с устройством на RS232.Он отправляет команду устройству, и устройство отправляет ответ обратно на BL2600, который затем обрабатывается.

Однако моя проблема заключается в том, что когда я отправляю команду, а затем жду ответаЯ не понимаю.Однако, если я устанавливаю точку останова в правильных местах и ​​выполняю один шаг по коду, я часто получаю ответ.Я поместил свой компьютер между BL2600 и устройством для прослушивания потока RS232 (после обнаружения первоначальной проблемы), и ответ отправляется независимо от того, была ли у меня точка останова или нет, но BL2600 видит его только в своих буферахесли я остановлюсь перед тем, как проанализировать код и попытаться найти его стартовый бит.Если я остановлюсь, когда будет просто читать всю строку потом, он не найдет ее.

Так что, звучит так, будто я не жду достаточно, так что теперь, чтобы быть смешным, я установилтайм-ауты для проверки буфера до 1 секунды (и с скоростью передачи данных 38400 бод, это лучше показывать в этом окне), и все же я ВСЕ ЕЩЕ ничего не получу, если не буду использовать точку останова и одношаговый.значительная часть моего кода:

    //clear the buffers
 serCwrFlush();
 while(serCwrUsed())
 {
  ;
 }
 startwait = MS_TIMER;
 while((serCrdUsed() > 1) && (device_timeout_check < 1000))
 {
  if (MS_TIMER < startwait)
  {                                    // fix the rollover
   device_timeout_check = MS_TIMER + (ULONG_MAX - startwait);  
  }

  else
  {                                   //set it like normal
   device_timeout_check = MS_TIMER - startwait;     
  }

  serCrdFlush();
 }
 serCputs("mpcal=d\r");     //This is what requests the response from the device
 while(serCwrUsed())
 {
  ;
 }
 startwait = MS_TIMER;
 while((serCrdUsed() < 11) && (device_timeout_check < 1000))
 {
  if (MS_TIMER < startwait)
  {                        // fix the rollover
   device_timeout_check = MS_TIMER + (ULONG_MAX - startwait);  
  }
  else
  {                       //set it like normal
   device_timeout_check = MS_TIMER - startwait;     
  }
 }
 //grab it
 temp=serCpeek();
 i=0;
        //It expects a response like "H0V0M00.0 /r"
        //So I am looking for the first character.
 while((temp != 'H' ) && (i<100))
 {
  serCgetc();     //breakpoint works here
  temp=serCpeek();
  i++;
 }
 c=serCread(comp_cal_string,20, 20);   //breakpoint doesn't work here

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

Ответы [ 3 ]

3 голосов
/ 28 января 2011

Существует ли причина, по которой вы не используете связь RS-232, управляемую прерываниями?Обычно случается, что прерывание запускается при переходе грани от схемы RS-232, и вы устанавливаете подпрограмму обработки прерывания (ISR) для ее обработки - таким образом, вы ВСЕГДА получаете возможность обрабатывать информацию, потому что прерывание является аппаратнымуправляемое общество.Импульс от схемы RS-232 может быть достаточно коротким, чтобы ваша петля опроса (см. Выше) просто его не видела.

Если ваш BL2600 - это то же устройство, что и здесь:

http://ftp1.digi.com/support/documentation/019-0113_N.pdf

В этом руководстве перечислены векторы прерываний для всех четырех последовательных портов на устройстве - см. SetVectIntern на стр. 476.

Кроме того, старые схемы RS-232 поддерживали только внутренние буферы16 байтов.Если вы хотите увеличить скорость передачи, вам, возможно, придется использовать функции DMA, которые присутствуют на BL2600.(Функции DMA должны автоматизировать передачу больших блоков данных из памяти в последовательный порт и наоборот.)

2 голосов
/ 29 января 2011

Ключом к надежности является обработка ошибок.

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

Циклы тайм-аута разбиваются тремя способами, которые могут повлиять на ваше чтение:

  • Значение device_timeout_check проверяется перед егозначение устанавливается внутри цикла.
  • MS_TIMER является изменчивым и может изменяться между временем, когда оно проверяется и используется для вычисления device_timeout_check.
  • Ничего не делается, когда происходит тайм-аут.

Чтобы исправить эти проблемы, сначала измените объявление startwait, чтобы избежать проблем с опрокидыванием: unsigned long startwait;.Затем реализуйте циклы времени ожидания следующим образом:

startwait = MS_TIMER;
do {
  device_timeout_check = (MS_TIMER - startwait >= 1000);
} while((serCrdUsed() > 1) && !device_timeout_check);

if (device_timeout_check) {
   /* Handle the timeout error here */
}

Это решит проблему, если device_timeout_check больше 999, когда ваш код достигнут.

Существует еще одна проблема с циклом, пытающимся обнаружить первый символ 'H'.Код до него гарантирует только 11 доступных символов.Цикл обнаружения выполняется 100 раз, но не дает дополнительного времени для получения символов.Если в буфере уже есть 11 или более символов, отличных от 'H', они будут использованы немедленно и будут ожидать 'H'.

Было бы лучше дождаться 'H'сначала, а затем ждать одиннадцать символов.Это решит проблему, если желаемому вводу предшествует нежелательный ввод.

0 голосов
/ 30 января 2011

Я думаю, что Динго имеет правильный ответ со своим первым открытием.device_timeout_check не инициализируется, по крайней мере, в коде, представленном здесь.Если он не инициализирован, то это просто мусор, оставленный в стеке вызовов, поэтому он может легко превысить 1000. В этом случае циклы while немедленно падают молча (tsk tsk), и цикл while, ожидающий 'H', будетбыстро пройти через 100 итераций, ничего не вытаскивая (скорее всего) из последовательного порта.

Кстати, почему 100?После того, как вы очистите буфер, эти дополнительные чтения, скорее всего, будут происходить так быстро, что они не найдут ничего нового.

Это также прекрасно объясняет поведение отладчика.Ваши циклы задержки никогда не задерживали ничего, и когда вы устанавливали точку останова в serCgetc (), вы позволяли последовательному порту догонять программу.

Простой способ проверить, действительно ли этоДело в том, чтобы настроить какое-то внешнее уведомление, прежде чем пытаться прочитать данные с последовательного порта.Либо мигайте светодиодом, либо отправьте пакет «сообщение получено» через последовательный порт.Затем с дешевой O-областью вы должны легко увидеть, как пакет «сообщение получено» (или светодиод мигает) перед приемом данных.

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

STATUS myCpeek( unsigned char *data)
{
  if ( 0 == serCrdUsed() )
    return ERROR_NO_DATA;
  *data = serCpeek();
  if ( serCParityError() )  //Just guessing at a function name here
  {
    return ERROR_PARITY_BAD;
  }
  return OK;
}

или что-то подобное.

...