Опубликовано 2010-05-07 11:30:31 автором Ruslan

Передача данных через UART в AVR. Урок AVR 9


Для связи микроконтроллера со своим старшим братом - ПК - можно использовать интерфейсы передачи данных, но так как я учебный курс по AVR стараюсь построить на микроконтроллере mega8, то предпочтительней всего для связи с ПК использовать интерфейс USART. Нет, можно, конечно, заюзать и USB, но USART в mega8 реализован аппаратно, а это значит, что нам не придется вручную реализовывать логику передачи данных, мы просто запишем данные в регистр, а самим процессом отправки уже будет рулить МК аппаратно.
Протокол UART (Universal asynchronous receiver/transmitter) является одним из самых распространённых протоколов передачи данных между устройствами. У Atmega8 один USART, выведен он на ножки PD0 — Rx, receiver (приемник) и PD1 — Tx, transmitter (передатчик). Вывод Usart у mega8 Давайте попробуем передать данные с пк. Когда с пк будет приходить 1, то светодиод будет светиться, когда 0, то гаснуть. Схема выглядит следующим образом:

Uart у proteus Далее нам нужно написать программу:
В CodeVision AVR создаем новый проект, частоту мк устанавливаем на 8 мегагерц, далее переходим во вкладку USART, там включаем приемник и передатчик

Uart у proteus

Уберем все лишнее и допишем свой код

 #include <mega8.h> 
 void main(void) 
 { 
 char date=0; 
  PORTC=0x00; 
 DDRC=0x01;  
 // USART initialization 
 // Communication Parameters: 8 Data, 1 Stop, No Parity 
 // USART Receiver: On 
 // USART Transmitter: On 
 // USART Mode: Asynchronous 
 // USART Baud Rate: 9600 
 UCSRA=0x00; 
 UCSRB=0x18; 
 UCSRC=0x86; 
 UBRRH=0x00; 
 UBRRL=0x33; 
  while (1) 
 { 
 date=UDR; 
  
 if (date=='1')   PORTC.0=1; 
 if (date=='0')   PORTC.0=0;  
 };    
 } 

У AVR есть регистр UDR. На самом деле, это два разных регистра, которые имеют один адрес. Когда записываем данные, то они попадают в регистр передатчика, а когда читаем - берутся из регистра приемника. Для отправки мы просто записываем данные в этот регистр и они улетят к приемнику, а если нам что-то пришло - считываем их из регистра.
Следить за UART вручную не нужно, все обслуживание можно повесить на прерывания. Когда нам приходят данные, генерируется прерывание по завершению приема, а когда данные отправятся - вызовется прерывание по опустошению
Компилим программу, закидываем в мк в протеусе. Для отсылки данных из терминала нужно поставить галочку возле:

передача данных через uart

Вводим единичку - светодиод светится

uart в Proteus

Вводим 0 - светодиод гаснет

передача данных через uart в Proteus

Работа на прерываниях

Как вы заметили, наша программа бесконечно ожидает прихода байта. Так делать нецелесообразно, потому что главный цикл загружен приемом и передачей данных через uart и больше ничего делать не может. Конечно, можно не зацикливаться, а например периодически раз в 10 милисекунд проверять, не пришли ли нам данные, в остальное время делать что-то своё. Но тогда, если передача идет на большой скорости, можно пропустить байты. Лучше всего эту малину замутить на прерываниях: пришли данные - вызвался обработчик прерывания и все. Для этого в CodeWizard AVR во вкладке USART нужно поставить галочку возле Rx Interrapt

