Редактор кода и симулятор Bascom
Окно редактора Bascom используется для ввода и редактирования текста программы. Он имеет удобную подсветку синтаксиса:
—
Зеленым обозначаются комментарии: это может быть любой текст после апострофа ( ‘ ). Используйте их, чтобы делать структуру программы понятной для всех. Вы потом себе сами спасибо скажете, открыв код через некоторое время.
— Красным обозначаются спецсимволы: *+-,./:;<>=&^%#@~()[]|?!@{}
— Полужирным синим выделяются ключевые слова Bascom. Например, Waitms 500. Кстати, по этим словам доступна справка — нужно установить курсор на интересующее слово и нажать F1.
— Черным обозначаются переменные.
Эти цвета установлены по умолчанию, но их можно изменить в настройках Options/Environment (вкладка Font):

Bascom претендует на звание «умного» редактора. Это значит, что он осуществляет форматирование кода программы по мере его ввода, делая его более опрятным и удобочитаемым. Например, он делает каждое вводимое слово с заглавной буквы. Еще он убирает лишние пробелы и добавляет их там, где надо, делая текст более разреженным. Все это можно так же сменить в тех же настройках:

Достаточно убрать галки «Don’t change case» и «Reformat Bas files». Последняя отменяет форматирование файлов сразу после открытия в редакторе.
Пока мы все еще копаемся в настройках среды (Environment), обратим внимание на вкладку «IDE»:

Оказывается, Bascom сохраняет изменения, внесенные в код,
перед
каждым компилированием! Это достаточно неожиданное поведение для редактора. Вы не можете просто взять и поменять код, а затем скомпилировать его, посмотрев, что будет. После нескольких таких «посмотреть что будет» ваш код может быть необратимо изменен, и этого нельзя избежать, не закрыв полностью Bascom и отказавшись от сохранения изменений. Это ненужное и вредное поведение редактора нужно осознавать и принимать как должное. Конечно, можно отключить автосохранение, сняв галку «Autosave on compile», но перед каждой компиляцией вам придется заново указывать имя файла для сохранения!
Синтаксические ошибки в Bascom
Синтаксические ошибки сродни орфографическим ошибкам или опечаткам. Например, вы хотели набрать Config, но промахнулись по клавишам и набрали Confih. Bascom такого слова не знает и при компиляции выдаст ошибку. Большинство таких ошибок выявляются на стадии компиляции. Если таковые имеются, Bascom откажется создавать bin-файл и выдаст список ошибок в нижнем окошке. Давайте попробуем испортить уже знакомый нам ledflasher.bas:

Попробуем скомпилировать код, нажав F7. Компилятор нам скажет следующее:

Дважды кликнем на первой строке в окне отчета, и редактор выделит в верхнем окне соответствующую строку:

Это довольно удобно — перепрыгивать сразу на нужную строку, особенно если вы пишете большую и запутанную программу.
Первая строка гласит «Assignment error…». Мы забыли объявить переменную, а Bascom требует объявления каждой переменной, которую мы используем. Сейчас давайте просто удалим эту строку.
Вторая строка в отчете говорит нам «Unknown statement…». Опять же, мы промахнулись по клавишам и не набрали вторую «o» в слове Loop.
Последняя строка отчета возникла из-за того, что Bascom после слова Do ожидал увидеть слово Loop. Нам достаточно исправить ‘Lop’ на ‘Loop’ и обе ошибки исчезнут.
Такое случается часто, когда одна синтаксическая ошибка по цепочке вызывает несколько. Поэтому не все записи в отчете могут быть очевидны. Тут Bascom есть куда стремиться!
Перекомпилируем нашу программу и увидим, что на этот раз в ней нет ошибок.
Обратите внимание:
Bascom выявляет синтаксические ошибки, но не логические! Поэтому если вы думаете, что компилятор не прав, сначала проверьте себя и свой код!
Симулятор Bascom
Перед использованием каких-то новых решений в коде, бывает полезно сначала проверить, насколько они хорошие. Симулятор позволяет вам пошагово проверить программу без программирования контроллера и использования железа вообще. Вы можете смотреть состояние портов ввода/вывода, значения переменных, аппаратных регистров и программной памяти. Также вы можете посмотреть, как контроллер взаимодействует с железом. Вы можете симулировать подключенный к МК индикатор, изменять состояние портов контроллера виртуальными кнопками, подводить нужное значение напряжения к АЦП и т.п.
Сначала давайте посмотрим, как мы можем симулировать работу светодиодной мигалки. Откроем все тот же ledflasher.bas и скомпилируем. Помимо .bin файла, компилятор создаст .dbg и .obj файлы, которые используются симулятором.
Запустим симулятор (F2):

В нижней части мы увидим окно с исходным кодом. В верхней части мы увидим кучу кнопочек для симуляции железа и вкладки, отображающие состояния переменных и регистров.
Когда мы запускаем симуляцию, мы можем видеть состояние портов ввода/вывода после каждой команды в программе. Чтобы отобразить «виртуальное железо», нажмем кнопку LCD. Появится дополнительное окно:

Появляется окно Hardware:

Теперь, если мы запустим программу на выполнение (F5), напротив текущей строки программы появится синяя стрелочка:

