Проблемы прерывания USART_RX_vect в Atmel Studio 6

Обсуждаем контроллеры компании Atmel.
m.zdorenko
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Вс май 03, 2015 14:18:46

Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение m.zdorenko »

Доброго времени суток.
Помогите понять в чем проблема, гугл не помог, может не там копал. Ситуация следующая:
Есть код.
Описание кода в краце:
Микроконтроллер настроен и работает на частоте 8МГц. Инициализируем 10 переменных ch_1_1...ch_2_5, инициализируем переменную буфера передачи данных макс 6 байт (1 байт команды и 5 байт параметров), инициализируем UART (9600, 8 бит 2 стоп бита), разрешаем прерывания по RX.
Сидим ждем прихода пакета. Пакет должен начинаться с < и заканчиваться >(эти символы не учитываются в пакете), кол-во данных в пакете не должно превышать максимального размера буфера, а так же первый байт пакета должен быть 1 или 2, в противном случае данные по UART игнорируются. При входе подходящего нам пакета, например
<123456>, принимаем его, загоняем в буффер значения ={1,2,3,4,5,6}. Так как первый байт буфера 1, то остальные байты буфера присваиваем переменным ch_1_1...ch_1_5, После этого значения переменных передаем обратно по UART, в той же последовательности, добавив первым байт команды. То есть должны получить пакет <123456>. В данном случае так и происходит. В спойлере код и скрин из монитора UART, отправленая и принятая команда.
Спойлер

Код: Выделить всё

#define F_CPU 8000000L
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

char  ch_1_1 = 255;
char  ch_1_2 = 0;
char  ch_1_3 = 0;
char  ch_1_4 = 10;
char  ch_1_5 = 10;

char  ch_2_1 = 0;
char  ch_2_2 = 255;
char  ch_2_3 = 0;
char  ch_2_4 = 10;
char  ch_2_5 = 10;

#define USART_bufferCountMax 6      /*Максимальное значение буфера для обмена по USART*/


int main(void)
{
    initialization(); 
  
    while(1)
    {
    }
}

void initialization() /*инициализация программы*/
{
  USART_Init( 51 );
  sei();
}

void USART_Init( unsigned int baud ) /*Инициализация UART*/ 
{
  UBRRH = (unsigned char)(baud>>8);  /* Set baud rate */
  UBRRL = (unsigned char)baud;
  UCSRA &= ~( 1<<U2X); // неудвоенная передача, нам спешить некуда
  UCSRC = (1<<USBS)|(3<<UCSZ0);  // Режим 8 бит, 2 стоповыx бита
  UCSRB |= (1<<RXEN)|(1<<TXEN);
  UCSRB |= (1 << RXCIE);
}

char  USART_buffer[] = {0};       /*Буффер обмана данными по UART*/
char  USART_buffer_count = 0;     /*Кол-во данных записаных в буфер в текущей передаче*/
char  USART_startReceiveData = 0; /*Флаг сигнализирующий о передаче*/

ISR(USART_RX_vect)
{
  char bit = UDR;

  if (USART_startReceiveData == 1)
  {
    if (bit == '>')
    {
      USART_startReceiveData = 0;
 
      if (USART_buffer[0] == '1')
      {
        ch_1_1 = USART_buffer[1];
        ch_1_2 = USART_buffer[2];
        ch_1_3 = USART_buffer[3];
        ch_1_4 = USART_buffer[4];
        ch_1_5 = USART_buffer[5];
      
        USART_Transmit('<');
        USART_Transmit('1');
        USART_Transmit(ch_1_1);
        USART_Transmit(ch_1_2);
        USART_Transmit(ch_1_3);
        USART_Transmit(ch_1_4);
        USART_Transmit(ch_1_5);
        USART_Transmit('>');        
      }        
      
      if (USART_buffer[0] == '2')
      {
        //ch_2_1 = USART_buffer[1];
        ch_2_2 = USART_buffer[2];
        //ch_2_3 = USART_buffer[3];
        ch_2_4 = USART_buffer[4];
        //ch_2_5 = USART_buffer[5];
        
        USART_Transmit('<');
        USART_Transmit('2');
        //USART_Transmit(ch_2_1);
        USART_Transmit(ch_2_2);
        //USART_Transmit(ch_2_3);
        USART_Transmit(ch_2_4);
        //USART_Transmit(ch_2_5);
        USART_Transmit('>');
      }
    }
    else 
    {
      if (USART_buffer_count != USART_bufferCountMax)
        USART_buffer[USART_buffer_count++] = bit;
      else
        return;
    }
  }  
  if (bit == '<')
  {
    USART_startReceiveData = 1;
    USART_buffer_count = 0;
  }  
}

