Шпаргалка начинающего программиста AVR МК

Делаем первые шаги в программировании микроконтроллера на языке Си.
Порты ввода-вывода AVR – самые простые, но необходимые знания

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

Напоминаю, что в качестве примера у нас выбран популярный AVR микроконтроллер Atmega8, а в качестве основного языка программирования – Си.
Однако приступим к делу:

И начнём мы с программирования портов ввода-вывода микроконтроллера.

1. Регистр выбора направления передачи данных DDR

Выводы (порты) микроконтроллера могут работать как входы и как выходы. Поэтому предварительно нужно настроить вывод МК на соответствующий режим посредством специального регистра, который называется DDR.
У каждого порта есть свой DDR регистр. Например, у Atmega8 три порта: B, C и D, а соответствующие им регистры называются: DDRB, DDRC и DDRD.
В том случае, если нам необходимо сконфигурировать вывод МК как вход, то в соответствующий разряд DDR регистра записывается ноль, если – как выход, то единица.
Одним из распространённых способов настройки DDR регистров является запись в виде двоичного кода с количеством разрядов, совпадающим с разрядностью порта. К примеру, чтобы настроить вывод PC0 как выход, мы должны написать следующую команду:

DDRC = 0b0000001;

Здесь префикс 0b идентифицирует следующее за ним число как двоичное, а порядковый номер бита отвечает номеру бита внутри порта. То есть последний (крайний правый) разряд этого числа соответствует PC0, предпоследний – PC1 и т. д. Как итог: PC0 настроен как выход, все остальные разряды (PC1...PC6) – как высокоимпедансные входы.
Поскольку порт С в Atmega8 содержит не 8 разрядов, а 7, то и количество битов в двоичном коде равно 7.

Ещё один пример с 8-разрядным портом D:

DDRD = 0b10001000;

Здесь третий и седьмой биты порта D сконфигурированы как выход, а остальные биты – как вход.

Если подставить двоичное число (то, что находится после 0b) в калькулятор и конвертировать его в шестнадцатеричный код, то можно полученное число также использовать в настройке бита, только при этом – 0b заменить на 0x.
Перепишем наши примеры с шестнадцатеричными числами:

DDRC = 0x01;
DDRD = 0x88;

Часто функциональное назначение отдельно взятого вывода удобнее задавать побитовой настройкой. Для того, чтобы нам настроить PC0 как выход, в этом случае следует записать следующую команду:

DDRC |= ( 1 << 0 );

Эта запись означает, что для нулевого разряда порта С (номер разряда указывает последняя цифра), т. е. для вывода PC0 мы прописали в DDR единицу и тем самым настроили его как выход.
А вот, если бы нам туда понадобилось прописать ноль, т. е. настроить PC0 как вход, то команда выглядела бы так:

DDRC &= ~( 1 << 0 );


Запишем в побитовой форме и второй пример – настроим третий и седьмой биты порта D как выходы:

DDRD |= ( 1 << 3 ); DDRD |= ( 1 << 7 );

Эти две команды можно заменить одной:

DDRD |= ( 1 << 3 )|( 1 << 7 );


2. Регистр выходных данных порта PORT

Служит для управления состоянием вывода.
Если вывод (контакт) сконфигурирован как выход, то единица в соответствующем бите регистра PORTx формирует на выводе сигнал высокого уровня, а ноль – формирует сигнал низкого уровня.
Если вывод (контакт) сконфигурирован как вход, то единица в бите регистра PORTx подключает к выводу внутренний подтягивающий pull-up резистор, который обеспечивает высокий уровень на входе при отсутствии внешнего сигнала.
Воспользуемся предыдущими примером, в котором мы установили вывод PC0 как выход, т. е. использовали команду:

DDRC = 0b0000001;

Тогда, чтобы установить на этом выходе высокий логический уровень, нам надо прописать:

PORTС = 0b0000001; – в двоичном коде, либо
PORTС = 0x01; – в 16-ричном, либо
PORTC |= (1 << PC0); – в побитовом

А для того, чтобы установить низкий уровень –

PORTС = 0b0000000; – в двоичном коде, либо
PORTС = 0x00; – в 16-ричном, либо
PORTC &= ~(1 << PC0); – в побитовом

Если мы введём:

PORTС = 0b0000101; – в двоичном коде, либо
PORTС = 0x05; – в 16-ричном, либо
PORTC |= (1 << PC0)|( 1 << PC2 ); – в побитовом,

то это будет означать, что на выходе PC0 присутствует высокий логический уровень, а ко входу PC2 подключён внутренний подтягивающий к питанию резистор.
Все остальные разряды порта С настроены как обычные высокоимпедансные входы.

Для некоторых приложений может оказаться полезной команда, которая переключает отдельный бит в противоположное состояние, т. е. единицу в ноль и наоборот. К примеру, для вывода PD3 данная логическая операция выглядит следующим образом:

PORTD ^= (1 << 3);


3. Регистр считывания состояния вывода PIN

Данный регистр непрерывно отражает текущее состояние выводов порта, причём независимо от того, используется вывод как вход или как выход. То есть, обратившись к нему, мы можем узнать, какое напряжение подано на входной вывод, либо установлено в ходе работы программы на выходном. Из всего этого следует, что PIN – это регистр, из которого можно только читать.

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

if (PINB & (1 << PINB1)) {какой-либо код}

ожидает появления на выводе PB1 высокого уровня (единицы).

А вот команда:

if (!(PINB & (1<<PINB1))) {какой-либо код}

ожидает появления на выводе PB1 низкого уровня (нуля).




 

Главная страница | Наши разработки | Полезные схемы | Это нужно знать | Вопросы-ответы | Весёлый перекур
© 2017 Vpayaem.ru   All Rights Reserved