Const указатель на член volatile структуры - PullRequest
0 голосов
/ 28 октября 2019

Я использую микроконтроллер для измерения АЦП. У меня есть проблема, когда я пытаюсь скомпилировать следующий код с помощью оптимизации -O2, MCU зависает, когда в коде присутствует функция PrintVal (). Я сделал некоторую отладку, и оказалось, что когда я добавляю флаг компилятора -fno-inline, код будет работать нормально даже с функцией PrintVal ().

Вот некоторый фон:

AdcIsr.c содержит прерывание, которое выполняется, когда АЦП завершает свою работу. Этот файл также содержит функцию ISRInit (), которая инициализирует переменную, которая будет содержать значение после преобразования. В основном цикле будет ожидать прерывания и только после этого получит доступ к AdcMeas.value.

AdcIsr.c
static volatile uin16_t* isrVarPtr = NULL;

ISR()
{
    uint8_t tmp = readAdc();
    *isrVarPtr = tmp;
}

void ISRInit(volatile uint16_t *var)
{
    isrVarPtr = var;
}
AdcMeas.c

typedef struct{
    uint8_t id;
    volatile uint16_t value;
}AdcMeas_t;

static AdcMeas_t AdcMeas = {0};

const AdcMeas_t* AdcMeasGetStructPtr()
{
    return &AdcMeas;
}
main.c

void PrintVal(const AdcMeas_t* data)
{
    printf("AdcMeas %d value: %d\r\n", data->id, data->value);
}

void StartMeasurement()
{
    ...
    AdcOn();
    ...
}

int main()
{
    ISRInit(AdcMeasGetStructPtr()->value);
    while(1)
    {
        StartMeasurement();
        WaitForISR();
        PrintVal(AdcMeasGetStructPtr());
        DelayMs(1000);
    }
}

Вопросы:

  1. Что-то не так с использованиемконстантных данных AdcMeas_t * в качестве аргумента функции PrintVal ()? Я понимаю, что AdcMeas.value может изменяться внутри прерывания, а PrintVal () может быть устаревшим.

  2. AdcMeas содержит «универсальный метод получения». Является ли хорошей практикой использование такого рода функций, чтобы разрешить доступ только для чтения к статической структуре? или я должен реализовать функции AdcMeasGetId () и AdcMeasGetValue (обратите внимание, что эта структура имеет только 2 члена, что, если она имеет 8 членов)?

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

1 Ответ

0 голосов
/ 31 октября 2019

Некоторые ошибки:

  • У вас нет заголовочных файлов, ни библиотеки, ни ваших собственных. Это означает, что все безнадежно сломано, пока вы не исправите это. Вы не можете делать несколько файловых проектов в C без заголовочных файлов.

  • *isrVarPtr = tmp; Здесь вы пишете в переменную без защиты от условий гонки. Если основная программа читает эту переменную за несколько шагов, вы рискуете получить неверные данные. Вам нужно защищаться от условий гонки или гарантировать атомарный доступ.

  • const AdcMeasGetStructPtr() является бредом, и нет никакого способа, которым return &AdcMeas; внутри него будет компилироваться с соответствующим компилятором C.

    Если у вас старый, но соответствующий компилятору C90, тип возвращаемого значения будет рассматриваться как int. В противном случае, если у вас есть современный компилятор C, даже определение функции не будет компилятором. Таким образом, может показаться, что с вашим компилятором что-то не так, что вызывает больше проблем, чем эта ошибка.

  • Объявление typedef struct в файле C и возвращение указателя на негоне имеет никакого смысла. Вам нужно изменить дизайн этого модуля. Вы могли бы иметь функцию получения, возвращающую экземпляр в частную структуру, если только когда-либо будет один ее экземпляр (синглтон). Однако, как уже упоминалось, он должен обрабатывать условия гонки.

Стилистические проблемы:

  • Пустые скобки () в объявлении функции почтивсегда неправильно в C. Это устаревший стиль и означает «принять любой параметр». Здесь C ++ отличается.

  • int main() не имеет никакого смысла в системе микроконтроллера. Вы должны использовать некоторую форму реализации, подходящую для отдельно стоящих программ. Наиболее часто поддерживаемая форма - это void main (void).

  • DelayMs(1000); - крайне сомнительный код в любой встроенной системе. Никогда не должно быть причины, по которой вы хотели бы повесить свой MCU, который будет бесполезным, с максимальным потреблением тока, на целую секунду.

В целом, похоже, вы выиграете от "непрерывное преобразование "АЦП. АЦП, которые поддерживают непрерывное преобразование, просто сбрасывают свои последние чтения в регистр данных, и вы можете получить их при помощи опроса, когда вам это нужно. Улавливание всех прерываний АЦП действительно для жестких систем реального времени, обработки сигналов и тому подобного.

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