Как адресуются контакты порта arduino, если я хочу получить к ним доступ с помощью указателя?

Итак, допустим, я хочу получить доступ к цифровому Pin 13. Это контакт порта B. Есть ли адрес памяти, связанный с этим выводом 13 Arduino Uno r3?

Как контакты порта B адресуются соответствующими номерами контактов, например, каков адрес цифрового вывода 13?

В настоящее время я предполагаю, что его PIN-адрес равен 0x05, поэтому мой указатель выглядит следующим образом

    uint8_t *adr=0x00+0x05;

Теперь, если я это сделаю

  *adr |= 0x20;

тогда должен ли я ожидать, что я пишу на какой-то PIN, поэтому я хотел бы знать, на какой технический паспорт я должен ссылаться для получения pin-адресов порта B?

В настоящее время мой код не работает, потому что независимо от того, к какому контакту я подключаю светодиод, он мигает. Что делать, если я не хочу использовать какую-либо библиотеку и просто пишу в адрес, и мне нужен контактный адрес ПОРТА B, как ссылаться на разные контакты?

Теперь предположим, что у меня есть код, который использует avr gcc

#include <avr/iom328p.h>//avr/io.h
#include    <util/delay.h>
#include <avr/sfr_defs.h>


#define     BLINK_DELAY_MS  18000

int main (void)
{
    DDRB |= _BV(DDB5);

    while(1)
    {
        PORTB |= _BV(PORTB5);
        _delay_ms(BLINK_DELAY_MS);

        PORTB &= ~_BV(PORTB5);
        _delay_ms(BLINK_DELAY_MS);
    }

    return 0;
}

Каким значениям соответствуют DDRB и _BV(DDB5); и PORTB и _BV(PORTB5);? Мне нравится делать это с помощью указателей, поэтому мне нужны адреса ПОРТА B для всех контактов, я знаю макросы, но мне нравятся фактические адреса. там должно быть какое-то техническое описание для этого, как оно называется. Есть ли у arduino то, что выдает адреса, отображенные в памяти?

Приведенный выше код предназначен просто для мигания светодиодного индикатора

, 👍5

Обсуждение

Что вы обнаружили, когда заглянули во включенные заголовочные файлы? Что вы обнаружили, когда прочитали документацию avr-libc? Что вы обнаружили, когда заглянули в технический паспорт Mega128? Почему это вам не помогло?, @the busybee

@thebusybee что для меня не имеет смысла, так это PORTB |= _BV (PORTB5) и DDRB |= _BV (DDB5); почему используется общий адрес PORTB и что, черт возьми, такое DDRB |= _BV (DDB5); где документация по этому вводу-выводу с отображением памяти. Это простой вопрос. Я проверил gcc avr, у него есть адреса. Но разве не должно быть какого-то описания для этих макросов и адресов. Это должно быть в листе данных, но подождите, что я на самом деле нашел, так это настройки страниц о макетах контактов при поиске таблицы данных arduino uno r3., @user786

Вот почему этот вопрос. Это должно было быть довольно просто для того, что я ищу, но, похоже, информации не хватает. Мне нужны объяснения, @user786

Используйте свои навыки веб-поиска и найдите "лист данных atmega128p" и "avr-libc". Возможно, вам придется немного почитать и подумать, ведь не на все в реальном мире даны ответы сразу в первой ссылке специально для вас. Мы ожидаем, что вы приложите немного усилий сами., @the busybee

Я думаю, ваша проблема заключается в каком-то неправильном представлении о том, как обрабатываются контакты ввода-вывода. Порт предназначен для нескольких выводов ввода-вывода. Один порт ввода-вывода обрабатывается одним битом регистра порта., @Juraj


1 ответ


Лучший ответ:

6

Адрес PORTB можно найти в техническом описании ATmega328P, раздел “Порты ввода-вывода”, подраздел “Описание регистра”. Он повторяется ближе к концу раздела “Сводка реестра”, где он задокументирован следующим образом:

0x05 (0x25)

По общему признанию, это сбивает с толку: есть два адреса! Существует сноска, которая дает некоторый намек на причину:

При использовании специальных команд ввода-вывода IN и OUT адреса ввода-вывода необходимо использовать 0x00 - 0x3F. При адресации регистров ввода-вывода как пространства данных с использованием инструкций LD и ST к этим адресам необходимо добавить 0x20.

Чтобы уточнить, этот регистр отображается в двух разных адресных пространствах:

  • Он имеет адрес ввода-вывода 0x05. Адресное пространство ввода-вывода является небольшим (6 бит). адресное пространство, выделенное для регистров ввода-вывода. На самом деле он слишком мал, чтобы вместить все регистры ввода-вывода. К нему можно получить доступ с помощью инструкций ввода и вывода. Адреса ниже 32 также могут быть адресованы по битам с помощью инструкций sbi, cbi, sbis и sbic.

  • Он имеет адрес данных 0x25. Это гораздо большее адресное пространство, которое предоставляет доступ ко всем регистрам ввода-вывода и к оперативной памяти. Он используется с семейством инструкций ld/st.

Поскольку языки C и C ++ не знают об адресном пространстве ввода-вывода, предполагается, что обычный указатель данных всегда указывает на адресное пространство данных. Таким образом, если вы хотите создать указатель на этот регистр, вы можете написать:

volatile uint8_t *adr = 0x25;  // PORTB

Обратите внимание на определитель volatile. Это необходимо для того, чтобы компилятор не был слишком “умным” и не оптимизировал некоторые ваши записи в предположении, что это просто оперативная память.

Затем вы можете включить светодиод с помощью:

*adr |= 1 << 5;  // установить ПОРТB5

С правильными параметрами оптимизации компилятор может оптимизировать это в sbi 0x05, 0x05, если он может доказать, что адрес , сохраненный в указателе, не изменяется.

Мне нужны адреса ПОРТА B для всех контактов, я знаю макросы, но мне нравятся фактические адреса.

Я бы порекомендовал вот что:

volatile uint8_t *adr = &PORTB;

Это позволяет избежать использования магических чисел в вашем коде и проясняет намерения программиста.

Еще одно последнее замечание. При компиляции вашего кода я получил:

include/avr/iom328p.h: [...]
error "Include <avr/io.h> instead of this file."

Просто включите <avr/io.h>: этот заголовок заботится о том, чтобы включить как правильные <avr/iomXXX.h>, так и <avr/sfr_defs.h>.

,

Я только что оставил комментарий о сопоставлении памяти с частью SBI в другом ответе. Это все равно, что читать мои мысли., @timemage

re: "если это может доказать, что адрес, сохраненный в указателе, не изменяется": вы можете помочь ему, сделав указатель const , например, volatile uint8_t * const adr, @mbrig