
Микроконтроллеры AVR
.pdfldi |
r16,8 |
;r1 содержит анализируемое число |
;счетчик цикла |
||
clr |
r0 |
;счетчик числа единиц в r1 |
loop: |
|
|
sbrc r1,0 |
;инкремент r0, если бит 0 r1 равен единице |
|
inc |
r0 |
|
lsr |
r1 |
;логический сдвиг r1 на один бит вправо |
dec |
r16 |
|
cpi |
r16,0x00 |
|
brne loop |
;бесконечный цикл |
|
rjmp PC |
|
Контрольные вопросы:
1.Логические команды.
2.Команды побитовой инверсии и дополнения до двух.
3.Каким образом реализуется команда TST? Какие способы ее реализации Вы еще можете предложить?
4.Какое значение принимает флаг С процессора после выполнения команды сдвига?
5.Отличия команд сдвига и вращения.
6.Отличия арифметического и логического сдвигов.
7.Реализация команд сдвигов и вращения влево через команды сложения.
8.Наращивание разрядности команд сдвигов.
9.Докажите, что при выполнении команд сдвига флаг S будет являться копией
флага C, если V принимает значение N C, а S всегда равен N V. 10.Алгоритм реализации операции умножения с помощью команд сдвига и
сложения.
Лабораторная работа №4.
Система команд AVR: команды манипуляций с битами. Модульное программирование. Подпрограммы
Цель работы: знакомство с командами манипуляций с битами, реализацией подпрограмм.
Порядок выполнения работы (п.п. 1-3 выполняются во внеаудиторное время):
1.Ознакомьтесь с теоретической частью лабораторной работы.
2.Разработайте блок-схемы программ для заданий 2-6.
3.Подготовьтесь к ответу на контрольные вопросы 1-10.
4.Выполните задания.
5.Защитите лабораторную работу.
К командам манипуляции с битами относятся команды установки и сброса отдельных разрядов в регистрах общего назначения и регистрах ввода/вывода.
Как уже говорилось, с помощью команд побитового И и ИЛИ реализуется сброс и установка битов регистров общего назначение. Еще четыре команды позволяют устанавливать и сбрасывать отдельные биты в регистрах
21