void USART_Transmit( unsigned char data ) /*Передача одного символа по UART*/ 
{
  while ( !( UCSRA & (1<<UDRE)) );
  UDR = data;
}
Изображение
Если смотрели код могли заметить, что там есть закомментированые строки при приеме данных, если байт команды = 2. Раскомментируем одну из них например //ch_2_3 = USART_buffer[3];, код который получился ниже в спойлере. Он отличается на 1 строку. И если мы будем отправлять такой же пакет как и в прошлый раз то увидим, что все идет не так как должно. В моем случае мы отправляем по UATR <123456>, а получаем <123356>??? :shock: :shock:
Это при том, что в данном случае программа обходит if с раскомментированой строкой. Так как команда которую он получил = 1. То есть отработает if (USART_buffer[0] == '1')

Сам код и скрин:
Спойлер

Код: Выделить всё

#define F_CPU 8000000L
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

char  ch_1_1 = 255;
char  ch_1_2 = 0;
char  ch_1_3 = 0;
char  ch_1_4 = 10;
char  ch_1_5 = 10;

char  ch_2_1 = 0;
char  ch_2_2 = 255;
char  ch_2_3 = 0;
char  ch_2_4 = 10;
char  ch_2_5 = 10;

#define USART_bufferCountMax 6      /*Максимальное значение буфера для обмена по USART*/


int main(void)
{
    initialization(); 
  
    while(1)
    {
    }
}

void initialization() /*инициализация программы*/
{
  USART_Init( 51 );
  sei();
}

void USART_Init( unsigned int baud ) /*Инициализация UART*/ 
{
  UBRRH = (unsigned char)(baud>>8);  /* Set baud rate */
  UBRRL = (unsigned char)baud;
  UCSRA &= ~( 1<<U2X); // неудвоенная передача, нам спешить некуда
  UCSRC = (1<<USBS)|(3<<UCSZ0);  // Режим 8 бит, 2 стоповыx бита
  UCSRB |= (1<<RXEN)|(1<<TXEN);
  UCSRB |= (1 << RXCIE);
}

char  USART_buffer[] = {0};       /*Буффер обмана данными по UART*/
char  USART_buffer_count = 0;     /*Кол-во данных записаных в буфер в текущей передаче*/
char  USART_startReceiveData = 0; /*Флаг сигнализирующий о передаче*/

ISR(USART_RX_vect)
{
  char bit = UDR;

  if (USART_startReceiveData == 1)
  {
    if (bit == '>')
    {
      USART_startReceiveData = 0;
 
      if (USART_buffer[0] == '1')
      {
        ch_1_1 = USART_buffer[1];
        ch_1_2 = USART_buffer[2];
        ch_1_3 = USART_buffer[3];
        ch_1_4 = USART_buffer[4];
        ch_1_5 = USART_buffer[5];
      
        USART_Transmit('<');
        USART_Transmit('1');
        USART_Transmit(ch_1_1);
        USART_Transmit(ch_1_2);
        USART_Transmit(ch_1_3);
        USART_Transmit(ch_1_4);
        USART_Transmit(ch_1_5);
        USART_Transmit('>');        
      }        
      
      if (USART_buffer[0] == '2')
      {
        //ch_2_1 = USART_buffer[1];
        ch_2_2 = USART_buffer[2];
        ch_2_3 = USART_buffer[3];
        ch_2_4 = USART_buffer[4];
        //ch_2_5 = USART_buffer[5];
        
        USART_Transmit('<');
        USART_Transmit('2');
        //USART_Transmit(ch_2_1);
        USART_Transmit(ch_2_2);
        //USART_Transmit(ch_2_3);
        USART_Transmit(ch_2_4);
        //USART_Transmit(ch_2_5);
        USART_Transmit('>');
      }
    }
    else 
    {
      if (USART_buffer_count != USART_bufferCountMax)
        USART_buffer[USART_buffer_count++] = bit;
      else
        return;
    }
  }  
  if (bit == '<')
  {
    USART_startReceiveData = 1;
    USART_buffer_count = 0;
  }  
}

