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. 1 является 0000 0001
  2. 1 << 2 после сдвига влево дает 0000 0100
  3. 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 высокий или нет.

Другие вопросы по тегам