ввода/вывода. Команды SBI и CBI, соответственно, устанавливают и сбрасывают отдельные биты регистров ввода/вывода с адресами 0x00…0x1F. Команды BSET и BCLR устанавливают и сбрасывают отдельные биты регистра статуса процессора SREG (он имеет адрес 0x3F в адресном пространстве регистров ввода/вывода). На основе команд BSET и BCLR с помощью компилятора реализуется целая группа команд установки и сброса флагов (мнемоники команд этой группы начинаются с символов SE и CL).
В большинстве микроконтроллеров (в AVR – в том числе) отдельные выводы группируются в порты. У At90S2313 – два порта: 8-разрядный B и 7-разрядный D. Каждому выводу порта x (где x – это B или D) соответствует по одному разряду в трех регистрах: направления передачи (DDRx – Data Direction Register x), состояния внешнего вывода (PINx), и выходного регистра (PORTx). На рисунке 3 приводится обобщенная структура выводов At90S2313. Единица в соответствующем разряде DDRx открывает выходной буфер, разрешая тем самым передачу данных из соответствующего разряда регистра PORTx на внешний вывод Px.n. Операция чтения из регистра ввода/вывода PORTx, позволяет получить данные, которые записаны в PORTx. Операция чтения из регистра ввода/вывода PINx позволяет получить информацию о логическом уровне, присутствующем на выводе Px в действительности. В таблице 3 приведено описание режимов работы выводов микроконтроллера в зависимости от значений соответствующих разрядов DDRx и PORTx.
Vcc |
RD |
|
|
Подтяжка |
& |
|
|
Q D |
|
|
|
C |
WD |
|
|
|
данных |
||
|
DDRx.n |
|
|
Px.n |
Q D |
|
|
|
C |
WP |
Шина |
|
PORTx.n |
|
|
|
RL |
|
|
|
RP |
|
|
RD - сигнал чтения регистра DDRx RL - сигнал чтения регистра PORTx RP - сигнал чтения состояния вывода
WD - сигнал записи регистра DDRx WP - сигнал записи регистра PORTx Vcc - напряжение питания
микроконтроллера
Рисунок 3. Обобщенная функциональная схема выводов общего назначения микроконтроллера At90S2313
22
Таблица 3. Режимы работы выводов At90S2313 в зависимости от состояния регистров DDRx и PORTx
DDRxn |
PORTxn |
Вход/ выход |
Подтяжка |
Комментарий |
0 |
0 |
Вход |
Выкл. |
Третье состояние (высокий импеданс) |
0 |
1 |
Вход |
Включена |
Px.n будет источником тока, если на |
|
|
|
|
него извне подать логический ноль |
1 |
0 |
Выход |
Выкл. |
Низкий уровень, двухтактный выход |
1 |
1 |
Выход |
Выкл. |
Высокий уровень, двухтактный выход |
До сих пор в рамках данного курса мы рассматривали программы, реализующие алгоритмы в виде единого целого. Такой метод проектирования программ, называемый монолитным, подходит для целей обучения или решения простейших прикладных задач.
С увеличением сложности задачи и объема программы монолитный метод становится неприемлемым – разработчик просто не в состоянии удерживать в своей памяти все необходимые детали. Естественный выход из такой ситуации
– переход к модульному программированию, т.е., разбиению большой и сложной задачи на более простые и мелкие части. В языках программирования низкого уровня такими частями являются подпрограммы.
Для реализации подпрограмм необходимы команды вызова подпрограммы и возврата из подпрограммы. Эти команды являются особыми командами передачи управления – для их работы требуется сохранение адреса возврата из подпрограммы. Для такого сохранения обычно используют стек. В некоторых процессорах такой стек реализуется аппаратно: имеется специальная память (обычно – всего несколько ячеек) и счетчик ячеек стека. При помещении информации в стек этот счетчик увеличивается, при извлечении – уменьшается. В других процессорах (в том числе – в At90S2313) стек реализуется аппаратнопрограммно: программистом под стек отводится область памяти данных, для доступа используется специальный регистр – указатель стека (англ. Stack Pointer – SP). Указатель стека хранит адрес вершины стека. После помещения информации в стек его указатель автоматически уменьшается; перед извлечением – увеличивается. Основное достоинство программного стека – потенциально бόльший объем, чем у аппаратного. Однако, перед использованием такого стека обязательно нужно проинициализировать указатель стека значением адреса конца области стека!
Механизм вызова подпрограммы и возврата из нее заключается в следующем. Команда вызова подпрограммы сохраняет в стеке адрес ячейки памяти следующей за этой командой (т.е., адрес следующей команды) и загружает в программный счетчик адрес вызываемой подпрограммы. После этого выполняется тело подпрограммы, в конце которой находится команда возврата. Команда возврата извлекает из стека адрес возврата (т.е., адрес команды, следующей за командой вызова) и загружает его в программный счетчик, возвращая тем самым управление вызывающе программе.
23
At90S2313 поддерживает команды относительного (RJMP) и косвенного
(IJMP) вызова подпрограмм. Обе эти команды являются безусловными. Другие процессоры поддерживают команды условного вызова подпрограмм; также, может задаваться абсолютный адрес подпрограммы. Возврат из подпрограмм обеспечивает команда RET.
Использование подпрограмм влечет несколько проблем:
1.В процессе своей работы подпрограммы изменяют содержимое различных регистров, ячеек памяти. При этом нельзя допускать порчи переменных, используемых в вызывающей программе (сохранение контекста).
2.Если подпрограмма обрабатывает какие-то данные, эти данные необходимо ей передать (передача параметров).
3.Если результатом работы подпрограммы являются какие-то данные, то необходимо их передать вызывающей программе (возврат результата).
Для сохранения контекста, очевидно, необходимо скопировать все регистры, которые используются подпрограммой, в некоторую область памяти; после выполнения – восстановить содержимое регистров. Наиболее удобно для целей сохранения/восстановления использовать механизм стека. В простейшем случае, это может быть тот же стек, что применяется для сохранения адреса возврата из подпрограммы, в других случаях – отдельный программно реализуемый стек.
Передачу параметров в подпрограммы можно организовать: через стек, через регистры, через глобальные переменные (неявно). Наиболее простой в случае программирования на Ассемблере для At90S2313 способ – передача параметров через регистры.
Возврат результата может происходить аналогичными способами. Если подпрограмма должна возвращать булево значение (ЛОЖЬ/ИСТИНА, 0/1), то это можно делать с помощью флага T из регистра состояния процессора.
При оформлении подпрограммы в ее заголовке следует обязательно указывать:
-назначение подпрограммы;
-способ передачи параметров;
-способ возврата результата;
-используемые ресурсы (изменяемые в процессе работы регистры, переменные, используемый объем стека).
На практике часто возникает необходимость обеспечить интерфейс микроконтроллера с внешними устройствами (микросхемы памяти различных типов, драйверы индикаторов, таймеры реального времени и т.д.). Во многих случаях это достигается путем программной эмуляции того или иного протокола с помощью команд манипуляции битами регистров ввода/вывода и команд условного выполнения. На рисунке 4 приводятся подключение и временная диаграмма обмена At90S2313 с микросхемой АЦП ADS1210 через программно эмулируемый порт SPI. По линии MOSI (Master Output Slave Input) происходит передача данных от микроконтроллера к АЦП; по линии MISO
24

