4.1. Ассемблер
Как известно, наиболее эффективные программы получаются при использовании языка Ассемблер. Стоит, правда, отметить, что при этом также увеличивается сложность и время разработки программы. Для микроконтроллеров семейства AVR имеется свободно распространяемый транслятор ассемблера — wavrasm. Также одновременно с транслятором ассемблера устанавливается программа для отладки программ на языке ассемблера для микроконтроллеров семейства AVR. Однако она заметно уступает свободно распространяемому фирмой Atmel отладчику AVR Studio, поэтому ее мы рассматривать не будем.
В этой главе читатели познакомятся с описанием транслятора ассемблера wavrasm. Этот транслятор преобразует команды в виде текстовых мнемоник (специальных сокращений) в закодированные в виде чисел-кодов команды микроконтроллеров. Полученный код можно использовать для работы совместно с отладчиком для проверки правильности работы программы. Также в результате работы транслятора можно получить так называемый файл прошивки, который используется программатором для занесения программы в память программ микроконтроллера.
Транслятор ассемблера работает в среде Microsoft Windows 3.11. Microsoft Windows 95/98 и NT. Кроме того, имеется версия ассемблера, работающая из командной строки MS-DOS. Она устанавливается одновременно с версией для Windows. Версия для Windows имеет встроенный полноэкранный текстовый редактор и справочную систему на английском языке.
В этом описании отсутствует описание системы команд микроконтроллеров, так как в главе 2 имеется таблица команд, и описаны способы адресации.
Это описание предполагает, что транслятор wavrasm правильно установлен на компьютер, на котором происходит работа.
Начало работы
Запустите транслятор ассемблера. С помощью команды меню File» Open откройте файл tutor.asm. В результате выполнения этой команды исходный текст программы на ассемблере будет загружен в программу и показан на экране. На рис. 4.1 показан примерный вид экрана.
Рис. 4.1. Окно транслятора с загруженной программой
Ассемблирование первой программы
После того как вы просмотрели текст, выберите команду меню Assemble. После этого появится второе окно (окно сообщений), которое содержит сообщения об ошибках. Окно сообщений будет располагаться поверх окна с исходным текстом программы на ассемблере, поэтому удобно предпринять некоторые действия по настройке расположения окон. Перейдите в окно с исходным текстом программы (просто щелкнув левой кнопкой мышки в любом месте текста программы) и выберите команду меню Windows» Tile Horizontal. Кроме того, полезно увеличить размер окна с исходным текстом программы и уменьшить окно сообщений. Для этого следует переместить верх окна сообщений с помощью мышки ниже. В результате на экране должна получиться картинка, похожая на изображенную на рис. 4.2.
Рис. 4.2. Вид экрана транслятора ассемблера с двумя окнами
Поиск и исправление ошибок
Глядя на окно сообщений, можно сделать вывод, что в процессе трансляции программы были обнаружены ошибки. В окне сообщений ошибки показываются следующим образом: в строке подряд идут название файла, в скобках номер строки, в которой обнаружена ошибка, и, наконец, краткое текстовое сообщение о характере ошибки. Естественно, ошибку следует найти и исправить. Щелкните левой кнопкой мышки на первом сообщении об ошибке в окне сообщений (которая находится на 7-й строке). Обратите внимание, что в окне с исходным текстом на строке 7 появится вертикальная красная линия. Сообщение об ошибке говорит о том, что как имена регистров можно использовать только имена r0…r31. Это верно, так как микроконтроллеры семейства AVR имеют 32 регистра общего назначения, а в строке 7 программы указано имя регистра r39, которого не существует. Фотография окна программы с описанной ситуацией показана на рис. 4.3.
Рис. 4.3. Окно программы с выделенной строкой с ошибкой
Двойной щелчок на сообщении ошибки в окне сообщений приводит к тому, что окно текстового редактора исходного текста становится активным, а курсор устанавливается в начало строки с ошибкой. Исправьте r39 на r19.
Ниже в окне сообщений показано еще сообщение об ошибке. Щелкните левой кнопкой мышки по следующему сообщению об ошибке.
Сообщение Illegal argument type or count говорит о том, что что-то неправильно в аргументах команды. Обратите внимание, что один из аргументов — тот самый, который мы только что исправили. Просмотрев все сообщения об ошибках, можно прийти к выводу, что все остальные ошибки были связаны с первой.
Чтобы определить, все ли ошибки исправлены, имеет смысл снова запустить трансляцию программы. Если ошибки остались, следует их исправить. Если ошибок больше нет, в окне сообщений появится сообщение об успешном завершении трансляции.
Формат программы на ассемблере
Программа на ассемблере представляет собой текстовый файл, который состоит из мнемоник — символьных обозначений команд микроконтроллера, меток и директив.
Любая строка может начинаться с метки — строки из символов и (или) цифр, заканчивающейся двоеточием.
Метки используются для обозначения текущей строки некоторым именем (меткой) для использования в командах условного или безусловного перехода, а также для обозначения участка в памяти для обращения к данным.
Строка исходного текста может иметь один из следующих видов:
1. [метка: ] директива [аргументы директивы] [комментарий]
2. [метка: ] мнемоника команды [аргументы команды] [комментарий]
3. Комментарий
4. Пустая строка
Комментарии всегда начинаются с символа «;».
Элементы, заключенные в квадратные скобки, могут отсутствовать. Текст, расположенный после символа «точка с запятой» до конца строки, полностью игнорируется ассемблером. Использование меток, мнемоник команд микроконтроллера и директив ассемблера подробнее будет рассмотрено чуть позднее.
Примеры записи строк:
label1:.EQU var1=100 ; Директива определения символьного
; имени var1, эквивалентного записи ”100"
.EQU var2=200 ; Определение имени var2, соответствующего "200"
test: rjmp test ; Бесконечный цикл (мнемоника команды микроконтроллера)
; Пустая строка
Обратите внимание, что не играет никакой роли, в каких местах расположены метки, команды ассемблера и директивы, важен только их порядок.
Команды микроконтроллера
Транслятор ассемблера позволяет использовать в тексте программы мнемоники (обозначения команд микроконтроллера), полностью совпадающие с их названием в системе команд микроконтроллера.
Команды микроконтроллеров семейства AVR делятся на несколько групп:
• арифметические и логические;
• команды условных и безусловных переходов;
• команды передачи данных;
• команды для работы с битами.
Краткое описание команд микроконтроллера можно найти в главе 2.
Для транслятора ассемблера нет разницы, какими буквами написаны слова, т. е. rjmp и RJMP совершенно равнозначны. Однако для удобства понимания программы рекомендуется все мнемоники и метки записывать строчными (маленькими) буквами, а директивы прописными (большими).
Директивы транслятора ассемблера
Транслятор ассемблера поддерживает достаточно много директив. Директивы не транслируются в программу для микроконтроллера. Они используются для указания транслятору ассемблера данных о расположении программы в памяти микроконтроллера, определения макросов и т. д.
Ниже приведен перечень директив транслятора ассемблера:
.BYTE — резервирует 1 байт для использования в качестве переменной;
.CSEG — сегмент программ;
.DB — определяет байт-константу;
.DEF — определяет символическое имя для регистра;
.DEVICE — задает тип целевого микроконтроллера;
.DSEG — сегмент данных;
.DW — определяет слово-константу;
.ENDMACRO — конец определения макроса;
.EQU — сопоставляет символьному имени арифметическое выражение;
.ESEG — сегмент EEPROM;
.EXIT — выйти из файла (конец текста программы);
.INCLUDE — загрузить исходный текст из другого файла;
.LIST — включить генерацию листинга;
.LISTMAC — включить печать содержимого макросов в листинге;
.MACRO — начать определение макроса;
.NOLIST — выключить генерацию листинга;
.ORG — установить расположение;
.SET — сопоставить символу выражение.
Обратите внимание, что все директивы должны начинаться с точки.
.BYTE — резервирует место (или несколько мест) размером 1 байт для переменной.
Директива BYTE резервирует один байт в памяти SRAM для реализации переменной. Для того чтобы иметь возможность обращаться к этой переменной, перед директивой BYTE должна стоять метка. Директива имеет один параметр — количество байтов для резервирования. Директива может использоваться только для резервирования места в памяти данных (смотри директивы CSEG, DSEG и ESEG).
Синтаксис:
Метка:.BYTE числовое выражение
Примеры:
.DSEG
var1:.BYTE 1 ; Резервируем 1 байт для переменной var1
able:.BYTE tab_size ; Резервируем tab_size байт
.CSEG
ldi r30,low(var1) ; Загружаем младший байт Z-регистра
ldi r31,high(var1) ; Загружаем старший байт Z-регистра
Id r1,Z; Загрузить содержимое переменной var1 в r1
.CSEG — сегмент кода.
Директива CSEG определяет начало сегмента кода (программ). В исходном тексте программы может быть несколько сегментов кода. Транслятор ассемблера в процессе компиляции программы объединяет все сегменты кода в один. Директива BYTE не может быть использована в сегменте кода. Если в программе нет явного указания названия сегмента, по умолчанию считается, что это сегмент кода. Директива CSEG не имеет никаких параметров. Сегмент кода имеет свой счетчик слов. Директива-ORG может быть использована для размещения кода или констант в определенном программистом месте памяти программ.
Синтаксис:
.CSEG
Пример:
.DSEG ; Начало сегмента данных
vartab: BYTE 4 ; Резервируем 4 байта в SRAM
.CSEG ; Начало сегмента кода
const:.DW 2 ; Запишем число 0x0002 в память программ
mov r1,r0 ; Что-нибудь сделаем
. DB — определить байты-константы в памяти программ или EEPROM.
Директива DB резервирует место в памяти программ или EEPROM. Для того чтобы иметь возможность обращаться к зарезервированному пространству, перед этой директивой следует ставить метку. Директива DB может быть расположена только в сегменте кода или EEPROM. Параметрами директивы DB является список выражений.
Список выражений представляет собой одно или несколько выражений, разделенных запятыми. Каждое выражение может быть равно числу от -128 до 255. Если выражение представляет собой отрицательное число, оно будет помещено в намять программ или EEPROM в дополнительном коде.
Если директива DB расположена в сегменте кода и имеет больше, чем одно выражение в списке параметров, выражения упаковываются таким образом, что два байта располагаются в одном слове памяти программ. Если число выражений нечетное, последнее выражение будет помещено в отдельное слово памяти программ, даже если после директивы DB следом расположена еще одна директива DB.
Синтаксис:
Метка:.DB список выражений
Пример:
.CSEG
const:.DB 0, 255, 0Ь01011100, — 128,0хаа
.ESEG
eeconst:.DB 0xff
.DEF — назначить регистру символьное имя.
Директива DEF позволяет назначить регистру символьное имя, что позволяет сделать программу гораздо понятнее и нагляднее. Можно назначить одному регистру несколько символьных имен. Символьное имя регистра может быть переопределено в последующем тексте программы.
Синтаксис:
.DEF символьное имя = регистр
Пример:
.DEF temp=r16.
.DEF for=r0
.CSEG
ldi temp, 0xf0 ; Загрузить в регистр temp число 0xf0
in ior, 0x3f ; Прочитать содержимое SREG и записать в регистр ior
еог temp, ior ; Исключающее ИЛИ между регистрами temp и ior
.DEVICE — определяет тип целевого микроконтроллера.
Директива DEVICE позволяет программисту указать, на каком микроконтроллере будет выполняться программа. Если в тексте программы указана эта директива, транслятор ассемблера будет проверять текст программы на наличие недопустимых операций (например, не поддерживаемых выбранным микроконтроллером). В случае попытки использования большего размера SRAM или EEPROM памяти, чем имеется у выбранного микроконтроллера, также будет выдано предупреждение. Если директива DEVICE отсутствует в тексте программы, разрешены все команды семейства микроконтроллеров AVR, а размеры памяти не проверяются.
Синтаксис:
DEVICE AT9DS1200 | AT90S2313 | AT9DS2323 | AT90S2343 | AT90S4414 | AT90S8515 | ATMEGA103
Примечание. Появляются новые модели микроконтроллеров, поэтому при необходимости использовать более новый микроконтроллер следует самостоятельно отслеживать разрешенные инструкции в тексте программы (соответственно не применяя директиву DEVICE) либо воспользоваться обновленной версией транслятора ассемблера.
Пример:
.DEVICE AT90S1200 ; Используется микроконтроллер AT90S1200
.CSEG
push r30 ; Эта запись вызовет сообщение о том, что выбранное устройство не поддерживает эту инструкцию
.DSEG — сегмент данных.
Директива DSEG определяет начало сегмента данных. В исходном тексте программы на ассемблере может быть несколько сегментов данных. В процессе трансляции все они будут объединены в один. Обычно сегмент данных содержит только директивы BYTE с метками. Сегмент данных имеет свой счетчик байтов. Директива ORG может быть использована для расположения переменных в конкретных местах SRAM. Директива DSEG не имеет параметров.
Синтаксис:
.DSEG
Пример:
.DSEG ;Начало сегмента данных
var1:.BYTE 1; Резервируем 1 байт для переменной var1
table:.BYTE tab_size ; Резервируем tab_size байт
.CSEG
ldi r30,low(var1) ;Загружаем младший байт Z-регистра
ldi r31.high(var1) ;Загружаем старший байт Z-регистра
Id r1,Z ;Загрузить содержимое переменной var1 в r1
.DW — определение слов-констант в памяти программ или EEPROM.
Директива DW резервирует место в памяти программ или EEPROM. Для того чтобы иметь возможность обращаться к зарезервированному пространству, перед этой директивой следует ставить метку. Директива DW должна быть расположена в сегменте кода или EEPROM. Параметрами директивы DW является список выражений.
Список выражений представляет собой одно или несколько выражений, разделенных запятыми. Каждое выражение может быть равно числу от -32768 до 65535. Если выражение представляет собой отрицательное число, оно будет помещено в память программ или EEPROM в дополнительном коде.
Синтаксис:
Метка:.DW список выражений
Пример:
.CSEG
varlist:.DW 0,56255, 0b0101110011101011, -12128, 0xaaff
.ESEG
eevar:.DW 0xff17
.ENDMACRO — конец описания макрокоманды.
Директива ENDMACRO определяет конец описания макрокоманды. Директива не имеет параметров. Для получения информации о макрокомандах смотри директиву MACRO.
Синтаксис:
.ENDMACRD
Пример:
MACRO SUBI16 ; Начало определения макрокоманды
subi r16,low(@0) ; Вычитаем младший байт
sbci r17, high(@0) ; Вычитаем старший байт
.ENDMACRO ; Конец определения макрокоманды
.SET — присвоить символьному обозначению выражение.
Директива SET присваивает символьному обозначению значение выражения. В дальнейшем это символьное обозначение может быть использовано в выражениях. Присвоенное значение — константа. В дальнейшем тексте программы это символьное выражение не может быть переопределено или изменено.
Синтаксис:
.EQU <символьное обозначение> = <выражение>
Пример:
.EQU io_offset = 0x23
.EQU porta = io_offset + 2
.CSEG ; Начало сегмента кода
clr r2 ; Очистить регистр r2
out porta,r2 ; Записать в порт А
.ESEG — EEPROM сегмент.
Директива ESEG определяет начало EEPROM сегмента. В исходном тексте программы может быть несколько EEPROM сегментов. Транслятор ассемблера в процессе компиляции программы объединяет все EEPROM сегменты в один. Директива BYTE не может быть использована в EEPROM сегменте. Директива ESEG не имеет никаких параметров. Сегмент EEPROM имеет свой счетчик байтов. Директива. ORG может быть использована для размещения кода или констант в определенном программистом месте памяти EEPROM.
Синтаксис:
.ESEG
Пример:
.DSEG ; Начало сегмента данных
vartab:.BYTE 4 ; Резервируем 4 байта в SRAM
.ESEG
eevar:.DW 0xff67 ; Инициализируем одно слово в EEPROM
.CSEG ;Начало сегмента кода
const:.DW 2 ;Запишем число 0x0002 в память программ
mov r1,r0 ;Что-нибудь сделаем
.EXIT — конец текста программы.
Директива EXIT указывает транслятору ассемблера, что следует завершить трансляцию программы. При отсутствии этой директивы транслятор ассемблера работает до тех пор, пока исходный файл не закончится (EOF). Если директив EXIT встречается в файле, включаемом в текст директивой INCLUDE, транслятор ассемблера продолжит работу со строки, следующей после соответствующей директивы INCLUDE.
Синтаксис:
.EXIT
Пример:
.EXIT ; Завершить обработку этого файла
.INCLUDE — вставить файл.
Директива INCLUDE указывает транслятору ассемблера на необходимость вставить в исходный текст программы другой файл. Реально при обработке этой директивы транслируется файл, указанный в директиве INCLUDE, после завершения его обработки (при достижении конца файла или директивы. EXIT) продолжается обработка основного файла. Вложенные файлы, в свою очередь, могут иметь директиву INCLUDE. Для облегчения понимания можно представить себе, что в текст программы вместо директивы INCLUDE вставляется соответствующий файл.
Синтаксис:
.INCLUDE "имя файла"
Пример:
; Файл iodefs.asm
.E0U sreg=0x3f ; Регистр статуса
.EQU sphigh=0x3e ; Старший байт стека
.EOU splow=0x3d ; Младший байт стека
;Файл incdemo.asm
.INCLUDE "iodefs.asm" ; Включить в текст программы файл incdemo.asm
in r0.sreg ; Прочитать содержимое регистра статуса
.LIST — включить генерацию листинга.
Директива LIST включает генерацию листинга. Ассемблер генерирует листинг, содержащий исходный текст на ассемблере, адреса и коды операций. По умолчанию генерация листинга включена. В комбинации с директивой NOLIST можно организовать печать только нужных фрагментов программы.
Синтаксис:
.LIST
Пример:
.N0LIST ; Отключить генерацию листинга
.INCLUDE "macro.inc" ; Включаемые файлы не будут
.INCLUDE “const.def" ; показаны в листинге
.LIST ; Включить генерацию листинга
.LISTMAC — включить раскрытие макрокоманд.
Директива LISTMAC указывает транслятору ассемблера на необходимость показа в листинге содержимого макрокоманд. По умолчанию в листинге показывается только название макрокоманды.
Синтаксис:
.LISTMAC
Пример:
MACRO МАСХ ; Определить макрокоманду
add r0,@0
еог г1,@1
.ENDMACRO ; Конец определения макрокоманды
.LISTMAC
МАСХ r2,r1 ; Вызов макрокоманды. В листинге будет показан ее текст
.MACRO — начало определения макрокоманды.
Директива MACRO указывает транслятору ассемблера на начало определения макрокоманды. Параметром директивы MACRO является имя определяемой макрокоманды. В дальнейшем при обнаружении в тексте программы имени макрокоманды транслятор ассемблера будет фактически заменять это имя на содержание макрокоманды. Макрокоманда может иметь до 10 параметров. Эти параметры имеют фиксированные имена: @0…@9. При вызове макрокоманды параметры должны быть представлены в виде списка, разделенного запятыми. Определение макрокоманды завершается директивой ENDMACRO.
При определении новой макрокоманды нельзя использовать другие макрокоманды (т. е. нельзя использовать вложенные макрокоманды).
Макрокоманда должна быть определена в тексте программы до того, как ее используют.
По умолчанию в листинге генерируется только вызов макрокоманды. Чтобы получить в листинге содержимое макрокоманд, следует использовать директиву LISTMAC. Текст макрокоманды в листинге помечен символом «+».
Синтаксис:
.MACRO
Пример:
MACRO SUBI16 ; Начало определения макрокоманды
subi r16,low(@0); Вычитаем младший байт
sbci r17,hlgh(@0); Вычитаем старший байт
ENDMACRO; Конец определения макрокоманды
CSEG; начало сегмента кода
SUBI16 9x1234,r16,r17 ; Вычесть 0x1234 из r17:r16
Примечание: r17:r16 в данном случае — пара регистров, содержащая 16-разрядное число.
.NOLIST — включить генерацию листинга.
Директива NOLIST выключает генерацию листинга. Ассемблер генерирует листинг, содержащий исходный текст на ассемблере, адреса и коды операций. По умолчанию генерация листинга включена. В комбинации с директивой LIST можно организовать печать только нужных фрагментов программы.
Синтаксис:
.NOLIST
Пример:
.NOLIST; Отключить генерацию листинга
.INCLUDE "macro.inc" ; Включаемые файлы не будут
.INCLUDE "const.def" ; показаны в листинге
.LIST ; Включить генерацию листинга
.ORG — установка значения счетчика расположения.
Директива ORG присваивает абсолютное значение счетчику. Параметром директивы является значение, которое должно быть присвоено счетчику. При использовании директивы ORG в сегменте данных будет определено значение, указывающее расположение и оперативной памяти SRAM. При использовании директивы ORG в сегменте кода будет определено значение, указывающее расположение в памяти программ. При использовании директивы ORG в сегменте EEPROM будет определено значение, указывающее расположение в памяти EEPROM.
Если перед директивой расположена метка (на этой же строке), метка получит значение параметра директивы. Значение по умолчанию для сегмента кода и EEPROM равно 0, а для SRAM — 32 (так как регистры занимают пространство с 0 до 31). Обратите внимание, что для EEPROM и SRAM отсчитываются байты, в то время как в памяти программ — слова.
Синтаксис:
.ORG выражение
Пример:
.DSEG; Начало сегмента данных (SRAM)
.ORG 0x37 ; Установить адрес SRAM 37Н
variable:.BYTE 1 ; Зарезервировать 1 байт по адресу 37Н SRAM
.ESEG ;Начало сегмента EEPROM
.ORG 0x20 ; Установить значение счетчика расположения
eevar:.DW 0xf77a ;Инициализировать слово в памяти EEPROM
.CSEG
.ORG 0x10 ; Установить счетчик на значение 0x10
mov r0,r1 ; Эта команда будет расположена в памяти; программ по адресу 0x10
.SET — присвоить символьному обозначению выражение.
Директива SET присваивает символьному обозначению значение выражения. В дальнейшем это символьное обозначение может быть использовано в выражениях. В дальнейшем тексте программы это символьное выражение может быть изменено.
Синтаксис:
.SET символьное обозначение = выражение
Пример:
SET io_offset = 0x23
.SET porta = io_offset + 2
CSEG ; Начало сегмента кода
clr r2; Очистить регистр г2
out porta,r2; Записать в порт А
Выражения
Ассемблер позволяет использовать в тексте программы выражения. Они могут содержать операнды, операции и функции. Все выражения имеют разрядность 32 бита.
Операнды
Могут быть использованы следующие операнды:
• определенные программистом метки, имеющие значение счетчика, в зависимости от места своего расположения;
• переменные, определенные с помощью директивы SET;
• константы, определенные с помощью директивы EQU;
• целые константы:
— десятичные (по умолчанию): 10,255,
— шестнадцатеричные (два вида записи): 0x0а, $0а, 0xff, $ff,
— двоичные: 0Ь00001010, 0b11111111;
• коды символов ASCII: 'А', 'а';
• строки ASCII (без нуля в конце строки): «String»;
• PC — текущее значение счетчика команд в памяти программ.
Функции
LOW(выражение) — возвращает младший байт выражения;
НIGH(выражение) — возвращает старший байт выражения;
ВУТЕ2(выражение) — возвращает 2 байта выражения;
ВУТЕ3(выражение) — возвращает 3 байта выражения;
ВУТЕ4(выражение) — возвращает 4 байта выражения;
LWRD(выражение) — возвращает биты 0—15 выражения;
HWRD(выражение) — возвращает биты 16–31 выражения;
РАGЕ(выражение) — возвращает биты 16–21 выражения;
ЕХР2(выражение) — возвращает 2^ выражения;
LOG2(выражение) — возвращает целую часть lоg 2(выражение).
Операции
Ассемблер поддерживает различные операторы, описанные ниже. При их использовании можно применять скобки.
Логическое НЕ
Обозначение: !
Описание: унарный оператор, возвращает 1, если выражение равно нулю, и 0, если выражение было не равно нулю.
Приоритет: 14.
Пример: ldi r16,!0xf0; Загрузить в г16 0x00
Побитовое НЕ
Обозначение: ~
Описание: унарный оператор, который возвращает исходное выражение со всеми инвертированными битами.
Приоритет: 14.
Пример: ldi r16.~0xf0; Загрузить в r16 0x0f
Унарный минус
Обозначение: —
Описание: возвращает число с измененным на противоположный знаком.
Умножение
Обозначение: *
Описание: возвращает результат умножения двух чисел. Приоритет: 13.
Пример: ldi r30,label*2; Загрузить в регистр r30 label*2
Деление
Обозначение: /
Описание: возвращает целую часть от деления левого параметра на правый.
Приоритет: 13.
Пример: ldi r30, label/2; Загрузить в регистр r30 label/2
Сложение
Обозначение: +
Описание: возвращает сумму двух чисел.
Приоритет: 12.
Пример: ldi г30,с1+с2; Загрузить в регистр r30 с1+с2
Вычитание
Обозначение: -
Описание: возвращает результат вычитания правого числа из левого.
Приоритет: 12.
Пример: ldi г17,с1-с2; Загрузить в регистр r30 с1-с2
Сдвиг влево
Обозначение: <<
Описание: возвращает значение левого числа, сдвинутое влево на число раз, равное правому числу.
Приоритет: 11.
Пример: ldi r17,1<<3; Загружает в регистр г17 число 1, сдвинутое влево на 3 бита
Сдвиг вправо
Обозначение: >>
Описание: возвращает значение левого числа, сдвинутое вправо на число раз, равное правому числу.
Приоритет: 11.
Пример: ldi r17,1>>2; Загружает в регистр r17 число 1, сдвинутое вправо на 2 бита
Меньше
Обозначение: <
Описание: возвращает 1, если первое число меньше второго, иначе— 0.
Приоритет: 10.
Пример: ori r18,bitmask*(c1
Меньше или равно
Обозначение: <=
Описание: возвращает 1, если первое число меньше второго или равно ему, иначе — 0.
Приоритет: 10.
Пример: ori r18,bitmask*(c<=c2)+1
Больше
Обозначение: >
Описание: возвращает 1, если первое число больше второго, иначе— 0.
Приоритет: 10.
Пример: ori r18,bitmask*(c1>c2)+1
Больше или равно
Обозначение: >=
Описание: возвращает 1, если первое число больше второго или равно ему, иначе — 0.
Приоритет: 10.
Пример: ori r18,bitmask*(c1>=c2)+1
Равно
Обозначение: ==
Описание: возвращает 1, если первое число равно второму, иначе — 0.
Приоритет: 9
Пример: andi г19, bitmask*(c1==c2)+1
Не равно
Обозначение: !=
Описание: возвращает 1, если первое число не равно второму, иначе — 0.
Приоритет: 9.
Пример:.SET flag=(c1!=с2)
Побитовое И
Обозначение: &
Описание: возвращает результат побитной операции «И» между операндами.
Приоритет: 8.
Пример: ldi r18,High(c1&c2)
Побитовое исключающее ИЛИ
Обозначение: ^
Описание: возвращает результат побитной операции «исключающее ИЛИ» между операндами.
Приоритет: 7.
Пример: ldi r18,Low(c1^c2)
Побитовое ИЛИ
Обозначение: |
Описание: возвращает результат побитной операции «ИЛИ» между операндами.
Приоритет: 6.
Пример: ldi ri8,Low(c2|c2)
Логическое И
Обозначение: &&
Описание: возвращает 1, если оба выражения не равны нулю, иначе — 0.
Приоритет: 5.
Пример: ldi r8,Low(ci&&c2)
Логическое ИЛИ
Обозначение: ||
Описание: возвращает 0, если оба выражения равны нулю, иначе — 0.
Приоритет: 4.
Пример: ldi r18,Low(ci||с2) Описание программы WAVRASM
Здесь опишем специфические особенности применения транслятора ассемблера WAVRASM.
Открытие файла программы
Теоретически нет ограничений на количество одновременно oткрытых файлов исходных текстов. Размер каждого файла не должен превышать примерно 28 Кб. Для работы с файлами большего размера следует использовать версию ассемблера, работающую из командной строки MS-DOS — avrasm. Также можно разбить всю программу на несколько файлов и объединить их с помощью директивы INCLUDE.
Для каждого открытого файла создается окно с его текстом.
Для создания нового файла следует выполнить команду меню File>>New (быстрая комбинация клавиш: Alt-F N). Для открытия существующего файла следует выполнить команду меню File>>Open (быстрая комбинация клавиш: Alt-F О).
Встроенный текстовый редактор
Перемещение по тексту программы
Для перемещения по тексту программы можно пользоваться следующими командами:
вправо — стрелка вправо;
влево — стрелка влево;
вверх — стрелка вверх;
вниз — стрелка вниз;
в начало строки — Ноmе;
в конец строки — End;
в начало файла — Ctrl+Home;
в конец файла — Ctrl+End.
Редактирование текста
Для редактирования текста следует пользоваться клавишами:
— вставить пробел — пробел;
— завершить строку — Enter;
— удалить символ слева от курсора — Backspace;
— удалить символ справа от курсора — Del.
Для разбиения строки на две следует установить курсор на место разбиения и нажать Enter.
Для объединения двух строк следует установить курсор в начало второй строки и нажать клавишу Backspace.
Выделение текста, операции копирования, перемещения и удаления осуществляются так же, как в любой программе для Windows.
Установка опций программы
Некоторые установки транслятора ассемблера могут быть изменены. Для этого следует выполнить команду меню Options. Появится окно, подобное изображенному на рис. 4.4.
Рис. 4.4. Окно установки опций программы
В этом окне можно установить расширение файла, содержащего листинг программы и файла с оттранслированным кодом. Менять их не рекомендуется.
Также здесь можно указать, какого типа должен генерироваться выходной файл. Имеется три типа файлов: Generic, Motorola S-record и Intel HEX.
Обратите внимание, что объектный файл (который используется отладчиком) всегда имеет расширение obj. Также, если в программе инициализируются значения в памяти EEPROM, генерируется файл с расширением еер, используемый программатором для прошивки в микроконтроллер в процессе программирования. Этот файл генерируется в формате Generic.
Опция Wrap relative jumps — разрешить относительную адресацию переходов. Эта опция полезна для использования с микроконтроллерами, имеющими 4 К слов памяти программ.
Опция Save before assemble — сохранять исходный текст программы каждый раз перед ее ассемблированием. Версия ассемблера для командной строки
Одновременно с установкой транслятора ассемблера для Windows, устанавливается версия для работы из командной строки MS-DOS. Эта версия транслятора не имеет никаких ограничений по объему транслируемой программы (т. е., в отличие от версии для Windows, размер файла может быть больше 28 кбайтов).
Вызывается программа следующим образом:
avrasm [-m|-i|-g] input.asm output.lst output.hex
В результате выполнения программы будет прочитан файл input.asm, сгенерирован файл листинга listfile.lst, файл скомпилированного кода для загрузки в память программ микроконтроллера output.hex и объектный файл *.obj, используемый отладчиком.
Назначение ключей программы
m — генерировать файл кода в формате Motorola S-Record;
i — генерировать файл кода в формате Intel HEX;
g — генерировать файл кода в формате Generic.
По умолчанию генерируется файл кода в формате Generic.
Для выбора типа файла следует уточнить, с каким типом файлов может работать программатор, которым программа будет заноситься в микроконтроллер.
Формат файлов, генерируемых транслятором ассемблера
Формат Generic
Рассматриваемый транслятор ассемблера может генерировать три различных типа файлов: Generic, Motorola S-Records и Intel HEX.
Рассмотрим один из этих форматов — Generic. Файлы этого формата — текстовые.
Структура файла очень проста. Каждая строка файла имеет вид: Адрес: код операции.
Здесь «Адрес» — 6 цифр (24 бита) шестнадцатеричного числа, и «код операции» — 4 цифры (16 битов) шестнадцатеричного числа. «Адрес» определяет адрес в памяти программ, а «код операции» — содержимое памяти по указанному адресу.
В качестве примера рассмотрим программу на ассемблере:
; Демонстрация формата Generic
mov r0,r1
inc r1
call oursub
.org 0x50 ; Установить адрес в памяти программ на 0x50
oursub: add r1,r2
ret
В результате трансляции этой программы будет получен файл gen_demo.rom следующего содержания:
000000:2с01
000001:9413
000002:940е
000003:0050
000050:0с12
000051:9508
Обратите внимание на то, что команды, состоящие из двух слов, размещаются в двух строках файла.
Если в программе был определен сегмент EEPROM, то генерируется файл для прошивки в EEPROM. Расширение этого файла еер. Этот файл всегда генерируется в формате Generic.
Формат объектного файла
Объектный файл содержит отладочную информацию и может быть использован отладчиком для проверки правильности работы программы.
Объектный файл имеет две части: record и trailer.
Заголовочная часть имеет следующий формат:
• смещение к исходным именам файлов (4 байга);
• смещение к объектным записям (4 байга);
• число байтов в каждой записи (1 байт);
• число имен файлов во второй части файла (1 байт);
• строку A VR Object File\0 (\0 означает, что строка завершена 0).
Длительность записей составляет 9 байтов каждая. Формат записи:
• адрес памяти программ (3 байта);
• код операции (2 байта);
• номер инструкции в исходном файле (1 байт, счет начинается с 0);
• номер строки в исходном файле (2 байга, счет начинается с 1);
• индикатор макроса (1 байт, 1 — если макрос, иначе — 0).
И наконец, trailer часть имеет следующий формат:
• имена файлов (заканчивающиеся на 0, число файлов в заголовке);
• ASCII 0.
Для примера рассмотрим программу (файл obj demo.asm):
; Демонстрация объектного формата
.equ const1=0x15
.equ const2=0x40
macro SWIN
swap @0
inc @0
.endmacro
start: ldi r16.const1
SWIN r16
ldi r16.const2
SWIN r16
rjmp start
.include "delay.asm"; Включение другого файла на ассемблере
Включаемый файл (delay.asm):
delay: dec r16
breq delay
ret
После трансляции будет получен объектный файл. Файл — бинарный. Для удобства рассмотрения он был переведен в 16-ричный формат, а столбцы были раздвинуты.
Смещение: Содержимое файла (в 16-ричном формате):
00000000: 00000074 Смещение к именам файлов
00000004: 0000001А
00000008: 09
00000009: 02
0000000A: 415652204F626A6563742046696C6500 Cтрока A0F
0000001А: 000000Е10500000В00 Первая запись
00000023: 000001950200000C01
0000002С: 000002950300000C01
00000035: 000003E40000000D00
0000003Е: 000004950200000Е01
00000047: 000005950300000Е01
00000050: 000006CFF900000F00
00000059: 000007950А01000400
00000062: 000008F3F101000500
0000006В: 000009950801000600 Последняя запись
00000074: 4F424A5F44454D4F2E41534D00 "0BJ_DEM0.ASH\0"
00000081: 44454С41592Е41534D00 "DELAY.ASM\0"
0000008В: 00 Конец объектного файла
4.2. Компилятор языка С CodeVision AVR
CodeVision представляет собой кросс-компилятор языка С, графическую оболочку и автоматический генератор программ, ориентированные на работу с семейством микроконтроллеров AVR фирмы Atmel. Внешний вид окна программы показан на рис. 4.5.
Рис. 4.5. Внешний вид окна программы CodeVision AVR
Программа представляет собой 32-разрядное приложение для работы в операционных системах Windows 95, 98, NT4.0 и 2000.
Кросс-компилятор включает в себя почти все элементы, соответствующие стандарту ANSI. Также в компилятор включены дополнительные возможности, ориентированные на использование архитектурных особенностей микроконтроллеров этого семейства и встроенных систем в целом.
Объектные файлы COFF позволяют осуществлять отладку программ с просмотром содержимого переменных. Для этого следует применять свободно распространяемый фирмой Atmel () отладчик AVR Studio debugger версии 3.5 или более поздний.
Для отладки систем, использующих последовательную передачу данных, в графической оболочке имеется встроенный Terminal.
Кроме стандартных библиотек языка С, компилятор имеет библиотеки для работы с:
• ЖКИ индикаторами со встроенным контроллером;
• шиной I2C фирмы Philips;
• датчиком температуры LM75 фирмы National Semiconductor;
• часами реального времени PCF8563 и РС8583 фирмы Philips, DS1302 и DS1307 фирмы Dallas Semiconductor;
• однопроводным протоколом фирмы Dallas Semiconductor;
• датчиками температуры DS1820 и DS1822 фирмы Dallas Semiconductor;
• датчиком температуры/термостатом DS1621 фирмы Dallas Semiconductor;
• памятью EEPROM DS2430 и DS2433 фирмы Dallas Semiconductor;
• шиной SPI;
• управлением режимами пониженного потребления энергии;
• временными задержками.
Также в CodeVision имеется автоматический генератор программ, который позволяет в течение считанных минут получить готовый код для следующих функций:
• настройка доступа к внешней памяти;
• определение источника прерывания Reset;
• инициализация портов ввода/вывода;
• инициализация внешних прерываний;
• инициализация таймеров/счетчиков;
• инициализация сторожевого таймера;
• инициализация UART;
• инициализация аналогового компаратора;
• инициализация встроенного АЦП;
• инициализация интерфейса SPI;
• инициализация поддерживаемых библиотеками CodeVision микросхем, работающих с однопроводным интерфейсом и шиной I2С;
• инициализация модуля ЖКИ-индикатора со встроенным контроллером.
Среда CodeVision AVR включает в себя программное обеспечение для работы с совместимым с платой STK200 программатором. После компиляции исходной программы на языке С полученный код может быть непосредственно запрограммирован в микроконтроллер. Этот программатор использует всего четыре сигнала: MOSI, MISO, SCK, RESET. Известно много простейших программаторов, соединяющихся с последовательным или параллельным портом IBM совместимого персонального компьютера.
Читателям предлагается на примере простейшей схемы познакомиться с применением демонстрационной версии компилятора языка С CodeVisionAVR, Для этого придется изготовить простой совместимый с STK200 кабель внутрисхемного программирования и несложную схему с микроконтроллером AT90S2313. В итоге проделанную работу можно будет проверить, запустив простую программу на языке С.
Изготовление кабеля для внутрисхемного программирования «STK200/300»
На рис. 4.6 показана электрическая принципиальная схема кабеля. Микросхема 74НС244 представляет собой буфер с тремя состояниями на выходах, что позволяет избежать влияния кабеля на схему после программирования микроконтроллера, не отключая кабеля.
Адаптер получил свое название от комплектующихся им отладочных плат фирмы Atmel для быстрого начала работы с микроконтроллерами At90s8515 и Atmega103 соответственно. На самом деле приведенная схема соответствует одновременно обеим адаптерам, в ней присутствуют перемычки для определения наличия как адаптера STK200 (выводы 2-12 разъема XI), так и STK300 (выводы 3-11).
Разводка колодки Х2 на приведенной схеме соответствует принятой фирмой Atmel для производимых ею плат.
Рис. 4.6. Простой кабель для внутрисхемного программирования
Простая демонстрационная схема на микроконтроллере AT90S8535
Чтобы проверить эту схему в работе, вам нужно иметь только один микроконтроллер AT90S2313, источник питания +5 В и кварцевый резонатор частотой 4 МГц. Кроме этого, потребуется несколько пассивных элементов — конденсаторов и резисторов. Электрическая принципиальная схема устройства изображена на рис. 4.7.
Для управления светодиодом в схеме использован всего один вывод микроконтроллера — PD1.
Рис. 4.7. Простейшая схема с микроконтроллером AT90S2313
Пример программы
Для проверки работы кабеля внутрисхемного программирования и демонстрационной схемы предлагается несложная программа, которая заставляет мигать светодиод. Оттранслированный код для этой программы можно найти на прилагаемом к книге компакт диске в файле blink.hex.
Текст программы:
// blink.с
#include <90s2313.h>
#include <delay.h>
void main()
{
// инициализация порта D
DDRD=0xff; // Порт D работает на вывод
PORTD=0x00;
while(1)
{
PORTD.1=0;
delay_ms(1000);
PORTD.1=1;
delay_ms(1000);
} // while(1)
} // main
Использование встроенного программатора CodeVision
Простейший способ работы с прорамматором — использование команды меню Project, подменю CONFIGURE. Если осуществить указанные на рис. 4.8 установки, оттранслированный код программы будет загружен в микроконтроллер непосредственно после успешной компиляции.
Рис. 4.8. Окно настройки проекта
Перед работой следует указать тип используемого программатора. На рис. 4.9 показан вид окна выбора типа программатора.
Рис. 4.9. Окно выбора типа программатора
После успешной трансляции должно появиться окно, подобное показанному на рис. 4.10. Для занесения программы в микроконтроллер, следует нажать кнопку «Program».
Рис. 4.10. Окно, появляющееся после успешной трансляции программы
Примеры программ для компилятора CodeVision AVR С
Процедуры работы со встроенным АЦП AT90S8535 без прерываний
Текст программы:
// В данном примере определяются две функции для работы с АЦП:
// void ImtADC(void) инициализация АЦП
// int fieadADC(unsigned char) чтение значения напряжения на заданном входе
#include <ioB535.h>
void InitADC(void)
{
ADMUX = 0 ; // выбрать вход номер 0
ADCSfi = 0xC0; // включить АЦП и запустить первое "пустое" преобразование
}
int ReadADC(unsigned char channel)
{
int i;
ADMUX = channel ; // Выбрать номер входа
ADCSR |= 0x40; // Начать преобразование
while (!(ADCSR & 0x10)); // Проверка завершения преобразования
ADCSR |= 0x10; //Очистка бита "Преобразование завершено" при помощи записи в него "1"
i = ADCL ; // Чтение младших 8 битов ПЕРВЫМИ
i += (int)ADCH << 8 ; // Чтение старших 2 битов, умножение их на 256 и сложение с младшим байтом
return i;
}
void main(void)
{
unsigned int temp;
InitADC(); // Инициализация АЦП
temp=ReadADC(0); // Измерить напряжение на нулевом входе АЦП (линия РАО порта А)
}
Пример вызова написанных на ассемблере функций из С программы
Материал взят из демонстрационной версии компилятора CodeVisionAVR С Compiler, автором которого является Pavel Haiduc, HP InfoTech S.R.L.
Текст программы:
// Определение функции на ассемблере. Эта функция возвращает а+Ь+с
#pragma warn- // Запретить предупреждения
int sum_abc(int a, int b, unsigned char с) {
#asm
ldd r30, у+3 ;R30=LSB а
Idd r31,у+4 ;R31=MSB а
Idd r26,у+1 ;R26=LSB b
Idd r27,у+2 ;R27=MSB b
add r30,r26 ;(R31,R30)=a+b
adc r31,r27
Id r26,у;R26=c
clr r27 ; Преобразование с типа unsigned char в тип int
add r30,r26; (R31,R30)=(R31,R30)+C
adc r31,r27
#endasm
}
#pragma warn+ // Разрешить предупреждения
void main(void) {
int r;
// Теперь вызовем функцию и сохраним результат в r
r=sum_abc(2,4,6);
}
Некоторые пояснения.
Компилятор передает параметры функции с помощью стека данных. Первым он передаст целый параметр а, затем b и в завершение с типа unsigned char. При каждой передаче регистровая пара Y увеличивается на размер параметра (4 для типа long, 2 для int, 1 для char).
В случае параметров, состоящих из нескольких байтов, первым передается старший байт. Как вы видите, стек растет вниз. После того как все параметры функции были записаны в стек (pushed), регистр Y указывает на последний параметр с, поэтому мы можем прочитать его значение в R26, воспользовавшись командой Id r26,у.
Параметр b был записан в стек перед с, поэтому он находится по более высокому адресу в стеке данных. Мы можем прочитать его значение, воспользовавшись командами ldd r27,у+2 (старший байт) и ldd r26,у+1 (младший байт).
Старший байт был записан в стек первым, поэтому он находится по более высокому адресу.
Параметр а был записан в стек перед Ь, поэтому он находится по более высокому адресу в стеке данных. Мы можем прочитать его значение, воспользовавшись командами ldd r27,у+4 (старший байт) и ldd r26,у+3 (младший байт).
Старший байт был записан в стек первым, поэтому он находится по более высокому адресу.
Функции возвращают свои значения в следующих регистрах:
R30 для типов char & unsigned char;
R30, R31 для типов int & unsigned int;
R30, R31, R22, R23 для типов long & unsigned long.
Поэтому наша функция должна вернуть ее результат в регистрах R30, R31.
После возвращения из функции компилятор автоматически генерирует код, освобождающий стек от параметров функции, поэтому можно не задумываться об этом.
Директива #pragma warn запрещает компилятору генерировать предупреждения о том, что функция не возвращает результат.
Это необходимо, потому что компилятору не известно, что мы делаем в нашей написанной на ассемблере функции.
Использование встроенного EEPROM
Материал взят из демонстрационной версии компилятора CodeVisionAVR С Compiler, автором которого является Pavel Haiduc, HP InfoTech S.R.L.
Текст программы:
// Контроллер: AT90S2313
// Модель памяти: TINY
// Размер стека данных: 64 bytes
flash char f[]="This is a test";
#pragma warn-
eeprom char e[16];
#pragma warn+
char r[16];
void main (void)
{
Char flash *ptr_to_flash;
char eeprom *ptr_to_eeprom;
char *ptr_to_ran;
// Копировать строку f из FLASH в
// Строку e в EEPROM
ptr_to_flash=f;
ptr_to_eeprom=e;
while (*ptr_to_flash)
*ptr_to_eeprom++=*ptr_to_flash++;
// Копировать строку e из EEPROM в
// строку г в оперативной памяти
ptr_to_eeprom=e;
ptr_to_ram=r;
while (*ptr_to_eeprom)
*ptr_to_ram++=* ptr_to_eeprom++;
// Стоп (бесконечный цикл)
while (1);
}
Работа с клавиатурой 4x4
Материал взят из демонстрационной версии компилятора CodeVisionAVR С Compiler, автором которого является Pavel Haiduc, HP InfoTech S.R.L.
Рис. 4.11. Схема соединения клавиатуры 4x4
Для индикации использован 2х16 алфавитно-цифровой ЖКИ, подсоединенный к порту PORTC следующим образом:
Текст программы:
#asm
.equ __lcd_port=0x15
#endasm
#include <lcd.h>
#include <stdio.h>
#include <delay.h>
#include <90sB515.h>
// Частота кварцевого резонатора [Гц]
#define F_XTAL 4000000L
// Линии PINDO…3 будут входами строк
#define KEYIN PIND
// Линии PORTD4..7 будут выходами столбцов
#define KEYOUT P0RTD
// Инициализация использованного таймера TIMER0
#define INIT_TIMER0 TCNT0=0x100L-F_XTAL/64L/500L
#define FIRST_COLUMN 0x80
#define LAST_COLUMN 0x10
typedef unsigned char byte;
// Здесь в виде бита сохраняется состояние каждой нажатой клавиши,
// бит 0 будет KEY0, бит 1 KEY1….
unsigned keys;
// Буфер ЖКИ-индикатора
char buf[33];
// Прерывание по таймеру TIMER 0 каждые 2 мс
interrupt [TIM0_OVF] void timer0_int(void)
{
static byte key_pressed_counter=20;
static byte key_released_counter,column=FIRST_COLUMN;
static unsigned row_data,crt_key;
// Перезагрузить таймер TIMERO
INIT_TIMER0;
row_data<<=4;
// Получить группу из 4 клавиш в переменной row_data
row_data|=¯KEYIN&0xf;
column>>=1;
if (column==(LAST_C0LUHN>>1))
{
column=FIRST_COLUHN;
if (row_data==0) goto new_key;
if (key_released_counter) — key_released_counter;
else
{
if (-key_pressed_counter==9) crt_key=row_data;
else
{
if (row_data!=crt_key)
{
new_key:
key_pressed_counter=10;
key_released_counter=0;
goto end_key;
};
if (!key_pressed_counter)
{
keys=row_data;
key_released_counter =20;
};
};
};
end_key:;
row_data=0;
};
// Выбрать следующий столбец, входы будут притянуты к 5 В
KEY0UT=¯column;
}
// Проверить, были ли нажаты клавиши
unsigned inkey(void)
{
unsigned k;
if (k=keys) keys=0;
return k;
}
void init_keypad(void)
{
DDRD=0xf0;
INIT_TIHERO;
TCCR0=3;
TIMSK=2;
#asm("sei")
}
main() {
unsigned k;
init_keypad();
lcd_init(16);
lcd_putsf("CVAVR Keypad");
// Читать состояние клавиш и индицировать код клавиши
while (1)
{
lcd_gotoxy(0,1);
if (k=inkey())
{
sprintf(buf,“Key code=%Xh“,k);
lcd_puts(buf);
}
else lcd_putsf("NO KEY ");
delay_ms(500);
}
}
Работа с алфавитно-цифровым ЖК-индикатором 2x16
Материал взят из демонстрационной версии компилятора CodeVisionAVR С Compiler, автором которого является Pavel Haiduc, HP InfoTech S.R.L.
Использован ЖК-индикатор со встроенным контроллером, подсоединенный к порту PORTC следующим образом:
Текст программы:
// ЖК-индикатор подсоединен к выходам порта P0RTC
// смотри файл lcd.h в директории..\inc
#asm
.equ __lcd_port=0x15;PORTC
#endasm
// Включить в состав программы описания и процедуры для работы с ЖК-индикатором
#include <lcd.h>
void main(void)
{
// Инициализировать ЖК-индикатор для работы
// с 2 строками по 16 символов
lcd_init(16);
// Перейти на 2-ю строку ЖК-индикатора
lcd_gotoxy(0,1);
// Отобразить сообщение
lcd_putsf("Hello world'');
// Остановиться (бесконечный цикл)
while (1);
}
Использование определенных пользователем символов при работе с ЖК-индикатором со встроенным контроллером
Материал взят из демонстрационной версии компилятора CodeVisionAVR С Compiler, автором которого является Pavel Haiduc, HP InfoTech S.R.L.
Использован алфавитно-цифровой ЖК-индикатор. Соединения между ЖК-индикатором и платой со схемой должны быть как можно короче.
Текст программы:
// Включить в программу определения и процедуры для работы со ЖК-индикатором
// в плате STK200/300
#include <lcdstk.h>
typedef unsigned char byte;
// Таблица для определенного пользователем символа
// стрелка, указывающая на верхний правый угол
flash byte char0[8]={
0b0000000,
0Ь0001111,
0b0000011,
0b0000101,
0b0001001,
0b0010000,
0b0100000,
0b1000000};
// Функция, использованная для определения заданного пользователем символа
void define_char(byte flash *рс. byte char_code)
{
byte i,a;
a=(char_code«3)|0x40;
for (i=0; i<8; i++) lcd_write_byte(a++,*pc++);
}
void main(void)
{
// Инициализация ЖКИ для работы
// с 2 строками по 16 символов в строке
lcd_init(16);
// Определить символ 0
define_char(char0,0);
// Переключиться в режим записи в память отображения (Display RAM)
lcd_gotoxy(0,0);
// Отобразить определенный пользователем символ
lcd_putsf("User defined\nchar 0:");
// Отобразить определенный пользователем символ 0
lcd_putchar(0);
// Стоп (бесконечный цикл)
while (1);
}
Бегущий огонь на светодиодах
Материал взят из демонстрационной версии компилятора CodeVisionAVR С Compiler, автором которого является Pavel Haiduc, HP InfoTech S.R.L.
8 светодиодов соединены с выходами порта PORTB и +5 В через резисторы сопротивлением 270 Ом, ограничивающие гок. Аноды светодиодов соединены с линией +5 В.
Текст программы:
// Определение регистров ввода-вывода для ATS0S8515
#include <90sS815.h>
// Частота кварцевого резонатора [Гц]
#define xtal 4000000
// Частота переключения светодиодов [Гц]
#define fmove 2
// Включить светодиод на линии 0 порта P0RTB
unsigned char led_status=0xfe;
// Процедура обработки прерывания по переполнению таймера TIMER1
// вызывается каждые 0,5с
interrupt [TIM1_OVF] void timer1_overflow(void)
{
// preset again TIMER1
TCNT1=0x10000-(xtal/1024/fmove);
// move the LEO
led_status<<=1;
led_status|=1;
if (led_status==0xff) led_status=0xfe;
// turn on the LED
P0RTB=led_status:
}
void main(void)
{
// Инициализация портов ввода-вывода
// Все выводы порта PORTB настроены на вывод информации
DDRB=0xff;
// Включить первый светодиод
PORTB=led_status,
// Инициализация таймера TIMER1
// Таймер TIHER1 отсоединен or линии OC1
// не включен режим широтно-импульсной модуляции PWM
TCCR1А=0;
// Частога таймера TIMER1 xtal/1024
TCCR1B=5;
// Предустановим значение таймера TIMER1
TCNT1=0x10000-(xtal/1024/fmove);
// Очистить флаги прерываний по таймеру
TIMER1 TIFR=0;
// Разрешить прерывания по переполнению таймера TIMER1
TIMSK=0x80;
// Все остальные виды прерываний запрещены
GIMSK=0;
// Разрешение глобальных прерываний
#fasm
sei
#endasm
// Бесконечный цикл, при этом возможно возникновение прерываний по переполнению таймера TIMER1
while (1);
}
Цифровой вольтметр с использованием АЦП фирмы Maxim типа МАХ1241
Измеренное значение передается с помощью интерфейса RS232. Параметры интерфейса: 9600 8N1.
Материал взят из демонстрационной версии компилятора CodeVisionAVR С Compiler, автором которого является Pavel Haiduc, HP InfoTech S.R.L.
Частота кварцевого резонатора: 4,000 МГц.
Подсоединение МАХ 1241 KAT90S8515.
Программатор после программирования контроллера должен быть отсоединен.
Текст программы:
#include <90s8515.h>
// Стандартная библиотека ввода/вывода
#include <stdio.h>
// Библиотека SPI-функций
#include <spi.h>
// Библиотека для формирования задержек
#include <delay.h>
// Опорное напряжение для МАХ1241 [мВ]
#define VREF 5000
// Определение управляющих сигналов для МАХ1241
#define NSHON P0RTB.0
#define NCS P0RTB.1
#define DOUT PINB.6
union adcu
{
unsigned char byte[2];
unsigned int word;
};
// Произвести одно аналого-цифровое преобразование и
// вернуть его результат unsigned
int max1241_read(void)
{
union adcu adc_data;
// Вывести микросхему MAX1241 из режима shutdown
NSHDN=1;
// Подождать 5 мкс для приведения МАХ1241 в рабочее состояние
delay_us(5);
// Теперь выбрать чип для начала преобразования
NCS=0;
// Ждать, пока преобразование не завершится
// DOUT будет равен 0 в процессе преобразования
while (DOUT==0);
// DOUT=1 —> преобразование завершено
// Прочитать младший байт (MSB)
adc_data.byte[1]=spi(0);
// Прочитать старший байт (LSB)
adc_data.byte[0]=spi(0);
// Снять сигнал выбора чипа
NCS=1;
// Перевести АЦП в режим shutdown
NSHDN=0:
// Форматировать результат преобразования и возврат результата
return (adc_data.word»3)&0xfff;
}
void main(void)
{
// Переменная для хранения результата преобразования
unsigned n;
// Инициализация портов ввода/вывода
// Port А
DDRA=0x00;
P0RTA=0x00;
// Port В
// Линия /SS установлена на вывод информации
// на уровне 1, это необходимо для работы
// SPI-порта в режиме мастер
DDRB=0xA3;
P0RTB=0x12;
// Port С
DDRC=0x00;
P0RTC=0x00;
// Port D
DDRD=0x00;
P0RTD=0x00;
// Инициализация UART (интерфейс RS-232)
// Параметры интерфейса: 8 битов данных, 1 стоп бит, без проверки четности
// приемник UART: отключен
// передатчик UART: включен
UCR=Ox08;
// Скорость передачи данных: 9600
UBRR=0x19;
// Инициализация SPI
// Режим работы SPI: мастер
// Тактовая частота SPI: 1000 000 кГц
// Порядок передачи данных: младший бит первый
SPCR=0x50;
putsf("MAX1241 Demo using the CodeVisionAVR С Compiler");
pUtSf ("*******************************************\n");
// Произвести аналого-цифровое преобразование и передать результаты
// через интерфейс RS-232
while (1)
{
n=max1241_read();
printf("HAX1241-> N=%4u U=964umV\r\n",n,(unsigned) ((long) n*VREF/4096));
// 0.3 sec. delay
delay_ms(300);
};
}
Использование ЖК-индикатора МТ10Т7-7
Микроконтроллер: AT90S8535-8PI.
Кварцевый резонатор: 4 МГц.
Подсоединение индикатора к порту Port С:
Текст программы:
void delay(void)
{
asm("del1: ldi r24,0x01");
asm("dl: dec r24");
asm('brne dl");
asm("dec r25");
asm("brne del1");
}
void STR0B_WR1(void)
{
asm("sbi 0x18,5");
delay();
asm("cbi 0x18,5");
}
void STR0B_ADR(void)
{
asm("cbi 0x18,4"):
delay();
asm("sbi 0x18,5");
delay();
asm("cbi 0x18,5");
delay();
asm("sbi 0x18,4");
}
void Set_Bus(unsigned char A)
{
If ((A&0x01)==0x01) asm("sbi 0x18,0");
else asm("cbi 0x18,0");
If ((A&0x02)==0x02) asmC'sbi 0x18,1");
else asm("cbi 0x18,1");
if ((А&0х04)==0х04) asm("sbi 0x18,2");
else asm("cbi 0x18,2");
if ((А&0х08)==0х0в) asm("sbi 0x18,3");
else asmC'cbi 0x18,3");
}
void Init_LCD(void)
{
unsigned char temp;
Set_Bus(0x0f);
STR0B_ADR();
Set_Bus(0x01);
STR0B_WR1();
Set_Bus(0);
STR0B_ADR();
for (temp=0;temp<20;temp++) STR0B_WR1();
}
unsigned char code7(unsigned char code)
{
switch(code)
{
case 0: return 0xee;
case 1: return 0x60;
case 2: return 0x2f;
case 3: return 0x6d;
case 4: return 0xe1;
case 5: return 0xcd;
case 6: return 0xcf;
case 7: return 0x68;
case 8: return 0xef;
case 9: return 0xed;
case 10: return 0;
}
return 0;
}
void out(unsigned char num)
{
num=code7(num);
Set_Bus(num);
STR0B_WR1();
delay0;
asm("swap %num"); Set_Bus(num);
STR0B_WR1();
delay();
}
void display(unsigned int N, unsigned int N1, unsigned int N2)
{ // NN N1N1N1N1 N2N2N2N2
Set_Bus(0);
STR0B_ADR();
out((unsigned int)(N/10)-10*(unsigned int)(N/100));
out(N-10*(unsigned int)(N/10));
out((unsigned int)(N1/1000)-10*(unsigned int)(N1/10000));
out((unsigned int)(N1/100)-10*(unsigned int)(N1/1000));
out((unsigned int)(N1/10)-10-(unsigned int)(N1/100));
out(N1-10*(unsigned int)(N1/10));
out((unsigned int)(N2/1000)-10*(unsigned int)(N2/10000));
out((unsigned int)(N2/100)-10*(unsigned int)(N2/1000));
out((unsigned int)(N2/10)-10*(unsigned int)(N2/100));
out(N2-10*(unsigned int)(N2/10));
}
«include <io8535.h>
void main()
{
DDRB = 0xFF; /* Port С настроен на вывод */
P0RTB = 0xff; /* Все линии порта С = 1 */
Init_LCD();
display(0,1,7);
while(1);
}
Динамическая индикация
Динамическая индикация с применением прерывания по переполнению таймера Timer 0. Вывод на индикатор происходит каждые 65 мс. Прерывания по таймеру 1 происходят с периодом примерно 1 с. При этом на единицу увеличивается значение на индикаторе. При достижении значения 20 происходит обнуление значения для вывода.
Микроконтроллер: AT90S2313.
Кварцевый резонатор: 4 МГц.
Текст программы:
#include <90s2313.h>
#include "HG.h"
// Timer 0 overflow interrupt service routine interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Reinitialize Timer's 0 value
TCNT0=0xFF;
// Place your code here
HG12();
}
// Timer 1 overflow interrupt service routine
interrupt [TIM1_0VF] void timer1_ovf_isr(void)
{
// Reinitialize Timer's 1 value
TCNT1H=0xf0;
TCNT1L=0xbe;
// Place your code here
N++;
if (N==20) N=0;
// Declare your global variables here
void main(void)
{
unsigned int temp,temp1,temp2;
// Input/Output Ports initialization
// Port В
P0RTB=0x00;
DDRB=0xFF;
// Port D
P0RTD=0x00;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 3906 kHz
// Mode: Output Compare
// OCD output: Disconnected
TCCR0=0x05;
TCNT0=0xFF;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 3,906 kHz
// Mode: Output Compare
// OC1 output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
TCCR1A=0x00;
TCCR1B=0x05:
TCNT1H=0xf0;
TCNT1L=0xbe;
0CR1H=0x00;
0CR1L=0x11;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
GIMSK=0x00;
MCUCR=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x82;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80:
// Global enable interrupts
#asm("sei")
init_HG();
while (1)
{
};
}
Звуковой генератор на частоту 1000 Гц
К нулевой линии порта В подсоединен транзисторный ключ, управляющий динамической головкой.
Микроконтроллер: AT90S2313.
Кварцевый резонатор: 4 МГц.
#include <90s2313.h>
// Процедура обработки прерывания Timer 1 по переполнению
interrupt [TIM1_0VF] void timer1_ovf_isr(void)
{
// Перезагрузить значение Timer 1
TCNT1H=0xff;
TCNT1L=0xfd;
if (PINB. 0–0) PORTB. 0=1; else P0RTB.0=0;
}
void main(void)
{
// Инициализация портов ввода/вывода
// Port В
DDRB=0xFF;
P0RTB=0x00;
// Port D
PORTD=0x00:
DDRD=0x00;
// Инициализация Timer 1
// Clock source: System Clock
// Clock value: 3906 kHz
// Mode: Output Compare
// OC1 output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
TCCR1A=0x00;
TCCR1B=0x05;
TCNT1H=0xff;
TCNT1L=0xfd;
0CR1H=0x00;
0CR1L=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x80;
P0RTB=0x00;
while (1);
}
Модель светофора
К линиям 0, 1 и 2 порта В подсоединены соответственно красный, желтый и зеленый светодиоды.
Микроконтроллер: AT90S2313.
Кварцевый резонатор: 4 МГц.
Текст программы:
#include <90s2313.h>
// Timer 1 overflow interrupt service routine
interrupt [TIM1_0VF] void timer1_ovf_isr(void)
{
// Reinitialize Timer's 1 value
TCNT1H=0xb3;
TCNT1L=0xb5;
// Place your code here
P0RTB=P0RTB<<1;
if (PINB,2==1) P0RTB=0x01;
}
// Declare your global variables here
void main(void)
{
// Declare your local variables here
// Input/Output Ports initialization
// Port В
DDRB=0xFF;
P0RTB=0x00;
// Port D
P0RTD=0x00;
DDRD=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 3906 kHz
// Mode: Output Compare
// OC1 output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
TCCR1A=0x00;
TCCR1B=0x05;
TCNT1H=0xb3;
TCNT1L=0xb5;
0CR1H=0x00;
OCR1L=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0xB0;
P0RTB=0x01;
while (1);
}
4.3. Компилятор
Imagecraft С
Очень интересен для рассмотрения С компилятор фирмы ImageCraft. Этот оптимизирующий компилятор достаточно компактен: дистрибутив имеет объем всего 2,5 Мбайт. После установки на диск компилятор занимает чуть больше 4 Мбайт. Несмотря на скромные размеры, он позволяет создавать вполне серьезные программы. Интегрированная среда разработки (IDE) работает в среде Windows 95/98/NT и включает в себя текстовый редактор с полноценной поддержкой русского языка и подсветкой синтаксиса программ, и менеджер проекта. Компилятор поддерживает работу практически со всеми AVR-микроконтроллерами, в том числе с новыми ATmega161/163 и FPSLIC АТ94. Для микросхем семейства ATtiny и AT90S1200, не имеющих внутреннего ОЗУ, имеется пакет ICC Tiny AVR. Опции компиляции можно выбрать из стандартного набора или установить самостоятельно, выбрав в поле «тип микросхемы» — custom device. Компилятор позволяет получить стандартный НЕХ-файл для загрузки в микросхему, и файл в формате COFF, необходимый для работы с отладчиком AVR Studio. Компилятор совместим со стандартом ANSI С. В исходном тексте можно использовать вставки на ассемблере.
Библиотеки, поставляемые в комплекте с компилятором, включают достаточно большое количество функций, в том числе специализированных, ориентированных на специфические особенности микроконтроллеров, такие как доступ к ЭСПЗУ, АЦП и SPI-интерфейсу. В интегрированной среде имеется достаточно подробно написанный help-файл, практически полностью повторяющий содержание книги, входящей в комплект поставки компилятора. Есть очень полезная возможность обратиться за помощью непосредственно на фирму ImageCraft, написав письмо по адресу . В отличие от многих других производителей программного обеспечения, эта фирма достаточно оперативно отвечает на вопросы пользователей. Несомненным преимуществом работы с компилятором ImageCraft С является возможность полноценной работы до приобретения С-компилятора. Последняя демо-версия пакета доступна на сайте производителя программы по адресу , причем эта версия максимально дружелюбна: пользователь может работать с исходными текстами неограниченной длины и компилировать файл для любой микросхемы. Единственным ограничением является время работы — 30 дней. Его достаточно для разработки даже крупного проекта. По истечении месяца пользователь должен принять решение: или переформатировать винчестер, чтобы еще раз установить демо-версию, либо приобрести официальный дистрибутив и право на техническую поддержку. Демонстрационная версия этого компилятора имеется на компакт-диске, прилагаемом к книге.
Ниже приведен пример простейшей программы для компилятора Imagecraft. Эта программа заставляет мигать восемь светодиодов, подключенных к порту В.
Текст программы:
// Микроконтроллер: A190S2313
#include <io2313.h>
#include «macros.h>
// Инициализация портов ввода/вывода
void init_ports(void)
{
DDRB = 0xFF; // Порт В работает на вывод
PORTB = 0xFF;
DDRD = 0x00; // Порт D работает на ввод
PORTD = 0x00;
}
// Временная задержка
void delay()
{
unsigned char a, b;
for (a = 1; a; a++)
for (b = 1; b; b++):
}
void main(void)
{
init_ports(); // Инициализация портов
PORTB = 0xff; // Погасили все светодиоды
delay();
PORTB = 0x00; // Зажгли все светодиоды
delay();
}
4.4. Компилятор языка С AVR GCC
Этот компилятор принципиально отличается от описанных выше тем, что он бесплатно распространяется, но при этом не имеет вообще никаких ограничений. Дело в том, что первоначальный вариант компилятора существовал (и существует) для операционной системы Линукс, практически, это — тот же компилятор, адаптированный для работы в среде Windows. По этой причине им несколько непривычно пользоваться, но он имеет достаточно неплохие характеристики.
Нижеприведенные программы идут в комплекте с свободно распространяемым компилятором AYR GCC.
Мигание светодиодами
Автор: Volker Oth.
Мигает светодиодами на плате STK200.
Текст программы:
#include <io.h>
typedef unsigned char u08;
int main(void)
{
u08 led, i, j, k;
outp(0xff.DDRB); /* Все выводы порта В работают на вывод
led = 1; /* Инициализировать начальное состояние */
for (;;) {
outp("led, PORTB); /* Инвертировать выход. 0 — светодиод включен */
led <<= 1; /* К следующему светодиоду */
if (!led) /* Переполнение: снова начать с линии В0 */
led = 1;
for (i=0; i<255; i++) /* Цикл формирования временной задержки */
for(j=0; j<255;j++) /* Вложенный цикл формирования временной задержки */
k++; /* Произвольное действие чтобы чем-то "занять" микроконтроллер */
}
}
Мигание светодиодами с использованием таймера 0
Автор: Volker Oth.
Мигает светодиодами, подключенными к порту В под управлением таймера 0.
Текст программы:
#include <io.h>
#include <interrupt.h>
#include <signal.h>
unsigned char led;
SIGNAL(SIG_OVERFLOW0) /* Обработчик прерывания переполнения таймера 0 */
{
outp("led, PORTB); /* Инвертировать выходные линии. 0 — светодиод горит */
led <<= 1; /* К следующему светодиоду */
if (!led) /* Переполнение; начать снова с линии В0 */
led = 1;
outp(0, TCNT0); /* Сбросить таймер, для возможности повторного «прерывания */
}
int main(void) {
{
outp(0xff,DDRB ); /* Все выводы порта В работают на вывод */
outp((1<<TOIE0), TIMSK); /* Разрешить прерывание по переполнению таймера 0 */
outp(0, TCNT0); /* Сбросить (обнулить) TCNTO */
outp(5. TCCR0); /* Включить предварительное деление СК/1024 */
led = 1; /* Инициализация начального состояния светодиодов» */
sei(); /* Разрешить прерывания «/
for (;;) {} /* Бесконечный цикл */
Иллюстрация использования внешних прерываний INT0 и INT1 и препроцессора
Автор: Volker Oth.
Текст программы:
#include <io.h>
#include <signal.h>
#include <interrupt.h>
#ifdef AVR_ATmega103
#define AVR_MEGA 1
#else
#ifdef AVR_ATmega603
#define AVR_MEGA 2
#else
#ifdef AVR_ATmega161
#define AVRMEGA 3
#else
#define AVR_MEGA 0
#endif
#endif
#endif
typedef unsigned char u08;
SIGNAL(SIG_INTERRUPTO) /* Обработчик внешнего прерывания into */
{
register u08 led = mp(PORTB);
if (led & 1)
led &= ~ 0x0f; else
led |= 0x0f;
out(led, PORTB); /* Зажечь светодиоды */
}
SIGNAL(SIG_INTERRUPT1) /* Обработчик внешнего прерывания int1 */
{
register u08 led = inp(PORTB);
if (led & 0x80)
led &= ~ 0xf0;
else
led |= 0xf0;
outp(led, PORTB); /* Зажечь светодиоды */
}
int main(void)
{
outp(0xff, DDRB); /* Все линии порта В на вывод (светодиоды) */
outp(0x00, DDRD); / * Все линии порта D на ввод (кнопки) */
#if AVR_MEGA
outp((1<<INT0)|(1<<INT1),EIMSK); /* Разрешить внешние прерывания into, inti */
#else
outp((1<<INT0)|(1<<INT1),GIMSK); /* Разрешить внешние прерывания into, inti */
outp((1<<ISC01)|(1<<ISC10)|(1<<ISC11),MCUCR); /* По спаду: int0, no нарастанию: int1 */
#endif
sei(); /* Разрешить прерывания */
for (;;) {} /* Бесконечный цикл */
}
Иллюстрация применения UART
Автор: Volker Oth.
Иллюстрация применения UART. Работает совместно с программой terminal или подобной.
Формат UART: 9600 бод, 8 битов, 1 стоп-бит, без проверки четности.
Текст программы:
#include <io.h>
#include <interrupt.h>
#include <signal.h>
#define F_CPU 4000000 /* 4 МГц */
#define UART_BAUD_RATE 9600 /* 9600 бод */
#define UART_BAUD_SELECT (F_CPU/(UART_BAUD_RATE*161)-1)
typedef unsigned char u08;
typedef char s08;
typedef unsigned short u16;
typedef short s16;
static volatile u08 *uart_data_ptr;
static volatile u08 uart_counter;
SIGNAL(SIG_UART_TRANS) /* Обработчик прерывания UART txd готов */
{
uart_data_ptr++;
if (--uart_counter)
outp(*uart_data_ptr, UDR); /* Записать байт в буфер данных */
}
SIGNAL(SIG_UART_RECV) /* Обработчик прерывания "прием завершен" */
{
register char led;
led = inp(UDR); /* Прочитать байт из буфера данных UART */
outp( ~ led, PORTB); /* Отобразить полученный байт на светодиодах, подключенных к порту В */
}
void uart_send(u08 *buf, u08
{
if (!uart_counter) { «Записать первый байт в буфер данных */
uart_data_ptr = buf;
uart_counter = size;
outp(*buf, UDR);
}
}
void uart_init(void) /* Инициализировать UART */
{ /* разрешить прерывания RxD/TxD */
outp((1<<RXCIE)|(1<<TXCIE)I(1<<RXEN)|(1<<TXEN),UCR);
/* установить скорость */
outp((uD8)UART_BAUD_SELECT, UBRR);
}
int main(void)
}
outp(0xff,DDRB); /* Все линии порта В на вывод */
outp(0x00, PORTB); /* Зажечь светодиоды */
uart_init();
sei(); /* Разрешить прерывания */
for (;;) { /* Бесконечный цикл */
uart_send("Serlal Data from AVR received###", 32);
}
}
Работа с EEPROM и UART
Автор: Volker Oth.
Читает и записывает EEPROM. При возникновении прерывания UART «передача завершена», содержимое EEPROM пересылается на компьютер. После получения байта от компьютера прерывание «прием завершен» отображает полученный байт на светодиодах и сохраняет его в EEPROM. Формат UART: 9600 бод, 8 битов, 1 стоп-бит, без проверки четности.
Текст программы:
#include <io.h>
#include «interrupt. h>
#include «signal. h>
#include «eeprom.h>
#define F_CPU 4000000 /* 4 МГц */
#define UART_BAUD_RATE 9600 /* 9600 бод */
#define EEPR0M_SIZE (E2END+1)
#define UART_BAUD_SELECT (F_CPU/(UART_BAUD_RATE*161)-1)
typedef unsigned char u08;
typedef char s08;
typedef unsigned short u16;
typedef short s16:
u16 read_counter; u16
write_counter;
SIGNAl(SIG_UART_RECV) /* Обработчик прерывания “прием завершен" */
{
register u08 ee_write;
ee_write = inp(UDR); /* Прочитать байт из буфера данных UART */
outp( ~ ee_write, PORTB); /* Отобразить байт на светодиодах */
eeprom_wb(write_counter, ee_write); /* Записать байт в EEPROM»/
if (++write_counter >= EEPR0M_SIZE) /* Переполнение: установить смещение 0 */
write_counter = 0;
}
SIGNAL(SIG_UART_TRANS) /* Обработчик прерывания "передача завершена" */
{
register u08 ee_read;
ee_read = eeprom_rb(read_counter); /* Прочитать следующий байт из EEprom */
outp(ee_read, UDR); /* Записать байт в буфер данных UART */
if (++read_counter >= write_counter) /* Переполнение: начать с 1-го символа */
read_counter = 0;
}
int main(void)
{
outp(0xff,DDRB); /* Все линии порта В на вывод */
outp(0x00, PORTB); /* Зажечь все светодиоды */
/* Разрешить прерывания RxD/TxD */
outp((1<<RXCIE)|(1<<TXCIE)|(1<<RXEN)|(1<<TXEN),UCR);
/* Установить скорость 9600 */
outp(UART_BAUD_SELECT, UBRR);
sei (); /* разрешить прерывания */
read_counter = 0; /* Начать читать с первого байта в EEPROM */
write_counter = 0; /* Начать запись с первого байта в EEPROH */
outp('#', UDRi); /* Записать 1-й байт в буфер данных UART */
for (;;) {} /* Бесконечный цикл */
}
Демонстрирует использование библиотеки вычислений с плавающей запятой
Автор: Volker Oth.
Демонстрирует использование библиотеки вычислений с плавающей запятой. Выполняет 4 основных арифметических операции. Результаты преобразуются в 16-битовый формат с фиксированной точкой и передаются на настольный ПК с помощью UART. Результаты могут быть просмотрены с помощью программы terminal или подобной:
$0000 (start identifier)
$006b = 107 = 10.0*(7.5+3.2)
$002b = 43 = 10.0*(7.5–3.2)
$00f0 = 240 = 10.0*(7.5*3.2)
$0017 = 23 = 10.0*(7.5/3.2)
Текст программы:
#include <io.h>
#include <interrupt.h>
#include <signal.h>
#define F_CPU 4000000
#define UART_BAUD_RATE 9600
#define UART_BAUD_SE LEOT (F_CPU/(UARr_BAUD_RATE*161)-1)
typedef unsigned char u08;
typedef char s08;
typedef unsigned short u16;
typedef short s16;
u08 uart_ready;
U08 *uart_data_ptr;
s08 uart_counter;
s16 result_buf[5]; /* Буфер результата */
float a_buf[2] = {7.};
SIGNAl(SIG_UART_TRANS) /* Обработчик прерывания uart txd готов*/
{
uart_data_ptr++;
uart_counter-;
if (uart_counter>0)
outp(*uart_data_ptr, UDR) ; /* Записать байт в буфер данных */
else
uart_ready = 1; /* Готов отсылать */
}
void uart_send(u08 *buf, u08 size) /* Послать буфер на uart */
{ /* Записать первый байт в буфер данных */
if (!uart_ready) return;
uart_ready = 0; /* Не готов отсылать */
uart_data_ptr = buf;
uart_counter = size:
outp(*buf, UDR);
}
void calc(float a, float b)
{
result_buf[0] = 0;
result_buf[1] = (a+b)*10.0;
result_buf[2] = (а-Ь)*10.0;
result_buf[3] = (a*b)*10.0;
result_buf[4] = (а/Ь)*10.0;
}
int main(void)
{
/ Разрешить прерывания RxD/TxD */
outp((1<<RXCIE)|(1<<TXCIE)|(1<<TXEN),UCR);
/«Установить скорость */
outp((u08)UART_BAUD_SELECT, UBRR);
uart_ready =1; /* Готов отсылать */
sei(); /* Разрешить прерывания */
for (;;) { /* Бесконечный цикл */
calc(7.5, 3.2);
uart_send((u08*)result_buf, 5*sizeof(s16));
}
}
Простейшие приемы печати и чтения UART
Автор: Volker Oth.
Назначение: демонстрирует простейшие приемы печати и чтения UART.
Текст программы:
#include "uart.h"
#include <progmem.h>
int main(void)
{
u08 data;
UART_Init(); /* Инициализация UART */
PRINT(“Hello World!");
EOL();
for (;;) { /* Бесконечный цикл */
PRINT("Press any key…");
EOL();
data = UART_ReceiveByte();
PRINTC'You pressed "');
UART_SendByte(data);
PRINT("' whicn is 0x");
UART_Printfu08(data);
PRINT(" in hexadecimal.");
EOL();
}
}
Получение доступа к данным в памяти программ
Текст программы:
#include <io.h>
#include <progmem.h>
typedef unsigned char u08;
u08 __attribute__ ((progmem)) leds[]={0xff, 0xe7, 0хс3, 0x81, 0x00, 0x81, 0хс3, 0xe7};
int main(void)
{
u08 i, j, k, l
outp(0xff.DDRB); / Все выводы порта В на вывод */
for (;;) {
for (1=0; l<< sizeof(leds);l++) {
outр(PRG_RDB(&leds[1]), PORTB):
for (i=0; i<255; i++) /* Цикл временной задержки */
for(j=0; j<255;j++) /* Вложенный цикл временной задержки */
k++; /* Любая операция (чтобы "занять" процессор) /
}
}
}
4.5. Программатор
Одним из самых необходимых устройств для работы с микроконтроллерами является программатор. Это специальный прибор, позволяющий оттранслированную программу занести непосредственно в память микроконтроллера. Без него вся работа будет только теорией.
Существуют различные виды программаторов. Различаются они по сложности, цене, программному обеспечению для работы. Для микроконтроллеров семейства AVR можно выделить наиболее удачные программаторы — AS1 производства фирмы Аргуссофт, и AVReAl — самодельный, сконструированный Александром Редчуком. Последний отличается исключительной простотой в изготовлении и качеством работы, не уступающим промышленным программаторам.
В этой главе читатели могут познакомиться со схемой программатора, которая может работать с программой AVReAl, и научиться пользоваться этим программатором.
Программа avreal.exe с авторским описанием работы с ней находится на компакт-диске, прилагаемом к книге.
Программатор AVReAl может работать с различными схемами программаторов. Остановимся на схеме, совместимой с использованной в стартовой плате STK200 фирмы Atmel. Почему именно эта схема? Потому что она же может работать совместно с компилятором языка С CodeVision AVR.
Схема программатора показана на рис. 4.12.
Рис. 4.12. Схема программатора ATMEL STK200/STK300
Легко увидеть, что схема действительно предельно проста. Тем не менее она позволяет осуществлять все необходимые операции: проверять память микроконтроллера на наличие в ней программы, стирать ее содержимое, зашивать новую программу и т. д.
Внешний вид собранного программатора показан на рис. 4.13.
Рис. 4.13. Внешний вид программатора
Программатор работает с портом LPT1, 2 или 3. Если у вас порт LPT занят (например, принтером), можно купить на радиорынке отдельную плату с LPT-портом от старого компьютера, настроить ее на адрес порта LPT2 или 3 и подключать программатор к ней.
Следует иметь в виду, что длина проводов, соединяющих программатор и схему с микроконтроллером, не должна превышать 15…20 см. При большей длине начинают очень сильно влиять наводки на провода и возникают ошибки при работе программатора. Для удобства работы следует приобрести удлинитель порта LPT и подключить программатор к нему.
В качестве разъема для программирования рекомендую разъем типа LDC10. На рис. 4.14 изображен внешний вид этого разъема и его цоколевка. Номера выводов на схеме программатора соответствуют номерам на этом разъеме.
Рис. 4.14. Разъем IDC10
Следует стараться использовать на всех своих схемах с микроконтроллерами AVR один тип разъема программирования и его цоколевку — в этом случае можно будет пользоваться одним программатором для любых схем.
Описание программатора avreal
Автор программатора и настоящего описания: Александр Редчук.
(E-mail: ).
AVReAl — программатор At90sXXXX через LPT.
Новые версии, описание и FAQ лежат на
;
.
Компилируется в следующих вариантах: 16-битовом DOS, для работы на процессорах начиная с 286; 32-битовом WIN32, для работы необходимы файлы: для Windows 95/98 — DLportIO.DLL, для Windows NT — LportIO.DLL и DLportIO.sys.
Это файлы из комплекта DriverLINX от Scientific Software Tools, Inc. (). Его поставка достаточно громоздкая, с примерами работы на С и VisualBASIC, автоматической инсталляцией DLportlO.SYS для Windows NT и т. д. — итого файл port95nt.exe имеет размер 1,6 Мб.
В переупакованном виде p95nt.zip лежит у автора на
.
Также существует вариант программатора для LINUX, но он еще недостаточно оттестирован.
Подключение LPT к чипу осуществляется через Altera ByteBlaster (ключ -ab) или через адаптер, совместимый с платами STK200/STK300 (ключ -as).
Подключение выводов процессоров:
При использовании буферированных адаптеров (Altera ByteBlaster, Atmel STK*00) программа рассчитана на работу в схеме с «родными» питанием и кварцем. Возможна генерация XTAL1 по линии LED в STK*00 и по дополнительной линии, выведенной на контакт 8 в ByteBlaster.
Программа использует файлы в формате INTEL HEX (avrasm -i). При этом она загружает файл прошивки не в массив, а в список. То есть различается ситуация «байт 0xFF в. hex» и «непомянугый байт». В результате есть возможность шить только то, что надо, остальное только проверять при необходимости (см. ключ — v+).
Для любителей патчить прямо по НЕХ-файлу: если не совпадает контрольная сумма строки, то задается вопрос: «игнорировать?». При ответе 'Y' (или 'у') эта и все остальные ошибки CSUM игнорируются (но сами символы контрольной суммы должны присутствовать, иначе программа завершит работу еще раньше по недопустимому символу в строке).
Для облегчения таких патчей (особенно «форматных» записей в EEPROM) реализована возможность, подсмотренная у программы от для программирования PIC через Tait-совместимое железо: перед анализом строки из нее убираются пробелы и табуляции. В итоге можно дать:
:08 0001 00 00 01 0203 0405 0 6 0 7 DB
Также игнорируются пустые строки и строки, начинающиеся с '#', последнее предназначено для помещения комментариев о версии непосредственно в НЕХ-файлы.
Проверяется верхний адрес в НЕХ-файле, если не помещается в опознанный чип, то никаких действий (кроме выдачи сообщений) не осуществляется. Проверяется перекрытие адресов записей в НЕХ-файле. При нахождении первого перекрытия производится выход из программы с указанием диапазона адресов перекрывающихся данных.
Для mega103 необходим расширенный формат НЕХ-файла (обычный не поддерживает объем больше 64 Кб). Запись прочитанных данных в файл всегда производится с дополнительными записями типа '04'-Extended Linear Address Record, как не имеющими разночтений. Чтение из НЕХ-файла записей типа '02' Extended Segment Address Record производится в соответствии с формированием их в AVRASM by Atmel (без предусмотренного документацией Intel сворачивания адреса смещения по модулю 64 Кб).
Вызов программы
avreal [ключи] [[-с] имя_файла_кода [[-d] имя_файла_данных]]
или
avreal [ключи] -d имя_файла_данных (когда нет желания трогать код)
При пустой командной строке (ни имен, ни ключей) не делается никаких операций с портами/чипом. Если есть только имена файлов, но нет относящихся к ним ключей (-г -w -v), то файлы игнорируются. Подробнее про работу с файлами и про ключи -с, -d рассказано после описания остальных ключей. Признак ключа — символ или V, регистр букв не важен.
Ключи
-? (-h) — выдать ключи и перечень поддерживаемых кристаллов.
avreal +name -?
(+name должен быть задан _раньше_ ключа -?) выдает список fuses, поддерживаемых в режиме ISP для чипа name.
+name — установить тип кристалла,
Обязательный ключ, никаких действий по умолчанию не производится.
Если задан только чип (больше нет ни ключей, ни имен файлов), то чип будет сброшен и выдана информация о нем (наличие, если есть доступные по ISP fuses — их состояние).
-р<число1>[,<число2>]
«число 1», шестнадцатеричное.
set Port 1, 2, 3 — номер LPT-порта, >0x100 — базовый адрес порта, если задан номер — адрес из BIOS MEMORY (не работает для Win32 и linux версий, там принято, что LPT1/2/3 это 378/278/3BC). Адрес в виде — рЗВС и в виде — р0х3ВС воспринимается как HEX число, если задан адрес — «сами попросили» — по умолчанию — р2 (LPT2).
«число2», с плавающей точкой, необязательный параметр, если указан, то не производится настройка на скорость порта, время обращения принимается равным <число2> микросекунд.
В Win32 версии настройка не производится никогда, если не указано — считается, что обращение к порту не быстрее 1 мкс.
-а<буква> — группа ключей «адаптер»;
-ab — работа через Altera ByteBlaster;
-as — работа через адаптер Atmel STK*00;
-аа — автоматический выбор ByteBlaster/STK;
-az — пытаться переводить выходы LPT в Z-состояние для «отключения» программатора от схемы («byte-blaster для ленивых»);
-аr — инверсия полярности сброса (например, для подачи его через резистор в базу присутствующего в схеме транзистора);
-ai# — установить время неактивного Reset после стирания равным #mS. Необходимо устанавливать большим времени задержки снятия сброса присутствующим в схеме с супервизором;
-ар — подавать питание чипа через свободные выходы данных LPT (несовместимо с — ab).
Рекомендуется поближе к чипу установить блокировочный конденсатор по питанию.
-о<число> задать частоту установленного кварца для настройки скорости SPI.
<число>=<частота в килогерцах>, по умолчанию 800 (0,8 МГц).
0 означает необходимость генерации XTAL из программы.
Работает со всеми адаптерами. У STK*00 для генерации XTAL используется линия LED. Байт-бластер должен быть доработан, см. .
-n[<число>] — использовать последние 2 байта кода как счетчик стираний.
Если указано <число>, то для записи счетчика используется оно, а не инкрементированное прочитанное значение.
При -ewn если последние 2 байта заняты кодом, то — n игнорируется.
При -w если в чипе записан счетчик, а последние 2 байта заняты кодом, то производится насильное стирание.
-е[-] — стереть чип.
'-' задает сохранение содержимого EEPROM способом прочесть/стереть/записать. Даже для megaX03 применяется этот способ, если хочется пользоваться имеющимся fuse EESAVE, следует установить его (-fe) отдельным запуском avreal.
-1, -2, -3, -4, -5 — увеличить задержки на программирование в 1, 5, 2, 3, 4, 5 раз соответственно (для программирования при пониженном напряжении).
-Ь — проверить на чистоту.
-r — прочитать из чипа в файл[ы].
-W[+] — записать в чип. Дополнительный '+' — если чип в этом задании не стирался и задана запись в EEPROM, то прописать FF в ячейки EEPROM, не заданные в HEX. Верификация этих ячеек на значение FF будет производиться, даже если был задан просто -v, а не — v+ (мы же эти ячейки писали).
-v[+] — верифицировать (только то, что есть в hex).
Дополнительный ’+’ вызывает проверку на FF «свободных» с точки зрения НЕХ-файла позиций.
-1[+]# -1# — установить уровень защиты # = 1 or 2.
-1+# — то же самое, только lock биты прошиваются до зашивки fuses (необходимо для включения BODEN и залочки 90s4433 в одном цикле подачи питания).
-f
value — ШЕСТНАДЦАТЕРИЧНОЕ значение без префиксов и суффиксов.
Для однобитовых fuse добавлены значения ON и OFF (прошить и стереть, 0 и 1 соответственно).
alias'bi — это однобуквенные сокращения для fusename=value, соответствующие буквенным обозначениям в версиях avreal до 1.22.
При наличии «противоречивых» fusename=val и/или alias выдается сообщение об ошибке.
В целях совместимости с предыдущими версиями оставлена возможность перечисления alias-ов без разделения запятыми.
Перечень fusename с диапазоном value и комментарием, а также Допустимые alias'bi для конкретного чипа можно получить при помощи avreal +chipname -?
Если работа с fuses по SPI поддерживается, то их состояние сообщается при любой операции с чипом, задание ключа — F необязательно.
OSCCAL (Tiny12, Tiny15, Mega163) рассматривается как Read-Only fuse;-)
В случае наличия — F
Не упомянутые fuse остаются неизменными (кроме BLB для megal61, megal63, так как они могут быть стерты по — Е).
AVReAl обеспечивает также расширенную поддержку osccal (см. ниже)
Группа BLB относится скорее к lock-битам, записать 1 поверх уже запрограммированной в 0 fuse невозможно. Если запрошена такая операция и чип не стирался, то программа завершает работу с соответствующим предупреждением.
Для tiny12, tiny15 поддерживается программирование SPIEN и RSTDSBL, будьте осторожны, SPIEN по умолчанию запрограммировано, ключ — fspien=1 (-fspien=off) _сотрет_ SPIEN и запретит дальнейшее низковольтное программирование. То же произойдет и при _программировании_ RSTDSBL (-frstdsbl=0 или — frstdsbl=0).
-% — выдавать по ходу дела дополнительную информацию (производимые действия и ответы чипа). Внутри. bat-файпов следует писать — %% (пожалуй, это был неудачный выбор — символ, имеющий особый смысл в bat-файлах, но меняться уже не будет).
-! — делать, что велено, даже если чип не распознан (или распознан «не так», как задано в +<имя чипа>), а также, если не обнаружен указанный в командной строке адаптер. Попытка стереть нераспознанный (возможно, просто залоченный) чип при наличии команды стирания производится и без - после чего проводится повторное детектирование чипа.
Возможны осмысленные комбинации:
/vw — записать, проверить;
-e-wv+ — понятно;
-bw — проверить на чистоту, если не пустая — завершить работу, иначе записать.
После ключа -d идет имя файла данных, после — с — имя кода, в этом случае порядок файлов не важен. Пробел между ключами -c/-d и именами не обязателен, т. е. допустимо как -cfoo.hex, так и -с foo.hex.
Если дано два имени файла без ключей -с и -d, то первое имя — файл кода, второе — файл данных (EEPROM).
Если имя одно и нет ключей -c/-d, то этот файл содержит данные для кода, и если он содержит информацию после верхнего адреса FLASH для заданного кристалла, то эта информация используется для программирования EEPROM данных. То есть если, например, для 90s2313 hex-файл содержал данные в адресах от 0x800 до 0x87F, то эти данные будут записаны в EEPROM по адресам 0x00-0x7F.
Для Mega163 и Tiny12 поддерживаются особые формы ключей - с и -d для записи значения OSCCAL по адресу offset (шестнадцатеричное значение без префиксов и суффиксов). Байт (слово для '?') по offset должен существовать в исходном НЕХ-файле. Используется адрес байта, а не слова, в том числе и при обращении ко flash коду.
— d*osccal=offset — как байт в EEPROM данных;
— c*osccal=offset — как байт во FLASH коде (под команду LPM);
— c?osccal=offset — врезать OSCCAL как часть команды LDI по ofFset,ofFset+1.
Например:
public osccal_ldi
…
osccal_ldi:
ldi R16,0xFF
out OSCCAL,R16
…
Далее смотрим по MAP-файлу значение osccal ldi, например, оно вышло 0x120
avreal +tiny12 -ewv -с foo.hex -c?osccal=120
Группа ключей может задаваться как одним аргументом (-wv)? так и раздельно (-v -w). Ключ с параметром (-р -с -d) может стоять в группе только последним. То есть допустимо, скажем, такое:-) — wddata.hex -bv+c prog.hex -ер1
Порядок ключей не важен, выполнение производится в порядке Е B W V L.
Если проверка (В, V) дала отрицательный результат, то дальнейшая работа не производится. То есть — ebwv12
Стереть, если стерлась — писать, если верифицировалась — залочить.
+tiny12 -w -с foo.hex -c*osccal=1f3 -fcks=3,boden=0
Для tiny12 записать во флэш кода файл foo.hex, по адресу 0x1F3 занести прочитанное из чипа значение OSCCAL, запрограммировать fuse boden и установить fuse CKSEL в бинарное значение 0011.
Возвращаемый код ошибки:
0 — все заказанное сделалось;
10 — not blank при — В, несравнение при — V[+];
20 — невозможность осуществить запрошенную операцию НЕХ-кода или перечень данных слишком большой для распознанного чипа.
Запрошенное для записи состояние BLB нельзя записать, не стерев чип (а команды стирания не было);
30 — не распознан конкретный чип (бывает при защищенном чипе, поэтому при — Е все равно делается попытка стереть, и если после этого тоже не распознан — программа завершает работу);
40 — адаптер не подключен (не удалось войти в программирование по алгортиму для At90s);
50 — ошибка при чтении (не найден, «не те» символы, не совпала контрольная сумма, ошибка чтения…) или записи (есть защищенный от перезаписи с таким же именем…) НЕХ-файла;
60 — недостаточно памяти для списков кода/данных;
70 — недопустимая командная строка (в том числе задан номер отсутствующего LPT).
При обнаружении ошибок просьба сообщать версию программы и очень желательно отослать копию расширенной выдачи программы по ключу — % (перенаправив выдачу в файл) по адресу .
Один из вариантов использования программатора
Программы командной строки удобны для использования в какой-либо системе автоматизации проектирования программ. Большинство IDE имеют настраиваемое меню TOOLS, в которое можно вставить вызов программы и передать ей аргументы, например, имя текущего файла, имя проекта и др.
Многие программисты пользуются для сборки проекта утилитой make даже в том случае, если пакет имеет интегрированную оболочку, но содержит и компилятор/линкер командной строки.
Для использования avreal с такими программами необходимо один раз правильно сформировать строки для вызова avreal и поместить их в соответствующие позиции меню TOOLS используемого IDE или как команды соответствующих целей в makefile.
При использовании avreal для работы с кристаллами «вручную» неудобно каждый раз набирать всю командную строку. Для упрощения работы можно заготовить командные файлы с постоянно используемыми ключами и в командной строке задавать только название контроллера и имена файлов.
Ниже приведены примеры таких командных файлов, написанные в предположении, что:
• используется адаптер Atmel STK200 или STK300 (ключ -as), подключенный к порту LPT1 (ключ -p1). *.Ьаt-файлы должны находиться в одной папке (директории) с программой avreal.exe;
• тактовая частота контроллера не ниже 3,686 МГц (3686 кГц, ключ — о3686). Без этого ключа avreal будет предполагать, что тактовая частота может быть ниже, вплоть до 0,8 МГц, что приведет к существенному увеличению времени работы.
При использовании avreal для Win32 необходимо в командном файле указать avreal32 либо переименовать avreal32.exe в avreal.exe.
--------------------
erase.bat
@if '%v'==' goto help
@avreal -as -р1 -0З686 +%1 -e
@goto exit
: help
@echo erase.bat — стирание AVR-контроллера
@echo Вызов:
@echo erase cpuname.
@echo где cpuname — имя используемого процессора
: exit
--------------------
erasen.bat
@if '#1'==' ' goto help
@avreal -as -р1 -0З686 +%1 -en
@goto exit
:help
©echo erasen.bat — стирание AVR-контроллера
©echo с записью в верхние два байта flash-числа стираний
©echo Вызов:
©echo erasen cpuname,
©echo где cpuname — имя используемого процессора
: exit
--------------------
write.bat
©if '%1'==" goto help
©avreal -as -р1 -0З686 +%1 -w %2 %3
©goto exit
:help
©echo write.bat — запись AVR-контроллера
©echo Записывается flash кода и, если задан файл, EEPROM данных
©echo Вызов:
©echo write cpuname codename dataname,
©echo где cpuname — имя используемого процессора
©echo codename — имя файла кода
©echo dataname — имя файла данных (необязательный параметр)
:exit
--------------------
writed.bat
©if '%1'==' ' goto help
©avreal -as -р1 -0З686 +%1 -wd %2
@goto exit: help
©echo writed.bat — запись AVR-контроллера
©echo Записывается только EEPROM данных
©echo Вызов:
©echo writed cpuname dataname,
©echo где cpuname — имя используемого процессора
©echo dataname — имя файла данных
:exit
--------------------
read.bat
©if '%1'==' ' goto help
©avreal -as -р1 -0З686 +%1 -r %2 %3
©goto exit: help
©echo read.bat — чтение из AVR-контроллера
©echo Считывается flash кода и, если задан файл, EEPROM данных
©echo Вызов:
©echo read cpuname codename dataname,
©echo где cpuname — имя используемого процессора
©echo codename — имя файла кода
©echo dataname — имя файла данных (необязательный параметр)
:exit
--------------------
readd.bat
©if #1'==' ' goto help
©avreal -as -р1 -0З686 +%1 -rd %2
©goto exit: help
©echo readd.bat — чтение из AVR-контроллера
©echo Считывается только EEPROM данных
©echo Вызов:
©echo readd cpuname dataname,
©echo где cpuname — имя используемого процессора
©echo dataname — имя файла данных
:exit
--------------------
verify.bat
©if #1'==' ' goto help
©avreal -as -р1 -0З686 +%1 -v %2 %3
©goto exit
:help
©echo verify.bat — верификация AVR-контроллера
©echo Проверяется flash кода и, если задан файл, EEPROM данных
©echo Вызов:
©echo verify cpuname codename dataname,
©echo где cpuname — имя используемого процессора
©echo codename — имя файла кода
©echo dataname — имя файла данных (необязательный параметр)
:exit
--------------------
verifyd.bat
©if '%1’==“ goto help
©avreal -as -р1 -0З686 +%1 -vd %2
©goto exit: help
©echo verifyd.bat — верификация AVR-контроллера
©echo Проверяется только EEPROM данных
©echo Вызов:
©echo verifyd cpuname dataname,
©echo где cpuname — имя используемого процессора
©echo dataname — имя файла данных
:exit
--------------------
check.bat
©if '%1’==' ' goto help
©avreal -as -р1 -0З686 +%1 -bn
©goto exit: help
©echo check.bat — проверка AVR-контроллера на чистоту (стертость)
©echo Если при стирании контроллера был использован файл erasen.bat,
©echo то будет сообщено число стираний контроллера, в противном
©echo случае будет сообщение "Number of erases not initalised",
©echo означающее, что верхние два байта flash тоже содержат 0xFF
©echo Вызов:
©echo verifyd cpuname dataname,
©echo где cpuname — имя используемого процессора
©echo dataname — имя файла данных
:exit
--------------------
lock, bat
©if ’%1'==' ' goto help
©avreal -as -р1 -0З686 +%1 -12
©goto exit
: help
©echo lock.bat — защита AVR-контроллера от чтения
©echo Вызов:
©echo lock cpuname
©echo где cpuname — имя используемого процессора
: exit
--------------------
lockv.bat
©if '%1'==" goto help
©avreal -as -pi -0З686 +%1 -v12 %2 %3
©goto exit
:help
©echo lockv.bat — защита AVR-контроллера от считывания с предварительной
©echo верификацией (при несовпадении содержимого защита не устанавливается)
©echo Вызов:
©echo lockv cpuname codename dataname,
©echo где cpuname — имя используемого процессора
©echo codename — имя файла кода
©echo dataname — имя файла данных (необязательный параметр)
:exit
--------------------
fuses.bat
@if '%1'==" goto help
©avreal -as -р1 -0З686 +%1 -wvf%2
©goto exit: help
©echo fuses.bat — запись fuses AVR-контроллера
©echo Вызов:
©echo fuses cpuname fuselist
@echo где cpuname — имя используемого процессора
@echo fuselist — перечисленные через запятую fuses, состояние
@echo которых следует изменить. Более подробно см.
©echo описание avreal
:exit
-
Примечания.
Имя используемого процессора задается так, как оно выглядит в списке поддерживаемых кристаллов при вызове avreal -h, например, 90s8515 или mega 103. Допускается также указывать имена с префиксом 'АТ', например, at90s8515 или atmegal03. Регистр букв значения не имеет.
Запись fuses достаточно произвести один раз, стирание кристалла их не стирает (за исключением boot lock bits в кристаллах с boot sector во flash, рассматриваемых программой avreal как fuses).
Неуказанные в команде fuses не изменяются.
Записанное состояние fuse — '0', стертое — '1'. Для уменьшения вероятности ошибки следует пользоваться мнемоническими обозначениями ON и OFF соответственно.
При записи fuses следует быть осторожным с изменением состояния SPIEN и RSTDSBL для тех кристаллов, у которых эти fuse доступны в режиме низковольтного программирования.
Контроллеры AVR поставляются с SPIEN=0(ON), RSTDISBL=1 (OFF). Эти значения необходимы для low voltage ISP.
Еще один вариант использования программатора
Идея очень простая — обычно в процессе проектирования схемы и написания для нее программы тип чипа и название файла программы (т. е. и кода) выбираются один раз в начале работы и в дальнейшем изменяются очень редко.
В начале работы создается подобный файл с указанием типа кристалла (в этом файле AT90S2313) и имени файла, и при дальнейшей работе при необходимости запрограммировать кристалл просто запускается этот *.Ьаt-файл.
Кстати, запускать его можно не только из командной строки MS-DOS, но и из среды Windows 95/98. В последнем случае удобно сделать ярлык для этого файла.
При выполнении этого командного файла производятся следующие действия: проверяется наличие адаптера, совместимого с STK200, наличие подключенного микроконтроллера. Содержимое памяти микроконтроллера стирается, осуществляется проверка на успешное завершение операции стирания, после чего в кристалл записывается *.hex-файл, указанный в командной строке (в этом примере test2313.hex):
avreal.exe +90s2313 -р378 -as -ebvw -с test2313.hex
Конкретный пример. Изготовьте простейшую конструкцию на микроконтроллере AT90S2313. Ее схема изображена на рис. 4.15.
Рис. 4.15. Схема на микроконтроллере AT90S2313
Эта схема управляет двумя светодиодами, подсоединенными к линиям РВ2 и РВ4 микроконтроллера. Файл прошивки памяти программ для этой схемы имеется на компакт-диске, прилагаемом к книге. При правильной сборке и программировании схемы светодиоды должны поочередно мигать.
Для каждого проекта следует заводить отдельную папку (директорию), в которой располагать все файлы, относящиеся к проекту.
Итак, для того чтобы, например, занести код, находящийся в файле test2313.hex в память программ микроконтроллера AT90S2313, необходимо:
1) скопировать программу avreal.exe в папку проекта;
2) оттранслировать текст программы, чтобы получить файл *.hex. В нашем случае файл test2313.hex имеется готовый на компакт-диске, прилагаемом к книге. Его следует скопировать его в папку проекта;
3) создать текстовый файл с именем test2313.bat, в котором должна быть строка
avreal.exe +90s2313 -р378 -as -ebvw -с test2313.hex
4) подключить программатор к порту LPT и разъему ISP (программирования) схемы на микроконтроллере AT90S2313;
5) включить питание схемы на микроконтроллере;
6) запустить файл test2313.bat.
Обратите внимание — файлы avreal.exe, *.bat (в нашем примере test2313.bat) и *.hex (в нашем случае test2313.hex) должны находиться в одной папке.
Если все было проделано верно, программа должна быть занесена в микроконтроллер, и светодиоды начнут мигать.
Если необходимо заносить код не только в память программ, но и в EEPROM, в конце строки в *.bat-файле следует добавить — d и название файла с прошивкой EEPROM.