Как работать с USART на AVR?




Работаем с UART на AVR



 

Пару слов о источнике информации

 

В начале поста, я стараюсь приводить источники, откуда я беру информацию. Обычно это ссылки на сайты разработчиков, где, я указываю какие стандарты и даташиты описывают данное устройство или технологию. Редко, в порядке исключения даю ссылки на хорошие (на мой взгляд) посты блогов, которым можно доверять. У технической информацию должен быть незыблемый источник

С UART так не выйдет … сама идея последовательной асинхронной передачи данных настолько стара, что, к сожалению, на технологию UART нет прямого стандарта, где было-бы рассказана его логика работы.

Но, забегу вперед, описание UART все таки есть, но косвенное … его можно найти в описаниях на физический протоколы RS-232, RS-422, RS-423, RS-485, но об этом позже.

 

 

Немного теории

 

UART (универсальный асинхронный приёмопередатчик) — одна из старейших и самых распространенных на сегодняшний день технологий передачи данных. Слово «асинхронный » означает, что интерфейс не использует линию для синхросигнала, приемник и передатчик заранее настраиваются на одну частоту.

Можно сказать с уверенностью, что каждый микроконтроллер/микропроцессор имеет в своем составе универсальный последовательный интерфейс — UART. Умея работать с данным портом вы развязываете себе руки, когда необходимо согласовать работу старых и современных электронных устройств, принять или передать данные в устройства.

В современных микроконтроллерах, часто вместо UART используют полностью с ним совместимый — USART (универсальный асинхронный/синхронный приёмопередатчик).

USART это более гибкий в настройки UART с дополнительными возможностями. Например в USART можно регулировать длину слова с более большим диапазоном (от 5 до 9) чем в UART (от 8 до 9). В USART как видно из названия возможна как асинхронная так и синхронная передача данных (в UART только асинхронная). При синхронной передачи помимо 2-ух линиданные и питания, используется дополнительная линия (XCK) с синхросигналом. С такой конфигурацией USART уже пересекается с интерфейсом SPI и его можно использовать как «ведущий » в интерфейсе SPI.

Мы будем рассматривать классический случай, когда интерфейс асинхронный (т.е. без линии синхросигнала).

Передача данных в UART осуществляется по одному биту в равные промежутки времени. Этот временной промежуток определяется заданной скоростью UART и для конкретного соединения указывается в бодах, что соответствует количество бит в секунду. Существует общепринятый ряд стандартных скоростей: 300; 600; 1200; 2400; 4800; 9600; 19200; 38400; 57600; 115200; 230400;460800; 921600 бод;

Скорость (S, бод) и длительность бита (T, секунд) связаны соотношением T=1/S.

Байт данных отправляются в пакетах (1 -й бит перед байтом данных и 2 -а бита после, количество бит опциональны).

(p.s. наличие и количество проверочного и стопового бита опциональны)

 

Для приема и передачи данных UART использует две линии данных и земля:

  • передающая данные (TXD или TX);
  • принимающая данные (RXD или RX);
  • земля (GND).

Уровню логической единицы и нуля соответствует уровням TTL:

  • т.е. 1-ца это +5В;
  • а 0 это .

 

 

Немного отступлю… все равно этот вопрос рано или поздно у вас возникнет…

UART понятно, а что тогда такое RS-232, COM?

читайте в посте по ссылке

 

 

Как работать с USART на AVR?

 

В качестве AVR микроконтроллера я буду рассматривать ATmega8.

  • за прием данных в USART (RxD) отвечает ножка PDO
  • за передачу данных из USART (TxD) отвечает ножка PD1
  • если будет использоваться линия синхронизации, то данную функцию несет ножка XCK

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

Для управлением работы с USART используются следующие регистры:

  • UCSRA — содержит в основном флаги состояния приема/передачи данных.
  • UCSRB — определяет какие прерывания генерировать при наступление событий, разрешает / запрещает передачу / прием, совместно с регистром UCSRC определяет разрядность передаваемого/принимаемого слова.
  • UCSRC — задает режим работы синхронный / асинхронный, определяет правила работы контроля данных — проверка на четность / не честность или отключено, количество стоп битов, совместно с регистром UCSRB определяет разрядность передаваемого/принимаемого слова, определяет по какому фронту принимать / передавать данные — по спадающему или по нарастающему.
  • UBRR — определяет скорость приема/передачи данных

 

