C - AVR - Простое описание PORTB, DDRB, PINB

Я работаю над школьным проектом и должен изучить основы C с контроллером atmega AVR.

Я не понимаю, как все настроено. Например, PORTB, PORTD, DDRB; DDRD, PINB, PIND и тому подобное. И я не знаю, как все работает с операторами if, while и т.д.

Может кто-нибудь дать мне короткое объяснение, пожалуйста?

У меня есть несколько строк кода...

DDRB = 0b00000011; // I know that here DDRB is set to input/output

И инструкция if:

if (PINB & (1 << PINB0)){
    A = true;
}

Может ли кто-нибудь объяснить мне, как работает это выражение if? Почему PINB & (1<< PINB0))?

Спасибо

Ответ 1

Вы имеете в виду, что такое if-condition PINB & (1<< PINB0))?

Он проверяет, включен ли PINB0 + 1 номер бит (от rhs) (1) в PINB или OFF (0).

Например. (a & (1 << 2)) проверяет, включен ли третий бит в a или OFF. В выражении используются два оператора << побитовый сдвиг влево и & поразрядный, а ниже я объяснил пример для одного байта:

  • 1 0000 0001
  • 1 << 2 после левого сдвига дает 0000 0100
  • a побитовое и с 0000 0100 дает либо все нули 0000 0000, либо 0000 0100

    3a. Если все нули тогда, если условие ложно (когда третий бит в a равен нулю).
     3b. Если результат побитового и 0000 0100, то если условие оценивается как истинное (когда третий бит в a - один).

Ответ 2

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

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

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

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

// Clock Prescalar Register for ATMega328p
#define CLKPR *0x61

в файле заголовка, связанном с частью (например, AVR libc).

Теперь, написав OSCCAL = 0b10000000 (или что-то еще, что я хочу записать, которое допустимо спецификациями в таблице данных), я могу напрямую получить доступ и изменить модуль prescalar часов для этой части.

Но часто нас интересует значение одного бита, а не всего байта. В результате мы используем побитовые операторы (такие как &, |, ~, << >>) для "маскировки" битов, которые мы заинтересованы в манипулировании.

Это обеспечивает одновременное преимущество, позволяющее нам считывать только значение из бит интереса, но не случайно менять любые биты, которые мы не хотим переключать.

Многие битовые позиции также задаются макросами. Например, бит 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));

The Takeaway

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

Однако, чтобы понять все эти макросы, вам нужно будет проконсультироваться (и прочитать, перечитать и перечитать) таблицу данных для своей части. К счастью, доступные для поиска PDF файлы доступны бесплатно с Atmel на вашей странице!

Ответ 3

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 высоким или нет.

Ответ 4

Для значений регистров рекомендуется проконсультироваться с

  • лист данных используемого устройства и
  • заголовочный файл, который поставляется с используемым компилятором C.

Короче говоря, последняя буква (B, D) означает порт, к которому вы обращаетесь: контакты GPIO сгруппированы по 8 раз, так что каждый порт имеет 8 контактов.

DDRx - это средство для установки направления каждого вывода порта.

PORTx и PINx используются для ввода и вывода, но поскольку я использую PORTA.IN, PORTB.DDR, PORTD.OUT и т.д., я не могу сказать сердцем, кто из них что-то делает.

Для основ языка есть книги и учебные пособия, которые позволяют вам изучать этот язык.