Обработка принятых по протоколу USART данных на примере ATmega8

Очень часто приходится осуществлять связь с различными устройствами через модуль USART микроконтроллера, принимать и отправлять данные. Вот как раз как можно обрабатывать данные и приведу пример обработки данных принятых по протоколу USART.

Для реализации нам понадобятся навыки работы с прерываниями , а именно нам понадобится вектор прерыванию срабатывающий на приход байта по каналу USART. Заглянув например в datasheet на микроконтроллер ATmega8 на странице 44 расположена таблица прерываний данного микроконтроллера.
таблица прерываний Attiny2313

Нам понадобится вектор номер 12 в таблице. В программе он будет обозначен как: USART_RXC_vect

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

В таблице прерываний микроконтроллера показано что вектор прерывания (вектор - это по сути источник, причина прерывания) может быть от нажатия кнопки подключенной к одному из двух входов Int0 и Int1 до срабатывания на переполнение внутреннего 16-ти битного счетчика микроконтроллера.

кусок кода для прерывания по приходу байта по протоколу USART:

  1. #include <avr/io.h>//Библиотека ввода/вывода
  2. #include <avr/interrupt.h>//Библиотека прерываний
  3.  
  4. //Подпрограмма-обработчик прерывания
  5. //по приходу байта на модуль USART
  6. ISR(USART_RXC_vect)
  7. {
  8. int b;
  9. b = UDR;//Присваиваем переменной b содержимое регистра UDR именно в нем хранится принятый байт
  10.  
  11. .....//Программа обработки принятого байта
  12. }

И так, основы прошли, теперь сама программа.
Для более приближенного знакомства давайте сделаем программку, которая будет определять что мы приняли и в соответствии с этим она будет выполнять определенное действие. В данной программа алгоритм следующий:
если мы получили по USART "1" - отправляем по USART букву "R",
а если приняли "2" - то отправляем по USART букву "L".

  1. #include <avr/io.h>//Библиотека ввода/вывода
  2. #include <avr/interrupt.h>//Библиотека прерываний
  3.  
  4. //Прототипы подпрограмм
  5. void USART_Transmit( unsigned char data );
  6. void USART_Init( unsigned int ubrr);
  7.  
  8. //Подпрограмма обработки прерывания
  9. ISR(USART_RXC_vect)
  10. {
  11. int b;
  12. b = UDR;
  13. // Выполняем обработку принятого байта
  14. if (b=='1')//Если приняли "1"
  15. {
  16. USART_Transmit('R');//Отправляем букву "R"
  17. USART_Transmit(0x0d);//переход в начало строки
  18. USART_Transmit(0x0a);//переход на новую строку
  19. }
  20. else//Если нет
  21. if (b=='2')//Если приняли "2"
  22. {
  23. USART_Transmit('L');//Отправляем букву "L"
  24. USART_Transmit(0x0d);//переход в начало строки
  25. USART_Transmit(0x0a);//переход на новую строку
  26. }
  27. }
  28.  
  29. void USART_Init( unsigned int ubrr)//Инициализация модуля USART
  30. {
  31. /* Задаем скорость работы USART */
  32. UBRRH = (unsigned char)(ubrr>>8);
  33. UBRRL = (unsigned char)ubrr;
  34. /* Разрешаем прием и передачу по USART */
  35. UCSRB=(1<<RXEN)|( 1<<TXEN);
  36. UCSRB |= (1<<RXCIE);
  37.  
  38. //UCSRB=(1<<RXEN)|(1<<TXEN)|(1<<RXCIE);
  39. /* Устанавливаем формат данных 8 бит данных, 2 стоп бита */
  40. UCSRC=0x86;// Инициализация именно для ATmega8
  41. UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
  42. }
  43.  
  44. void USART_Transmit( unsigned char data ) //Функция отправки данных
  45. {
  46. while ( !(UCSRA & (1<<UDRE)) ); //Ожидание опустошения буфера приема
  47. UDR = data; //Начало передачи данных
  48. }
  49.  
  50. int main(void)//главная программа
  51. {
  52. //Скорость USART 115200 при кварцевом генераторе 16MHz
  53. USART_Init (8);
  54.  
  55. USART_Transmit('O');//Передаем при включении
  56. USART_Transmit('k');//сообщение "Ok!", что свидетельствует
  57. USART_Transmit('!');//о правильно работе программы
  58.  
  59. USART_Transmit(0x0d);//переход в начало строки
  60. USART_Transmit(0x0a);//переход на новую строку
  61.  
  62. sei();//разрешаем глобально прерывания
  63.  
  64. while(1)//вечный цикл
  65. {//тут пусто, да можно и так писать :)
  66. }//
  67. }

Программа написана под микроконтроллер ATmega8 для других микроконтроллеров семейства AVR подпрограмма инициализации модуля USART может быть другой (для Attiny2313 точно другая, смотрите в разделе шаблоны).