void USART_Transmit( unsigned char data ) /*Передача одного символа по UART*/ 
{
  while ( !( UCSRA & (1<<UDRE)) );
  UDR = data;
}
Изображение
Микроконтроллер подключен к питанию 5v через стабилизатор 7805 от блока питания 12v 1.5A, ресет контроллера привязан к питанию через резистор 4.7k Для UART использую переходник Arduino USB to TTL конвертер FTDI FT232RL. По трем проводам GND,RX,TX. В питании контроллера и в том что прием данных идет правильно - уверен. Уже исключил эти факторы. :? Наверно =)
Atmel Studio 6 (Version: 6.2.1563 - Service Pack 2) Устанавливал как есть, по умолчанию так сказать.

Помогите понять в чем причина и как с ней бороться.
Реклама
mas123
Потрогал лапой паяльник
Сообщения: 312
Зарегистрирован: Вс июл 29, 2012 16:25:39

Re: Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение mas123 »

m.zdorenko писал(а): #define USART_bufferCountMax 6 /*Максимальное значение буфера для обмена по USART*/
....
char USART_buffer[] = {0}; /*Буффер обмана данными по UART*/
...
ch_1_1 = USART_buffer[1];
ch_1_2 = USART_buffer[2];
ch_1_3 = USART_buffer[3];
ch_1_4 = USART_buffer[4];
ch_1_5 = USART_buffer[5];
Я таки извиняюсь, но какого размера выделен буфер приема? Я вижу размер буфера в ОДИН байт, и куда там попадают байты со 2 по 6?
Мне сиё правильным видится как: char USART_buffer[USART_bufferCountMax];
Так что комментарий там совершенно правильный, это буфер обмана! :))
Реклама
m.zdorenko
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Вс май 03, 2015 14:18:46

Re: Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение m.zdorenko »

:facepalm: :facepalm: :facepalm: :facepalm: нет слов...
Да, буфер "обмана" :)) , сколько раз просматривал код и не заметил.

:shock: Но тогда каким чудом оно отрабатывает в первом случае?
И ведь правильно выводит любую комбинацию из любых 6 символов обратно, главное что б на первом месте была "1"
mas123
Потрогал лапой паяльник
Сообщения: 312
Зарегистрирован: Вс июл 29, 2012 16:25:39

Re: Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение mas123 »

m.zdorenko писал(а):Но тогда каким чудом оно отрабатывает в первом случае?
Посмотри "атчет" линкера - что и где он в памяти размещает.
Возможно, сразу после "буфера обмана" идут какие-то переменные, которые модифицируются после приема.
Хотя, гадать "почему оно работало именно так" в случае переполнения буфера - бессмысленное занятие.

Кстати, я бы не стал делать передачу ответного пакета из 8 байт прямо внутри обработчика прерываний приема.
И контроль переполнения буфера с дыркой: в кадре если потеряешь символ ">", то следующий кадр гарантировано теряешь.
Реклама
Эиком - электронные компоненты и радиодетали
m.zdorenko
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Вс май 03, 2015 14:18:46

Re: Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение m.zdorenko »

mas123 писал(а):И контроль переполнения буфера с дыркой: в кадре если потеряешь символ ">", то следующий кадр гарантировано теряешь.
Спасибо. Да я это знаю, этот кусок кода я урезал для проверки. В оригинальном у меня:

Код: Выделить всё

...
        USART_RX_startReceiveData = 0; /*Прием пакета окончен*/
        USART_RX_buffer_count = 0; /*Обнуляем счетчик записанных в буфер значений*/
        memset(USART_RX_buffer, 0, USART_RX_bufferCountMax);  /*заполняем буфер нулями*/
        return; /*выходим из процедуры*/
...
В оригинальном у меня 2 буфера, один для приема второй для передачи. Хотя для передачи он мне не нужен, могу и сам собрать, так даже меньше действий будет.

mas123 писал(а):Кстати, я бы не стал делать передачу ответного пакета из 8 байт прямо внутри обработчика прерываний приема.
А вот тут можно поподробней? Не понимаю почему? По моему мнению, мы получили какой-то пакет от другого устройства, обработали его и тут же отправили ответ.
Единственное что, возможно при получении завершающего байта запрещать прерывания по RX, для того, что б не прилетел еще какой-то пакетик пока не отправятся мои данные.
Реклама
mas123
Потрогал лапой паяльник
Сообщения: 312
Зарегистрирован: Вс июл 29, 2012 16:25:39

