(3-е издание). Практическое программирование микроконтроллеров Atmel AVR на языке ассемблера

Увидел как-то интересный видеоролик в сети, в нем демонстрировалась игра змейка реализованная на микроконтроллере и светодиодной матрице 8х8, потом нашел еще несколько подобных роликов, которые заинтересовали меня. Среди них также был ролик, где на “мощном” микроконтроллере была собрана игра тетрис. После просмотра, я решил разработать собственный вариант устройства, в котором совмещены обе игры, с применением микроконтроллера PIC16F688 и двух светодиодных матриц, которые отображают игровое поле с разрешением 8х16 точек.

Схема устройства показана ниже. Вывод информации на матрицы H1, H2 в динамическом режиме осуществляется посредством сдвиговых регистров DD2, DD3, DD4. Выходы микросхем DD2, DD3 подключены к анодам матриц. Катоды обеих матриц подключены к коллекторам транзисторов VT1-VT8, управляющие сигналы для которых формируются микросхемой DD4. Микроконтроллер загружает данные в регистр DD4, при переполнении которого, информация с 9 вывода передается на вход регистра DD3, далее таким же образом данные передаются на регистр DD2. Резисторы R1-R16 ограничивают ток через светодиоды матриц. Резисторы R17-R23 устанавливают ток базы транзисторов VT1-VT8. Микроконтроллер работает на частоте 8 МГц от внутреннего генератора. Частота обновления изображения составляет 100Гц.


После подачи питания, на игровом поле отображается заставка игры “Змейка”. В верхней части поля высвечивается цифра 1, в нижней части представлено изображение фрагмента игры. При нажатии на кнопку SB5 “Старт/Пауза”, выполняется переход в меню игры, в верхней части которого отображается уровень игры в виде цифр от 1 до 9. Уровень игры устанавливается кнопкой SB1 “Вверх”, при каждом нажатии происходит последовательное увеличения номера уровня на единицу. После цифры 9, снова высвечивается цифра 1. От установленного уровня игры зависит начальная длина змейки, так для 1-го уровня длина составляет 3 точки, для 9-го 11 точек. В нижней части меню отображается информация о скорости движения змейки. Цифре 1 соответствует минимальная скорость, а цифре 9 максимальная. Значение скорости устанавливается кнопкой SB4 “Вниз” подобно установке уровня игры. Свечение светодиодов по периметру поля в меню означает, что выбран режим игры с наличием границ по периметру поля. В этом режиме, при выходе змейки за пределы игрового поля наступает проигрыш. Если в меню, светодиоды по периметру поля погашены, то выбран режим без наличия границ. В этом случае при выходе за пределы игрового поля, голова змейки появляется с противоположной стороны поля. Кнопками SB2 “Вправо” и SB3 “Влево” устанавливается требуемый режим игры. При первоначальном входе в меню игры, значение длины и скорости устанавливаются на единицу, выбирается режим с наличием границ.

После нажатия кнопки “Старт/Пауза” из меню игры, на игровом поле высвечивается змейка в базовом положении и случайная свободная точка. Нажатие любой из кнопок “Вверх”, “Влево”, “Вправо” приводит змейку в движение по соответствующему напрвлению. После начала движения, для управления змейкой также становится доступна кнопка “Вниз”. При наезде на светящуюся точку, длина змейки увеличивается. После набора 14 точек происходит переход на следующий уровень игры. После 9-го уровня происходит переход на первый уровень. В случае наезда змейки на собственное туловище, или выхода за пределы игрового поля в режиме наличия границ, наступает проигрыш. После 3-х проигрышей происходит возврат в меню игры, где указан текущий уровень игры и скорость. После начала движения змейки, нажатиями кнопками “Старт/Пауза” можно приостановить и возобновить игру.

Для выхода из меню игры необходимо удерживать нажатой кнопку “Старт/Пауза” в течении 1 секунды, после чего на игровом поле высветится заставка игры. Переключение между играми осуществляется нажатием любой из кнопок “Вверх”, “Вниз”, “Влево”, “Вправо”. При этом высвечивается заставка соответсвующей игры.