Обратите внимание, как включаются все вывода порта D после строки ‘PortD = 255’ и выключаются после строки ‘PortD = 0’.
(Заметьте, что симулятор показывает 8 светодиодов для порта D, хотя в AT90S2313 наружу выведены только 7. Также заметьте, что симулятор показывает индикаторы состояния регистров ввода/вывода для текущей модели контроллера. Попробуйте сменить строку «$regfile = «2313def.dat» на «$regfile = «m128def.dat», перекомпилируйте, перезапустите симуляцию и нажмите кнопку LCD. В ATMega128 всего 7 регистров ввода/вывода!)
Мы можем остановить симуляцию кнопкой Stop program. Обычно запускать программу на произвол судьбы и следить за ней со стороны не очень удобно. Лучше пользоваться кнопкой Step into code (F8). Симулятор будет делать паузу после каждой строки, давая вам время рассмотреть, что происходит. Заметьте, что симулирование команды waitms 50 займет гораздо больше времени чем 50 мс. В общем, на таких командах симулятор работает слишком медленно. Вставьте директиву «$sim» после строки «$crystal = 4000000» и перекомпилируйте программу. Вы увидите, что все команды задержки будут пропущены. Но не забудьте убрать ее и перекомпилировать программу заново перед прошивкой контроллера! Если вы забудете сделать это, все задержки из конечной программы пропадут, и контролелр будет вести себя некорректно!
Работа с переменными
О переменных уже было сказано в главе 6, при необходимости обратитесь к ней.
Создадим новый проект и введем такую программу:
Скомпилируем и запустим симулятор. В первой ячейке таблицы на вкладке Variables введем имя переменной Counter:
Щелкнем по Refresh variables. Это будет обновлять значения переменных в таблице по ходу выполнения программы. Будем давить по Step into Code и смотреть на значение переменной Counter:
Нажмем Run program (F5) и будем следить, как значение переменной увеличивается до 255, после чего она переполняется и становится равна 0.
Вкладка Locals может отображать значения переменных, которые используются локально в подпрограмме или функции.
Вкладка Interrupts показывает состояние прерываний. Вы можете принудительно вызвать внешнее прерывание на выводах Int0/Int1.
Форум РадиоКот :: Просмотр темы — BASCOM AVR в вопросах и ответах
| Автор: | edm2007 [ Вс мар 10, 2013 12:50:29 ] |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах |
|
Так и надо приводить код, вызывающий ошибки. А то пишите одно, а компилируете другое. Уберите строку $lib «mcsbyte.lbx». |
| Автор: | tomas111 [ Вс мар 10, 2013 13:00:27 ] |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах |
|
edm2007 писал(а): Так и надо приводить код, вызывающий ошибки. А то пишите одно, а компилируете другое. Уберите строку $lib «mcsbyte.lbx». Спасибо!!! Все откомпилилось! |
| Автор: | tomas111 [ Вс мар 10, 2013 13:02:29 ] |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах |
|
А вот в протеусе не работает … |
| Автор: | edm2007 [ Вс мар 10, 2013 13:04:52 ] |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах |
|
Работает, я проверял. На AVCC не забыли питание подать? |
| Автор: | tomas111 [ Вс мар 10, 2013 13:07:55 ] | |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах | |
|
edm2007 писал(а): Работает, я проверял. На AVCC не забыли питание подать? НЕ забыл! висит питание ….
|
| Автор: | edm2007 [ Вс мар 10, 2013 13:20:57 ] |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах |
|
У меня все работает. Только добавил Код: Config Single = Scientific , Digits = 2 чтобы до двух знаков после запятой обрезать. И один канал АЦП вывел для наглядности. |
| Автор: | tomas111 [ Вс мар 10, 2013 13:24:37 ] |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах |
|
А у меня снова ошибка!! Что за фигня …. |
| Автор: | edm2007 [ Вс мар 10, 2013 13:30:03 ] |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах |
|
Это непосредственное значение АЦП. Оно от 0 до 1023. |
| Автор: | tomas111 [ Вс мар 10, 2013 13:34:30 ] |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах |
|
Я про верхние показания … они то и вроде ограничивают диапазон. От 0 до 80 |
| Автор: | edm2007 [ Вс мар 10, 2013 13:43:57 ] |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах |
|
tomas111 писал(а): И почему показания такие огромные !? tomas111 писал(а): Я про верхние показания … они то и вроде ограничивают диапазон. От 0 до 80 Послушайте, а 15,72 в каком именно месте больше? Это во-первых. А во-вторых, в коде ограничивается Channel_1 до 80, в то время как выводится Chvar_1. Так что ни о каком ограничении речь не идет, смотрите внимательнее в код. Свой проект отправлю, но у меня Proteus 7.7. |
| Автор: | tomas111 [ Вс мар 10, 2013 14:09:19 ] |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах |
|
Получил! Спасибо! |
| Автор: | edm2007 [ Вс мар 10, 2013 15:38:49 ] |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах |
|
Отправил в личку. |
| Автор: | tomas111 [ Вс мар 10, 2013 18:52:30 ] |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах |
|
edm2007 писал(а): Отправил в личку. Спасибо! очень хорошо получилось! |
| Автор: | freeman401 [ Вс мар 10, 2013 22:29:07 ] |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах |
|
Помогите пожалуйста с прошивкой вот код: Код: $regfile = «attiny13.dat» Do Pwm0a = 25 ‘задали начальные 30 вольт на выходе усилителя класса D Ask_inter: ‘ опрос ножки запускающего входа Ramp_fr: ‘ начинаем рост пилы Ramp_re: ‘ спад пилы Loop ‘ зацикливаем все End Вся проблема в том, что на сроках: Код: F =((a / 32) / N) *(b / 1024) и Код: R =((a / 32) / N) -((a / 32) / N) *(b / 1024) проверка синтаксиса выдает ошибку «3 parameters expected» С бейсиком раньше дело имел, но не очень хорошо его помню |
| Автор: | max50 [ Пн мар 11, 2013 07:21:09 ] |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах |
|
tomas111 писал(а): проверка синтаксиса выдает ошибку «3 parameters expected» Все правильно. Код: F_1= =a / 32 F_1, F_2, F_3 — нужно объявить в начале программы. Тип выбрать в зависимости от результата. |
| Автор: | freeman401 [ Пн мар 11, 2013 12:56:34 ] |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах |
|
Надеюсь, после ведения этих переменных код влезет в 1Кб ;D |
| Автор: | max50 [ Пн мар 11, 2013 12:59:44 ] |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах |
|
freeman401 писал(а): адеюсь, после ведения этих переменных код влезет в 1Кб Надежда умирает последней. |
| Автор: | freeman401 [ Пн мар 11, 2013 13:33:44 ] |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах |
|
Все теперь правильно, но пишет, что «Out of SRAM space» |
| Автор: | edm2007 [ Пн мар 11, 2013 13:37:27 ] |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах |
|
Пробуйте на Си. |
| Автор: | freeman401 [ Пн мар 11, 2013 13:55:46 ] |
| Заголовок сообщения: | Re: BASCOM AVR в вопросах и ответах |
|
лучше я контроллер возьму тини85, он мне даже дешевле выходит, а памяти в 8 раз больше |
| Страница 170 из 300 | Часовой пояс: UTC + 3 часа |
| Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |
===================================== Справочник по программированию «Bascom-AVR» ==
Обработка прерываний
Обстоятельства и правила возникновения прерывания
Прерывания в микроконтроллере AVR возникают при возникновении событий, обусловленных изменением состояния аппаратного компонента периферии, находящейся на кристалле. Предусмотрено прерывания по следующим событиям:
—изменение уровня на входной линии порта. Возможные варианты срабатывания на низкий, высокий или любое изменение уровня;
—переполнение счетчика таймера;
—совпадение значения счетчика таймера с заданным фиксированным значением;
—прием байта приемником одного из интерфейсов (UART, SPI, I2C);
—опустошением передатчика одного из интерфейсов
—окончанием задержки отработанной сторожевым таймером;
—окончание преобразования АЦП;
—окончание записи в EEPROM;
—изменения соотношения аналоговых уровней, сравниваемых компаратором.
Наличие событий прерывания и сочетание с другими функциями определяется моделью микроконтроллера. Для каждого типа прерываний предусмотрен собственный вектор – адрес, с которого начинается исполнения программы в случае регистрации события. Все векторы прерывания размешены в программной памяти, начи-
ная с нулевого адреса. Размер области вектора составляет:
—два байта для облегченных микроконтроллеров (семейства Mega и всех семейства Tiny) и предусматривает размещение в векторе только одной короткой команды перехода RJMP;
—четыре байта для микроконтроллеров семейства Mega и позволяет разместить в векторе и короткую RJMP
идлинную команду перехода JMP.
В векторе прерывания может быть еще размещена команда возврата RETI (возврат без обработки). Никаких других разумных вариантов применения иных команд не предполагается. По команде, размещенной в векторе, производится переход к самой программе обработки события прерывания.
Чтобы в Bascom-AVR обозначить адрес такого перехода записываются следующие директивы:
|
‘——————— |
|
|
‘ назначение векторов прерывания |
‘вектор внешнего прерывания 0 |
|
On Int0 Int0_int Nosave |
|
|
On Timer0 Timer0_int Nosave |
‘вектор прерывания от таймера 0 |
|
On Urxc Rxd_int Nosave |
‘вектор прерывания от приемника UART |
|
‘——————— |
которые содержат:
—прерывания (или тип), по которому компилятор данный вектор соответствующему адресу (определяемому моделю микроконтроллера);
—имя метки, с которой начинается программы обработки прерывания;
—необязательная опция Nosave , запрещающая компилятору автоматическое сохранение всех регистров общего назначения (R0-R31) и регистра статуса SREG. Применение данной опции рекомендуется, но требует от программиста самостоятельного определения списка сохраняемых регистров. Этот список определяется выполняемыми операциями при обработке прерываний. Перемещение данных требует сохранения только используемых регистров, а использование арифметических и логических команд еще сохранения статуса SREG.
Происхождение прерываний
Прерывание происходит в случае выполнения, как минимум, трех условий:
а) наличие общего разрешения прерываний, которое производится установкой (в «1») бита SREG.7 (бита I: Global Interrupt Enable). Управление этим битом может производиться многими способами. Напрямую установка его значения производится ассемблерными командами SEI (разрешение) и CLI (запрещение) или соответствующими командами Bascom-AVR:
|
‘——————— |
‘разрешить прерываниЯ |
|
Enable Interrupts |
Или
|
‘——————— |
‘запретить прерываниЯ |
|
Disable Interrupts |
б) разрешения выбранного типа прерывания. Как правило, разрешение прерывания производится установкой (в «1») соответствующего бита регистров управления. Запись данной операции операторами Bascom-AVR выполняется следующим образом:
============================================================================= 21
===================================== Справочник по программированию «Bascom-AVR» ==
|
‘——————— |
‘разрешить прерывание |
таймера |
0 |
|
|
Enable Timer0 |
||||
|
Enable Int0 |
‘разрешить |
внешнее прерывание |
0 |
|
|
Enable Urxc |
‘разрешить |
прерывание |
по заполнению приемника |
|
|
‘——————— |
Однако лучше применять следующую форму записи, как более очевидную и экономичную с точки зрения размера кода:
|
Timsk = &B00000001 |
‘разрешить прерывание таймера 0 |
в) возникновения события прерывания. Тип события, по которому будет происходить прерывание, определяется программистом на этапе начального конфигурирования периферии микроконтроллера. Тип прерывания может быть выбран только из списка, предусмотренного для используемой модели микроконтроллера. Используемый тип прерывания приспосабливается к задаче пользователя непосредственно с помощью внутренней периферии или дополнительного внешнего оборудования.
Приоритеты прерываний
В микроконтроллерах AVR отсутствует механизм перераспределения векторов прерывания. При наличии условий возникновения нескольких прерываний первым обрабатывается находящееся выше в списке векторов (с меньшим адресом). Когда происходит прерывание, то остальные оказываются автоматически запрещенными, вследствие очистки (сброса) бита I. То есть, по умолчанию, вложенные прерывания невозможны. Обеспечение вложенности прерываний осуществляется программным методом. Для этого достаточно в начале программы обработки прерывания вновь установить бит I.
Программный механизм прерываний
При возникновении любого прерывания происходит переход на исполнение команды, записанной по адресу соответствующего вектора. При этом в стеке запоминается адрес (два байта) команды, которая должна исполняться после завершения обработки прерывания (которая бы выполнялась при отсутствии прерывания). Указатель стека при наступлении прерывания уменьшается на два. Таким образом, прерывания эквивалентно выполнению двух команд — CALL и CLI. Для возврата к исполнению прерванной программы после завершения обработки прерывания применяется команда RETI, эквивалентная двум командам — RET (возврат по адресу, запомненному в стеке) и SEI (разрешение прерываний). После завершения обработки прерывания указатель стека возвращается к исходному значению (увеличивается на два). Источником прерывания всегда является соответствующий флаговый бит, устанавливаемый аппаратно по совпадению назначенных условий. После выполнения обработки прерывания по команде RETI сбрасывается и бит, вызвавший прерывание. Однако имеются случаи, когда этого не происходит (смотреть описание микроконтроллера) и требуется его программный сброс.
Сохранение данных прерванной программы
Для обеспечения правильной работы прерванной программы требуется сохранение данных, которые могут быть испорчены при обработке прерывания. Предлагаемый (по умолчанию) компилятором вариант сохранения всех регистров общего назначения для оптимального программирования не годится. Во-первых, очень редко в программе обработки прерывания используется не более четырех регистров. Во-вторых, даже эта мера не позволяет использовать в программе прерывания все функции Bascom-AVR. В число запрещенных входят функции, использующие служебные области памяти — внешние переменные, служебный строковый буфер, программный стек (обработка строк, вычисления (обработка) чисел в формате с плавающей точкой, обработка протоколов связи и т.п.). О наличие служебных областей можно узнать, посмотрев файл отчета (“Cntr-W”) после компиляции (до этого нужно еще нужно назначить его создание и включение в список внутренних переменных). В число разрешенных функций входят:
—операторы назначения и перезаписи данных;
—целочисленные вычисления;
—проверка условий с целыми числами;
—управление внутренними и внешними периферийными устройствами.
Тем не менее, рекомендуется программу обработки прерываний выполнять только на ассемблере, предельно сократив количество выполняемых действий (операций).
Другие вопросы совместного использования ресурсов
Кроме очевидных и не очень очевидных случаев использования общих регистров памяти в главной программе и программе прерывания, следует иметь в виду другие возможности совместного использования ресурсов.
Например, время исполнения участка программы разорванного прерыванием увеличивается. В одних случаях это становится просто заметным и появляется в искажение звука при программной генерации сигналов или модуляция яркости индикаторов, время свечения которых определяется программно. В других случаях сбои, вызванные обработкой прерывания, становятся критичными для работы программы. Как это проявляется:
—замедляется реакция на внешние события или они пропускаются совсем;
—пропускаются отдельные элементы последовательно принимаемые данные;
============================================================================= 22
===================================== Справочник по программированию «Bascom-AVR» ==
—происходит нарушение формы (временных соотношений) программно формируемой временной диаграммы для управления внешним устройством;
—происходит удлинение процесса записи (или считывания) данных, посредством программного интерфейса. Причем такое удлинение процесса обмена данных могут быть недопустимыми для периферийного устройства.
Особый случай — считывание (или запись) данных в регистры изменяемые (или соответственно считываемые) в процессе обработки прерывания. Дефект подобного рода проявляется только тогда, кода размер данных превышает один байт. За счет разделения прерыванием процесса модификации данных нарушается их целостность. Из-за низкой вероятности такого наложения, проявление данного дефекта имеет случайный характер и зависит от времени исполнения участков программы, примыкающих к критичному. Для внешнего наблюдателя, при этом складывается впечатление, что появление сбоя обусловлено каким-то определенным значением обрабатываемых данных. Естественно, дезориентирует и затрудняет поиск ошибки.
Для решения описанных выше проблем нужно запрещать прерывания на время считывания или записи критичных данных или исполнения критичной операции.
Управление прерываниями
Настройка конфигурации системы прерывания производится при начальной инициализации микроконтроллера и может изменяться в процессе работы программы. При этом необходимо придерживаться определенных правил:
—выполнять разрешение или запрещение прерывания нужно с одновременным сбросом флагов, вызывающих этот тип прерывания. Сброс флагов прерывания соответственно выполняется перед разрешением и запрещение после запрещения. Этим исключается несанкционированный вызов программы прерывания. При необходимости учет значения флагов прерывания (например, переполнения счетчика) производится программно;
—нужно сбрасывать флаг в самой программе прерывания, если для данного вида прерывания это не делается автоматически (смотреть datasheet);
—перед тем, как разрешить прерывание требуется подготовить условия для его правильного прохождения. Например, перед разрешением прерывания таймера необходимо записать в него такое значение, чтобы прерывание наступало не произвольно, а не ранее того момента, когда для этого будут подготовлены другие компоненты системы;
—предотвращать возможность вызовы прерываний с периодичностью, меньше или даже близкой к времени его обработки. Когда суммарное время обработки прерываний превышает 50 процентов, программы становится неработоспособной;
—недопустимо включение в программы прерывания бесконечных циклов ожидания событий. По возможности, вообще следует исключать использование в прерываниях циклов ожидания. Это позволит однозначно прогнозировать время исполнения.
Встроенные прерывания
В некоторых функциях “Bascom-AVR” предполагается использование прерываний. Главным образом, это функции программных интерфейсов, работающие режимах синхронизации от внешних устройств (в режиме ведомого — Slave). Библиотеки “Bascom-AVR”, обычно, используют для этого самые популярные прерывания Int0 и Timer0. Это нужно учитывать при проектировании системы и не занимать прерывания, используемые такими функциями, другими задачами. При этом резервируются и линии портов соответственно используемым прерываниям. Прерывания используют следующие функции: AT-клавиатура, I2C – двухпроводный программный интерфейс (ведомый), SPI – последовательный программный интерфейс (ведомый), TCP/IP – сетевой протокол с микросхемой W3100A, RC5 –программный инфракрасный порт дистанционного управления. Типы используемых прерываний: внешнее от изменения уровня — Int0 или Int2, от переполнения счетчиков — Timer0 или Timer2. Причем компилятор во всех случаях предлагает выбрать одного из двух каждого типа.
Оформление программ прерывания
Важнейшей частью программы обработки прерывания является сохранение, а затем перед завершением восстановление регистров общего назначения. По умолчанию автоматически сохраняются все регистры (R0…R31 и статусный регистр SREG). Если в операторе, формирующем вектор прерывания, применена опция NOSAVE, то операции автоматического сохранения-восстановления регистров не будут включены в текст программы, а об этом нужно позаботится самостоятельно. Компилятор “Bascom-AVR” не предоставляет ассемблерного листинга. Написав программу обработки прерывания с использованием операторов бейсика, весьма затруднительно определить список используемых регистров, чтобы произвести их выборочное сохранение. Поэтому рекомендуется программы обработчика прерывания выполнять на ассемблере. Это оптимально во всех отношениях. И хорошая практика, чтобы не забыть ассемблер, и быстрое исполнение программы, и надежная предсказуемая работа программы, независимость от версии компилятора.
Чтобы обеспечить возврат из программы обработки с разрешением прерываний следует применить команду микроконтроллера RETI. Компилятор делает это автоматически — первая команда RETURN, встретившаяся после метки с именем вектора прерывания скомпилируется как команда микроконтроллера RETI. Чтобы такая автозаме-
============================================================================= 23
===================================== Справочник по программированию «Bascom-AVR» ==
на произошла в нужном месте, даже применяя ассемблер, необходимо завершить его текст оператором Bascom RETURN. Это указание реализовано в последующих примерах.
Выполняя программу на ассемблере, важно обеспечить связь этой части программы с программой, написанной на бейсике. Эта связь осуществляется следующим образом:
— передача управления, когда в любом месте программы на бейсике может вызываться ассемблерная программа. Нужно только указать ее имя – метку, с которой она начинается. Например,
|
‘ …… |
‘ перезаписать данные |
|
Gosub Transfer |
|
|
‘ …… |
Также в любом месте программы на бейсике может быть вставлена ассемблерная вставка. Однако в программе прерывания может быть вызвана подпрограмма, написанная на ассемблере. Вызов лучше выполнять с помощью более короткой команды RCALL. При этом вызываемый модуль должен быть расположен в тексте программы поблизости, учитывая ограниченный диапазон перехода;
— передача данных через переменные, определенные в заголовке программы. Имена переменных помещаются в фигурные скобки. При необходимости можно указывать части много байтных переменных. Например,
|
‘ …… |
‘»новые данные» |
|
Dim Ndat As Byte |
|
|
Dim R_bd As Long |
‘двоичный результат |
|
‘ …… |
|
|
$asm |
‘запишем сумму |
|
Sts {r_bd} , R0 |
|
|
Sts {r_bd + 1} , |
R1 |
|
Sts {r_bd + 2} , |
R26 |
|
Sts {r_bd + 3} , |
R27 |
|
Ldi R31 , &HFF |
|
|
Sts {ndat} , R31 |
|
|
Rjmp Adci_2 |
|
|
$end Asm |
— запись в регистры индексов (адресов), определяемых при компиляции. Операции, указанные в последующем примере могут без ограничения использоваться в программах прерывания, так как они модифицируют только регистр приемника данных. Например,
‘———————
Dim K_dc0 As Single
Dim Fldb As Single
‘———————
‘ ……
‘перезапись данных
Transfer:
Loadadr K_dc0 , X ‘записать адрес переменной K_dc0 в индексный регистр X Loadadr Fldb , Z ‘записать адрес переменной Fldb в индексный регистр Z
$asm
Ld R16 , Z+
St X+ , R16
Ld R16 , Z+
St X+ , R16
Ld R16 , Z+
St X+ , R16
Ld R16 , Z+
St X+ , R16 $end Asm
Return ‘———————
‘ ……
‘установка индексного регистра Z для считывания байтовых данных
|
Ldi R30 |
, |
Low(Tab_phs * 2) |
‘записать адрес метки Tab_phs в индексный регистр Z |
|
|
Ldi R31 |
, |
High(Tab_phs * 2) |
‘младший и старший байты |
|
|
‘ …… |
||||
|
‘установка специального индексного регистра компилятора |
||||
|
Restore |
Tab_phs |
‘запись указателя на метку в регистры R8 и R9 |
||
|
‘ …… |
||||
|
Tab_phs: |
55 |
, |
55 , 55 , 56 |
‘поля данных |
|
Data |
||||
|
‘ …… |
||||
|
M12: |
Tmpb |
‘считывание данных |
||
|
Read |
============================================================================= 24
===================================== Справочник по программированию «Bascom-AVR» ==
Индексы, получаемые в приведенном выше примере, предполагают побайтную адресацию (соответствуют нумерации байт). Имеется еще одна форма загрузки адреса метки, предполагающая получение адреса перехода для его загрузки в программный счетчик.
‘ ……
‘установка индексного регистра Z для операции перехода
|
Ldi |
R30 |
, |
Low(M12 * 1) |
‘записать адрес метки M12 в индексный регистр Z |
|
|
Ldi |
R31 |
, |
High(M12 * 1) |
‘младший |
и старший байты как адрес перехода |
|
Ijmp Z |
‘переход |
по считанному адресу |
‘ ……
— следует упомянуть об аналогичных операторах, недопустимых в программах прерывания. Вот они
|
‘——————— |
|
|
Dim W As Word |
|
|
‘——————— |
|
|
‘ …… |
‘запись в переменную W указателя на переменную fldb |
|
W = Varptr(fldb) |
|
|
W = Loadlabel(Tab_phs) |
‘запись в переменную W указателя на метку |
|
‘ …… |
Типовые программы прерывания
Далее приведены примеры программ обработки прерываний различного типа.
Пример 1 — Прерывание таймера
|
‘———————————————————————————- |
‘счетчик временных интервалов, задаваемых в главной программе |
|
Dim R_tim As Byte |
|
|
‘ …… |
‘вектор прерывания от таймера 0 |
|
On Timer0 Timer0_int Nosave |
|
|
‘ …… |
‘режим таймера 0: Fкв/1024 — часы реального времени |
|
Tccr0 = &B00000101 |
|
|
Enable Timer0 |
‘разрешить прерывание таймера |
|
Enable Interrupts |
‘разрешить прерывания |
‘ ……
‘———————————————————————————-
‘обработка прерывания таймера 0 (8-битный таймер) ‘используется как часы реального времени с частотой 10 мс ‘для этого организована схема деления 8 МГц/1024/78
|
Timer0_int: |
||
|
$asm |
‘сохраним регистры |
|
|
Push R31 |
||
|
In R31 , Sreg |
||
|
Push R31 |
||
|
‘—— |
‘переустановим счетчик |
|
|
Ldi R31 , 178 |
||
|
Out Tcnt0 , R31 |
||
|
‘—— |
‘обработка счетчика переменных временных интервалов |
|
|
Lds R31 , {r_tim} |
||
|
And |
R31 , R31 |
|
|
Breq |
Intt0_e |
|
|
Dec |
R31 |
|
|
Sts {r_tim} , R31 |
||
|
‘—— |
||
|
Intt0_e: |
||
|
Pop R31 |
‘восстановим регистры |
|
|
Out Sreg , R31 |
||
|
Pop R31 |
$end Asm Return
‘———————————————————————————-
Пример 2 — Прерывание от изменения уровня на линии порта
|
‘———————————————————————————- |
‘признак «Есть новые данные энкодера» |
|
Dim Edat As Byte |
|
|
Dim R_cdec As Byte |
‘СЧЕТЧИК ЩЕЛЧКОВ ВЛЕВО |
|
Dim R_cinc As Byte |
‘СЧЕТЧИК ЩЕЛЧКОВ ВПРАВО |
|
‘ …… |
‘вектор внешнего прерывания 0 |
|
On Int0 Int0_int Nosave |
|
|
‘ …… |
|
|
‘——————— |
‘IDLE — разрешить, INT0 — по спаду |
|
Mcucr = &B10000010 |
|
|
‘——————— |
|
|
‘ …… |
‘разрешить внешнее прерывание 0 |
|
Enable Int0 |
============================================================================= 25
===================================== Справочник по программированию «Bascom-AVR» ==
|
Enable Interrupts |
‘разрешить прерывания |
|
‘ …… |
|
|
‘———————————————————————————- |
‘ОБРАБОТКА ВНЕШНЕГО ПРЕРЫВАНИЯ 0, ОБСЛУЖИВАЮЩЕГО ДВУХФАЗНЫЙ ЭНКОДЕР ‘ПРЕРЫВАНИЕ ПРОИСХОДИТ ПО СПАДУ НА ВХОДЕ P_CHA. ЗАТЕМ ПРОГРАММА ИНТЕГРИРУЕТ ‘(ФИЛЬТРУЕТ) ЭТОТ УРОВЕНЬ, ДОЖИДАЯСЬ НАДЕЖНОГО УСТАНОВЛЕНИЯ «0». В МОМЕНТ ‘ФИКСАЦИИ «0» НА ЛИНИИ P_cha РЕГИСТРИРУЕТСЯ УРОВЕНЬ P_chb , ПО КОТОРОМУ И
|
‘ОПРЕДЕЛЯЕТСЯ НАПРАВЛЕНИЕ ВРАЩЕНИЯ |
||||
|
‘——————————————- |
P_cha Alias PIND.2 |
‘ОПРЕДЕЛЕНИЕ ПОРТОВ ВВОДА КОДА ЦИФРОВОЙ РУЧКИ |
||
|
‘ |
||||
|
‘ |
P_chb Alias PIND.3 |
|||
|
‘——————————————- |
‘КОНСТАНТА ИНТЕГРИРОВАНИЯ УРОВНЯ НА ВХОДЕ |
|||
|
Const Con_irt = 30 |
||||
|
‘——— |
||||
|
Int0_0: |
‘УРОВЕНЬ ВЫСОКИЙ — ОТКАТ СЧЕТЧИКА |
|||
|
Inc R31 |
||||
|
Cpi R31 , 45 |
‘это Con_irt*1.5 |
|||
|
Brne |
Int0_1 |
‘ЕСЛИ ЖДЕМ СЛИШКОМ ДОЛГО — ВЫХОД |
||
|
‘ |
Rjmp |
Int0_e |
||
|
ПРЕРЫВАНИЕ ОТ ЦИФРОВОЙ РУЧКИ |
||||
|
‘ВНЕШНЕЕ |
||||
|
Int0_int: |
||||
|
$asm |
Push |
R31 |
‘сохраним регистры |
|
|
In R31 , Sreg |
||||
|
‘ |
Push |
R31 |
||
|
Ldi R31 , 30 |
‘ПОСТОЯНАЯ ИНТЕГРИРОВАНИЯ |
|||
|
Int0_1: |
Pind , 2 |
|||
|
Sbic |
‘ЕСЛИ НА НОЖКЕ «1» |
|||
|
Rjmp |
Int0_15 |
|||
|
Dec R31 |
‘ПОКА НЕ ОБНУЛИЛСЯ СЧЕТЧИК ЖДЕМ |
|||
|
Brne |
Int0_1 |
‘УСТАНОВЛЕНИЯ НИЗКОГО УРОВНЯ |
||
|
‘ |
Rjmp |
Int0_2 |
||
|
Int0_15: |
‘УВЕЛИЧИВАЕМ СЧЕТЧИК |
|||
|
Inc R31 |
||||
|
Cpi R31 , 60 |
‘ЕСЛИ НА «1» УСТАНОВЛЕНА СЛИШКОМ ДОЛГО |
|||
|
Brne |
Int0_e |
‘НА ВЫХОД |
||
|
‘ |
Rjmp |
Int0_1 |
||
‘ПРОГРАММА РАСЧИТАНА НА КОДОВЫЙ ПЕРЕКЛЮЧАТЕЛЬ ‘С НОРМАЛЬНО РАЗОМКНУТЫМИ КОНТАКТАМИ, ЗАМЫКАЮЩИМИСЯ
‘ТОЛЬКО В МОМЕНТ ЩЕЛЧКА. ЭТО ОЧЕНЬ УПРОЩАЕТ ЗАДАЧУ
‘———————————————
‘|<—— ВРАЩЕНИЕ ВЛЕВО (ИЛИ НАОБОРОТ, В ЗАВИСИМОСТИ ОТ МОНТАЖА)
|
‘chA |
—¦ |
——— |
—— ОПРЕДЕЛЕНИЕ НАПРАВЛЕНИЯ |
||||
|
‘ |
¦ |
chA |
¦ |
¦ |
ВРАЩЕНИЯ ЦИФРОВОГО КОДЕРА |
||
|
‘ |
— |
— |
ОСНОВАНО НА АНАЛИЗЕ СОСТОЯНИЯ |
||||
|
‘chB |
——| |
| |
———chB |
¦ |
¦ |
—- КАНАЛА «B» В МОМЕНТ ЗАМЫКАНИЯ |
|
|
‘ |
¦ | ¦ |
(ЩЕЛЧКА) В КАНАЛЕ «A» |
|||||
|
‘ |
| |
— |
— |
||||
|
‘ |
| |
|<—— |
ВРАЩЕНИЕ ВПРАВО |
||||
|
‘——————————————— |
|||||||
|
Int0_2: |
|||||||
|
‘ОБРАБОТКА ИЗМЕНЕНИЯ УРОВНЯ |
|||||||
|
‘——— |
Sbis |
Pind , 3 |
‘ОПРЕДЕЛИМ НАПРАВЛЕНИЕ ВРАЩЕНИЯ |
||||
|
‘ |
Rjmp |
Int0_3 |
|||||
|
‘ВРАЩЕНИЯ ВЛЕВО (УМЕНЬШЕНИЕ) |
‘УВЕЛИЧИМ СЧЕТЧИК ЩЕЛЧКОВ ВЛЕВО |
||||||
|
Lds R31 , {r_cdec} |
|||||||
|
Inc R31 |
|||||||
|
Sts {r_cdec} , R31 |
|||||||
|
‘ |
Rjmp |
Int0_4 |
|||||
|
Int0_3: |
||
|
‘ВРАЩЕНИЯ ВПРАВО (УВЕЛИЧЕНИЕ) |
‘УВЕЛИЧИМ СЧЕТЧИК ЩЕЛЧКОВ ВПРАВО |
|
|
Lds |
R31 , {r_cinc} |
|
|
Inc |
R31 |
|
|
Sts |
{r_cinc} , R31 |
|
|
Int0_4: |
R31 , &HFF |
|
|
Ldi |
‘поставить признак «НОВЫЕ ДАННЫЕ ЕНКОДЕРА» |
|
|
Sts |
{edat} , R31 |
|
|
‘——— |
||
|
Int0_e: |
R31 |
|
|
Pop |
||
|
Out |
Sreg , R31 |
|
|
Pop |
R31 |
============================================================================= 26
===================================== Справочник по программированию «Bascom-AVR» ==
$end Asm Return
‘———————————————————————————-
Пример 3 — Прерывание АЦП при завершении преобразования
|
‘———————————————————————————- |
‘временные байтовые данные |
||
|
Dim Tmpb As Byte |
|||
|
Dim B_adc As Byte |
‘указатель «есть новые данные внутреннего АЦП» |
||
|
Dim Dadc As Word |
‘данные АЦП (внутреннего) |
||
|
Dim Ua As Single |
‘временное значение |
||
|
‘ …… |
‘IDLE – разрешить |
||
|
Mcucr = &B10000000 |
|||
|
‘ …… |
|||
|
‘—————————————— |
|||
|
‘ измерение с помощью внутреннего АЦП результат Ua, выражен в Вольтах шкалы |
|||
|
Rd_iadc: |
‘внешняя опора АЦП со входа AREF, внутренняя выключена |
||
|
Admux = &B00000001 |
|||
|
Adcsr = &B10001110 |
‘измерение по входу PA1 (напряжение) |
||
|
‘разрешить АЦП с частотой тактирования F / 64 в режиме |
|||
|
‘ |
‘с естественным положением битов, прерывание разрешено |
||
|
‘произвести 16 измерений |
|||
|
For Tmpb = 1 To 16 |
|||
|
Set Adcsr.6 |
‘запустить АЦП |
||
|
Rdiadc1: |
‘останов |
||
|
Idle |
|||
|
If B_adc = 0 Then |
‘есть данные внутреннего АЦП? |
||
|
Goto Rdiadc1 |
‘нет — повторить |
||
|
End If |
|||
|
Next Tmpb |
‘запретить АЦП |
||
|
Adcsr = &B00000110 |
|||
|
Dadc = Dadc — 25 |
‘коррекция смещения нуля |
||
|
Ua = Dadc : Dadc = 0 |
‘в формат с плавающей точкой, а исходный очистить |
||
|
Ua = Ua * 0.0003052 : Return |
‘привести к шкале 0… |
5 В |
|
|
‘—————————————— |
|||
|
‘обработка прерывания от внутреннего АЦП |
|||
|
Adc_int: |
|||
|
$asm |
‘сохраним регистры |
||
|
Push R31 |
|||
|
In R31 , Sreg |
|||
|
Push R31 |
|||
|
Push R30 |
|||
|
Push R29 |
|||
|
‘—— |
|||
|
‘считать данные внутреннего АЦП |
‘считать сумму |
||
|
lds R29 , {Dadc} |
|||
|
Lds R30 , {Dadc + 1} |
‘считать показани |
||
|
In R31 , Adcl |
|||
|
Add R29 , R31 |
‘добавить к сумме показания АПЦ |
||
|
In R31 , Adch |
|||
|
Adc R30 , R31 |
|||
|
Sts {Dadc} , R29 |
|||
|
Sts {Dadc + 1} , R30 |
|||
|
‘—— |
‘есть данные внутреннего АЦП |
||
|
Ldi R31 , 255 |
|||
|
Sts {B_adc} , R31 |
|||
|
‘—— |
|||
|
Adcinte: |
‘восстановим регистры |
||
|
Pop R29 |
|||
|
Pop R30 |
|||
|
Pop R31 |
|||
|
Out Sreg , R31 |
|||
|
Pop R31 |
|||
|
Reti |
|||
|
$end Asm |
|||
|
Return |
|||
|
‘———————————————————————————- |
Пример 4 — Прерывание приемника и передатчика UART
|
‘———————————————————————————- |
‘признак «Есть новые данные из RS» |
|
|
Dim Rdat As Byte |
||
|
Dim Cnt_rc As Byte |
‘счетчик принимаемых из RS символов |
|
|
Dim R_cch As Word |
‘указатель буфера принимаемых символов |
|
|
Dim Bufrr As String * 20 |
‘принятой строки из RS |
|
|
Dim Bufr As String * 20 |
‘обрабатываемой строки из RS |
|
|
Dim T_cch As Word |
‘указатель буфера передаваемых символов |
|
|
Dim Buft As String * 20 |
‘передаваемая строка |
|
|
============================================================================= |
27 |
===================================== Справочник по программированию «Bascom-AVR» ==
‘ ……
‘———————
‘UART:
|
$baud = |
9600 |
‘скорость 9.6 кБ |
|
$crystal = 8000000 |
‘при кварце 8 МГц |
|
|
‘——————— |
||
|
‘ назначение векторов прерывания |
‘вектор прерывания от приемника UART |
|
|
On Urxc |
Rxd_int Nosave |
|
|
On Utxc |
Txd_int Nosave |
‘вектор прерывания от приемника UART |
|
‘——————— |
‘очистить переменные приемного буфера |
|
|
Gosub Clr_bufrr |
||
|
Enable Urxc |
‘разрешить прерывание приемника UART |
|
|
Enable Utxc |
‘разрешить прерывание передатчика UART |
|
|
Enable Interrupts |
‘разрешить прерывания |
|
|
‘——————— |
||
|
‘ …… |
‘передаваемая строка |
|
|
Buft = «TRANSFERED DATA» |
||
|
Gosub Print_tb |
‘передать буфер |
|
|
‘ …… |
||
|
‘———————————————- |
||
|
‘ обработка прерывания приемника UART |
||
|
Rxd_int: |
||
|
$asm |
‘сохраним регистры |
|
|
Push R31 |
||
|
In R31 , Sreg |
||
|
Push R31 |
||
|
Push R30 |
||
|
Push R27 |
||
|
Push R26 |
||
|
‘——— |
||
|
‘принимаем данные интерфейса |
‘значение текущей позиции буфера |
|
|
Lds |
R26, {R_cch} |
|
|
Lds |
R27, {R_cch + 1} |
‘считать принятый символ |
|
In R31 , Udr |
||
|
‘преобразование строчного символа в прописной |
||
|
Andi R31 , &h7f |
‘ограничение диапазона символов |
|
|
Cpi |
R31 , &h61 |
‘ниже кода символа ‘a’? (нижняя граница) |
|
Brcs Rxdc_0 |
‘да — переход |
|
|
Cpi |
R31 , &h7b |
‘выше кода символа ‘z’? (верхняя граница) |
|
Brcc Rxdc_0 |
‘да — переход |
|
|
Andi R31 , &h5f |
‘между ними — наложить маску |
|
|
‘—— |
||
|
Rxdc_0: |
R31 , &H0A |
‘CR? |
|
Cpi |
||
|
Breq Rxdc_e |
‘игнорировать |
|
|
Cpi |
R31 , &H0D |
‘LF? |
|
Breq Rxdc_2 |
‘это конец строки |
|
|
St X+ , R31 |
‘остальное записывать в буфер |
|
|
Lds |
R30, {Cnt_rc} |
|
|
Inc |
R30 |
‘число 20 – длина буфера |
|
Cpi |
R30 , 20 |
|
|
Breq Rxdc_e |
‘если не последняя позиция |
|
|
Rxdc_1: |
{r_cch} , R26 |
‘записать измененный указатель буфера |
|
Sts |
||
|
Sts |
{r_cch + 1} , R27 |
‘и новое значение счетчика символов |
|
Sts |
{cnt_rc} , R30 |
|
|
Rxdc_e: |
R26 |
|
|
Pop |
||
|
Pop |
R27 |
|
|
Pop |
R30 |
|
|
Pop |
R31 |
|
|
Out |
Sreg , R31 |
|
|
Pop |
R31 |
|
|
Reti |
||
|
‘——— |
||
|
‘принят |
конец строки – нужно переписать принятые данные в промежуточный буфер |
|
|
Rxdc_2: |
R31 , &HFF |
|
|
Ldi |
‘поставить признак наличия принятой строки в буфере Bufr |
|
|
Sts |
{rdat} , R31 |
|
|
‘——— |
||
|
‘займем |
еще регистры (Y) для копирования из Bufrr в Bufr |
|
|
Push R29 |
‘сохраним их |
|
|
Push R28 |
||
|
$end Asm |
‘указатель буфера Bufr в Y на начало |
|
|
Loadadr Bufr , X |
||
|
$asm |
R28 , R26 |
‘применим такой извратный способ, чтобы компилятор |
|
Mov |
||
|
Mov |
R29 , R27 |
‘не увидел явного использования программного стека |
|
$end Asm |
============================================================================= 28
===================================== Справочник по программированию «Bascom-AVR» ==
|
Loadadr Bufrr , X |
‘указатель буфера Bufrr в X на начало |
|
$asm |
‘считать число принятых символов |
|
Lds R30, {Cnt_rc} |
|
|
Rxdc_c: |
‘считать из Bufrr |
|
Ld R31 , X+ |
|
|
St Y+ , R31 |
‘записать в буфер Bufr |
|
Dec R30 |
|
|
Brne Rxdc_c |
‘записать в буфер Bufr конец строки |
|
St Y , R30 |
|
|
Pop R28 |
‘восстановим указатель программного стека |
|
Pop R29 |
|
|
‘——— |
|
|
$end Asm |
‘указатель буфера Bufrr в X снова на начало |
|
Loadadr Bufrr , X |
|
|
$asm |
‘и сбросить значение счетчика символов |
|
Rjmp Rxdc_1 |
|
|
$end Asm |
‘пустая команда, на место которой компилятор |
|
Return |
|
|
‘ |
‘поставит обязательную команду RETI |
|
‘ обработка прерывания передатчика UART |
|
|
Txd_int: |
‘сохраним регистры |
|
Push R31 |
|
|
In R31 , Sreg |
|
|
Push R31 |
|
|
Push R27 |
|
|
Push R26 |
|
|
‘—— |
‘значение текущей позиции буфера |
|
Lds R26 , {t_cch} |
|
|
Lds R27 , {t_cch + 1} |
|
|
Ld R31 , Y+ |
‘проверить на нуль |
|
And R31 , R31 |
|
|
Breq Txdint1 |
‘если он равен 0 — переход |
|
!Out Udr , R31 |
‘записать передаваемый символ |
|
Sts {t_cch} , R26 |
‘записать измененный указатель буфера |
|
Sts {t_cch + 1} , R27 |
|
|
‘—— |
|
|
Txdint1: |
‘восстановим регистры |
|
Pop R27 |
|
|
Pop R26 |
|
|
Pop R31 |
|
|
!Out Sreg , R31 |
|
|
Pop R31 |
|
|
Reti |
|
|
$end Asm |
|
|
Return |
|
|
‘———————————————- |
|
|
‘ …… |
|
|
‘———————————————- |
|
|
‘передача буфера |
|
|
Print_tb: |
‘добавить к содержимому буфера команды конца строки |
|
Buft = Buft + Chr(13) + Chr(10) |
|
|
T_cch = Varptr(buft) |
‘установить указатель на начало буфера |
|
Udr = Peek(t_cch) |
‘инициализировать начало передачи, загрузив |
|
‘первый символ в передатчик это можно было бы не делать, |
|
|
‘если бы можно установить бит TXC (Ucsra , 6), |
|
|
Incr T_cch |
‘а использовать бит UDRE (Ucsra , 5) нельзя |
|
‘установить указатель на следующий символ |
|
|
Return |
|
|
‘———————————————- |
|
|
‘очистить переменные приемного буфера |
|
|
Clr_bufrr: |
‘сам буфер (записать нуль в начало) |
|
Bufrr = «» |
|
|
Rdat = 0 |
‘признак наполнения |
|
Cnt_rc = 0 |
‘счетчик принятых символов |
|
R_cch = Varptr(bufrr) |
‘указатель буфера на начало |
|
Return |
|
|
‘———————————————————————————- |
Разумеется, что при отсутствии необходимости экономить ресурсы микроконтроллера программа прерывания может быть выполнена без ассемблерных вставок. Ниже приведен пример программы, содержащей такой обработчик прерываний. Сохранение регистров общего назначения выполняется компилятором самостоятельно (опция NOSAVE не применена) и все операции обработки данных производятся с использованием операторов Bas- com-AVR.
============================================================================= 29
===================================== Справочник по программированию «Bascom-AVR» ==
Пример 5 — Прерывание от изменения уровня на линиях порта
|
‘———————————————————————————- |
«m644def.dat» |
‘для чипа ATMega644 |
|
$regfile = |
||
|
‘ …… |
||
|
Dim Num_port As Byte |
‘номер порта с изменившимся уровнем |
|
|
Dim Dub_pa |
As Byte |
‘дублер порта A |
|
Dim Dub_pb |
As Byte |
‘дублер порта B |
|
Dim Dub_pc |
As Byte |
‘дублер порта C |
|
Dim Dub_pd |
As Byte |
‘дублер порта D |
|
Dim Tmpb As Byte |
‘временные байтовые данные |
‘ ……
‘определим действующие линии портов как константы
|
Const Pcamsk = &B11111111 |
‘порта PA |
|
|
Const Pcbmsk = &B11111111 |
‘порта PB |
|
|
Const Pccmsk = &B00000011 |
‘порта PC |
|
|
Const Pcdmsk = &B00111100 |
‘порта PD |
|
|
‘ …… |
||
|
On Pcint0 Pc_int0 |
‘векторы прерывания от изменения уровней на линиях портов |
|
|
On Pcint1 Pc_int1 |
||
|
On Pcint2 Pc_int2 |
||
|
On Pcint3 Pc_int3 |
||
|
‘ …… |
||
|
‘настроить систему |
‘разрешим прерывания от изменения уровны во всех портах |
|
|
Pcicr = &B00001111 |
||
|
Pcmsk0 |
= Pcamsk |
‘определим действующие линии портов: порта PA |
|
Pcmsk1 |
= Pcbmsk |
‘порта PB |
|
Pcmsk2 |
= Pccmsk |
‘порта PC |
|
Pcmsk3 |
= Pcdmsk |
‘порта PD |
|
Dub_pa |
= Pina And Pcamsk |
‘запомнить текущее состояние линий портов |
|
Dub_pb |
= Pinb And Pcbmsk |
|
|
Dub_pc |
= Pinc And Pccmsk |
|
|
Dub_pd |
= Pind And Pcdmsk |
|
|
Enable |
Interrupts |
|
|
‘ …… |
||
|
‘главный цикл |
||
|
Mc: |
Num_port <> 0 Then |
|
|
If |
||
|
Print Num_port : Num_port = 0 |
||
|
End If |
||
|
Goto Mc |
|
‘————————————— |
обработки прерываний от изменения уровня, сообщающие главной программе |
|
|
‘программы |
||
|
‘о наличии |
изменения ненулевым значением переменной Num_port |
|
|
‘————————————— |
порта A |
|
|
‘по линиям |
||
|
Pc_int0: |
Pina Xor Pcamsk : Tmpb = Pina Xor Dub_pa : Num_port = 0 |
|
|
Tmpb = |
||
|
Gosub Search_pin |
‘добавить в Num_port номер позиции единицы |
|
|
Return |
||
|
‘————————————— |
порта B |
|
|
‘по линиям |
||
|
Pc_int1: |
Tmpb = Pinb Xor Pcbmsk : Tmpb = Pinb Xor Dub_pb : Num_port = 8
|
Gosub Search_pin |
‘добавить в Num_port номер позиции единицы |
|
Return |
|
|
‘————————————— |
|
|
‘по линиям порта C |
|
|
Pc_int2: |
|
|
Tmpb = Pinc Xor Pccmsk : Tmpb = Pinc Xor Dub_pc : Num_port = 16 |
|
|
Gosub Search_pin |
‘добавить в Num_port номер позиции единицы |
|
Return |
‘—————————————
‘по линиям порта D Pc_int3:
Tmpb = Pind Xor Pcdmsk : Tmpb = Pind Xor Dub_pd : Num_port = 24
|
Gosub Search_pin |
‘добавить |
в Num_port номер позиции единицы |
|
|
Return |
|||
|
‘————————————— |
«1» в измененного |
уровня, на |
самом деле, это преобразование |
|
‘подпрограмма поиска |
|||
|
‘позиционного кода в |
Tmpb в двоичный в |
Num_port. Методом сдвига вправо и искремента результата |
============================================================================= 30