C - AVR - простое объяснение PORTB, DDRB, PINB
Я работаю над школьным проектом и должен изучить основы C с контроллером AVR atmega.
Я не понимаю, как все настроено. Например, PORTB, PORTD, DDRB; DDRD, PINB, PIND и все в таком духе. И я не знаю, как все работает с операторами if, циклами и т. Д.
Может кто-нибудь дать мне краткое объяснение, пожалуйста?
У меня есть несколько строк кода...
DDRB = 0b00000011; // I know that here DDRB is set to input/output
И если заявление:
if (PINB & (1 << PINB0)){
A = true;
}
Может кто-нибудь объяснить мне, как работает это "если утверждение"? Зачем PINB & (1<< PINB0))
?
Спасибо
4 ответа
Микропроцессоры используют карту памяти для взаимодействия своих аппаратных функций с программным обеспечением.
По сути, в памяти есть статические адреса, которые оборудование будет использовать для определения своей функциональности. Они зависят от производителя, детали, а иногда даже от того, как деталь настроена.
Таблица данных для детали скажет вам точное место в памяти для управления различными функциями. Тем не менее, это обычно очень утомительно. В результате таблица данных также (почти) всегда будет давать имя этому конкретному месту в памяти, которое описывает его функциональные возможности. Еще раз, эти названия являются изготовителями и частями.
Чтобы сделать этот интерфейс проще для программистов, люди (производитель или сообщество) часто будут создавать макросы в этих местах памяти. Например, вы можете найти
// Clock Prescalar Register for ATMega328p
#define CLKPR *0x61
в заголовочном файле, связанном с деталью (например, AVR libc).
Теперь, написав OSCCAL = 0b10000000
(или что-либо еще, что я хочу написать, что допустимо согласно спецификациям в техническом описании) Я могу напрямую получить доступ и изменить модуль прескалярных часов для этой части.
Но часто нас интересует значение одного бита, а не всего байта. В результате мы используем побитовые операторы (такие как &
, |
, ~
, <<
>>
) "замаскировать" биты, которыми мы заинтересованы в манипулировании.
Это дает одновременное преимущество, позволяя нам читать значение только из интересующего вас бита, не изменяя при этом случайные биты, которые мы не хотим переключать.
Многие позиции битов также задаются макросами. Например, бит 7 в OSCCAL
назван CLKPCE
(опять же из таблицы).
CLKPCE, скорее всего, определяется (по крайней мере, в AVR libc - стандарты различаются):
#define CLKPCE 7
потому что он определяет сдвиг бита, необходимый для достижения желаемого бита внутри OSCCAL
,
Чтобы поговорить о нем, я могу сделать несколько вещей.
Установите бит
Чтобы установить бит, мы хотим сделать его равным 1, не затрагивая другие биты. Для этого мы используем маску OR следующим образом:
OSCCAL = (OSCCAL | (1 << CLKPCE));
Я оставлю это вам, чтобы рассмотреть битовые операторы и посмотреть, как это работает.
Очистить бит
Здесь мы хотим сделать это 0, не затрагивая другие биты. Это будет выглядеть примерно так:
OSCCAL = (OSCCAL & ~(1 << CLKPCE));
Запросите бит
При запросе нам нужно выражение, которое возвращает ненулевое значение, если бит был установлен (1), и ноль, если бит был очищен (0). Это будет выглядеть так:
(OSCCAL & (1 << CLKPCE));
Еда на вынос
Используя эти разные побитовые операции с предопределенными макросами, мы можем напрямую контролировать и запрашивать состояние оборудования, используя эту статическую карту памяти.
Однако, чтобы разобраться во всех этих макросах, вам нужно будет обратиться (и прочитать, и перечитать, и перечитать) к вашей таблице данных. К счастью, PDF-файлы с возможностью поиска доступны бесплатно на Atmel на вашей странице!
Вы имеете в виду, что такое условие? PINB & (1<< PINB0))
?
Проверяет, PINB0 + 1
бит числа (от rhs) включен (1) в PINB
или ВЫКЛ (0).
Например. (a & (1 << 2))
проверяет, включен ли 3-й бит в a
или ВЫКЛ. В выражении используются два оператора <<
битовое смещение влево и &
побитово и ниже я объяснил для одного примера байта:
1
является0000 0001
1 << 2
после сдвига влево дает0000 0100
a
поразрядно и с0000 0100
дает либо все нули0000 0000
или же0000 0100
3a. Если все нули, то если условие ложно (когда третий бит в
a
это ноль).
3b. Если результат побитовый и есть0000 0100
тогда, если условие оценивается как истинное (когда третий бит вa
это один).
Для значения регистров, желательно проконсультироваться
- паспорт устройства, которое вы используете, и
- файл заголовка, который поставляется вместе с компилятором C, который вы используете.
Короче, последнее письмо (B
, D
) означает порт, к которому вы обращаетесь: контакты GPIO сгруппированы по 8, так что каждый порт имеет 8 контактов.
DDRx
это средство для установки направления каждого контакта порта.
PORTx
а также PINx
используются для ввода и вывода, но, как я привык использовать PORTA.IN
, PORTB.DDR
, PORTD.OUT
и т.д., я не могу наизусть сказать, кто из них что делает.
Для основ языка есть книги и учебные пособия, которые позволят вам выучить этот язык.
if (PINB & (1 << PINB0)){
A = true;
}
Этот код проверяет, PIN 0 in PORTB
является HIGH or LOW
, Если он высокий, то назначает A = true;
Вот, PINB
-> Читает данные из PORTB, (1<<PINB0)
-> Сделать 0-й бит как 1 и AND
оба значения, чтобы узнать, есть ли PIN 0 в PORTB
высокий или нет.