Re: Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение mas123 »

m.zdorenko писал(а):В оригинальном у меня:
...
memset(USART_RX_buffer, 0, USART_RX_bufferCountMax); /*заполняем буфер нулями*/
return; /*выходим из процедуры*/
А зачем заполнять нулями буфер приема? Он же всё равно заполнится принятыми данными.
Всё равно - протокол помехо неустойчив. Что будет, если потеряем байт ">"? Опять же - теряем этот и следующий кадр.
Ну и ситуация, когда "биты изгибаются" и внутри "<>" приходит совсем не то, что было передано.
m.zdorenko писал(а):Не понимаю почему?
На момент передачи буфера остановлены все основные процессы, теряются все остальные прерывания. Оно тебе точно надо?
К тому же, внутри прерывания(!) делать передачу по UART через поллинг, АКА опрос регистров - это совсем уж забивать гвозди микроскопом.
m.zdorenko писал(а):По моему мнению, мы получили какой-то пакет от другого устройства, обработали его и тут же отправили ответ.
Обработка делается в основном процессе. Передача - через основной процесс, а лучше всего на прерываниях от UART-TX.
m.zdorenko писал(а):что б не прилетел еще какой-то пакетик пока не отправятся мои данные.
Т.е. потеря возможного пакета в момент передачи - это допустимая ситуация?
Реклама
m.zdorenko
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Вс май 03, 2015 14:18:46

Re: Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение m.zdorenko »

mas123 писал(а): А зачем заполнять нулями буфер приема? Он же всё равно заполнится принятыми данными.
Привычка :) Очищать глобальные переменные после использования.
mas123 писал(а): Всё равно - протокол помехо неустойчив. Что будет, если потеряем байт ">"? Опять же - теряем этот и следующий кадр.
Ну и ситуация, когда "биты изгибаются" и внутри "<>" приходит совсем не то, что было передано
"Кадр" - это пакет данных, в поем понимании. Например <123456>, ну а если быть правильным то 0х3C 0х0C 0х00 0х00 0х00 0х0A 0х0A 0х3E .
Да так и есть.
Предыстория:
Увидел в нете решение по замене штатной подсветки панели приборов и печки в автомобиле на белых SMD 5050 светодиодах, с возможностью по кнопке, регулировки яркости с памятью.
Сам же давно искал повод заняться изучением микроконтроллеров. Первый привод был, сделал регулятор оборотов куллера на 18B20 и Attyny45, но там был копипаст примера из библиотеки 1-Wire для CV, так что не считается. А это уже поинтересней, решил усложнить задачу: Подсветка на RGB светодиодах на 2-3 канала, выбор любого цвета из спектра, регулировка яркости в двух режимах ночь/день, управление из вне по UART компьютер/мобильный пульт, UART включается только тогда когда подключается управляющее устройство, сохранение данных при выключении, готовые проекты не смотреть, все с нуля.


