简体   繁体   English

指向 volatile 结构成员的 const 指针

[英]Const pointer to volatile struct member

I'm using microcontroller to make some ADC measurements.我正在使用微控制器进行一些 ADC 测量。 I have an issue when I try to compile following code using -O2 optimization, MCU freezes when PrintVal() function is present in code.当我尝试使用 -O2 优化编译以下代码时遇到问题,当代码中存在 PrintVal() function 时,MCU 冻结。 I did some debugging and it turns out that when I add -fno-inline compiler flag, the code will run fine even with PrintVal() function.我做了一些调试,结果发现当我添加-fno-inline编译器标志时,即使使用 PrintVal() function,代码也能正常运行。

Here is some background:这里有一些背景:

AdcIsr.c contains interrupt that is executed when ADC finishes it's job. AdcIsr.c 包含在 ADC 完成工作时执行的中断。 This file also contains ISRInit() function that initializes variable that will hold value after conversion.该文件还包含 ISRInit() function,它初始化将在转换后保存值的变量。 In main loop will wait for interrupt and only then access AdcMeas.value.在主循环中将等待中断,然后才访问 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);
    }
}

Questions:问题:

  1. Is there something wrong with usage of const AdcMeas_t* data as argument of the PrintVal() function?使用 const AdcMeas_t* 数据作为 PrintVal() function 的参数是否有问题? I understand that AdcMeas.value may change inside interrupt and PrintVal() may be outdated.我知道 AdcMeas.value 可能会在中断内部发生变化,并且 PrintVal() 可能已过时。

  2. AdcMeas contains a 'generic getter'. AdcMeas 包含一个“通用吸气剂”。 Is this a good practice to use this sort of function to allow read-only access to static structure?这是使用这种 function 来允许对 static 结构进行只读访问的好习惯吗? or should I implement AdcMeasGetId() and AdcMeasGetValue functions (note that this struct has only 2 members, what if it has 8 members)?或者我应该实现 AdcMeasGetId() 和 AdcMeasGetValue 函数(请注意,这个结构只有 2 个成员,如果它有 8 个成员怎么办)?

I know this code is a bit dumb (waiting for interrupt in while loop), this is just an example.我知道这段代码有点笨(在while循环中等待中断),这只是一个例子。

Some bugs:一些错误:

  • You have no header files, neither library include or your own ones.您没有 header 文件,既不包含库文件,也不包含您自己的文件。 This means that everything is hopelessly broken until you fix that.这意味着在你修复它之前,一切都被无可救药地破坏了。 You cannot do multiple file projects in C without header files.在没有 header 文件的情况下,您不能在 C 中执行多个文件项目。

  • *isrVarPtr = tmp; Here you write to a variable without protection from race conditions.在这里,您在没有竞争条件保护的情况下写入变量。 If the main program reads this variable in several steps, you risk getting incorrect data.如果主程序分几个步骤读取此变量,则可能会获得不正确的数据。 You need to protect against race conditions or guarantee atomic access.您需要防止竞争条件或保证原子访问。

  • const AdcMeasGetStructPtr() is gibberish and there is no way that the return &AdcMeas; const AdcMeasGetStructPtr()是胡言乱语,没有办法return &AdcMeas; inside it would compile with a conforming C compiler.它内部将使用符合要求的 C 编译器进行编译。

    If you have an old but conforming C90 compiler, the return type will get treated as int .如果您有一个旧但符合 C90 的编译器,则返回类型将被视为int Otherwise, if you have a modern C compiler, not even the function definition will compiler.否则,如果你有一个现代的 C 编译器,甚至 function 定义都不会编译。 So it would seem that something is very wrong with your compiler, which is a greater concern than this bug.因此,您的编译器似乎出了点问题,这比这个错误更令人担忧。

  • Declaring the typedef struct in the C file and then returning a pointer to it doesn't make any sense.在 C 文件中声明typedef struct然后返回指向它的指针没有任何意义。 You need to re-design this module.你需要重新设计这个模块。 You could have a getter function returning an instance to a private struct, if there is only ever going to be 1 instance of it (singleton).如果只有一个实例(单例),您可以让 getter function 将实例返回到私有结构。 However, as mentioned, it needs to handle race conditions.但是,如前所述,它需要处理竞争条件。

Stylistic concerns:风格问题:

  • Empty parenthesis () in a function declaration is almost always wrong in C. function 声明中的空括号()在 C 中几乎总是错误的。 This is obsolete style and means "accept any parameter".这是过时的样式,意思是“接受任何参数”。 C++ is different here. C++ 在这里有所不同。

  • int main() doesn't make any sense at all in a microcontroller system. int main()在微控制器系统中根本没有任何意义。 You should use some implementation-defined form suitable for freestanding programs.您应该使用一些适用于独立程序的实现定义的形式。 The most commonly supported form is void main (void) .最普遍支持的形式是void main (void)

  • DelayMs(1000); is highly questionable code in any embedded system.在任何嵌入式系统中都是高度可疑的代码。 There should never be a reason why you'd want to hang up your MCU being useless, with max current consumption, for a whole second.永远不应该有理由让你的 MCU 在最大电流消耗的情况下挂掉一整秒。

Overall it seems you would benefit from a "continuous conversion" ADC.总体而言,您似乎将从“连续转换”ADC 中受益。 ADCs that support continuous conversion just dump their latest read in the data register and you can pick it up with polling whenever you need it.支持连续转换的 ADC 只需将其最新读取数据转储到数据寄存器中,您可以在需要时通过轮询来获取它。 Catching all ADC interrupts is really just for hard realtime systems, signal processing and similar.捕获所有 ADC 中断实际上仅适用于硬实时系统、信号处理等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM