Прием посылки из нескольких байт через USART МК ATMEGA168
Эта запись находится в рубриках: "Полезный опыт и Справочные материалы".
Вы можете комментировать здесь либо в любимой социальной сети.
|
Последовательная передача информации цифровыми сигналами имеет широкое применение в бытовой и промышленной электронике. Дистанционное управление телевизором, обмен информацией персонального компьютера с USB устройствами, передача данных о работе разветвленных систем по промышленным шинам, например, MODBUS - все перечисленные способы передачи данных основаны на сигналах, состоящих из многобайтных посылок, периодически следующих от управляющего устройства к принимающему прибору. Организации приема посылки из множества байт микроконтроллером ATmega168 посвящена эта статья.
Многобайтные посылки
Передавать информацию по одному байту очень медленно и неудобно. При измерении аналоговой величины с хорошей точностью в одном байте невозможно передать значение более 255. При объединении в одну информационную сеть более двух устройств приходится использовать адресацию, что требует расширения информационной посылки до нескольких байт.
Программируемый логический контроллер управляет работой прибора 1 и прибора 2.
Допустим, на одной шине данных, подключенной к интерфейсу управляющего программируемого логического контроллера, размещены два прибора. Контроллер, управляя работой двух приборов, должен адресовать информацию то одному, то другому. Для определения, какая посылка какому прибору предназначена, в посылке содержится байт с адресом прибора. В такой сети движутся посылки из нескольких байт, каждая посылка должна содержать байт с адресом и байт с контрольной суммой, подтверждающей достоверность информации. Посылки для разных приборов могут содержать разное количество байт. Например, для прибора 1 посылка содержит 5 байт, а для прибора 2 посылка содержит 8 байт. Прибор должен "узнавать" посылку, предназначенную именно ему. Определение требуемой посылки может происходить не только по адресу, но и по количеству байт в посылке.
Посылки из 8 байт
Сигналы из посылок по восемь байт.
Передаваемые современными компьютерами и контроллерами сигналы имеют временные параметры, поддерживаемые с высокой точностью. Принимающее устройство получает информацию, опираясь на анализ интервалов времени электрических сигналов. Важной характеристикой сигнала является скорость передачи.
Существует перечень стандартных скоростей. Одни из наиболее часто встречающихся скоростей передачи информации: 9600 и 19200 бит в секунду. Для приема одного байта достаточно правильно указать настройки портов передающего и принимающего устройств.
Если нужно принять посылку из нескольких байт, то принимающее устройство должно использовать критерии, позволяющие определить принадлежность нескольких байт к одной посылке, определять первый и последние байты в посылке, не объединять ошибочно байты из разных посылок в одну. Проще всего объединить несколько байт в одну посылку, направляя их в канал связи через короткие интервалы времени, как изображено на рисунке. Интервал между байтами может быть ограничен некоторым значением, например, 0,6 мс. Если интервал уменьшается, то байты по прежнему относятся к одной посылке - это может понадобиться для увеличения скорости передачи, но если интервал длиннее критического значения, то байт будет отнесен принимающим прибором к следующей посылке.
На рисунке первой изображена форма сигнала посылки из 8 байт в упрощенном виде. Короткий временной интервал 0,5 мс между байтами позволяет принимающим прибором распознать одну посылку. Между посылками большие промежутки времени различной длины, как изображено на нижнем рисунке.
Виды последовательных интерфейсов, взаимодействующих с микроконтроллером.
Информационные посылки проходят через различные схемы, преобразующие сигнал приходящий из передающих каналов различной природы в электрический формат, соответствующий требованиям порта USART микроконтроллера. Временные параметры передачи каждого байта в посылке должны соответствовать требованиям USART, указанным в программе.
Алгоритм приёма посылки
Из множества байт посылки в памяти микроконтроллера формируется массив данных для дальнейшей обработки. В рассматриваемом примере 8 байтам посылки соответствует 8 ячеек памяти, расположенных в адресном пространстве друг за другом. Для записи посылки в память микроконтроллера разработана подпрограмма, предназначенная для использования в составе различных программ микроконтроллера. Подпрограмма работает по алгоритму, изображенному на рисунке.
Алгоритм работы подпрограммы приема посылки из 8 байт.
Микроконтроллер переходит к выполнению подпрограммы при поступлении байта в порт USART. Из регистра порта байт переписывается в ячейку ОЗУ, где хранится короткое время, а потом будет скопирован в другую ячейку ОЗУ, составляющую массив данных посылки. При получении байта останавливается таймер, в котором фиксируется время с момента получения последнего байта. Выполняется проверка значения времени, сохраненного в таймере. Если время превышает критическое значение, значит определен первый байт в посылке. Если время не превышено, то выполняется вторая проверка, не было ли ранее переполнения таймера. Если переполнения не было, то это означает, что продолжается прием посылки и байт записывается в формирующийся массив. В любом случае, после проверки каждого интервала времени признак переполнения устанавливается в состояние, соответствующее отсутствию переполнения.
При приеме следующего байта будет опять выполнена эта проверка. Для записи байта в свою ячейку массива увеличивается значение в специальной регистровой паре на 1, хранящей адрес ячейки из массива. Затем производится запись принятого байта в ячейку с вычисленным адресом в предыдущей операции. Производится проверка: заполнен весь массив из восьми байт? Если массив заполнен, то пара регистров, в которой хранится адрес ячейки массива, подготавливается для записи первого байта следующей посылки. В конце подпрограммы включается таймер для измерения времени до приема следующего байта.
Программа приема посылки
Программа с использованием алгоритма, описанного только что, составлена на ассемблере микроконтроллера ATMEL AVR. В составе программы имеется подпрограмма, в которой реализован алгоритм представленный ранее. Текст программы содержит необходимые директивы и команды для максимального упрощения использования в текстовом редакторе пакета AVRstudio 4.12 и предназначен для копирования с экрана при разработке программ. В соответствии с правилами текстового редактора AVRstudio комментарии предваряются двоеточием, директивы - точкой, метки заканчиваются двоеточием.
В программу входят две подпрограммы INIT_USART и RECEIVER_BAIT. Подпрограмма INIT_USART предназначена для установки режима работы порта USART. Подпрограмма RECEIVER_BAIT соответствует рассмотренному выше алгоритму.
INIT_USART начинается с метки INIT_USART и заканчивается командой возврата из подпрограммы RET. Если INIT_USART выделена в отдельную подпрограмму, то она должна находится в конце программного текста, где обычно находятся все подпрограммы, как сделано в примере. Программа не содержит команды вызова подпрограммы INIT_USART. При использовании приведенного здесь текста программист в зависимости от функций создаваемой программы вводит команду вызова подпрограммы INIT_USART. Если инициализация порта выполняется один раз в начале выполнения программы микроконтроллером, то оформлять инициализацию USART в виде отдельной подпрограммы ненужно. В этом случае метку INIT_USART и команду RET следует убрать из текста и перенести команды этой подпрограммы в начало основной программы.
Установка режима USART производится путем записи констант в специальные регистры порта. В регистр UBRR0L порта USART записывается константа 47, устанавливающая режим работы порта с информацией, поступающей со скоростью 19200 бод. Константа 47 используется при частоте тактового генератора 14,7456 МГц. В приведенном тексте подпрограммы инициализации USART установлен режим, при котором порт может принимать информацию и передавать, разрешаются прерывания при приеме байта и при передаче. Установка режима выполняется записью единиц в специальные биты регистра UCSR0B.
Прием информации может выполняться с различной скоростью. Для изменения скорости приема в регистр UBRR записывается соответствующая константа. Асинхронный режим работы 8 бит без проверки на четность устанавливается по умолчанию.
Константы, записываемые в регистр UBRR0L, для установки скорости приема данных при частоте тактового генератора 14,7456 MГц.
Скорость приема информации |
Константа |
4800 |
191 |
9600 |
95 |
14400 |
63 |
19200 |
47 |
28800 |
31 |
38400 |
23 |
57600 |
15 |
Назначение и названия битов регистра UCSR0B для настройки USART.
Название бита |
Назначение |
RXCIE0 |
Разрешение прерывания uart rxc после окончания приема если в бите установлена 1. |
TXCIE0 |
Разрешение прерывания uart txc если в бите установлена 1. При завершении передачи байта и отсутствии второго байта поступает прерывание UART TXC. |
UDRIE0 |
Разрешается прерывание при очистке регистра данных. Если в бите установлена 1, то разрешено прерывание UART DRE. |
RXEN0 |
Разрешается прием при установке бита в 1. Вход контроллера подключается к порту. |
TXEN0 |
Разрешается передача при установке бита в 1. Выход контроллера подключается к порту. |
Подпрограмма RECEIVER_BAIT является обработкой прерывания, поэтому заканчивается командой RETI. В тексте программы директивы выделены зеленым цветом, основная программа синим, инициализация USART красным. Текст подпрограммы RECEIVER_BAIT имеет темно-синий цвет.
.DEF TEMP=R16
.DEF TF=R26
.DEF ZIRO=R27
;прерывание по переполнению таймера 0
.ORG OVF0ADDR LDI TF,0 RETI ;запись нуля в регистр, используемый в качестве индикатора
;переполнения таймера
;прерывание по приему байта
.ORG URXCaddr JMP RECEIVER_BAIT
START:
LDI TEMP,LOW(RAMEND) ;ИНИЦИАЛИЗАЦИЯ УКАЗАТЕЛЯ СТЕКА
OUT SPL,TEMP
LDI TEMP,HIGH(RAMEND)
OUT SPH,TEMP
CLR ZIRO
PROGR:
……………
……………
……………
……………
RJMP PROGR
INIT_USART:
LDI TEMP, 47 ;установка скорости обмена 19200
STS UBRR0L, TEMP ;для частоты тактового 14,7456 Мгц
LDI TEMP, (1<<TXEN0)+(1<<TXCIE0)+(1<<RXEN0)+(1<<RXCIE0)
;передатчик и приемник готов к работе, разрешены прерывания uart rxc и uart txc
STS UCSR0B, TEMP ;вход микроконтроллера подключается к порту usart
RET ;возврат из подпрограммы
; программа перейдет сюда по приему байта
RECEIVER_BAIT:
PUSH TEMP ;coхранение в стеке регистра
IN TEMP, SREG
PUSH TEMP ;сохранение в стеке регистра состояния
PUSH R31 ;сохранение данных других программ
PUSH R30 ;сохранение данных других программ
;адрес первой ячейки памяти массива $111
LDS R30, $100 ;сохранение данных этой программы сохраненных ранее
LDI R31, 1 ;старшую половину адреса в младший регистр
LDS TEMP, UDR0
STS $106, TEMP ;сохранение полученного из usart байта в памяти
;—————
;остановка и обнуление таймера сохранение результата в $105
OUT TCCR0B, ZIRO ;остановка таймера
IN TEMP, TCNT0 ;пересылка содержимого таймера-счетчика
STS $105, TEMP ;сохранение результата счета в памяти
OUT TCNT0, ZIRO ;сброс базового счетчика
;—————-
LDS TEMP, $105 ;время между кадрами в условных единицах
CPI TEMP, 10 ;выяснение: время между кадрами
;1 такт соответствует одному периоду тактовой частоты генератора, что составляет 0,000’000’067 с.
;критическое время, измеренное таймером: 0,000’000’067 * 1024 = 0,000’068’608, 0,000’068’608 * 10 ;=0,000’686’08 секунд
BRLO T_MIN ;переход. время между кадрами меньше межбайтового интервала
LDI R30, $10 ;сброс адреса. время больше межбайтового интервала
RJMP GO_FREIM ;переход на продолжение приема посылки
T_MIN:
CPI TF, 0 ;проверка регистра-индикатора. Переполнение таймера было?
BRNE GO_FREIM ;переход если переполнения не было. время говорит о продолжении посылки
LDI R30, $10 ;сброс адреса. это малое время вследствие недавней перезагрузки таймера
;а не приема байта только что. Значит, это большой интервал
GO_FREIM: ;интервал мал (продолжение посылки)
LDI TF, 1 ;сброс регистра-индикатора переполнения после приема байта
INC R30 ;увеличивается номер с каждым байтом
LDS TEMP, $106 ;запись в память байта
ST Z, TEMP ;по вычисленному адресу ($111-$118)
MOV TEMP, R30
SUBI TEMP, $18 ;проверка израсходовано 8 адресов?
BRSH RES_ADR ;больше $18 или равно
RJMP NO_R_ADR ;меньше $18
RES_ADR: ;завершился прием посылки
LDI R30, $10 ;подготовка указателя адреса для приема следующей посылки
NO_R_ADR: ;это не конец посылки
; включение таймера
LDI TEMP, 5
OUT TCCR0B, TEMP ;коэффициент деления предделителя таймера 1024
LDI TEMP, (1<<TOIE0)
STS TIMSK0, TEMP ;разрешение прерывания по переполнению таймера
;———————-
STS $100, R30 ;сохранение в памяти для последующего запуска подпрограммы
POP R30 ;восстановление данных для других программ
POP R31 ;восстановление данных для других программ
POP TEMP
OUT SREG, TEMP
POP TEMP
RETI ;возврат из подпрограммы после обработки прерывания
;———————————————————————————————–
Возможно, при размещении на сайте какая-то часть кода утерялась. Прикладываем авторский вариант в файле .doc:
В начале текста программы с помощью директивы DEF присваиваются условные имена регистрам. TEMP – регистр временного хранения, регистр TF – регистр-индикатор переполнения таймера, ZIRO – регистр в котором хранится 0. Удобно зарезервировать регистр с значением 0, это позволяет упростить программу и сократить время на ее выполнение.
.DEF TF=R26
.DEF ZIRO=R27
С помощью директивы ORG определяются действия программы при обработке прерываний. Прерывание, вызванное переполнением таймера с номером 0, имеет имя OVF0. Его обработка заключается в записи 0 в индикатор переполнения с помощью команды LDI TF,0.
.ORG OVF0addr LDI TF,0 RETI
При приеме байта портом USART выполняется соответствующее прерывание с именем URXC.
.ORG URXCaddr JMP RECEIVER_BAIT
Происходит переход на выполнение специальной подпрограммы с именем RECEIVER_BAIT. Выполнение программы микроконтроллером начинается с нескольких команд описывающих инициализацию стека:
START:
LDI TEMP, LOW (RAMEND)
OUT SPL, TEMP
LDI TEMP, HIGH (RAMEND)
OUT SPH, TEMP
Далее производится запись нуля в специально зарезервированный для этого регистр. Этому регистру присвоено условное имя ZIRO.
CLR ZIRO
При приеме байта портом USART происходит переход к выполнению подпрограммы RECEIVER_BAIT. В начале выполнения микроконтроллером программы производится инициализация порта USART. Это необходимо для указания режима роботы порта. Инициализация производится подпрограммой INIT_USART.
RECEIVER_BAIT – подпрограмма позволяющая принять посылку из 8 байт, поступающих в порт USART и сохранить ее в памяти микроконтроллера. В начале работы подпрограммы в стеке сохраняются регистр флагов процессора и регистровая пара Z, состоящая из регистров R30 и R31. Это необходимо для предотвращения нарушения работы основной программы микроконтроллера и других подпрограмм. Подпрограмма RECEIVER_BAIT может быть вызвана в любой момент, содержимое регистровой пары Z должно сохраниться для дальнейшей работы микроконтроллера после окончания выполнения подпрограммы RECEIVER_BAIT.
LDS R30, $100
В младшем регистре R30 пары Z восстанавливается значение, подсчитанное при предыдущем выполнении подпрограммы RECEIVER_BAIT. Это значение хранилось в ячейке ОЗУ с адресом $100.
LDI R31, 1
В регистр R31, старший регистр пары Z записывается старшая половина адреса массива ячеек, в который будет записана принятая посылка. Адреса этих ячеек памяти: $111-$118. Значение адреса разбивается на две части, в старшую половину регистровой пары вносится: сколько раз в значении адреса поместится число $100, поэтому в R31 записывается 1.
LDS TEMP, UDR0
STS $106, TEMP
Принятый байт, из-за приема которого была вызвана эта подпрограмма, записывается в ячейку памяти с адресом $106.
OUT TCCR0B, ZIRO
IN TEMP, TCNT0
STS $105, TEMP
OUT TCNT0, ZIRO
Для определения временного интервала между предыдущим байтом и полученным производится остановка таймера. Выполняется запись результата подсчета времени в ячейку с адресом $105 памяти микроконтроллера и производится обнуление таймера. После выполнения предварительных операций в программе следуют команды определения соответствия времени между байтами критерию принадлежности к одной посылке.
LDS TEMP, $105
CPI TEMP, 10
Величина временного интервала сравнивается с константой 10. Если принимаемые байты относятся к одной посылке, то с помощью команды BRLO T_MIN производится переход к выполнению команд, находящихся после метки T_MIN.
T_MIN:
CPI TF, 0
BRNE GO_FREIM
LDI R30, $10
Выполняется еще одна проверка длительности измеренного временного интервала. Таймер может измерять интервалы времени небольшой продолжительности, но при измерении временного интервала, больше чем может измерить таймер, происходит его переполнение, которое фиксируется в специальном регистре-индикаторе TF, зарезервированном как индикатор переполнения. Если переполнения не было, значит, интервал короткий, так как значение времени, измеренное таймером, было проверено ранее. Если определено что принятый байт первый в посылке, так как значение таймера больше 10 или было переполнение, то выполняются команды:
LDI R30, $10
RJMP GO_FREIM
В этих командах производится запись в младший регистр пары Z адреса первой ячейки массива данных посылки. Затем выполняется безусловный переход к командам, записанным после метки GO_FREIM для продолжения приема и записи посылки нескольких байт.
GO_FREIM:
LDI TF, 1
INC R30
LDS TEMP, $106
ST Z, TEMP
После приема первого байта посылки регистр-индикатор переполнения таймера TF программно устанавливается в 1. Команда LDI TF, 1 так расположена в тексте программы, что если она будет выполняться после приема второго и других байтов в посылке, то регистр-индикатор TF будет устанавливаться в 1. Условные и безусловные переходы направлены так, что при переполнении таймера вследствие продолжительного временного интервала регистр-индикатор сначала будет проанализирован, а потом уже установлен в 1.
Для формирования массива из байт посылки увеличивается адрес, указывающий в какую ячейку памяти записать принятый байт. Адрес находится в паре регистров R30, R31. Принятый байт записывается в ячейку памяти по адресу, хранящемуся в регистровой паре Z, состоящей из R30, R31. Кроме контроля коротких временных интервалов программа проверяет количество байт в посылке, контролируя сколько ячеек для записи массива было израсходовано.
MOV TEMP, R30
SUBI TEMP, $18
BRSH RES_ADR
RJMP NO_R_ADR
RES_ADR:
LDI R30, $10
NO_R_ADR:
Последняя ячейка массива имеет адрес $118. Младшая половина адреса хранится в регистре R30. При переходе к записи следующего байта посылки происходит увеличение адреса только изменением значения в R30. Контролируя содержимое R30 можно определить конец массива. Если весь массив заполнен, то происходит переход на метку RES_ADR, в результате чего подготавливается регистр R30 для начала записи следующего массива. Сформированный массив будет использован в работе микроконтроллера. Если в R30 нет числа $18, то произойдет переход на метку NO_R_ADR для продолжения формирования массива при поступлении нового байта. После операций сохранения массива контроллер приступает к управлению таймером. Выполняется включение таймера.
LDI TEMP, 5
OUT TCCR0B, TEMP
LDI TEMP, (1<<TOIE0)
STS TIMSK0, TEMP
Происходит включение таймера указанием коэффициента деления частоты тактового генератора. Разрешается обработка прерывания по переполнению таймера. Подпрограмма завершается операциями сохранения и восстановления данных для возврата в основную программу.
STS $100, R30
POP R30
POP R31
POP TEMP
OUT SREG, TEMP
POP TEMP
В ячейке $100 сохраняется адрес ячейки массива, куда был записан последний байт. Из стека переписывается содержимое пары Z, регистра TEMP и регистра флагов микроконтроллера.
RETI
Выполняется возврат из подпрограммы.
Особенности приема посылки
В результате работы программы принятая посылка сохранена в массиве из восьми ячеек находящихся с адреса $111 по $118. Обработка полученных данных происходит в других участках программы микроконтроллера: проверяется контрольная сумма, в случае адресной посылки сверяется адрес, содержащийся в посылке с адресом прибора, производится дальнейшая обработка информации. Если принимающий прибор ориентирован на прием посылки 8 байт, а в канале информации будут присутствовать посылки по 7 байт или менее, то они будут записаны в первые ячейки массива, но проверка контрольной суммы должна запретить их дальнейшую обработку. Если в посылке более восьми байт, то они циклически будут записываться в восемь ячеек памяти, а при проверке контрольной суммы также будет наложен запрет на использование этой информации из-за неверной контрольной суммы.
Модификация программы для приема различных посылок
Приведенный тест программы может быть легко модифицирован для работы с другими параметрами канала связи. Адаптация к другой скорости приема проводится в подпрограмме INIT_USART в первой команде LDI TEMP, 47. Вместо константы 47 следует записывать другую константу, соответствующую требуемой скорости, ориентируясь на таблицу в статье. Если требуется принимать посылки другой длины, то нужно изменить проверку последнего адреса в массиве в команде
SUBI TEMP, $18 ;проверка израсходовано 8 адресов?
Например, при приеме посылки из четырех байт сверять с константой $14, а при приеме посылки из 14 байт с константой $1E. Изменение интервала между байтами в посылке потребует изменения в проверке числа, накопленном в таймере.
Автор Денисов П.К., simferopol1970 {not_for_spam} gmail.com, Симферополь.
Метки: AVR
Радиолюбителей интересуют электрические схемы:
Компаратор фазы сигнала тахогенератора с полым немагнитным ротором
Расчет количества витков в катушке