О каждом регистре немного поподробнее…

Регистр UCSRA состоит из следующих бит:

 

 

  • RXC — флаг завершения приема, устанавливается в 1 при наличие непрочитанных данных в буфере приемник — UDR;
  • TXC — флаг завершения передачи, устанавливается в 1 при передачи всех разрядов из передатчика — UDR;
  • UDRE — флаг опустошения регистра передатчика, устанавливается в 1 при пустом буфере передатчика — UDR после передачи;
  • FE — флаг ошибки кадрирования, устанавливается в 1 при обнаружение неправильного кадра, когда стоп бит равен 0-лю
  • DOR — флаг переполнения регистра приемника, устанавливается в 1, когда байт данных принят, а предыдущий еще не прочитан из UDR;
  • PE — флаг ошибки контроля четности, устанавливается в 1 при обнаружение ошибки контроля четности (если включена проверка);
  • U2X — бит установки удвоенной скорости обмена, если установлена 1, то скорость передачи удваивается (частота делится на 8, а не на 16), данный бит используется только при асинхронном режиме работы;
  • MPCM — бит мультипроцессорного обмена, если установлена 1, то контроллер аппаратно не принимает информацию, а только кадры с адресами, далее устанавливается бит завершения приема (или прерывание) и программа обрабатывает адрес, её ли это адрес. Отличие информации от адреса определяется с помощью 9-ого бита в режиме 9-и битового обмена.

 

Регистр UCSRB состоит из следующих бит:

 

 

  • RXCIE — бит разрешения прерывания по завершению приема, если установлена 1, то при установке флага RXC регистра UCSRA произойдет прерывание «прием завершен «;
  • TXCIE — бит разрешения прерывания по завершению передачи, если установлена 1, то при установке флага TXC регистра UCSRA произойдет прерывание «передача завершена «;
  • UDRIE — бит разрешения прерывания по опустошению регистра передатчика, если установлена 1, то при установке флага UDRE регистра UCSRA произойдет прерывание «регистр данных пуст «;
  • RXEN — бит разрешения приема, при установки 1 разрешается работа приемника USART и переопределяется функционирование вывода RXD;
  • TXEN — бит разрешения передачи, при установки 1 разрешается работа передатчика USART и переопределяется функционирование вывода TXD;
  • UCSZ2 — бит формат посылок, данный бит совместно с битами UCSZ1 и UCSZ0 регистра UCSRC определяют количество бит данных в кадрах

  • RXB89-ый разряд принимаемых данных при использование 9-и битого режима, считывать из данного бита нужно до считывание регистра UDR;
  • TXB8 — 9-ый разряд передаваемых данных при использование 9-и битного режима, записывать в данный бит нужно до записи в регистр UDR.

 

Регистр UCSRC состоит из следующих бит:

 

 

  • URSEL — тут надо пояснить, это немного странный бит, он отвечает за выбор регистра UCSRC или UBRR, при установке 1 мы работаем с регистром UCSRC, при 0 мы работаем с регистром UBRR;
  • UMSEL — бит выбора режима асинхронный или синхронный, если установлен 1 — режим синхронный (т.е. с использованием линии синхронизации XCK), если 0 — режим асинхронный;
  • UPM1, UPM0 — биты выбора режима проверки на четность / нечетность;

  • USBS — бит отвечающий за количество стоп-битов, если установлена 1два стоп-бита, если 0один стоп-бит;
  • UCSZ1, UCSZ0 — совместно с битом UCSZ2 регистра UCSRB определяют количество бит данных в кадрах (см. таблицу выше);
  • UCPOL — бит полярность тактового сигнала, при синхронном режиме определяет по какому фронту принимать / передавать данные – по спадающему или по нарастающему.

 

Регистр UBRR отвечает за скорость обмена, он состоит из двух 8-и битных регистров — UBRRH и UBRRL

 

 

Повторюсь, бит URSEL отвечает за выбор регистра UCSRC или UBRR, при установке 1 мы работаем с регистром UCSRC, при 0 мы работаем с регистром UBRR. Биты с UBRR0 до UBR11 устанавливают скорость передачи в бодах, но не прямую, а через следующие формулы:

