реклама на сайте
подробности

 
 
> scmRTOS+485-й, Как правильно пользоваться каналом?
Colobox
сообщение Feb 4 2008, 09:18
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 36
Регистрация: 31-10-07
Пользователь №: 31 901



Доброго времени суток!
Простенькая вроде прога и все хорошо и логично, и работает… но только 40 сек.
Программка общения МК с терминалкой. Терминалка посылает каждые 50 мс команду опроса длиной 4 байта плюс кс- 3f 0 0 0 3f, в ответ МК кидает также 4 байта плюс кс: 47 0 0 0 47, но это детали. Проц АТмега 8, 12МГц, сист. тик- 6 мс
Проблема в том, что примерно через 40 сек, видимо, не проходит сброс счетчика принятых байт и контрольной суммы. Перерывания по- уарту (прием байта) вызываются.
Подскажите, где тут может быть баг или неправильное понимание?
Код
#define scmRTOS_ISRW_TYPE   TISRW_SS
……………………………………………………
#define  scmRTOS_CONTEXT_SWITCH_SCHEME      0
……………………………………………………
OS::channel<unsigned char,10> chn_Rx;//канал на 10 байт
……………………………………………………
//-------------------------------------------------------------------------
#pragma vector = USART_RXC_vect
OS_INTERRUPT void RX(void)
{
OS::scmRTOS_ISRW_TYPE ISR;
UART_Rx();
}
//-------------------------------------------------------------------------
void UART_Rx(void)  
{
unsigned char udrx=UDR;//принимаем байт
if(chn_Rx.get_free_size()) chn_Rx.push(udrx);// запихиваем принятый байт в канал
}
//---------------------------------------------------------------------------
…………………………………………………………………………
OS_PROCESS void TPRx::Exec()
{
  unsigned char count_rx_byte=0;// счетчик принятых байт
  unsigned char RxBuffer[LEN_RX];//приемный буфер
  unsigned char rx_crc=0;// контрольная сумма
    for(;;)
    {
    unsigned char rx=0;
     if (chn_Rx.pop(rx,2))//вытаскиваем из очереди очередной байт
         {
          RxBuffer[count_rx_byte]=rx;//в буфер его
          //вычисляем  КС:
          if(count_rx_byte<LEN_RX-1)  rx_crc=rx_crc^RxBuffer[count_rx_byte];
              else  //если подошел последний байт пакета и КС совпала:
                   if((count_rx_byte==LEN_RX-1)&&(RxBuffer[count_rx_byte]==rx_crc))
                                  Answer();//функция загрузки в ответ  первого байта передачи в UDR
// дальнейшие загрузки байтов- по прерыванию от UART (передача)
          count_rx_byte++;//на следующий байт
          }  else  //если через 2 тика сист. таймера (12 мс) ничего не пришло- сбрасываем параметры приема:
          {
           count_rx_byte=0;//сюда через сек 40 уже не приходим...
           rx_crc=0;
          };
     }//end_of_for(;;)
} end_of_ OS_PROCESS
//---------------------------------------------------------------------------
…………………………………………………………………


Еще по-теме,- в одной из веток по scmRTOS:
Цитата(Сергей Борщ @ Oct 1 2007, 17:53) *
Ну например прерывание передачи по UART забирает данные из OS:channel<uint8_t>. А данные там кончились... В этом случае pop() попытается передать управление другой задаче, и это приведет к краху. Поэтому прежде чем вызвать pop() надо проверить - а есть ли данные. Аналогично для push().


Почему должен быть крах? Вроде так и надо- нет работы- уйди… А в случае вызова рор() или push() из обработчика прерывания ,- перепланировщик там же не имеет действия!
Хотя, если из void UART_Rx(void) исключить "if(chn_Rx.get_free_size()) "- проц виснет савсем.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
Сергей Борщ
сообщение Feb 4 2008, 13:02
Сообщение #2


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



или я не до конца понял ваш алгоритм, или в
Код
if((count_rx_byte==LEN_RX-1)&&(RxBuffer[count_rx_byte]==rx_crc))
      Answer();