К чему это я... :roll: А... :)
При отправке любого пакета приходит или ответ или код ошибки. Мне кажется, что проще на стороне управляющего модуля реализовать повторную передачу данных при ошибке/потере байта/потере пакета/некорректных данных, чем проверять текущий пакет на приемнике. Да и проверить его полностью не возможно. Наверно. Дело вот в чем, первый и последний байт пакета - 0х3C (<) и 0х3E (>) соответственно. Второй байт это код запроса/ответа. Остальные 5 байт могут принимать значения от 0х00 до 0хFF, тут же есть проблема в том что любой из них может принять значение 0х3E, то есть конец пакета. Так же есть запросы состоящие из 3 байт, например 0х3C 0х0B 0х3E - запрос на получение данных 5 переменных 1-го канала. Это нужно на передатчике все отслеживать. Так же на передатчике нужно отслеживать и корректность пакета принятого приемником. Была ситуация когда вместо 0х00 контроллер загонял в буфер 0х80, на переходнике USB=>UART норм, выключил питание убрал все лишнее с макетки, а так же землю и питания с Uart переходника отключил - вроде норм. Как по другому - даже не представляю сейчас. :(
mas123 писал(а): На момент передачи буфера остановлены все основные процессы, теряются все остальные прерывания. Оно тебе точно надо?
К тому же, внутри прерывания(!) делать передачу по UART через поллинг, АКА опрос регистров - это совсем уж забивать гвозди микроскопом.
Обработка делается в основном процессе. Передача - через основной процесс, а лучше всего на прерываниях от UART-TX.
Это конечно минус, если учесть что RGB светодиоды будут работать на программном ШИМ через прерывание таймера по переполнению. Но так как прием/передача по UART будет осуществляться редко, думал допустимо. Однако, я же изучать сел. А не сделать как нибудь. :) Что такое "поллинг" не в курсе. А вдруг в регистре есть что то ждем, потом отправляем. Или я Вас не понял.
Алгоритм по основной программе тогда какой? При приеме данных обрабатываем их и загоняем ответ в буфер отправки, при этом ставим флаг что есть данные на отправку. В основной программе проверяем флаг наличия данных на отправку если он есть начинаем отправлять данные. Однако в момент когда отправлен 3 байт из 8 может прийти пакет по Uart и так как прерывания имеют более высокий приоритет, то пойдет обработка прерывания по RX, а отправка данных остановится. При этом в прерывании пакет так же будет требовать буфер ответа который занят, то есть мы зависнем или же перезапишем буфер отправки новыми данными. Тоже и с прерываниями на отправку. Или что то с алгоритмом не так понял? Вообщем нужно подумать =)
m.zdorenko
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Вс май 03, 2015 14:18:46

Re: Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение m.zdorenko »

Не редактирую, предыдущее так как а вдруг уже прочитано =)

Я сейчас понимаю Вы имели ввиду что так же необходимо проверять регистр UCSRA?
биты:
• Bit 4 – FE: Frame Error
• Bit 3 – DOR: Data OverRun
• Bit 2 – UPE: USART Parity Error
mas123
Потрогал лапой паяльник
Сообщения: 312
Зарегистрирован: Вс июл 29, 2012 16:25:39

Re: Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение mas123 »

m.zdorenko писал(а):Привычка :) Очищать глобальные переменные после использования.
У тебя занулён указатель/счетчик принятых байт. Этого достаточно.
m.zdorenko писал(а):При отправке любого пакета приходит или ответ или код ошибки.
Это в идеальном мире. В реальном же мире на линию связи действуют помехи, которые искажают сигналы: биты теряются, появляются "левые", или же искажаются.
ТАк что до приемника может дойти искаженный кадр, и к передатчику может вернуться искаженный ответ/ошибка.
m.zdorenko писал(а):управляющего модуля реализовать повторную передачу данных при ошибке/потере байта/потере пакета/некорректных данных, чем проверять текущий пакет на приемнике. Да и проверить его полностью не возможно. Наверно.
Почитай как реализованы протоколы передачи данных "во взрослых" системах.
Проверяется кадр без особых проблем. Вокруг тебя столько протоколов с контролем... :))
m.zdorenko писал(а):Остальные 5 байт могут принимать значения от 0х00 до 0хFF, тут же есть проблема в том что любой из них может принять значение 0х3E, то есть конец пакета.
Вот ты сам нашел ещё одну "дырку" это... так сказать протокола.
А теперь просчитай, что случится при искажении данных внутри "<>". Когда ты отправляешь "<123456>", а принимается "<198765>".
И эту "команду" приемник примет и начнёт выполнять. Интересно, какой будет результат?
m.zdorenko писал(а):Что такое "поллинг" не в курсе. А вдруг в регистре есть что то ждем, потом отправляем.
Поллинг, в данном случае - опрос готовности бита.
У тебя так и сделано - крутишься в while(), пока регистр передатчика не пуст, потом кладёшь в него байт.
А правильно - пришло прерывание "регистр передатчика пуст", и в обработчике оного ты просто кладешь следующий байт и выходишь из прерывания.
m.zdorenko писал(а):При приеме данных обрабатываем их и загоняем ответ в буфер отправки, при этом ставим флаг что есть данные на отправку.
В принципе - да.
Можно:
1) в прерывании записывать принятые данные в кольцевой буфер. В основной программе читать из буфера и искать начало и конец пакета. По обнаружению пакета проверить его целостность, разобрать принятые данные и выполнить команду.
2) прямо в прерывании производить анализ потока: поиск начала пакета,во время приема данных кадра контролировать целостность. По окончанию приема в буфер выставить флаг "успешно приняли кадр". В основной программе - анализ принятого, разбор и выполнение команды.
m.zdorenko писал(а):Однако в момент когда отправлен 3 байт из 8 может прийти пакет по Uart и так как прерывания имеют более высокий приоритет,
После установки флага "приняли кадр" дальнейший прием выключается. После освобождения буфера приема, т.е. главный поток данные обработал - прием запускается снова.
Для передачи данных используется независимый буфер, в нём главный процесс конструирует передаваемый кадр и UART на прерываниях его передает. И прием нового кадра ему в этом не мешает.
m.zdorenko писал(а):Я сейчас понимаю Вы имели ввиду что так же необходимо проверять регистр UCSRA?
Вообще-то да, это тоже надо проверять в обработчике прерывания UART-RX.
Но так же контролируется и сам кадр. Почитай про протоколы. В упрощенном виде, кадр с контролем выглядит так:

