有没有办法解决C中的单个位?

时间:2012-04-10 02:05:49

标签: c 8051

您好我已经对位可寻址微控制器进行了一些研究。在我的路径中遇到的唯一一个是英特尔MCS-51(wiki page),它今天仍然非常常用...我想知道你是否可以直接在C中解决一点,例如在 SFR区域wiki 8051 memory architecture

我在SFR中寻址的位是直接进行位寻址,还是在字节寻址的位域中进行逐位操作,还是完全不同的?

具体来说,从这里开始:Check if a single bit is set,看起来这个位是用MOV直接操作的,我想知道这是否可能在C(带扩展)或者它看起来只是按位操作,但是在后台有一些编译器的东西只使用字节?

作为后续问题,是否有任何可寻址的现代处理器?

6 个答案:

答案 0 :(得分:8)

在普通C中(没有任何扩展,无论它们是什么),您可以将变量声明为位字段。它可以节省大量的打字并且不易出错。

这是一个示例程序。它使用具有相同大小的常规类型的并集声明了一个位字段。

#include <stdio.h>

int main(int argc, char *argv[])
{
    typedef struct 
    {
        union
        {
            struct {
                int bit0:1;
                int bit1:1;
                int bit2:1;
                int bit3:1;
                int bit4:1;
                int bit5:1;
                int bit6:1;
                int bit7:1;
            };
            unsigned char byte;
        };
    } EigthBits;

    EigthBits b;

    b.byte = 0;
    printf("Will be 0 ==> %d\n", b.byte);

    b.bit4 = 1;
    printf("Will be 16 ==> %d\n", b.byte);
}

将打印此输出:

    Will be 0 ==> 0
    Will be 16 ==> 16

例如,将值设置为控制寄存器上的各个位非常有用。您可以设置更多位(如int two_bits:2;)以满足您的需求。

答案 1 :(得分:6)

这并不罕见。例如,SDCC(Small Device C Compiler)是MCS-51的流行编译器。你会找到the manual here。最相关的部分是3.4.1,它描述了MCS-51的语言扩展:

  

3.4.1.6 __bit

     

这是数据类型和存储类说明符。当变量是   声明为有点,它被分配到位可寻址存储器中   8051,例如:

 __bit test_bit;
     

将1写入此变量会生成汇编代码:

 D2*00 setb _test_bit
     

位可寻址存储器由128位组成   数据存储器中的0x20至0x2f。除了这个8051特定的存储类,大多数架构都支持ANSI-C位域4。根据ISO / IEC 9899,没有显式签名修饰符的位和位域实现为无符号。

答案 2 :(得分:5)

在C中,您通常读取一个字节,然后屏蔽您想要的位,但某些特定于处理器的编译器会为您预先定义寄存器甚至单个位。例如,Keil Cx51用户指南定义了bitsfr数据类型。

您可以使用sfr这样的类型:

sfr P0 = 0x80;    // Port 0 is accessed at address 80h.
P0 = 0x20;        // Write 20h to Port 0.

要使用一次一个字节的方法,你可以这样做:

#define SFR (* (unsigned char *) 0x80)  // Address of SFR is 0x80.

#define BIT0 0x01  // LSB of any byte
#define BIT1 0x02
#define BIT2 0x04
. . .
#define BIT7 0x80  // MSB of any byte

// Read BIT1 of SFR. sfrBit1 is 1 if BIT1 is set, 0 if not.
unsigned char sfrBit1 = SFR & BIT1  ?  1 : 0;

// Set BIT0 of SFR.
SFR |= BIT0;

// Clear BIT2 of SFR.
SFR &= ~BIT2;

为方便起见,您可以定义实用程序宏来设置和清除单个位:

#define SET(reg, bit) reg |=  (1 << bit)  // Sets a bit in reg.
#define CLR(reg, bit) reg &= ~(1 << bit)  // Clears a bit in reg.

SET(SFR, 1); // Set BIT1 
CLR(SFR, 2); // Clear BIT2

答案 3 :(得分:2)

处理器8051定义了一些指令,用于将单个位清除为0,设置为1或测试值后跟条件分支,以便在该位置位或清零时绕过以下代码。

这些指令非常有效,仅使用2个字节。第一个字节定义指令,第二个字节是操作数,用于标识要使用的位,总共256位。

前128位引用16个SFR字节(P0的地址0x80为0到7位,SFR的第8位为15,P1为0,对于SF的位为120,对于SFR 0xF8为120到127)。

接下来的128位,如上面Hans Pasant所述,引用了0x20和0x2F之间的16字节内部RAM。

8051实际读取整个字节,测试,设置或清除指定位,并将所有8位写回同一位置(测试除外)。除了有效之外,这些指令也不会修改任何寄存器,如R0到R7,累加器等。

C编译器可以轻松接受超过128&#34; __ bit&#34;变量并用大多数人描述的经典二进制掩码操作替换上面提到的有效汇编代码。但是,Keil编译器实现的最简单的解决方案是在使用128位以上的变量时声明错误。

有一些DSP和图形处理器可以处理指定数量的位。这在编写有效的压缩算法,一些绘图程序等时非常有用。例如,德州仪器的TMS34010可以为每个存储器访问使用不同的位数定义两组寄存器。循环可以使用来自第一组的寄存器一次读取例如3位,并且使用第二组中的寄存器写入11位。在内部,存储器控制器仍然读取16位,并且写回16位并且仅修改每个16位字内的指定位数。所有内存操作都引用了一个位,而不是一个字。例如,程序计数器在执行每条指令时递增16。如果低位为非零,硬件将产生异常,但是为了执行某种类型的混淆,德州仪器很容易制作一个可以接受读取操作码的芯片,但有些位移位。

C语言的发明者预测,有一天可能会有一些处理器可以进行位寻址。他们解释说,当使用位结构时(例如Ixe013所描述的)读取/写入整个字的当前限制可以在将来解除。不幸的是,位可寻址处理器在软件世界中没有引起太多关注。

答案 4 :(得分:1)

“C(带扩展名)”中可以做任何事情,因为带有扩展名的C可以是任何方言,为你带来与天空中的馅饼等效的编程。

在ISO标准C中,最小的可单独寻址的存储单元是字节,由字符类型表示。

通过访问周围位的整个单元来执行对位(甚至结构的位字段成员)的访问。

如果处理器可以寻址位,那么可能有一种方法可以通过C编译器的内联汇编语言实现,如果有这样的话。或外部链接的汇编语言例程。

答案 5 :(得分:1)

这取决于你的意思,通过“一种解决方式”。编写一些将执行此类操作的set_bit(address, bit, value)get_bit(address, bit, value)函数没有问题。但是get_bit至少会返回char字节。

字节地址限制自然来自大多数现代计算机使用的硬件。这非常类似于硬盘驱动器的512字节扇区,这是用于读取或写入的最小IO操作。但是,这并不能阻止您将单个字节和位写入其中。