日期 | 作者 | 版本 | 说明 |
---|---|---|---|
2020.12.03 | Tao | V0.0 | 1. 增加了版本记录表 2.增加了使用位域/联合体实现位操作 |
功能介绍
位运算
位运算就是直接对整数在内存中的二进制位进行操作,它是C语言的强大的特性之一。
功能 | 位运算符 | 说明 |
---|---|---|
按位与 | a & b | |
按位或 | a | b | |
按位异或 | a ^ b | 位相同为0,位不同为1 |
按位取反 | ~a | |
左移 | a << b | a左移b位,就是a乘以2的b次方 |
右移 | a >> b | a右移b位,就是a除以2的b次方 |
需要注意它与逻辑运算的区分。
功能 | 逻辑运算符 |
---|---|
逻辑与 | a && b |
逻辑或 | a |
逻辑非 | !a |
在进行嵌入式开发时,常会有对寄存器进行位运算的场景。通过使用位运算,可以提高程序的执行效率,但会使代码变得生涩难懂。通过设置合适的位掩码,我们可以封装一些常用的位操作方法,如复位、置位、翻转、取值等。以下是四种比较常用位运算的函数实现。
位域操作
有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便。C语言又提供了一种数据结构,称“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。 位域是结构体的一种:
typedef struct
{
uint8_t Bit0:1;
uint8_t Bit1:1;
uint8_t Bit2:1;
uint8_t Bit3:1;
uint8_t Bit4:1;
uint8_t Bit5:1;
uint8_t Bit6:1;
uint8_t Bit7:1;
} BitDataStruct;
位域/联合体联用
在进行某些算法的C语言编程的时候,需要使几种不同类型的变量存放到同一段内存单元中。也就是使用覆盖技术,几个变量互相覆盖。这种几个不同的变量共同占用一段内存的结构,在C语言中,被称作“共用体”类型结构,简称共用体,也叫联合体。联合体跟结构体的区别在于:他们外表相似,但在内存布局上存在着关键性的区别,结构体每个成员依次存储,联合体中所有成员的偏移地址都是0,也就是所有成员是叠在一起的,所以在联合体中在某一时刻,只有一个成员有效。在结构体中各成员有各自的内存空间,一个结构体变量的总长度大于等于各成员长度之和。而在联合体中,各成员共享一段内存空间,一个联合变量的长度等于各成员中最长的长度。
通过位域/联合体联用,我们可以定义一个既可以实现按位操作又能实现按字节统一操作的结构体变量。
typedef union
{
BitDataStruct BitData;
uint8_t ByteData;
} BitDataUnion;
定义类型
typedef struct
{
uint8_t bit0:1;
uint8_t bit1:1;
uint8_t bit2:1;
uint8_t bit3:1;
uint8_t bit4:1;
uint8_t bit5:1;
uint8_t bit6:1;
uint8_t bit7:1;
} BitDataStruct;
typedef union
{
BitDataStruct BitData;
uint8_t ByteData;
} BitDataUnion;
按位操作
BitDataUnion BitData_PortCtrl; //声明变量
BitData_PortCtrl.BitData.bit0 = 0; //将第0位置0
按字节操作
BitDataUnion BitData_PortCtrl; //声明变量
BitData_PortCtrl.ByteData = 0x00; //将8位全部置0
位运算封装源码
/**
* @brief 将某个字节的某一位 置0
* @param byte: byte need to be operated
* @param bitNum: number of the bit
* @retval result of the operation
*/
uint8_t BitOpt_ResetBit(uint8_t byte, uint8_t bitNum)
{
byte &= ~(0x01<<bitNum);
return byte;
}
/**
* @brief 将某个字节的某一位 置1
* @param byte: byte need to be operated
* @param bitNum: number of the bit
* @retval result of the operation
*/
uint8_t BitOpt_SetBit(uint8_t byte, uint8_t bitNum)
{
byte |= (0x01<<bitNum);
return byte;
}
/**
* @brief 将某个字节的某一位 翻转
* @param byte: byte need to be operated
* @param bitNum: number of the bit
* @retval result of the operation
*/
uint8_t BitOpt_ReverseBit(uint8_t byte, uint8_t bitNum)
{
byte ^= (0x01<<bitNum);
return byte;
}
/**
* @brief 获取某个字节的某一位的值
* @param byte: byte need to be operated
* @param bitNum: number of the bit
* @retval result of the operation (0 or 1)
*/
uint8_t BitOpt_GetBit(uint8_t byte, uint8_t bitNum)
{
return (byte & (0x01<<bitNum))>>bitNum;
}