Код: Выделить всё

СТАРТ
длина данных
...данные...
контрольная сумма кадра (например, простейшая XOR-сумма)
СТОП
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18670
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение ARV »

mas123 писал(а):Но так же контролируется и сам кадр. Почитай про протоколы. В упрощенном виде, кадр с контролем выглядит так:

Код: Выделить всё

СТАРТ
длина данных
...данные...
контрольная сумма кадра (например, простейшая XOR-сумма)
СТОП
стоить особо отметить, что для бинарных протоколов довольно остро стоит проблема отличить последовательности "старт пакета" и "стоп пакета" от находящихся внутри пакета данных. решается эта проблема по-разному, например, байт-стаффингом
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
m.zdorenko
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Вс май 03, 2015 14:18:46

Re: Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение m.zdorenko »

На текущий момент склоняюсь к вариации:
Пакет состоит {<}{c}{ud}{crc}{>}
< - байт символ, старта пакета
с - кол-во байт данных в пакете
ud - данные пакета
crc - контрольная сумма пакета
> - байт символ окончания пакета данных

Так можно будет контролировать целостность и корректность пакета.
1) пакет данных начинается с символа {<}
2) пакет данных заканчивается символом {>} этот символ должен быть на позиции => позиция{<} + {с} + 2
3) crc{ud} должно быть равно {crc}
4) Максимальная длина пакета не должна вылазить за макс. значение буфера приема.
5) Bit 4 – FE: Frame Error = 0
6) Bit 3 – DOR: Data OverRun = 0
7) Bit 2 – UPE: USART Parity Error = 0
При любом из несоответствий считаем пакет не корректным и отправляем код ошибки. Что в свою очередь является запросом на повтор пакета от передатчика.
mas123 писал(а):Почитай как реализованы протоколы передачи данных "во взрослых" системах.
А можно ссылочку? К понятию можно отнести много чего, а что конкретно является правильным новичку определить сложно.
ARV писал(а):стоить особо отметить, что для бинарных протоколов довольно остро стоит проблема отличить последовательности "старт пакета" и "стоп пакета" от находящихся внутри пакета данных. решается эта проблема по-разному, например, байт-стаффингом
Думаю проверки 1 и 2 должны единазначно определить начало и конец пакета.

Но все равно это никак не спасет от сьеденных каналом байт - это в любом случае потеряный пакет или 2.
mas123
Потрогал лапой паяльник
Сообщения: 312
Зарегистрирован: Вс июл 29, 2012 16:25:39

Re: Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение mas123 »

m.zdorenko писал(а):Пакет состоит {<}{c}{ud}{crc}{>}...
с - кол-во байт данных в пакете
Более ожидаемо увидеть как "l - длина пакета" :)
m.zdorenko писал(а):4) Максимальная длина пакета не должна вылазить за макс. значение буфера приема.
Если посмотреть на формат кадра, то видно что "C" должно быть не меньше 2 (1 байт данных + CRC).
Или не меньше... у тебя 3 байта минимальная посылка? Значит не меньше 4.
m.zdorenko писал(а):А можно ссылочку? К понятию можно отнести много чего, а что конкретно является правильным новичку определить сложно.
Гугли x-modem, z-modem, CAN, FT 1.2 (IEC 60870-5-101), ...
Да вообще загугли "протоколы передачи данных" :)
m.zdorenko писал(а):Но все равно это никак не спасет от сьеденных каналом байт - это в любом случае потеряный пакет или 2.
В идеале - максимум 1 кадр потеряешь.
А наличие таймаутов на обеих сторонах - позволяет повторно передать пакет, который заблудился в дебрях проводов.
m.zdorenko
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Вс май 03, 2015 14:18:46

