Программирование AVR

Программирование AVR (94)

Для того чтобы дальше разбираться с TWI модулем, нужно ознакомиться с его регистрами, и сейчас нам придется проделать эту нудную работу. Разбор регистров будет вестись на примере микроконтроллера atmega16. В других микроконтроллерах возможны небольшие отличия. 

В составе некоторых микроконтроллеров AVR есть модуль двухпроводного последовательного интерфейса (Two -wire Serial Interface или TWI). Модуль предназначен для организации обмена данными между микросхемами, подключенными к двухпроводной шине. Основное преимущество этого интерфейса перед SPI и UART`ом - это возможность организации сети из нескольких устройств. 

Двухпроводный интерфейс является аналогом I2C интерфейса фирмы Philips, только в случае AVR, не поддерживает высокие скорости передачи данных (свыше 400 kbit/s). Соображения, по которым Atmel использует другое названия, видимо связано с нежеланием платить Philips за лицензию.

В этом материале мы разберемся с основами двухпроводного последовательного интерфейса, а в следующих перейдем к работе с TWI модулем AVR.

Один из самых простых модулей микроконтроллеров AVR - это аналоговый компаратор. Он сравнивает между собой два напряжения и запоминает результат сравнения в регистре. Также он может вызывать прерывания, если результат сравнения изменился, и управлять схемой захвата таймера Т1 (конечно если он есть). 

Обычно аналоговый компаратор используется как однобитный АЦП. Например, компаратором можно отслеживать уровень заряда батареи или момент перехода переменного напряжения через ноль. Еще он может быть задействован для измерения длительности аналоговых сигналов и в ряде извращений нестандартных решений. Таких как многоразрядный АЦП последовательного приближения. 

В этой статье мы разберемся, как пользоваться аналоговым компаратором на примере atmega16.


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

Парсер принимает в буфер поток символов и разбирает их на слова. Под словами в данном случае подразумевается один или несколько символов отделенных пробелами. Количество пробелов неважно, все они заменяются в буфере одним символом окончания строки ('\0'). Прием данных выполняется до первого символа перевода каретки ('\r'). Если внутренний буфер переполняется, данные перестают приниматься, но символ перевода каретки все равно ожидается.

Когда входная последовательность символов (входная строка) обработана, мы получаем следующий результат - в буфере лежат принятые слова, мы знаем количество этих слов и имеем указатели на каждое из них.

Далее нам нужно только написать интерпретатор принятых слов. Для этого в программном модуле парсера есть несколько дополнительных функций - функции для сравнения строк и функции для перевода строки в число.




Следующий режим работы таймера Т0 - это режим CTC (Clear Timer on Compare) или "сброс при совпадении". Таймер в этом режиме работает следующим образом. 

При инициализации таймера мы очищаем счетный регистр TCNT0, а в регистр сравнения OCR0 загружаем число. Затем устанавливаем режим СТС и требуемый коэффициент предделителя. 

Таймер начинает работу. По каждому импульсу тактового сигнала счетный регистр увеличивает свое значение на единицу. Когда значение счетного регистра совпадет с регистром сравнения, установится флаг OCF0, счетный регистр сбросится и счет продолжится с нуля.

По сути, таймер микроконтроллера -  это цифровой счетчик, только "навороченый". На вход счетчика подается тактовый сигнал, по каждому импульсу которого счетчик увеличивает свое значение. При возникновении событий - переполнение счетчика или совпадение его значения с заданным - генерируется запрос на прерывание. 

Давайте разберем, как пользоваться таймером Т0 в режиме Normal. В этом режиме таймер считает от какого-то начального значения счетного регистра до максимально возможного (до 255 или 0xFF). Когда таймер Т0 досчитывает до максимума, то в следующий такт таймера возникает переполнение счетного регистра TCNT0 - он обнуляется и устанавливается флаг TOV0. Если в программе разрешены прерывания глобально (флаг I регистра SREG) и прерывание таймера Т0 по переполнению (флаг TOIE0 регистра TIMSK), то микроконтроллер вызовет соответствующий обработчик. Если значение счетного регистра совпадет с регистром сравнения OCR0, то установится флаг OCF0 и при разрешенном прерывании по событию совпадение, запустится его обработчик.

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

   AVR ядро основано на продвинутой RISC архитектуре оптимизированной для Си кода. Это позволяет разрабатывать хорошие и дешевые продукты с широкой функциональностью.
   Когда речь идет об оптимизации, мы обычно имеем в виду две вещи: размер кода и скорость его выполнения. В настоящее время Си компиляторы имеют различные варианты оптимизации, позволяющие разработчикам получать эффективный код по одному из этих критериев. 
   Хороший Си код дает компилятору больше возможности по его оптимизации. Однако, в некоторых случаях оптимизация кода по одному из критериев ухудшает другой, поэтому разработчик должен искать баланс между ними для удовлетворения своих требований. Понимание некоторых нюансов программирования на Си для AVR позволяет разработчикам фокусировать свои усилия в нужном направлении для достижения эффективного кода. 
   В этой статье мы рассмотрим рекомендации по программированию на Си для компилятора avr-gcc. Однако эти советы могут быть использованы и с другими компиляторами.

   Во всех микроконтроллерах AVR есть конфигурационные fuse биты. Это такие биты, которые задают ряд глобальных настроек микроконтроллера, например, источник тактового сигнала, пороговое напряжение схемы сброса, размер загрузочной области, разрешение сторожевого таймера и т.д. 
   Fuse биты хранятся во флэш памяти, поэтому сохраняют свое значение при отсутствии питания. Обычно они устанавливается однократно на этапе первичного программирования прошивки.
   Неправильно установленные fuse биты могут нарушить работу системы. В лучшем случае микроконтроллер будет работать, например, на неправильной частоте, а в худшем мы потеряем возможность программирования микроконтроллера по SPI интерфейсу. Это может произойти или по не знанию, или в результате случайной ошибки.
   Существует способ, который может предотвратить часть таких ситуаций. Он состоит в том, чтобы заложить в программу микроконтроллера сравнение fuse битов с требуемыми значениями. Что-то вроде самоконтроля. Но для того чтобы их можно было проверять, их нужно сначала прочитать. И сейчас мы разберемся, как это сделать.

   Внутренняя программа микроконтроллера AVR может читать и записывать любой байт EEPROM памяти. Однако при программировании EEPROM`a внешним программатором чтение и запись осуществляется постранично. В зависимости от типа микроконтроллера страницы EEPROM памяти имеют разный размер. Например, у микроконтроллера atmega16 размер страницы EEPROM памяти равен 4-ем байтам. 
   Существует мнение, что заявленный производителем ресурс EEPROM памяти AVR микроконтроллеров, равный 100000 циклов запись/чтение, относится не к единичной ячейке памяти, а к целой странице. То есть если мы в один байт EEPROM`а atmega16 запишем 100000 раз, остальные три ячейки страницы памяти потеряют свой ресурс, будучи вроде ни разу не тронутыми. 
   Мне стало интересно узнать, соответствует ли это действительности, и я провел небольшой тест EEPROM памяти atmega16. Понятно, что этот тест не является каким-то глубоким научным исследованием, но это все же лучше, чем ничего.