Достаточно ли floating point при доступе к переменной из ISR?

Допустим, я хочу изменить глобальную переменную внутри процедуры обслуживания прерываний. Я должен убедиться, что любые переменные, которые я изменяю, изменчивы. Работает ли использование летучего указателя на данные, которые я хочу изменить, если сами данные не являются летучими?

В моем случае данные-это структура, но меняется ли ответ, если данные являются классом, массивом или просто переменной?

#include <Arduino.h>

#define PIN_INTERRUPT  2

typedef struct MyStruct
{
    int a_field;
} MyStruct;


MyStruct struct_data;
int array_data[32];

volatile bool _flag_ISR = false;
volatile MyStruct *_struct_ISR = &struct_data;
void myISR()
{
    // просто некоторые примеры
    int read = digitalRead(PIN_INTERRUPT);
    _struct_ISR->a_field = read;
    _arr_data_ISR[4] = read;
    
    _flag_ISR = true;
}

void setup()
{
    attachInterrupt(digitalPinToInterrupt(PIN_INTERRUPT), myISR, CHANGE);
}

void loop()
{
    if (_flag_ISR)
    {
        // сделайте обработку здесь...
        _flag_ISR = false;
    }
}

, 👍2

Обсуждение

Я думаю, что неправильно понял ваш вопрос, через который проходит первая пара, вероятно, потому, что (я предполагаю) под "изменчивым указателем" вы действительно имели в виду "указатель на изменчивый", и это различие очень важно. Итак, вы спрашиваете: "что касается связи между ISR и основной линией исполнения, достаточно ли использовать указатель НА volatile*, если* указываемая вещь сама по себе не является volatile квалифицированной?", @timemage


1 ответ


1

Во-первых, помните, что то, что вы написали, не является изменчивым указателем, это указатель на изменчивые данные. Если вы всегда обращаетесь к объекту через этот указатель, вы должны быть в порядке. Если вы используете указатель в ISR, но получаете доступ к данным непосредственно в главном коде (минуя volatile квалификатор), то программа может потерпеть неудачу.

Рассмотрим следующее:

void loop()
{
    if (_flag_ISR) {
        _flag_ISR = false;
        Serial.println(struct_data.a_field);
    }
}

Как только компилятор вводит вызов loop() из main(), основная программа выглядит так

int main()
{
    init();  // Настройка инициализации ядра Arduino
    setup();
    for (;;) {  // встроенный loop()
        if (_flag_ISR) {
            _flag_ISR = false;
            Serial.println(struct_data.a_field);
        }
    }
}

И теперь, поскольку struct_data не изменчива, компилятор может законно оптимизировать код, избегая повторного доступа к одному и тому же Расположение оперативной памяти:

int main()
{
    init();  // Настройка инициализации ядра Arduino
    setup();
    register int data_copy = struct_data.a_field;
    for (;;) {  // встроенный loop()
        if (_flag_ISR) {
            _flag_ISR = false;
            Serial.println(data_copy);
        }
    }
}

И теперь программа печатает только нули.

,

Голосовать за тебя. Мне кажется, я слишком буквально воспринял их "летучий указатель". Предполагая, что они подтверждают это понимание того, что они имели в виду, ваш ответ имеет почти все, что я должен сказать об этом в любом случае. Я немного удивлен, что вы используете ключевое слово register., @timemage

@timemage: Ключевое слово "register" редко используется в реальном коде. Здесь я использую его только для выражения идеи о том, что компилятор может выбрать сохранение копии данных во внутреннем регистре процессора (или наборе регистров)., @Edgar Bonet

Это вторая половина того, что я искал. Знаешь, тебе даже не разрешают использовать его в 17-м., @timemage