Re: Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение m.zdorenko »

Да, можно еще добавить проверку минимальной длины. Так же можно еще добавить счетчик пакетов обмена. Синхронить его при начале обмена. И будем знать что потерялось.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18670
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение ARV »

m.zdorenko писал(а):Думаю проверки 1 и 2 должны единазначно определить начало и конец пакета.
а если в середине пакета будет символ '<' и по воле случая вы начнете прием не с начала пакета, а с середины? т.е. впоймаете этот символ и воспримите его как маркер начала пакета?

я уже говорил, что для символьных протоколов проблема не очень остро стоит: вы всегда можете сделать протокол таким, что маркеры внутри пакета никогда не будут передаваться (например, пакет начинается с символа '<', а внутри пакета передаются только символы '0'-'9'). но если у вас протокол бинарный, т.е. вместо символов у вас числа, вы не можете гарантировать заранее, что передаваемые числа не совпадут по значению с маркерами, и поэтому вам нужно продумать протокол, исключающий неоднозначное трактование таких символов.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
m.zdorenko
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Вс май 03, 2015 14:18:46

Re: Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение m.zdorenko »

ARV писал(а): а если в середине пакета будет символ '<' и по воле случая вы начнете прием не с начала пакета, а с середины? т.е. впоймаете этот символ и воспримите его как маркер начала пакета?
В этом случае пакет не пройдет остальные проверки и будет все равно откинут как ошибочный.
Давайте посмотрим на пакет ,буду побайтно в столбик писать, что б пронумеровать:
0 - {<}
1 - {6}
2 - {<}
3 - {a}
4 - {s}
5 - {d}
6 - {f}
7 - {f}
8 - {crc}
9 - {>}

Мы не получили байты 0,1 - то есть программа будет считать что пакет у нас начнется с 2 байта.
Какова вероятность того что 3 байт будет равен кол-ву данных юзера в пакете в данной ситуации "3" и контрольная сумма {crc} будет равна контрольной сумме по 4,5,6 байтах.
Думаю ничтожно мала :) Хотя можно посчитать.

Да, и скажите, пожалуйста как то в одном из постов, Вы, писали что PORTB это переменная, а PB1 это бит в этой переменной с которым мы работаем или подменяем.
Если так то PORTB переменная какого типа?
Интересует возможность написания такого кода:
...
#define portCount 3
#define channelCount 3

Код: Выделить всё

char counter = 0;
[b]object[/b] ports[portCount] = {PORTB,PORTA,PORTC}; //масив используемых портов
char pins[portCount][channelCount] = {{PB1,PB2,PB3},{PA1,PA2,PA3},{PC1,PC2,PC3}}; //масив пинов в соответствующем порте
char counters[portCount][channelCount] = {{210,250,230},{15,200,100},{0,255,140}}; // длительность шим для порта
...
ISR (TIM0_OVF_vect)  //обработка прерывания по переполнению таймера
{
  if (++counter==0) //счетчик перехода таймера через ноль
  {
     for(char x = 0; x < portCount; x++) //включаем все каналы
       for(char y = 0; y < channelCount ; y++)
          ports[x] |=(1<<pins[x][y]);
  }

     for(char x = 0; x < portCount; x++) //подаем 0 на канал при достижении заданной длительности
       for(char y = 0; y < channelCount ; y++)
         if (counter==counters[x][y])         
           ports[x] &=~(1<<pins[x][y]);
}
...
В краце это код для програмного шим управления 3 каналами по 3 линии в каждом. Ну для 3-х ргб лент, например.
Чем данный код хорош - тем что можно увеличивать или уменьшать кол-во каналов только увеличивая или уменьшая массивы.
Единственная загвоздка - как прописать ссылку на порт.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18670
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение ARV »

рассмотрите ситуацию чуть шире, чем вы только что сделали: вы приняли "старт" в середине пакета, следующий байт, предположим, равен 200 - это как бы длина пакета... ваша программа будет тупо ждать 200 байт, а их, может и не будет никогда... а может и будет, но 25 следующих пакетов вы пропустите, как данные этого пакета... а может там что-то важное...

