繁体   English   中英

指向 volatile 结构成员的 const 指针

[英]Const pointer to volatile struct member

我正在使用微控制器进行一些 ADC 测量。 当我尝试使用 -O2 优化编译以下代码时遇到问题,当代码中存在 PrintVal() function 时,MCU 冻结。 我做了一些调试,结果发现当我添加-fno-inline编译器标志时,即使使用 PrintVal() function,代码也能正常运行。

这里有一些背景:

AdcIsr.c 包含在 ADC 完成工作时执行的中断。 该文件还包含 ISRInit() function,它初始化将在转换后保存值的变量。 在主循环中将等待中断,然后才访问 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. 使用 const AdcMeas_t* 数据作为 PrintVal() function 的参数是否有问题? 我知道 AdcMeas.value 可能会在中断内部发生变化,并且 PrintVal() 可能已过时。

  2. AdcMeas 包含一个“通用吸气剂”。 这是使用这种 function 来允许对 static 结构进行只读访问的好习惯吗? 或者我应该实现 AdcMeasGetId() 和 AdcMeasGetValue 函数(请注意,这个结构只有 2 个成员,如果它有 8 个成员怎么办)?

我知道这段代码有点笨(在while循环中等待中断),这只是一个例子。

一些错误:

  • 您没有 header 文件,既不包含库文件,也不包含您自己的文件。 这意味着在你修复它之前,一切都被无可救药地破坏了。 在没有 header 文件的情况下,您不能在 C 中执行多个文件项目。

  • *isrVarPtr = tmp; 在这里,您在没有竞争条件保护的情况下写入变量。 如果主程序分几个步骤读取此变量,则可能会获得不正确的数据。 您需要防止竞争条件或保证原子访问。

  • const AdcMeasGetStructPtr()是胡言乱语,没有办法return &AdcMeas; 它内部将使用符合要求的 C 编译器进行编译。

    如果您有一个旧但符合 C90 的编译器,则返回类型将被视为int 否则,如果你有一个现代的 C 编译器,甚至 function 定义都不会编译。 因此,您的编译器似乎出了点问题,这比这个错误更令人担忧。

  • 在 C 文件中声明typedef struct然后返回指向它的指针没有任何意义。 你需要重新设计这个模块。 如果只有一个实例(单例),您可以让 getter function 将实例返回到私有结构。 但是,如前所述,它需要处理竞争条件。

风格问题:

  • function 声明中的空括号()在 C 中几乎总是错误的。 这是过时的样式,意思是“接受任何参数”。 C++ 在这里有所不同。

  • int main()在微控制器系统中根本没有任何意义。 您应该使用一些适用于独立程序的实现定义的形式。 最普遍支持的形式是void main (void)

  • DelayMs(1000); 在任何嵌入式系统中都是高度可疑的代码。 永远不应该有理由让你的 MCU 在最大电流消耗的情况下挂掉一整秒。

总体而言,您似乎将从“连续转换”ADC 中受益。 支持连续转换的 ADC 只需将其最新读取数据转储到数据寄存器中,您可以在需要时通过轮询来获取它。 捕获所有 ADC 中断实际上仅适用于硬实时系统、信号处理等。

暂无
暂无

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

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