微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 单片机C语言位操作实例

单片机C语言位操作实例

时间:11-24 来源:互联网 点击:
C语言本身有较强的位处理功能,但在控制领域有时候经常需要控制某一个二进制中的某一位,为此在MCS_51的KEIL C51中扩充了两个数据类型bit和sbit。前者可以在MCS_51的位寻址区进行分配,而后者只能定义为可位寻址的特殊功能寄存器SFR中的某一位。这两个扩充为MCS_51应用C语言编程带来很大的方便。AVR的C语言中除了CodeVisionAVR定义了bit数据类型外,其余都没有类似的定义,而sbit类型所有C语言都没有定义。相比较,进行位操作运算CodeVisionAVR的功能最强,它一方面有bit类型的数据,可用于位运算;另外在访问寄存器时可以直接访问寄存器的某一位,例如访问DDRB的B2位可以这样访问:

DDRB.3 = 1;

而在IAR、ICCAVR和GCCAVR中没有bit类型的运算,当它们需要访问寄存器的某一位时,只能使用ANSI C语言的位运算功能。

C语言是为描述系统而设计,因此它具有汇编语言所能完成的一些功能,有较好的位操作指令:“&”,“|”,“~”、“<”、“>>”。在控制领域,经常需要控制某一个二进制位,标准C有两种方法实现单个位的操作。

1. 用“读-修改-写”实现对单个位的操作

在没有单个位的位操作指令的情况下,一般是采用“读-修改-写”的方法实现单个位的位操作,即:

Ø 通过与0“与”操作,将某一位清0。例如,使i变量的第0位为0,实现方法为:i = i&0xfe;

Ø 通过与1相 “或”操作,将某一位置1。例如,使i变量的第0位为1,实现方法为 i = i|0x01;

Ø 通过与1进行“异或”操作,将某一位取反。例如,使i变量的第0位取反,实现方法为 i = i^0x01。

注意:采用“读-修改-写”的方法时不要影响其他位。即某位清0时,其他位与1相 “与”;某位置1时,其他位与0“或”;取反时,其他位与0“异或”。

很多程序员喜欢采用下面的移位方式,语句简练:

#define bit(x) (1<(x))

#define LED 2

PORTB|= bit(LED); //将PORTB第二位置1,点亮连接在I/O口的LED

该方式下,程序运行时会增加移位操作,生成的代码较大。若按如下方式直接定义生成的代码就不会有移位操作:

#define LED 0X04

PORTB |= LED;

也有程序员采取如下宏定义的方法实现单个位的操作,使用十分方便:

#define SET_BIT(x,y) ((x)|=(0x0001<(y)))//置x的第y位

#define CLR_BIT(x,y) ((x)&=~( 0x0001<(y)))//清x的第y位为0 #define CPL_BIT(x,y) ((x)^= (0x0001<(y)))//取反x的第y位

#define GET_BIT(x,y) (((x)&(1<读取x的第y位

#define LET_BIT(x,y,z) ((x)=(x)&(~(1<(y)))|((z)<(y)))//

将x的第y位写上z(0/1)

2. 通过位域的(Bit Field )的方法实现位操作

在系统寄存器设置时,很多时候并不需要修改完整的字节,而是只修改一个或几个位,标准C提供了一种基于结构体的数据结构——位域。位域就是把一个存储单元中的二进制划分为几个不同的区域,并说明每个区域的位数,每个域有一个域名,允许在程序中按域名进行操作。位域的定义格式如下:

Struct 位域结构名

{

位域列表;

};

位域列表格式为:类型说明符 位域名:位域长度

Struct k

{

unsigned int a:1;

unsigned int :2;

unsigned int b:3;

unsigned int :0;//空域

}k1;

说明:

Ø 各位依次从低位到高位排列,排满一个存储单元,按地址接着排下一个单元。

Ø 位域可以无域名,但不能被引用。例如,第2域,这时它只用来填充和调整位置。

Ø 第四行称为空域,目的是将目前存储单元的剩余部分分为一个域,且填充0。

位域的引用,例如;

k1.a = 1;//置k1的BO位为1

k1.b = 7;//置k1的B3-B5位为111

用位域定义位变量,操作I/O口,产生的代码紧凑、高效。定义的方法如下;

typedef struct INT8_bit_struct

{

unsigned bit0:1; unsigned bit1:1; unsigned bit2:1;

unsigned bit3:1; unsigned bit4:1; unsigned bit5:1;

unsigned bit6:1;unsigned bit7:1;

}bit_field;

再次宏定义每一个位,使用方法如下:

#define _PINB 0x23

#define _PORTB 0X25

…………

#define IOB2i (*(volatile bit_field *)(_PINB)).bit2

#define IOB2o (*(volatile bit_field *)(_PORTB)).bit2

例如:

void main(void)

{

unsigned char I;

IOB2o = 0;//B口B2位输出低电平

i = IOB2i;//读B口B2位,将B口B2位上的电平值送给i

//

}

对于没有扩展位变量的C语言环境,在汇编下没有单个位的位操作的MCU,通过位域的方法操作I/O口是最佳的方法;汇编下有单个位的位操作指令的MCU,可以嵌入式汇编,但是程序的移植性可能会下降,建议使用位域的方法进

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top