UBRR = (fCK /(BAUD * 16)) — 1

UBRR = (fCK /(BAUD * 8)) — 1

Где fCK — тактовая частота микроконтроллера в герцах;

BAUD — требуемая скорость в бодах;

16 и 8 коэффициент делителя частоты, зависит от бита U2X регистра UCSRA,

      • при 1 — коэффициент 8;
      • при 0 — коэффициент 16;

UBRR — содержимое регистра UBRRH и UBRRL.

Мы будем использовать «классический UART » (т.е. асинхронный без линии синхронизации) с скоростью 9600 бод, 8-бит данных, 1-ин стоп-бит, без проверки на четность.

(в сокращенной записи данную конфигурацию записывают в виде «9600/8-N-1 «, где 9600 это скорость, 8-количество бит данных в кадре, N-без проверки четности, 1-количество стоп-битов, если интересно описание сокращенного формата записи легко можно нагуглить)

Итак, я опишу последовательность действий для передатчика UART и далее приведу ассемблерный и С код для ATmega8, который можно будет опробовать на проекте Proteus.

Последовательность действий для инициализации UART в режиме 9600/8-N-1 и передачи байта данных:

1. пусть ATmega8 тактируется от 8 МГц, первым делом, установим скорость 9600 бод, для этого рассчитаем значение регистра UBRR по формуле UBRR = (8 000 000 /(9 600 * 16)) – 1, результат равен 52,083, округлим его до 52 (или 0x34), запишем в UBRR значение 0x34;

2. разрешаем работу передатчика, записываем в регистр UCSRB значение 00001000 (установили бит TXEN);

3. устанавливаем формат кадра 8 бит данных, без проверки четности и асинхронный режим, записываем в UCSRC значение 10000110 или 0x86 (установили биты URSEL, UCSZ1, UCSZ0);

4. отправляем байт данных, записываем байт в регистр UDR и делаем задержку пока бит UDRE регистра UCSRA не будет равен нулю.

 

Код на ассемблере для ATmega8

