Использование изменяемого ключевого слова в Arduino digitalWrite - PullRequest
0 голосов
/ 26 апреля 2019

Функция digitalWrite(pin, val) Arduino работает, сначала извлекая адрес памяти регистра данных порта для соответствующего pin, а затем изменяя значение по этому адресу.Это фактическая реализация из wiring_digital.c:

void digitalWrite(uint8_t pin, uint8_t val)
{
    uint8_t timer = digitalPinToTimer(pin);
    uint8_t bit = digitalPinToBitMask(pin);
    uint8_t port = digitalPinToPort(pin);
    volatile uint8_t *out;

    if (port == NOT_A_PIN) return;

    // If the pin that support PWM output, we need to turn it off
    // before doing a digital write.
    if (timer != NOT_ON_TIMER) turnOffPWM(timer);

    out = portOutputRegister(port);

    uint8_t oldSREG = SREG;
    cli();

    if (val == LOW) {
        *out &= ~bit;
    } else {
        *out |= bit;
    }

    SREG = oldSREG;
}

Сначала digitalPinToPort(pin) преобразует номер пина Arduino в число, которое идентифицирует порт ATmega (PB / PC / PD) с использованием массива, хранящегося в SRAM:

// Arduino.h
#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )

// pins_arduino.h
const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
    PD, /* 0 */
    PD,
    PD,
    PD,
    PD,
    PD,
    PD,
    PD,
    PB, /* 8 */
    PB,
    PB,
    PB,
    PB,
    PB,
    PC, /* 14 */
    PC,
    PC,
    PC,
    PC,
    PC,
};

Затем этот номер порта используется для получения адреса памяти фактического регистра данных порта.Адреса регистров данных портов хранятся в SRAM и доступны с помощью макроса portOutputRegister(port):

// Arduino.h
#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) )

// pins_arduino.h
const uint16_t PROGMEM port_to_output_PGM[] = {
    NOT_A_PORT,
    NOT_A_PORT,
    (uint16_t) &PORTB,
    (uint16_t) &PORTC,
    (uint16_t) &PORTD,
};

Этот адрес имеет локальную переменную out.Почему объявлено volatile, а oldSREG нет?Оба они являются регистрами.

(и еще один вопрос: почему port_to_output_PGM массив uint16_t вместо uint8_t?)

1 Ответ

0 голосов
/ 26 апреля 2019

Модификатор volatile в основном говорит, что эта переменная может быть изменена извне. Это заставляет компилятор (и особенно оптимизатор) не оптимизировать доступ к этой переменной.

Так что нет необходимости, если вы сохранили содержимое SREG, чтобы иметь возможность восстановить его в предыдущем состоянии, но вы определенно не хотите иметь неправильное значение регистров PINx, потому что компилятор оптимизировал считывание актуальных данных из-за отсутствия Летучий модификатор.

Например:

while (PIND & _BV(PD2)); // wait for the button press (active low)

не будет работать должным образом, если PIND не будет изменчивым. Это будет прочитано один раз и никогда больше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...