В верхнй части заставки игры “Тетрис” высвечивается цифра 2, в нижней части представлено изображение фрагмента игры. Переход в меню игры осуществляется нажатием кнопки “Старт/Пауза”. В верхней части меню отображается количество баллов набранных игроком. Баллы начисляются за каждую удаленную строку. Счетчик баллов ведет счет до 99, затем обнуляется, и счет начинается заново. При старте каждой новой игры, счетчик также обнуляется. В нижней части меню отображается информация о скорости движения фигур, которая устанавливается кнопками “Вверх”, “Вниз” соответственно. После нажатия кнопки “Старт/Пауза” из меню, начинается игра, в верхней части поля появляются случайные фигуры, которые можно перемещать кнопками “Влево” и “Вправо” в соответсвующую сторону. Кнопка “Вверх” поворачивает фигуру на 90 градусов по часовой стрелке, при каждом нажатии. Удерживая нажатой кнопку “Вниз”, можно ускорить движение фигуры. Кнопкой “Старт/Пауза” можно приостановить и возобновить игру. Игра заканчивается когда новая фигура не может поместиться на игровом поле, после чего происходит переход в меню, где можно просмотреть количество баллов набранных игроком. Выход из меню выполняется также как в игре “Змейка”.

Если в течении 4 минут не была нажата ни одна из кнопок, то устройство переходит в режим пониженного энергопотребления, микроконтроллер отключает светодиодные матрицы, и переходит в спящий режим. Устройство “просыпается” после нажатия кнопки “Старт”, и возвращается в прежнее состояние.

В устройстве применены резисторы – типоразмера 1206 для поверхностного монтажа. Конденсаторы С2, С3 – керамические типоразмера 1206. Светодиодные матрицы H1, H2 – TOM-1088BG-B зеленого цвета свечения с диаметром светодиодов 3мм, и разрешением 8х8 точек. Кнопки стандартные тактовые.

Источник питания – стабилизированный блок питания напряжением 3,7-5В, также можно использовать гальванические элементы или аккумуляторы, например 3 последовательно соединненные батарейки по 1,5В типоразмера AA или AAA, я например использую 3 батарейки AA. Устройство сохраняет работоспособность при снижении напряжения питания до 3,3В, при этом уменьшается яркость свечения светодиодных матриц.

ВВЕДЕНИЕ. Микроконтроллеры, их возникновение и применение
Предыстория микроконтроллеров
Электроника в греческом стиле
Почему AVR?
Что дальше?

ЧАСТЬ I. ОБЩИЕ ПРИНЦИПЫ УСТРОЙСТВА И ФУНКЦИОНИРОВАНИЯ ATMEL AVR

Глава 1. Обзор микроконтроллеров Atmel AVR

Семейства AVR
Особенности практического использования МК AVR

Глава 2. Общее устройство, организация памяти, тактирование, сброс

Память программ
Память данных (ОЗУ, SRAM)
Энергонезависимая память данных (EEPROM)
Способы тактирования
Сброс
Особенности подключения дополнительной внешней памяти данных

Глава 3. Знакомство с периферийными устройствами

Порты ввода-вывода
Таймеры-счетчики
Аналого-цифровой преобразователь
Последовательные порты
U ART
Интерфейс SPI
Интерфейс TWI (12С)
Универсальный последовательный интерфейс USI

Глава 4. Прерывания и режимы энергосбережения

Прерывания
Разновидности прерываний
Режимы энергосбережения
Потребление МК AVR
Потребление МК AYR и режимы энергосбережения

ЧАСТЬ II. ПРОГРАММИРОВАНИЕ МИКРОКОНТРОЛЛЕРОВ ATMEL AVR

Глава 5. Общие принципы программирования МК семейства AVR

Ассемблер или С?
Способы и средства программирования AVR
Редактор кода
Об AVR Studio
Обустройство ассемблера
Программаторы
О hex-файлах
Команды, инструкции и нотация AVR-ассемблера
Числа и выражения
Директивы и функции
Общая структура AVR-программы
Обработка прерываний
RESET
Простейшая программа
Задержка
Программа счетчика
Использование прерываний
Задержка по таймеру
Программа счетчика с использованием прерываний
О конфигурационных битах

Глава 6. Система команд AVR

Команды передачи управления и регистр SREG
Команды проверки-пропуска
Команды логических операций
Команды сдвига и операции с битами
Команды арифметических операций
Команды пересылки данных
Команды управления системой
Выполнение типовых процедур на ассемблере
О стеке, локальных и глобальных переменных

Глава 7. Арифметические операции

Стандартные арифметические операции
Умножение многоразрядных чисел
Деление многоразрядных чисел
Операции с дробными числами
Генератор случайных чисел
Операции с числами в формате BCD
Отрицательные числа в МК

Глава 8. Программирование таймеров

8- и 16-разрядные таймеры
Формирование заданного значения частоты
Отсчет времени
Точная коррекция времени
Частотомер и периодомер
Частотомер
Периодомер
Управление динамической индикацией
LED-индикаторы и их подключение
Программирование динамической индикации
Таймеры в режиме PWM

