4

如何写入单个位?我有一个 1 或 0 的变量,我想将其值写入 8 位reg变量中的单个位。

我知道这会设置一点:

reg |= mask; // mask is (1 << pin)

这会清楚一点:

reg &= ~mask; // mask is (1 << pin)

有没有办法让我在一行代码中做到这一点,而不必确定输入的值是高还是低?

4

6 回答 6

10

假设value01

REG = (REG & ~(1 << pin)) | (value << pin);

我使用REG而不是register因为正如@KerrekSB在 OP 评论中指出的那样,register是一个 C 关键字。

这里的想法是我们计算一个REG清除指定位的值,然后根据value我们设置该位。

于 2013-09-01T18:48:02.067 回答
2

因为你用嵌入标记了这个,我认为最好的答案是:

if (set)
    reg |= mask; // mask is (1 << pin)
else
    reg &= ~mask; // mask is (1 << pin)

(您可以将其包装在宏或内联函数中)。原因是像 AVR 这样的嵌入式架构具有位设置和位清除指令,并且与其他指令相比,分支的成本并不高(因为它在具有推测执行的现代 CPU 上)。GCC 可以识别该if语句中的习语并产生正确的指令。更复杂的版本(即使在现代 x86 上测试时它是无分支的)可能无法组装成嵌入式系统上的最佳指令。

确定的最好方法是分解结果。您不必成为专家(尤其是在嵌入式环境中)来评估结果。

于 2013-09-01T19:43:52.740 回答
2

C 的一个被忽视的特性是位打包,它非常适合嵌入式工作。您可以定义 astruct以单独访问每个位。

typedef struct
{
    unsigned char bit0 : 1;
    unsigned char bit1 : 1;
    unsigned char bit2 : 1;
    unsigned char bit3 : 1;
    unsigned char bit4 : 1;
    unsigned char bit5 : 1;
    unsigned char bit6 : 1;
    unsigned char bit7 : 1;
} T_BitArray;

: 1告诉编译器您只希望每个变量的长度为 1 位。然后只需访问您的变量reg所在的地址,将其转换为您的位数组,然后单独访问这些位。

((T_BitArray *)&reg)->bit1 = value;

&reg是你的变量的地址。((T_BitArray *)&reg)是相同的地址,但现在编译器将其视为T_BitArray地址并((T_BitArray *)&reg)->bit1提供对第二位的访问。当然,最好使用更具描述性的名称bit1

于 2013-09-01T19:47:14.853 回答
0

我认为您要问的是,您是否可以在不先读取其所在字节的情况下对单个位执行写指令。如果是这样,那么不,您不能这样做。与C语言无关,只是微处理器没有寻址单个位的指令。即使在原始机器代码中,如果您想设置一个位,您必须读取它所在的字节,更改该位,然后将其写回。没有其他方法可以做到这一点。

于 2013-09-01T19:00:58.790 回答
0

重复您如何设置、清除和切换一个位,我也会重新发布我的答案,因为还没有人提到 SET 和 CLEAR 寄存器:

由于这被标记为“嵌入式”,我假设您使用的是微控制器。以上所有建议都是有效且有效的(读取-修改-写入、联合、结构等)。

然而,在一次基于示波器的调试过程中,我惊讶地发现,与将值直接写入微控制器的 PORTnSET / PORTnCLEAR 寄存器相比,这些方法在 CPU 周期中具有相当大的开销,这在存在紧密循环/高电平的情况下产生了真正的差异-频率 ISR 的切换引脚。

对于那些不熟悉的人:在我的示例中,微控制器有一个反映输出引脚的通用引脚状态寄存器 PORTn,因此执行 PORTn |= BIT_TO_SET 会导致对该寄存器的读取-修改-写入。

但是,PORTnSET / PORTnCLEAR 寄存器采用“1”表示“请将此位设为 1”(SET)或“请将此位设为 0”(CLEAR),而“0”表示“不要管该引脚”。因此,您最终会得到两个端口地址,具体取决于您是设置还是清除该位(并不总是方便),但反应更快,汇编代码更小。

于 2013-09-04T14:59:01.047 回答
0
//Through Macro we can do set resset Bit
#define set(a,n)   a|=(1<<n);
#define reset(a,n) a&=(0<<n);
//toggle bit value given by the user
#define toggle(a,n)  a^=(1<<n);

int a,n;
int main()
{
     printf("Set Reset particular Bit given by User ");
     scanf("%d %d",&a,&n);
     int b =set(a,n)   //same way we can call all the macro
     printf("%d",b);
     return 0;
}
于 2022-02-19T15:02:05.673 回答