Никак не хочет работать -

Никак не хочет работать - одно ехо. Скинте пожалуйста проект AVR Studio (исходники) пожалуйста.

строки uart

Добрый день. У меня появилась такая идея как управление мк через uart с пк.
Как отправлять строки на ПК я разобрался, только вот одна проблема как отправить строку с пк, которую приням мк выполнил команду например PORTB=0x01; ну или меняла какие то переменные. Вообще такое возможно?

да в обработчик прерывания

да в обработчик прерывания можно записать комманду выполнения любой функции.
Что касается функционала функции, то он ограничивается только возможностями микроконтроллера!

строки uart

Еще раз здравствуйте. Со строками разобрался. отправляю через терминал PUTTY контроллер принимает и с помощью функции сравнения strncmp(); выполняет команды. Появилась другая проблема, когда печатаешь символы в терминале и они отправляются на МК,но мк не отправляет мне обратно то что я напечатал, хочется сделать что то вроде консоли. То есть напечатал символ контроллер его принял и вывел сразу в терминал, а то получается что я печатаю в слепую.

А как ты принимаешь и

А как ты принимаешь и сравниваешь строки ?
Если не трудно кинь примерчик)

Сравнивать нужно функцией

Сравнивать нужно функцией strcmp(str1,str2);

Со строками лично я не

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

  1. #include <avr/io.h>
  2. #include<avr/interrupt.h>
  3.  
  4. void USART_Transmit( unsigned char data );
  5. void USART_Init( unsigned int ubrr);
  6.  
  7. int a=0;
  8.  
  9. char mass [2] = {0,0};
  10.  
  11. ISR(USART_RXC_vect)
  12. {
  13. int b;
  14. b = UDR;
  15.  
  16.  
  17. mass[a] = b;
  18. if (a==1)
  19. { a=0;}
  20. else
  21. a = a+1;
  22.  
  23.  
  24.  
  25. if (b=='y')//Если приняли "2"
  26. {
  27. USART_Transmit('L');
  28. USART_Transmit(0x0d);
  29. USART_Transmit(0x0a);
  30. }
  31. }
  32.  
  33. void USART_Init( unsigned int ubrr)
  34. {
  35. /* Set baud rate */
  36. UBRRH = (unsigned char)(ubrr>>8);
  37. UBRRL = (unsigned char)ubrr;
  38. /* Enable receiver and transmitter */
  39. UCSRB=(1<<RXEN)|(1<<TXEN);
  40. UCSRB |= (1 << RXCIE);
  41.  
  42. //UCSRB=(1<<RXEN)|(1<<TXEN)|(1<<RXCIE);
  43. /* Set frame format: 8data, 2stop bit */
  44. UCSRC=0x86;//
  45. UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
  46. }
  47.  
  48. void USART_Transmit( unsigned char data ) //Функция отправки данных
  49. {
  50. while ( !(UCSRA & (1<<UDRE)) ); //Ожидание опустошения буфера приема
  51. UDR = data; //Начало передачи данных
  52. }
  53.  
  54. int main(void)
  55. {
  56. USART_Init (8);//115200 16MHz
  57.  
  58. USART_Transmit('O');
  59. USART_Transmit('k');
  60. USART_Transmit('!');
  61.  
  62. USART_Transmit(0x0d);
  63. USART_Transmit(0x0a);
  64.  
  65. sei();
  66.  
  67. while(1)
  68. {
  69. if (mass[0]=='1')
  70. {
  71. if(mass[1]=='2')
  72. {
  73. USART_Transmit('Y');
  74. USART_Transmit('e');
  75. USART_Transmit('S');
  76.  
  77. USART_Transmit(0x0d);
  78. USART_Transmit(0x0a);
  79.  
  80. mass [0] = 0;
  81. mass [1] = 0;
  82. }
  83. }
  84. }
  85. }

Шаблон программы USART

Шаблон программы USART ECHO

Вот код проги, которая просто принмает и отправляет назад символ.

протокол NMEA

А как обрабатывать сообщения из gps приемника в протоколе NMEA и выводить их на lcd?

GPS приемник периодически

GPS приемник периодически посылает по UART пакет данных (если он такого не делает - нужно его настроить, чтобы он посылал нам сообщение GGA, в котором содержиться широта-долгота-высота-полушария-время). Теперь нужно выдрать широту-долготу, высоту над уровнем моря, и что там тебе еще нужно. Структуру пакета можно прочитать в мануале описывающим NMEA. Выдирается все просто, знаем что широта - выводиться в байтах 18-24, делаем в цикле приема пакета счетчик, как только он достигает 18-ти, выводим принятые данные сразу на ЖКИ, а как достигнет 25 - уже ничего не выводим. И так для каждого измерения.