При работе с микроконтроллерами, многие задачи сводятся к управлению периферийными устройствами, для этого необходимо управлять устройствами, содержащимися в микроконтроллере (теми, которые связываются с периферийными устройствами). В AVR Libc поддержаны два варианта решения этой задачи:
Можно
получить
доступ к
регистру
ввода / вывода
с помощью
функций,
подобных outb()
:
или присвоить какое либо значение символьному обозначению регистра ввода / вывода.
PORTA = 0x33;
Какой метод компилятора использовать, решает программист. Но, например, если он напишет
PORTA |= 0x40;
компилятор может оптимизировать это в использование sbi инструкции.
Например, следующие два утверждения эквивалентны:
Произведенный код идентичен для обоих. Без оптимизации, компилятор строго придерживается исходного кода, но со включенной оптимизацией произведённый код будет использовать наиболее быстрые и короткие инструкции.
Обратите внимание, что особая осторожность должна быть предпринята при работе с некоторым регистрами ввода / вывода 16-битных таймеров, где возможен доступ и из главной программы и в подпрограмме обслуживания прерывания. См. Почему некоторые 16-и разрядные регистры таймеров иногда громятся?
В новых
версиях
компилятора
инструкции манипуляций
с битами - sbi/cbi больше
не поддерживаются.
Теперь sbi (sfr,bit) следует заменять на sfr |= _BV(bit), а cbi (sfr,bit) - на sfr &= ~(_BV(bit));
Например, вместо: sbi(PORTB, PB1); принято писать: PORTB |= _BV(PB1);
Управление битами |
|
#define |
_BV(bit) (1 << (bit)) |
Макроопредеения управления битами регистров ввода/вывода |
|
#define |
bit_is_set(sfr,
bit) (_SFR_BYTE(sfr) &
_BV(bit)) |
#define |
bit_is_clear(sfr, bit) (!(_SFR_BYTE(sfr) & _BV(bit))) |
#define |
loop_until_bit_is_set(sfr, bit) do { } while (bit_is_clear(sfr, bit)) |
#define |
loop_until_bit_is_clear(sfr, bit) do { } while
(bit_is_set(sfr, bit)) |
#include <avr/io.h>
Конвертирует номер разряда в байтовое значение.
Примечание: Изменение бита выполняется компилятором, затем результат вставляется в код. Таким образом, время на выполнение _BV() не расходуется.
Примеры
использования:
TCCR1A
= _BV(PWM10) | _BV(PWM11) | _BV(XCOM11); //
Устанавливаем
10-разрядную,
не
инвертирующую
ШИМ,
TIMSK
= _BV(TOIE1); //
Устанавливаем
флаг
разрешения
прерываний
от Т/С1
PORTA &= ~(_BV(PA7)); //
Сбрасываем в
«0» разряд 7
порта A
#include <avr/io.h>
Проверяет,
содержит ли
разряд bit в
регистре
ввода/вывода sfr лог.
0. Если да, то
возвращается
результат отличный
от нуля, если
указанный
разряд содержит
лог.1, то
возвращается
0.
#include <avr/io.h>
Проверяет, содержит ли разряд bit в регистре ввода/вывода sfr лог. 1. Если да, то возвращается результат отличный от нуля, если указанный разряд содержит лог.0, то возвращается 0.
#include <avr/io.h>
Ожидает
до тех пор,
пока bit в
регистре sfr содержит
лог.1.
#include <avr/io.h>
Ожидает до тех пор, пока bit в регистре sfr содержит лог.0.