.nolist;данная директива отключает генерацию кода в листинг, т.е. далее в файле *.lss не будет фиксироваться ассемблерный код .include "m8def.inc" ;подключение стандартного заголовочного файла для ATmega8 .list ;данная директива включает генерацию кода в листинг, т.е. далее в файле *.lss будет фиксироваться ассемблерный код .equ fCK = 8000000;частота в герцах .equ BAUD = 9600;скорость для UART в бодах .equ UBRR_value = (fCK/(BAUD*16))-1;расчитываем значение для регистра UBRR .cseg ;данная директива означает, что дальше идет код программы .org 0 ;данная директива означает, что код программы будет располагаться с 0ого адреса в FLASH ;ВЕКТОР ПРЕРЫВАНИЙ rjmp initial;прерывание от …, ссылаемся на обработчик прерывания - initial rjmp 0 ;rjmp service_INT0;внешнее прерывание 0 rjmp 0 ;rjmp service_INT1;внешнее прерывание 1 rjmp 0 ;rjmp service_OC2;совпадение TCNT2 и OCR2 rjmp 0 ;rjmp service_OVF2;переполнение TCNT2 rjmp 0 ;rjmp service_ICP1;захват в ICP1 rjmp 0 ;rjmp service_OC1A;совпадение TCNT1 и OCR1A rjmp 0 ;rjmp service_OC1B;совпадение TCNT1 и OCR1B rjmp 0 ;rjmp service_OVF1;переполнение TCNT1 rjmp 0 ;rjmp service_OVF0;переполнение TCNT0 rjmp 0 ;rjmp service_SPI;прерывание от модуля SPI rjmp 0 ;rjmp service_URXC;получение байта по USART rjmp 0 ;rjmp service_UDRE;опустошение UDR в USART rjmp 0 ;rjmp service_UTXC;передача байта по USART rjmp 0 ;rjmp service_ADCC;прерывание от АЦП rjmp 0 ;rjmp service_ERDY;завершение записи в EEPROM rjmp 0 ;rjmp service_ACI;прерывание от компаратора rjmp 0 ;rjmp service_TWI;прерывание от модуля TWI rjmp 0 ;rjmp service_SPMR;завершение выполнения spm ;УСТАНОВКА СТЕКА initial: ldi R16,low(RAMEND);скопируем в R16 младщий байт из константы RAMEND, которая определена в m8def.inc и хранит размер SRAM out SPL,R16;скопируем значение из R16 в SPL ldi R17,high(RAMEND);скопируем в R16 старший байт из константы RAMEND, которая определена в m8def.inc out SPH,R17;скопируем значение из R17 в SPH ;КОД ОСНОВНОЙ ПРОГРАММЫ main: rcall init_USART ldi R16,0b01010011 rcall USART_send ;шлем 0x53, это ASCII код знака 'S' ldi R16,0b00101101 rcall USART_send;шлем 0x2D, это ASCII код знака '-' ldi R16,0b01000101 rcall USART_send;шлем 0x45, это ASCII код знака 'E' loop: rjmp loop ;ПОДПРОГРАММА ИНИЦИАЛИЗАЦИИ USART МОДУЛЯ init_USART:ldi R16,high(UBRR_value);устанавливаем скорость 9600 бод out UBRRH,R16 ldi R16,low(UBRR_value) out UBRRL,R16 ldi R16,(1<<TXEN);разрешаем работу передатчика out UCSRB,R16 ldi R16,(1<< URSEL)|(1<< UCSZ0)|(1<< UCSZ1) out UCSRC,R16;устанавливаем режим 8 бит данных, без проверки четности, асинхронный режим ret USART_send:sbis UCSRA,UDRE;ждем пока бит UDRE регистра UCSRA не будет пуст rjmp USART_send out UDR,R16 ;посылаем байт по UART, кладем данные в регистр UDR ret

  .nolist;данная директива отключает генерацию кода в листинг, т.е. далее в файле *.lss не будет фиксироваться ассемблерный код .include "m8def.inc";подключение стандартного заголовочного файла для ATmega8 .list;данная директива включает генерацию кода в листинг, т.е. далее в файле *.lss будет фиксироваться ассемблерный код   .equ fCK = 8000000;частота в герцах .equ BAUD = 9600;скорость для UART в бодах .equ UBRR_value = (fCK/(BAUD*16))-1;расчитываем значение для регистра UBRR   .cseg;данная директива означает, что дальше идет код программы .org 0;данная директива означает, что код программы будет располагаться с 0ого адреса в FLASH   ;ВЕКТОР ПРЕРЫВАНИЙ rjmp initial;прерывание от …, ссылаемся на обработчик прерывания - initial rjmp 0;rjmp service_INT0;внешнее прерывание 0 rjmp 0;rjmp service_INT1;внешнее прерывание 1 rjmp 0;rjmp service_OC2;совпадение TCNT2 и OCR2 rjmp 0;rjmp service_OVF2;переполнение TCNT2 rjmp 0;rjmp service_ICP1;захват в ICP1 rjmp 0;rjmp service_OC1A;совпадение TCNT1 и OCR1A rjmp 0;rjmp service_OC1B;совпадение TCNT1 и OCR1B rjmp 0;rjmp service_OVF1;переполнение TCNT1 rjmp 0;rjmp service_OVF0;переполнение TCNT0 rjmp 0;rjmp service_SPI;прерывание от модуля SPI rjmp 0;rjmp service_URXC;получение байта по USART rjmp 0;rjmp service_UDRE;опустошение UDR в USART rjmp 0;rjmp service_UTXC;передача байта по USART rjmp 0;rjmp service_ADCC;прерывание от АЦП rjmp 0;rjmp service_ERDY;завершение записи в EEPROM rjmp 0;rjmp service_ACI;прерывание от компаратора rjmp 0;rjmp service_TWI;прерывание от модуля TWI rjmp 0;rjmp service_SPMR;завершение выполнения spm   ;УСТАНОВКА СТЕКА initial: ldi R16,low(RAMEND);скопируем в R16 младщий байт из константы RAMEND, которая определена в m8def.inc и хранит размер SRAM out SPL,R16;скопируем значение из R16 в SPL ldi R17,high(RAMEND);скопируем в R16 старший байт из константы RAMEND, которая определена в m8def.inc out SPH,R17;скопируем значение из R17 в SPH   ;КОД ОСНОВНОЙ ПРОГРАММЫ main: rcall init_USART ldi R16,0b01010011 rcall USART_send;шлем 0x53, это ASCII код знака 'S' ldi R16,0b00101101 rcall USART_send;шлем 0x2D, это ASCII код знака '-' ldi R16,0b01000101 rcall USART_send;шлем 0x45, это ASCII код знака 'E' loop: rjmp loop   ;ПОДПРОГРАММА ИНИЦИАЛИЗАЦИИ USART МОДУЛЯ init_USART:ldi R16,high(UBRR_value);устанавливаем скорость 9600 бод out UBRRH,R16 ldi R16,low(UBRR_value) out UBRRL,R16 ldi R16,(1<<TXEN);разрешаем работу передатчика out UCSRB,R16 ldi R16,(1<< URSEL)|(1<< UCSZ0)|(1<< UCSZ1) out UCSRC,R16;устанавливаем режим 8 бит данных, без проверки четности, асинхронный режим ret   USART_send:sbis UCSRA,UDRE;ждем пока бит UDRE регистра UCSRA не будет пуст rjmp USART_send out UDR,R16;посылаем байт по UART, кладем данные в регистр UDR ret

 

Код на С для ATmega8

/* * GccApplication4.cpp * * Author: Admin */ #define F_CPU 8000000 // Рабочая частота контроллера #define BAUD 9600L // Скорость обмена данными #define UBRRL_value (F_CPU/(BAUD*16))-1 //Согластно заданной скорости подсчитываем значение для регистра UBRR #include <avr/io.h> #include <util/delay.h> void init_USART() { UBRRL = UBRRL_value; //Младшие 8 бит UBRRL_value UBRRH = UBRRL_value >> 8; //Старшие 8 бит UBRRL_value UCSRB |=(1<<TXEN); //Бит разрешения передачи UCSRC |=(1<< URSEL)|(1<< UCSZ0)|(1<< UCSZ1); //Устанавливем формат 8 бит данных } void send_UART(char value) { while(!(UCSRA & (1 << UDRE))); // Ожидаем когда очистится буфер передачи UDR = value; // Помещаем данные в буфер, начинаем передачу } int main(void) { init_USART(); //инициализация USART в режиме 9600/8-N-1 send_UART(0x53); //посылаем ASCII код знака 'S' send_UART(0x2D); //посылаем ASCII код знака '-' send_UART(0x45); //посылаем ASCII код знака 'E' while(1) { _delay_ms(1000); } }

  /* * GccApplication4.cpp * * Author: Admin */ #define F_CPU 8000000 // Рабочая частота контроллера #define BAUD 9600L // Скорость обмена данными #define UBRRL_value (F_CPU/(BAUD*16))-1 //Согластно заданной скорости подсчитываем значение для регистра UBRR   #include <avr/io.h> #include <util/delay.h>   void init_USART() { UBRRL = UBRRL_value; //Младшие 8 бит UBRRL_value UBRRH = UBRRL_value >> 8; //Старшие 8 бит UBRRL_value UCSRB |=(1<<TXEN); //Бит разрешения передачи UCSRC |=(1<< URSEL)|(1<< UCSZ0)|(1<< UCSZ1); //Устанавливем формат 8 бит данных }   void send_UART(char value) { while(!(UCSRA & (1 << UDRE))); // Ожидаем когда очистится буфер передачи UDR = value; // Помещаем данные в буфер, начинаем передачу }   int main(void) { init_USART(); //инициализация USART в режиме 9600/8-N-1 send_UART(0x53); //посылаем ASCII код знака 'S' send_UART(0x2D); //посылаем ASCII код знака '-' send_UART(0x45); //посылаем ASCII код знака 'E' while(1) { _delay_ms(1000); } }

 

Результат работы в Proteus:

Скачать hex файл прошивки и проект в Proteus — ссылка

 

Если к TxD микроконтроллера подключить логический анализатор в Proteus, то можно увидеть осциллограмму работы USART. Я продемонстрирую скриншот с логического анализатора, с фрагментом импульсов для знака ‘E’ (0x45).

 

 

 

P.S. Если вы захотите создать собственный проект в Proteus, то вам необходимо настроить контролер ATmega8 на 8 МГц (для работы UART), как это сделать см. скриншот ниже:

 



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2020-01-14 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: