我正在编程一个PIC18F94K20与一个MCP7941X I2C RTCC船和一个24AA128 I2C串行EEPROM设备一起工作。目前,我的代码成功地导入了RTCC的秒/天/etc值,并启动了计时器,每秒钟切换一个LED。
我试图增加代码来读取这些值的正确数据,但是当我试图解释这些值中的各种“额外”位时,我却遇到了麻烦。内存映射可能会在某种程度上帮助阐明我的问题:

例如,以小时列或02h地址为例。位6被设置为1来切换12小时的时间,增加01000000的小时位。我可以在这个地址读取字节的全部内容,但是我想使用一个if语句来检测12小时或24小时的时间是否到位,并进行相应的调整。我并不担心10小时的比特,因为我可以通过一个BCD转换循环(我认为)来计算这一点。
我之前使用了C中的位或运算符来将原始小时数据增加到24小时。我将这个特殊情况下的小时初始化为0x11,并将12小时控制位设置为0x64。设定时间时:
WriteI2C(0x11|0x64);正如你所看到的,它使用按位或。
当读取时间时,如何将运算符合并到代码中以将多余的位与实际的时间位分开?我试着做这样的事:
current_seconds = ReadI2C();
current_seconds = ST & current_seconds;但那完全毁了一切。它会编译,但是设备会在这个序列上“卡住”。
如何将ST / AMPM / VBATEN位与我所需要的实际数据分开,对于循环所呈现的各种情况(例如,如果位6=0,读取回12小时时间,如果bit6 = 1,则为24小时时间,等等),有什么好的方法来实现它们?
我是一个C新手,这是我第一次尝试电子,所以我真的很感谢任何帮助。谢谢。
发布于 2014-02-20 15:36:40
若要删除(零)位,可以使用具有所有其他位集的掩码和值,即您希望为零的比特的补充,例如:
value_without_bit_6 = value & ~(1<<6);若要在整数中隔离位,则可以使用仅设置这些位的掩码和值。对于检查标志,这是您需要做的全部工作,例如,
if (value & (1<<6)) {
// bit 6 is set
} else {
// bit 6 is not set
}若要读取较大位内小整数偏移量的值,首先隔离比特,然后根据最低位的索引将其右移(将最小有效位移到正确位置),例如:
value_in_bits_4_and_5 = (value & ((1<<4)|(1<<5))) >> 4;对于更具可读性的代码,您应该使用常量或#defined宏来表示所需的各种位掩码,例如:
#define BIT_VBAT_EN (1<<3)
if (value & BIT_VBAT_EN) {
// VBAT is enabled
}另一种方法是使用位字段来定义双边投资条约的组织,例如:
typedef union {
struct {
unsigned ones:4;
unsigned tens:3;
unsigned st:1;
} seconds;
uint8_t byte;
} seconds_register_t;
seconds_register_t sr;
sr.byte = READ_ADDRESS(0x00);
unsigned int seconds = sr.seconds.ones + sr.seconds.tens * 10;位字段的一个潜在问题是编译器生成的代码可能是不可预测的大代码或低效代码,这有时会引起微控制器的关注,但显然读和写更好。(另一个经常提到的问题是,bit字段的组织,例如endianness,在C标准中基本上没有具体说明,因此无法保证跨编译器和跨平台可移植。然而,我的观点是,微控制器的低层次开发往往本质上是不可移植的,所以如果您找到正确的位布局,我不会认为使用位字段是“错误的”,特别是对于爱好者项目。)
然而,您可以使用宏完成类似的可读性语法;只是宏本身的可读性较差:
#define GET_SECONDS(r) ( ((r) & 0x0F) + (((r) & 0x70) >> 4) * 10 )
uint8_t sr = READ_ADDRESS(0x00);
unsigned int seconds = GET_SECONDS(sr);发布于 2014-02-20 15:40:39
关于位掩蔽本身,您需要在您的微控制器中建立一个内存映射的模型。最简单、最受欢迎的方法是#define一些位掩码,如下所示:
#define REG1_ST 0x80u
#define REG1_10_SECONDS 0x70u
#define REG1_SECONDS 0x0Fu
#define REG2_10_MINUTES 0x70u
...然后在读取每个字节时,屏蔽您感兴趣的数据。例如:
bool st = (data & REG1_ST) != 0;
uint8_t ten_seconds = (data & REG1_10_SECONDS) >> 4;
uint8_t seconds = (data & REG1_SECONDS);重要的部分是尽量减少源代码中“神奇数字”的数量。
书面数据:
reg1 = 0;
reg1 |= st ? REG1_ST : 0;
reg1 |= (ten_seconds << 4) & REG1_10_SECONDS;
reg1 |= seconds & REG1_SECONDS;请注意,我忽略了这个I2C的通信。
https://stackoverflow.com/questions/21911979
复制相似问题