(Master Input Slave Output) – от АЦП к микроконтроллеру. Захват данных по этим линиям должен происходить по отрицательному фронту сигнала синхронизации SCK, формируемого микроконтроллером. Микросхема АЦП реагирует на сигналы SCK, MOSI и формирует сигнал MISO только в том случае, когда сигнал выборки /CS имеет низкий логический уровень. Ниже приводятся подпрограммы, обеспечивающие обмен At90S2313 и ADS1210.
SCK |
t |
At90S2313 |
ADS1210 |
MOSI |
|
|
|
|
|
|
PD3 |
MISO |
SDOUT |
|
I7 |
I6 |
I5 |
I1 |
I0 |
|
MOSI |
||||
t |
PD4 |
SDIO |
||||||||
MISO |
|
|
|
|
|
|
PD5 |
SCK |
SCLK |
|
O7 |
O6 |
O5 |
O1 |
O0 |
t |
CS |
||||
PD6 |
CS |
|||||||||
|
|
|
|
|||||||
|
|
ADS1210: захват входных данных |
|
|
|
|
||||
|
|
ADS1210: готовность выходных данных |
|
|
|
Рисунок 4. Обмен At90S2313 с микросхемой АЦП ADS1210
.EQU mosi_bit = 0x4
.EQU miso_bit = 0x3
.EQU |
sck_bit |
= |
0x5 |
.EQU |
ss_bit |
= |
0x6 |
;бит PORTx, отвечающий за линию MOSI ;бит PORTx, отвечающий за линию MISO ;бит PORTx, отвечающий за линию SCK ;бит PORTx, отвечающий за линию CS_ADC
;=================================================================== ;Подпрограмма инициализации SPI-порта
;r16 - используется spi_ini:
ldi r16,(EXP2(mosi_bit)|EXP2(sck_bit)|EXP2(ss_bit)|EXP2(cs_res_bit)) out DDRD,r16 ;разрешение выходов mosi, sck, ss
sbi PORTD,ss_bit sbi PORTD,cs_res_bit cbi PORTD,sck_bit cbi PORTD,mosi_bit
ret
;=================================================================== ;Подпрограмма эмуляциии SPI-порта
;r18 должен содержать передаваемый байт
;r17 содержит принятый байт |
|
;r16 - используется |
|
spi_emulation: |
;регистр сдвигаемой маски |
ldi r16,0x80 |
|
clr r17 |
;очистка регистра-приемника |
spi_m1: |
;MOSI=0 |
cbi PORTD,mosi_bit |
|
sbrc r18,7 |
; |
sbi PORTD,mosi_bit |
;MOSI=1 если нужно выдать 1 |
sbi PORTD,sck_bit |
;SCK=1 |
lsl r18 |
;сдвиг передаваемого байта |
sbic PIND,miso_bit |
;проверка уровня MISO |
or r17,r16 |
;SCK=0 |
cbi PORTD,sck_bit |
|
lsr r16 |
;сдвиг регистра-маски |
brne spi_m1 |
|
ret |
|
25