протокол должен позволять вам синхронизироваться с потерей только одного пакета - того, в середине которого вы встряли в прием. а ждать, пока придет весь пакет и по CRC его сбрасывать - это дополнительная защита от искажения данных, но не способ синхронизации приема.

переменная PORTB в WinAvr определена как volatile unsigned char. точнее, это макрос, который раскручивается более сложно, но в конечном итоге это будет именно volatile unsigned char.

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

Мой уютный бложик... заходите!
m.zdorenko
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Вс май 03, 2015 14:18:46

Re: Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение m.zdorenko »

ARV писал(а):рассмотрите ситуацию чуть шире, чем вы только что сделали: вы приняли "старт" в середине пакета, следующий байт, предположим, равен 200 - это как бы длина пакета... ваша программа будет тупо ждать 200 байт, а их, может и не будет никогда... а может и будет, но 25 следующих пакетов вы пропустите, как данные этого пакета... а может там что-то важное...

протокол должен позволять вам синхронизироваться с потерей только одного пакета - того, в середине которого вы встряли в прием. а ждать, пока придет весь пакет и по CRC его сбрасывать - это дополнительная защита от искажения данных, но не способ синхронизации приема.
Для меня пакеты нечто новое. Хотя в принципе по моему алгоритму не должно быть такого. Сейчас как раз над ним работаю. Закончу выложу. Вместе с своим протоколом, тогда будет наглядней :))
ARV писал(а):переменная PORTB в WinAvr определена как volatile unsigned char. точнее, это макрос, который раскручивается более сложно, но в конечном итоге это будет именно volatile unsigned char.
PB1 - это опять-таки макрос, обозначающий номер бита в порту.
PB0...PB7 это просто, циферки если говорить грубо. 0...7 А вот с портом поинтересней. Для выполнения кода что писал ранее нужно в массив загонять ссылку на адрес данных в памяти и все будет замечательно. Закончу с UART обязательно займусь этим =)
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18670
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение ARV »

m.zdorenko писал(а):нужно в массив загонять ссылку на адрес данных в памяти
это называется указатель :)
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
mas123
Потрогал лапой паяльник
Сообщения: 312
Зарегистрирован: Вс июл 29, 2012 16:25:39

Re: Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение mas123 »

ARV писал(а):ваша программа будет тупо ждать 200 байт, а их, может и не будет никогда...
Здесь нас спасает таймаут приема.
Ещё можно внутри кадра разместить два контейнера: "короткий" с кодом команды и длиной данных, и "длинный" с самими данными. И оба контейнера "защитить" контрольной суммой.
ARV писал(а):но 25 следующих пакетов вы пропустите
А тут помогает выдача "квитанции" об успешном приеме каждого пакета (или оптом - группы пакетов).
Стаффинг - конечно вариант, да. Только в случае "изгибания битов", когда принимаем не переданный байт, а "уникальный байт СТАРТ" - будет та же самая ситуация.
m.zdorenko писал(а):Для меня пакеты нечто новое. Хотя в принципе по моему алгоритму не должно быть такого. Сейчас как раз над ним работаю.
Гм, это какой по счету разработанный алгоритм будет? :shock:
А то куча народу уже ...цать лет придумывает разные протоколы, но так пока и не придумали ИДЕАЛЬНЫЙ ПРОТОКОЛ. Чуть-чуть поскромнее надо бы. :))
m.zdorenko
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Вс май 03, 2015 14:18:46

Re: Проблемы прерывания USART_RX_vect в Atmel Studio 6

Сообщение m.zdorenko »

ARV писал(а):Гм, это какой по счету разработанный алгоритм будет?
А то куча народу уже ...цать лет придумывает разные протоколы, но так пока и не придумали ИДЕАЛЬНЫЙ ПРОТОКОЛ. Чуть-чуть поскромнее надо бы.
Никто не говорит об идеальном. Так свой, для себя. Что б разобраться. =)
Что т я совсем туплю. глупый вопрос. Скорость ком порта 9600 б/с то есть если биты будут непрерывным потоком идти. то частота прерываний будет 9600*8 = 76,8КГц? То есть между прерываниями остается время на работу основного процесса, при условии что отработка прерывания не занимает все это пространство?
Ответить

Вернуться в «AVR»