Глава 9. Использование EEPROM

Еще раз о сохранности данных в EEPROM
Запись и чтение EEPROM
Хранение констант в EEPROM

Глава 10. Аналоговый компаратор и АЦП

Аналого-цифровые операции и их погрешности
Работа с аналоговым компаратором
Интегрирующий АЦП на компараторе
Принцип работы и расчетные формулы
Программа интегрирующего АЦП
Встроенный АЦП
Пример использования АЦП
Программа

Глава 11. Программирование SPI

Основные операции через SPI
Аппаратный вариант
Программный вариант
О разновидностях энергонезависимой памяти
Запись и чтение flash-памяти через SPI
Программа обмена с памятью 45DB011В по SPI
Запись и чтение flash-карт
Подключение карт ММС
Подача команд и инициализация ММС
Запись и чтение ММС

Глава 12. Интерфейс TWI (12С) и его практическое использование

Базовый протокол 12С
Программная эмуляция протокола 12С
Запись данных во внешнюю энергонезависимую память
Режимы обмена с памятью АТ24
Программа
Часы с интерфейсом 12С
Запись данных
Чтение данных

Глава 13. Программирование UART/USART

Инициализация UART
Передача и прием данных
Пример установки часов DS1307 с помощью UART
Приемы защиты от сбоев при коммуникации
Проверка на четность
Как организовать корректный обмен
Дополнительные возможности USART
Реализация интерфейсов RS-232 и RS-485
Преобразователи уровня для RS-232
RS-485

Глава 14. Режимы энергосбережения и сторожевой таймер

Программирование режима энергосбережения
Пример прибора с батарейным питанием
Доработка программы
Использование сторожевого таймера

ПРИЛОЖЕНИЯ

Приложение 1. Основные параметры микроконтроллеров Atmel AVR

Приложение 2. Команды Atmel AVR
Арифметические и логические команды
Команды операций с битами
Команды сравнения
Команды передачи управления
Команды безусловного перехода и вызова подпрограмм
Команды проверки-пропуска и команды условного перехода
Команды переноса данных
Команды управления системой

Приложение 3. Тексты программ
Демонстрационная программа обмена данными с flash-памятью 45DB011В по интерфейсу SPI
Процедуры обмена по интерфейсу 12С

Приложение 4. Обмен данными с персональным компьютером и отладка программ через UART
Работа с COM-портом в Delphi
COM-порт и Windows API
Работа с СОМ через готовые компоненты
Установка линии RTS в DOS и Windows
Программа СОМ2000
Отладка программ с помощью терминальной программы

Приложение 5. Словарь часто встречающихся аббревиатур и терминов
Соответствие терминов на русском их переводу на английский
Соответствие терминов на английском их переводу на русский

Литература
Предметный указатель

Всем добрый вечер! Веду свою трансляцию из уютного мира, который называется «ассемблер». Сразу поясню что тема касается микроконтроллеров AVR - и я пока ещё не знаю, пригодится ли этот пост тем, кто хочет использовать ассемблер для любой другой задачи. Дело в том, что я буквально несколько дней назад начал учить ассемблер с нуля - нужно сделать одно устройство - и я решил сделать в нём всё самостоятельно. Так вот - в один прекрасный день понял, что учить ассемблер абсолютно бесполезно! Ассемблер можно только понять! То есть всем тем, кто хочет программировать на ассемблере я настоятельно рекомендую детально вникнуть в то, каким образом ФИЗИЧЕСКИ работает микроконтроллер, а затем уже изучать тонкости команд.
Так вот, я пожалуй начну небольшой цикл статей, в которых буду с самого начала рассказывать как именно я понял те или иные вещи в программировании на ассемблере - думаю для тех, кто вообще не понимает что такое асм я буду как раз таким «переводчиком» с языка тех, кто в этом деле очень хорошо шарит.