count_rx_byte++;//на следующий байт
если контрольная сумма не совпала, то вы будете продолжать складывать следующие байты в RxBuffer[count_rx_byte]=rx; и выйдете за пределы буфера.

Почему не попадаете в точку выхода по тайм-ауту действительно непонятно. А системный таймер тикает, его прерывания происходят? Поставьте дерганье ногой в OS::SystemTimerUserHook(), убедитесь, что прерывания работают.

Цитата(Colobox @ Feb 4 2008, 11:18) *
Почему должен быть крах? Вроде так и надо- нет работы- уйди… А в случае вызова рор() или push() из обработчика прерывания ,- перепланировщик там же не имеет действия!
если нет работы (очередь пуста или переполнена) pop() или push() вызовет перепланировку и перевод текущего процесса в ожидание. Но ведь во-первых невозможно предугадать, какой из процессов будет текущим на момент вызова прерывания. И может он спать совсем не хочет smile.gif А во-вторых, вызов планировщика и процедура смены контекста вернет программу в один из потоков, но не в окончание обработчика прерывания. В результате выход из прерывания никогда не произойдет, прерывания обстанутся заблокированными, а на стеке прерванного процесса - каша из регистров, сохраненных обработчиком и переключателем контекста. Примерно так.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Colobox
сообщение Feb 5 2008, 06:47
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 36
Регистрация: 31-10-07
Пользователь №: 31 901



Цитата(Сергей Борщ @ Feb 4 2008, 16:02) *
если контрольная сумма не совпала, то вы будете продолжать складывать следующие байты в RxBuffer[count_rx_byte]=rx; и выйдете за пределы буфера.

Абсолютно правильное замечание; исправил, но порочный эффект не исчез.
Цитата(Сергей Борщ @ Feb 4 2008, 16:02) *
Почему не попадаете в точку выхода по тайм-ауту действительно непонятно. А системный таймер тикает, его прерывания происходят? Поставьте дерганье ногой в OS::SystemTimerUserHook(), убедитесь, что прерывания работают.

В системе крутится еще один процесс-просто лампочкой мигает, прерывание также сигнализирует о себе; после сбоя связи с ними ничего не происходит- как мигали, так и мигают. Так-что системный таймер тикает.
Цитата(Сергей Борщ @ Feb 4 2008, 16:02) *
если нет работы (очередь пуста или переполнена) pop() или push() вызовет перепланировку и перевод текущего процесса в ожидание. Но ведь во-первых невозможно предугадать, какой из процессов будет текущим на момент вызова прерывания. И может он спать совсем не хочет smile.gif

Серьезный эффект, согласен. Но тогда, может, стоит предусмотреть в этом сервисе, перед переводом текущего процесса в ожидание, некую проверку, скажем, ISR_Nest_Count,- если отлична от нуля, перевод не производить. По-крайней мере, в мануале на ось это стоит оговорить!
Цитата(Сергей Борщ @ Feb 4 2008, 16:02) *
А во-вторых, вызов планировщика и процедура смены контекста вернет программу в один из потоков, но не в окончание обработчика прерывания. В результате выход из прерывания никогда не произойдет, прерывания обстанутся заблокированными, а на стеке прерванного процесса - каша из регистров, сохраненных обработчиком и переключателем контекста. Примерно так.

А разве из обработчика прерывания можно вызвать планировщик и менять контексты? Точнее, будет ли вызов планировщика иметь эффект:
Код
if scmRTOS_CONTEXT_SWITCH_SCHEME == 0
void OS::TKernel::Scheduler()
{
TCritSect cs;
if(ISR_NestCount) return;//в прерывании  ISR_NestCount>0
..........................................
..........................................
..........................................

А уже после отработки прерывания, перед выходом в программу (ISR_NestCount==0), и произойдет вызов планировщика, возымеющий эффект…
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 31st July 2025 - 01:38
Рейтинг@Mail.ru


Страница сгенерированна за 0.01377 секунд с 7
ELECTRONIX ©2004-2016