我需要在EEPROM中存储8个继电器的状态。我不想为移位而烦恼,我喜欢使用位场。所以我想这样定义它们。
typedef struct{
uint8_t RELAY0_STATE:1;
uint8_t RELAY1_STATE:1;
uint8_t RELAY2_STATE:1;
uint8_t RELAY3_STATE:1;
uint8_t RELAY4_STATE:1;
uint8_t RELAY5_STATE:1;
uint8_t RELAY6_STATE:1;
uint8_t RELAY7_STATE:1;
}relay_nvm_t;
relay_nvm_t relay_nvm;
在我的主代码流程中,我用以下方法设置每个继电器的状态 relay_nvm
变量。例子
...
if(something)
{
relay_nvm.RELAY0_STATE = 1;
relay_nvm.RELAY1_STATE = 0;
relay_nvm.RELAY2_STATE = 1;
relay_nvm.RELAY3_STATE = 0;
relay_nvm.RELAY4_STATE = 1;
relay_nvm.RELAY5_STATE = 1;
relay_nvm.RELAY6_STATE = 0;
relay_nvm.RELAY7_STATE = 1;
}
最后,当我需要对EEPROM进行读写的时候,我只需投下 relay_nvm
到 uint8_t
读写一个字节到EEPROM。但我得到的是 error: conversion to non-scalar type requested
错误。下面是我的函数。
static void NVM_Relay_Read(void)
{
relay_nvm = (relay_nvm_t)NVM_ReadEepromByte(NVM_RELAY_INDEX);
}
static void NVM_Relay_Write(relay_nvm_t rs)
{
NVM_WriteEepromByte(NVM_RELAY_INDEX, (uint8_t)rs);
}
有什么办法可以克服这个错误吗?我想我可以通过类型化来实现。使用bitfields使我的工作非常容易,并使代码易于理解。
我知道在这种情况下,由于有填充物,bitfields可能不安全,但我想我可以通过使用 POP-PUSH
(是否值得?)
我看到了更多处理这个问题的方法。
使用联合。
使用指针类型转换。*((uint8_t*)&relay_nvm)
使用 uint8_t:
uint8_t relay_nvm;
#define RELAY0_MASK 1
#define RELAY1_MASK 2
#define RELAY2_MASK 4
...
#define RELAY7_MASK 128
// set exact relays state:
relay_nvm = RELAY0_MASK | RELAY2_MASK | RELAY4_MASK | ... ;
// set single relay (others left unchanged):
relay_nvm |= RELAY2_MASK;
// clear single relay (others left unchanged):
relay_nvm &= ~RELAY2_MASK;
// check current state of a relay:
if (relay_nvm & RELAY2_MASK) { ... }
我不想为移位而烦恼,我喜欢使用位域。
如果使用位元运算符是一个 "麻烦",那么在你掌握它们的窍门之前,你可能不应该写嵌入式系统代码......这是写非标准、非可移植代码的一个非常糟糕的理由。
与位智版本不同,位字段会有大量的问题:未定义的位序、endianess-dependence、不好指定的签名性、对齐& padding hiccup等等。你已经在用 uint8_t
比特字段,因为C标准没有涉及到这些。
如果你坚持使用位字段,你必须阅读具体的编译器文档,了解它们是如何实现的。不要假设关于东西如何分配有任何保证,因为在这种情况下没有标准化。
你的具体问题是,你不能直接从结构类型转换(一个 汇总 - 容器类型")到一个 uint8_t
并返回,原因与为什么不能用数组来做同样的事情。你必须使用指向第一个元素的指针来代替,然后将这个指针转为 uint8_t*
和去引用。但是,这也带来了很多其他的问题,比如对齐、兼容类型和 "严格的别名"。
一般来说,structs和联合体都不太适合用于内存映射的目的,尤其是在可移植性方面。最起码,你必须使用 #pragma pack(1)
或类似的编译器专用命令。
所以,你真的应该考虑完全放弃位域,在原始的 uint8_t
,因为这样可以解决很多问题。
顺便说一下,所有存储在EEPROM中的变量必须是 volatile
是合格的,所有指向它们的指针也必须是合格的。否则很有可能在启用优化的时候,程序就会乱套。