;=================================================================== ;Подпрограмма включения сигнала выборки АЦП
ADS1212_select:
cbi PORTD,ss_bit
ret
;=================================================================== ;Подпрограмма снятия сигнала выборки АЦП
ADS1212_unselect:
sbi PORTD,ss_bit
ret
Задания:
1.Пронаблюдайте работу программы из примера 8. Какую функцию выполняет оператор out SPL,r16 ?
2.Напишите подпрограмму, которая устанавливает флаг T, если выполняется условие (r0.0!=r1.7)&&( r0.3==r1.4)&&r1.2, и сбрасывает его в противном случае.
3.Напишите подпрограмму, которая производит умножение двух чисел, лежащих в диапазоне от 0 до 3, используя таблицу произведений.
4.Напишите программу, которая настраивает порт PB.1 как выход.
5.Напишите программу, которая настраивает Таймер 0 на синхронизацию от тактового сигнала микроконтроллера с коэффициентом деления 8.
6.Нарисуйте временную диаграмму работы драйвера 7-сегментного индикатора D1 на рисунке 5. Согласно нарисованной временной диаграмме разработайте подпрограмму, которая выводит 1 байт данных в драйвер D1.
|
|
D Q |
dp |
|
|
|
|
|
|
|
|
C |
g |
|
|
|
D Q |
DATA |
|
|
|
|
||
|
|
|
/CS |
|
|
|
C |
f |
|
|
|
D Q |
CLK |
|
|
|
|
SEL |
|
|
|
C |
e |
|
|
|
D Q |
|
|
|
|
|
|
|
|
|
C |
d |
|
|
|
D Q |
|
|
|
|
|
Vcc |
|
|
|
C |
|
|
|
|
c |
|
|
|
|
D Q |
|
|
|
|
|
|
|
|
|
C |
b |
|
|
|
D Q |
|
|
/CS |
& |
|
|
|
C |
|
|
||
CLK |
a |
|
||
|
D Q |
|
||
DATA |
|
|
|
|
|
|
C |
|
|
|
|
D1 |
D2 |
|
|
|
|
Рисунок 5. Схема индикации |
|
PB.1 |
At90S2313 |
|
PB.1
PB.1
PB.1
D3
SEL
26
Пример 8:
Показывает организацию вызова подпрограмм в микроконтроллерах AVR на примере преобразования ASCII-символов шестнадцатеричных чисел (‘0’…’9’ и ‘A’…’F’) в соответствующее им двоичное представление.
.INCLUDE "..\appnotes\2313def.inc" ;подключение файла со
.DSEG |
|
;спецификацией регистров ввода/вывода |
|
|
|
.ORG 0x60 |
.BYTE 10 |
;входной массив ASCII-символов |
InArr: |
||
OutArr: |
.BYTE 10 |
;выходной массив двоичных чисел |
.CSEG |
;сегмент кода |
|
rjmp Reset |
;вектор прерывания, вызываемого по сбросу микроконтроллера |
|
Reset: |
;начало программы |
ldi |
r16,0x90 |
|
out |
SPL,r16 |
;указатель X проинициализирован значением |
ldi |
XL,LOW(InArr) |
|
ldi |
XH,HIGH(InArr) |
;адреса начала массива InArr |
ldi |
YL,LOW(OutArr) |
;указатель Y проинициализирован значением |
ldi |
YH,HIGH(OutArr) |
;адреса начала массива OutArr |
ldi |
r17,10 |
|
loop: |
|
;передача исходного ASCII-символа |
ld r16,X+ |
||
rcall ascii_to_bin |
;вызов подпрограммы преобразования ASCII/двоич. |
|
st Y+,r16 |
;сохранение двоичного эквивалента |
|
dec |
r17 |
|
cpi |
r17,0 |
|
brne |
loop |
|
rjmp PC |
;бесконечный цикл |
;подпрограмма преобразует ASCII-символ 16-ного числа в двоичное число ;символ передается через r16, результат возвращается через r16
ascii_to_bin: |
|
|
cpi |
r16,0x39 |
|
brcs |
atb_m1 |
|
subi |
r16,0x30 |
;символ '0'...'9' |
rjmp atb_end |
|
|
atb_m1: |
|
;символ 'A'...'F' |
subi r16,0x37 |
||
atb_end: |
|
|
ret |
|
|
Контрольные вопросы и задания:
1.Опишите процесс вызова подпрограммы и возврата из нее.
2.Объясните, почему команды переходов, вызова/возврата из подпрограмм требуют для своего выполнения двух и более тактов, тогда как остальные команды – только один такт?
3.Виды команд передачи управления (переходы/вызовы, условные/безусловные, абсолютные/относительные/косвенные).
4.Сравните модульный и монолитный подход к разработке программного обеспечения.
27
5.Способы передачи параметров в подпрограммы, возвращения результата, сохранения контекста вызывающей программы.
6.Способы реализации стека для хранения адреса возврата из подпрограммы. Проблемы, связанные с использованием стека.
7.Какими средствами можно установить, сбросить, инвертировать значения отдельных битов регистров общего назначения?
8.Какими средствами можно установить, сбросить, инвертировать значения отдельных битов регистров ввода/вывода?
9.Какие средства в AVR существуют для копирования значений отдельных
битов из регистра в регистр?
10.Порты ввода/вывода At90S2313: функциональная схема, работа, способы использования.
Лабораторная работа №5. Прерывания. Программные автоматы
Цель работы: знакомство с организацией системы прерываний, программной реализацией автоматов с помощью микроконтроллеров.
Порядок выполнения работы (п.п. 1-3 выполняются во внеаудиторное время):
1.Ознакомьтесь с теоретической частью лабораторной работы.
2.Разработайте блок-схемы программ для заданий 1-4.
3.Подготовьтесь к ответу на контрольные вопросы 1-7.
4.Выполните задания.
5.Защитите лабораторную работу.
Имеется необходимость во взаимодействии процессора с внешним миром, его реакциях на внешние события. К организации этого взаимодействия можно подойти следующими способами:
-Процессор может периодически опрашивать состояния внешних входов, периферийных устройств и т.п. Такую чисто программную обработку внешних событий называют поллингом. Поллинг требует больших ресурсов времени процессора и обеспечивает невысокую скорость реакции на внешние события, причем, временные затраты с уменьшением времени реакции возрастают.
-Процессор может быть дополнен узлом, который независимо от самого процессора опрашивает состояния входов и периферийных устройств. В случае обнаружения какого-либо события (появление на внешнем входе того или иного фронта или уровня, изменение флага состояния периферийного устройства и т.п.), этот дополнительный узел прерывает выполнение процессором его текущего потока команд, загружая в программный счетчик адрес специальной подпрограммы. Такое принудительное изменение хода выполнения программы называется прерыванием, а вызываемая подпрограмма – подпрограммой обслуживания или обработки
28
прерывания (иногда используют термин "обработчик прерывания").
Событие вызывающее прерывание называется источником прерывания. В отличие от поллинга, прерывания обеспечивают реакции даже на кратковременные события с минимальными затрата времени процессора.
Организация опроса внешних выводов и устройств с помощью поллинга очевидна: программа представляет собой бесконечный цикл, в котором и производится анализ их состояния. В случае обнаружения интересующего события, происходит переход к ветви алгоритма, обрабатывающей это событие. Такую ветвь удобно оформить в виде подпрограммы.
В чем сходства и каковы различия между обычной подпрограммой и подпрограммой обработки прерывания?
Сам термин "подпрограмма" предполагает использование механизма вызова из основной программы некоторого модуля, с последующим возвратом управления основной программе. В случае обычной подпрограммы, адрес ее начала в том или ином виде содержится в команде вызова. Адрес обработчика прерывания задается через таблицу векторов прерываний. Каждому источнику прерывания соответствует свой вектор – одна или несколько ячеек памяти. В некоторых процессорах вектор хранит адрес начала обработчика прерывания. В других (к ним относятся и микроконтроллеры AVR) – первую (или, несколько первых) команду собственно обработчика прерывания. При этом, как правило, в векторе размещается команда безусловного перехода к основной части обработчика.
Из неопределенности точки вызова следует и то, что такой подпрограмме нельзя передавать параметры, а сама она не может возвращать параметры через стек или флаги слова состояния процессора (но вполне может изменять значения глобальных переменных).
Аналогично с вызовом обычной подпрограммы, при вызове обработчика прерывания в стеке автоматически сохраняется адрес возврата – адрес команды, с которой должно продолжится выполнение основной программы.
Особенностью вызова обработчика прерывания является неопределенность ее места вызова из основной программы. Поэтому подпрограмма обработки прерывания должна сохранять содержимое арифметических флагов процессора в том состоянии, в котором они находились на момент ее вызова. Проиллюстрируем такую необходимость. Предположим, основной фрагмент программы содержит следующие операторы:
mov r0, r5 |
;1 |
cmp r0, r1 |
;2 |
brne m1 |
;3 |
clr r4 |
;4 |
rjmp m2 |
;5 |
m1: |
; |
ser r4 |
;6 |
m2: |
|
… |
|
29
Пусть после выполнения команды №2 была вызвана подпрограмма обработки прерывания. Если эта подпрограмма изменит значение флага нулевого результата Z, то в регистр r4 может быть загружено неверное значение.
По этой же причине, подпрограмма обработки должна сохранять содержимое всех регистров, которые она использует, и которые используются в прерываемой программе.
Как правило, для сохранения флагов и регистров используется программный стек: в начале обработчика прерывания содержимое всех используемых регистров и флагов помещается в стек, откуда оно извлекается в конце обработчика. Следующий пример показывает подпрограмму обработки прерывания приемника последовательного порта. Обратите внимание, что, поскольку, доступ к стеку производится через его вершину, то порядок извлечения данных из стека – обратный порядку сохранения. В этом примере регистр X используется как глобальная переменная (указатель буфера) и, потому, не сохраняется в стеке.
;Обработчик прерывания от приемника последовательного порта
RX_Complete_ISR:
push r0 |
;сохраняем r0 |
push r16 |
;сохраняем r16 |
in r0,sreg |
;сохраняем состояние флагов процессора |
push r0 |
; |
in r0,UDR |
;считываем содержимое приемника |
ldi r16,0x30 |
; |
cp r0,r16 |
; |
brlo m1 |
;корректируем полученный символ, |
inc r0 |
;если необходимо |
m1: |
;сохраняем символ в буфере |
st X+,r0 |
|
pop r0 |
; |
out sreg,r0 |
;восстанавливаем состояние флагов процессора |
pop r16 |
;восстанавливаем r16 |
pop r0 |
;восстанавливаем r0 |
reti |
|
Один и тот же сигнал прерывания может присутствовать постоянно (если, например, прерывание формируется при наличии на входе заданного уровня). В этом случае, возникает угроза рекурсии вызова обработчика прерывания. Либо, во время работы одного обработчика прерывания может произойти событие, вызывающее другое прерывание – возникает проблема вложенности прерываний. Бывает необходимо запретить реакцию на все или некоторые источники прерываний. Могут возникнуть одновременно несколько событий, вызывающих прерывания – возникает необходимость выбора порядка их обслуживания. Для решения этих задач существуют следующие механизмы:
-Глобальный запрет (маскирование) прерываний – запрещает обслуживание прерываний от любых источников. Обычно, слово состояния процессора содержит бит глобального запрета/разрешения прерываний (в AVR – бит I). Если слово состояния доступно через пространства памяти
30