uart на прерываниях
Генерим код, и получаем

 #include  <mega8.h>  
 #ifndef RXB8 
 #define RXB8 1 
 #endif  
 #ifndef TXB8 
 #define TXB8 0 
 #endif  
 #ifndef UPE 
 #define UPE 2 
 #endif  
 #ifndef DOR 
 #define DOR 3 
 #endif  
 #ifndef FE 
 #define FE 4 
 #endif  
 #ifndef UDRE 
 #define UDRE 5 
 #endif  
 #ifndef RXC 
 #define RXC 7 
 #endif  
 #define FRAMING_ERROR (1<<FE) 
 #define PARITY_ERROR (1<<UPE) 
 #define DATA_OVERRUN (1<<DOR) 
 #define DATA_REGISTER_EMPTY (1<<UDRE) 
 #define RX_COMPLETE (1<<RXC)  
  // USART Receiver buffer 
 #define RX_BUFFER_SIZE 8 char rx_buffer[RX_BUFFER_SIZE];  
 #if RX_BUFFER_SIZE<256 unsigned char rx_wr_index,rx_rd_index,rx_counter; 
 #else unsigned int rx_wr_index,rx_rd_index,rx_counter; 
 #endif
   // This flag is set on USART Receiver buffer overflow bit rx_buffer_overflow;  
 // USART Receiver interrupt service routine interrupt [USART_RXC] void usart_rx_isr(void) 
 { char status,data; status=UCSRA; 
 data=UDR; 
 if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0) 
 {    
 rx_buffer[rx_wr_index]=data; 
 if (++rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0; 
 if (++rx_counter == RX_BUFFER_SIZE) 
 { 
 rx_counter=0;  
 rx_buffer_overflow=1; 
 }; 
 };  
 if (data=='1')   PORTC.0=1;  
 if (data=='0')   PORTC.0=0; 
 } 
  
 #include  <stdio.h >  
 void main(void) 
 { 
 // Port C initialization 
 PORTC=0x00; 
 DDRC=0x01;  
 // USART initialization 
 // Communication Parameters: 8 Data, 1 Stop, No Parity 
 // USART Receiver: On 
 // USART Transmitter: Off 
 // USART Mode: Asynchronous 
 // USART Baud Rate: 9600 
 UCSRA=0x00; 
 UCSRB=0x90; 
 UCSRC=0x86; 
 UBRRH=0x00; 
 UBRRL=0x33; 
  // Global enable interrupts 
 #asm("sei") 
  while (1) 
 { 
 }; 
 } 

Здесь codewizard сгенерировал разные проверки четности и буфер для записи данных, которые пришли. Нам для того, чтобы засветить светодиод все это не нужно, поэтому удаляем лишнее, и получаем

 #include <mega8.h> 
 #include <stdio.h> 
 // USART Receiver interrupt service routine interrupt [USART_RXC] void usart_rx_isr(void) 
 { 
 char data; 
 data=UDR;  
          
 if (data=='1')   PORTC.0=1;  
 if (data=='0')   PORTC.0=0; 
 } 
  
 void main(void) 
 { 
 // Port C initialization 
 PORTC=0x00; 
 DDRC=0x01; 
  // USART initialization 
 // Communication Parameters: 8 Data, 1 Stop, No Parity 
 // USART Receiver: On 
 // USART Transmitter: Off 
 // USART Mode: Asynchronous 
 // USART Baud Rate: 9600 
 UCSRA=0x00; 
 UCSRB=0x90; 
 UCSRC=0x86; 
 UBRRH=0x00; 
 UBRRL=0x33; 
  // Global enable interrupts 
 #asm("sei") 
  
 while (1)
        {  
 }; 
 } 

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

Переходим к железу
Если у вашего пк есть COM порт, то вам для сопряжения с микроконтроллером понадобится преобразователь уровней ТТЛ – RS232. Его легко собрать на микросхеме MAX232. Он нужен, потому что напряжение на выходе данных из COM-порта ПК:
  • логическая "1" от -5 до -15 вольт
  • логический "0" от +5 до +15 вольт
а в мк
  • логическая "1" от 1,8 до напряжения питания вольт
  • логический \"0\" от 0 до 1,3 вольт
Схема подключения RS232 примерно такая Схема подключения RS232 примерно такая Если у вашего ПК нет СОМ-портов, то нужно юзать адаптер на микросхеме FT232 - он подключается к USB вашего ПК и в системе появляется виртуальный СОМ порт, а на выводах FT232 соответствующие сигналы UART. Схема подключения RS232 примерно такая

Комментарии - (2)

Добавить комментарий

Для отправки комментария вы должны авторизоваться.