Сразу скажу, что я более-менее вкурил эту тему с подачи DIHALT - поэтому эти статейки будут являться неким переводом с супер-пупер-ассемблерно-микроконтроллерного языка на язык понятный большинству людей. Ну а гуру надеюсь будут меня поправлять по ходу пьесы и если вдруг я что то объясню неправильно - то они поправят меня.
Итак первые выводы об ассемблере, которые я сделал пару дней назад, меня потрясли до глубины души - и я просидел за статьями DI HALT"а с 11 вечера до 5 утра - после чего лёг спать довольным и счастливым. Я понял суть программирования на ассемблере для микроконтроллеров.
Как же это объяснить ещё проще? Думаю нужно начать с самой сути.
***
Изначально не будем вдаваться в технические подробности (о них мы поговорим в следующей статье) - просто представьте, что есть 3 персонажа :
1. Микроконтроллер - это англичанин Стив, который приехал к русскому. Он идеально знает английский язык, но по-русски он вообще не понимает - ни единого слова. Только английский. Он проиграл в споре и обязался делать бесприкословно всё то, о чём его попросит русский.
2. Ассемблер - это переводчик Вася у которого мама англичанка а папа русский. Он знает идеально и английский и русский язык.
3.Мы - это русский, к которому приехал англичанин. Ну то есть мы это мы=) При этом мы идеально знаем русский язык и (!!!) чуть-чуть английский - самую малость, со словариком.
***
Представьте такую ситуацию - англичанин сидит у Вас в комнате на стуле. А Вы сидите себе за компом и читаете этот пост, как вдруг у Вас внезапно открылась форточка! Вот ведь незадача! Ветер дует, занавеска превратилась в парус… Было бы неплохо закрыть! Но вот ведь как лень вставать со стула, снимать ноги с системника, запихивать их в тапочки, отставлять кружку с кофе(пивом) и идти бороться со стихией. И тут Вы внезапно осознаёте, что у нас то в комнате есть проспоривший англичанин, которого самое время погонять! И вы ему так мило говорите «Дружище! Закрой форточку пожалуйста, а потом можешь опять присесть на стул!» а он сидит, смотрит на вас с недоумением и ничего не делает! Можно конечно по щам надавать - но он же тогда всё равно вас не поймёт! Тогда Вы звоните своему другу-переводчику Василию - он приходит, и садится рядом с англичанином на стул. И вы говорите - Переведи: «Стив, пойди и закрой форточку, а потом обратно сядь на стул!» Переводчик переводит на английский - англичанин понимает и идёт закрывает форточку, а затем приходит и садится на стул.
В этом моменте нужно просто понять роль ассемблера в этой цепочке «Мы-Ассемблер-Контроллер»
То есть как бы что такое ассемблер все поняли? Тогда читаем дальше.
***

Так вот, представляем такую ситуацию. Васе говоришь - «Слушай, ну короче такое дело - я калькулятор дома забыл, раздели 56983 на 2 и скажи Стиву, чтобы он столько раз отжался на кулаках» и Вася на калькуляторе считает и говорит Стиву по-английски " Отожмись на кулаках 28491 раз" Это называется «ДИРЕКТИВА» - другими словами директива это задание для Васи, результат выполнения которой это действие Стива.

Есть другая ситуация - Вы говорите Васе «Скажи Стиву, чтобы он отжался 28491 раз» и Вася просто переводит Ваши слова на английский. Это называется ОПЕРАТОР

Всё просто - есть директива и есть оператор. Оператор - это Ваше прямое указание что делать Стиву - Вася тут только переводит Ваше требование на инглиш. А Директива - это задание для самого Васи - и Вася сначала делает то, что Вы ему сказали, а потом уже в зависимости от результата говорит Стиву что-либо.

Теперь мы будем мучать англичанина регулярно! Но предварительно нужно получше познакомиться с нашим переводчиком Васей. Нужно знать следующее - Вася всегда Вас слушается беспрекословно - что ему сказали, то он и делает. Васин калькулятор не имеет десятичных знаков - если вы глянете пример с отжиманиями то 56983 \ 2 = 28491.5 - но у Васи всё после запятой обрубается - и он видит только целое число - причём неважно там будет 28491.000001 или там будет 28491.9999999 - для Васи это один фиг будет 28491 в обоих случаях. Ничего не округляется. Ещё важная информация про Васю. Вася жесток - ему пофиг на то, что Стив затрахается отжиматься двадцать восемь тысяч раз. Ему сказали - Вася перевёл. Причём не только перевёл - но и заставил сделать то, что Вы попросили. Так что если Стив помрёт на двадцать три тысячи пятьсот тринадцатом отжимании - то это будет исключительно Ваша вина.

Собственно это пока что всё. В следующем посте будем копать глубже - пока же просто достаточно понять это. Просто представить эту ситуацию и понять что к чему, кто исполняет какую роль и чем директива отличается от оператора.
А дальше мы постараемся называть всё своими именами и примерно прикинуть как же ассемблер работает с микроконтроллером по взрослому.



Понравилась статья? Поделиться с друзьями: