Очень часто требуется связать микроконтроллер с компьютером. Проще всего для этого использовать интерфейс UART. В этой статье постараюсь подробно рассказать что это за интерфейс и как с ним работать.
Интерфейс UART имеет две сигнальные линии – RxD и TxD. RxD – линия приёма данных, а TxD – передачи. Чтобы подключить микроконтроллер к компьютеру нужен какой-нибудь переходник, о котором я расскажу позже, а сейчас покажу как подключить этот самый переходник к микроконтроллеру. Подключается он по такой схеме:
Как видно, всё очень просто. Земли переходника и микроконтроллера объединяются, а сигнальные линии соединяются крест-накрест, то есть RxD микроконтроллера на TxD переходника, а RxD переходника на TxD микроконтроллера, поскольку RxD – линия приёма, а TxD – передачи.
Переходники.
Как я и говорил, расскажу немного о переходниках. Существуют переходники USB<->UART и RS232<->UART. Соответственно первые подключаются к компу через USB порт, а вторые – через RS232 aka COM порт. Переходник RS232<->UART можно собрать на специальной микросхеме, самая известная из них – MAX232. Вот схема такого переходника:
Также есть микросхема MAX3232. Это аналог MAX232, только выходные уровни у неё не 5В, а 3,3В. Ещё можно собрать такой переходник на 2-х транзисторах.
Переходник USB<->UART можно собрать на микроконтроллере, а можно на специальных микросхемах вроде FT232RL или PL-2303. Также в качестве такого переходника можно использовать датакабель от старых Сименсов.
Как проверить переходник?
Проверяется переходник очень просто. Нужно соединить выводы RxD и TxD и попробовать послать байт из терминальной программы на компьютере. Он должен тут же придти обратно.
В качестве терминальной программы я использую Terminal(скачать её можно в конце статьи). Итак, запустим терминалку и попробуем проверить переходник.
Для начала в графе “COM port” выберем порт, выберем скорость (я предпочитаю 9600) и нажмём “Connect”. Теперь мы подключились к порту и попробуем что-нибудь отправить. Как видно, мой переходник отлично работает и переданные байты возвращаются.
Подключаем микроконтроллер.
Переходник собран и работает и теперь мы попробуем написать простенькую программку для микроконтроллера, которая будет просто отправлять символ в порт.
Для начала разберемся с инициализацией. Вот код инициализации:
.equ Clock = 8000000
.equ BaudRate = 9600
.equ UBRR_Value = Clock/(16*BaudRate)-1
;======================================================
ldi r16,low(UBRR_Value)
out UBRRL,r16; Устанавливаем скорость
ldi r16,high(UBRR_Value)
out UBRRH,r16
;======================================================
ldi r16, (1<<RXEN)|(1<<TXEN); Подключаем приёмник и
out UCSRB,r16; передатчик.
;—————————————————–
ldi r16, (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1)
out UCSRC, r16; 8 бит данных, 1 стоп бит
Разберём этот код по порядку. Сначала мы определяем скорость, с которой нам нужно работать и тактовую частоту микроконтроллера. Тактовую обязательно нужно указать правильно, иначе вместо наших байтов в терминалку посыпется мусор всякий. Также, при работе с UART, нужно использовать как можно более стабильный тактовый генератор. Лучше всего внешнй кварц. После этого, вычисляется значение, которое нужно подгрузить в регистры, задающие скорость – UBRRL и UBRRH (младший и старший байты соответственно). После того, как скорость настроена, включается передатчик и приёмник записью единиц в биты RXEN и TXEN в регистре UCSRB. Давайте подробно рассмотрим значение других нужных нам битов этого регистра.
- RXCIE, TXCIE и UDRIE – биты, разрешающие прерывания по приему байта, окончанию передачи байта и пустом регистре UDR соответственно. Установкой их в 1 разрешаем прерывания.
- RXEN, TXEN – как я уже сказал, биты, включающие приёмник и передатчик соответственно. Установкой в 1 включаем приёмник или передатчик.
Остальные бты используются крайне редко и мы их рассматривать не будем. Теперь рассмотрим значение некоторых битов оставшихся двух регистров – UCSRA и UCSRC. Начнём с UCSRA:
- TXC, RXC и UDRE – флаги прерываний по окончанию передачи, приёма и по опустошению регистра данных.
- U2X – если записать в этот бит 1, то скорость UART удвоится.
- UPE – флаг ошибки чётности. При ошибке он выставится в 1.
Теперь UCSRC. Тут нас интересуют лишь биты, задающие размер одного байта – UCSZ0 и UCSZ1. Для стандартной посылки 8 бит, нужно записать в них единицы.
Для прима и передачи данных по UART’у в микроконтроллере есть регистр UDR. Он двойной, то есть, чтобы отправить данные нужно их побайтно записать в этот регистр, а чтобы принять – дождаться окончания приёма и просто считать их из этого же регистра.
Итак, напишем программку, которая будет в цикле посылать буковку i в порт. Сразу приведу её текст:
;Пример работы с интерфейсом UART.
;Автор lpa
;http://radioelektr.ru
;======================================================.include “m16def.inc”; Используем Мегу16
;======================================================
.equ Clock = 8000000
.equ BaudRate = 9600
.equ UBRR_Value = Clock/(16*BaudRate)-1;======================================================
ldi r16,low(UBRR_Value)
out UBRRL,r16; Устанавливаем скоростьldi r16,high(UBRR_Value)
out UBRRH,r16;======================================================
ldi r16, (1<<RXEN)|(1<<TXEN); Подключаем приёмник и
out UCSRB,r16; передатчик.;—————————————————–
ldi r16, (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1)
out UCSRC, r16; 8 бит данных, 1 стоп бит;—————————————————–
Main:
sbis UCSRA,UDRE
rjmp pc-1; Ожидание готовности передатчикаldi r16,’i’; Отправка байта
out UDR,r16rjmp main; Зацикливаемся
;======================================================
В начале идёт процедура инициализации, а потом в цикле командой sbis мы проверяем, не опустошился ли регистр данных. Если UDR готов, мы посылаем байт в порт.
Как и говорил, в микроконтроллерах AVR есть три прерывания, которые относятся к этому интерфейсу – по приёму байта, по окончанию передачи и по опустошению регистра данных. Так что байт можно отправлять в прерывании по опустошению регистра данных. Немного перепишем программку, и она будет выглядеть так:
;Пример работы с интерфейсом UART.
;Автор lpa
;http://radioelektr.ru
;======================================================.include “m16def.inc”; Используем Мегу16
;======================================================
.equ Clock = 8000000
.equ BaudRate = 9600
.equ UBRR_Value = Clock/(16*BaudRate)-1;======================================================
.ORG $000
rjmp RST
.ORG $002
reti
.ORG $004
reti
.ORG $006
reti
.ORG $008
reti
.ORG $00A
reti
.ORG $00C
reti
.ORG $00E
reti
.ORG $010
reti
.ORG $012
reti
.ORG $014
reti
.ORG $016
reti
.ORG $018
rjmp Send_Byte
.ORG $01A
reti
.ORG $01C
reti
.ORG $01E
reti
.ORG $020
reti
.ORG $022
reti
.ORG $024
reti
.ORG $026
reti
.ORG $028
reti.ORG INT_VECTORS_SIZE
;======================================================
Send_Byte:; Обработчик прерывания
ldi r16,’i’; Отправка байта
out UDR,r16RETI
;======================================================
Rst:
ldi r16,low(RAMend)
out SPL,r16ldi r16,high(RAMend)
out SPH,r16; Инит стека;————————————————
ldi r16,low(UBRR_Value)
out UBRRL,r16; Устанавливаем скоростьldi r16,high(UBRR_Value)
out UBRRH,r16;======================================================
ldi r16, (1<<RXEN)|(1<<TXEN)|(1<<UDRIE); Подключаем приёмник и
out UCSRB,r16; передатчик.;—————————————————–
ldi r16, (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1)
out UCSRC, r16; 8 бит данных, 1 стоп битSEI; Разрешаем прерывания
;—————————————————–
Main:
rjmp main; Зацикливаемся
;======================================================
Как видно, здесь в главном цикле никаких действий не производится, а байт отправляется в прерывании. Кстати, принимать бат тоже очень удобно в прерывании по приёму байта.
Также интерфейс UART очень удобно использовать при отладке программ. К примеру, если нужно понять, проходит ли контроллер определённый кусок кода или нет. Для эт ого в нужном месте нужно просто отправить байт и из терминальной программы судить прорабатывает контроллер этот кусок кода или нет. Когда нужно узнать, что находится в определённом регистре, тоже можно слить содержимое регистра в порт.
radioelektr.ru