如何写入单个位?我有一个 1 或 0 的变量,我想将其值写入 8 位reg
变量中的单个位。
我知道这会设置一点:
reg |= mask; // mask is (1 << pin)
这会清楚一点:
reg &= ~mask; // mask is (1 << pin)
有没有办法让我在一行代码中做到这一点,而不必确定输入的值是高还是低?
假设value
是0
或1
:
REG = (REG & ~(1 << pin)) | (value << pin);
我使用REG
而不是register
因为正如@KerrekSB在 OP 评论中指出的那样,register
是一个 C 关键字。
这里的想法是我们计算一个REG
清除指定位的值,然后根据value
我们设置该位。
因为你用嵌入标记了这个,我认为最好的答案是:
if (set)
reg |= mask; // mask is (1 << pin)
else
reg &= ~mask; // mask is (1 << pin)
(您可以将其包装在宏或内联函数中)。原因是像 AVR 这样的嵌入式架构具有位设置和位清除指令,并且与其他指令相比,分支的成本并不高(因为它在具有推测执行的现代 CPU 上)。GCC 可以识别该if
语句中的习语并产生正确的指令。更复杂的版本(即使在现代 x86 上测试时它是无分支的)可能无法组装成嵌入式系统上的最佳指令。
确定的最好方法是分解结果。您不必成为专家(尤其是在嵌入式环境中)来评估结果。
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 *)®)->bit1 = value;
®
是你的变量的地址。((T_BitArray *)®)
是相同的地址,但现在编译器将其视为T_BitArray
地址并((T_BitArray *)®)->bit1
提供对第二位的访问。当然,最好使用更具描述性的名称bit1
我认为您要问的是,您是否可以在不先读取其所在字节的情况下对单个位执行写指令。如果是这样,那么不,您不能这样做。与C语言无关,只是微处理器没有寻址单个位的指令。即使在原始机器代码中,如果您想设置一个位,您必须读取它所在的字节,更改该位,然后将其写回。没有其他方法可以做到这一点。
重复您如何设置、清除和切换一个位,我也会重新发布我的答案,因为还没有人提到 SET 和 CLEAR 寄存器:
由于这被标记为“嵌入式”,我假设您使用的是微控制器。以上所有建议都是有效且有效的(读取-修改-写入、联合、结构等)。
然而,在一次基于示波器的调试过程中,我惊讶地发现,与将值直接写入微控制器的 PORTnSET / PORTnCLEAR 寄存器相比,这些方法在 CPU 周期中具有相当大的开销,这在存在紧密循环/高电平的情况下产生了真正的差异-频率 ISR 的切换引脚。
对于那些不熟悉的人:在我的示例中,微控制器有一个反映输出引脚的通用引脚状态寄存器 PORTn,因此执行 PORTn |= BIT_TO_SET 会导致对该寄存器的读取-修改-写入。
但是,PORTnSET / PORTnCLEAR 寄存器采用“1”表示“请将此位设为 1”(SET)或“请将此位设为 0”(CLEAR),而“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;
}