如何使用掩码获取少量位值

时间:2018-01-02 13:12:08

标签: c bit-manipulation bitwise-operators

我正在开发一个MCU,每个GPIO端口有16个引脚。我有一个中断路由,我需要看看引脚14,13和12的输入数据寄存器是高电平还是低电平。我创建了这个简单的测试场景,看看我是否可以在uint8_t变量中读取和存储特定的引脚:

#include <stdio.h>
#include <stdint.h>

#define GPIO_PIN_0                 ((uint16_t)0x0001)  /* Pin 0 selected    */
#define GPIO_PIN_1                 ((uint16_t)0x0002)  /* Pin 1 selected    */
#define GPIO_PIN_2                 ((uint16_t)0x0004)  /* Pin 2 selected    */
#define GPIO_PIN_3                 ((uint16_t)0x0008)  /* Pin 3 selected    */
#define GPIO_PIN_4                 ((uint16_t)0x0010)  /* Pin 4 selected    */
#define GPIO_PIN_5                 ((uint16_t)0x0020)  /* Pin 5 selected    */
#define GPIO_PIN_6                 ((uint16_t)0x0040)  /* Pin 6 selected    */
#define GPIO_PIN_7                 ((uint16_t)0x0080)  /* Pin 7 selected    */
#define GPIO_PIN_8                 ((uint16_t)0x0100)  /* Pin 8 selected    */
#define GPIO_PIN_9                 ((uint16_t)0x0200)  /* Pin 9 selected    */
#define GPIO_PIN_10                ((uint16_t)0x0400)  /* Pin 10 selected   */
#define GPIO_PIN_11                ((uint16_t)0x0800)  /* Pin 11 selected   */
#define GPIO_PIN_12                ((uint16_t)0x1000)  /* Pin 12 selected   */
#define GPIO_PIN_13                ((uint16_t)0x2000)  /* Pin 13 selected   */
#define GPIO_PIN_14                ((uint16_t)0x4000)  /* Pin 14 selected   */
#define GPIO_PIN_15                ((uint16_t)0x8000)  /* Pin 15 selected   */
#define GPIO_PIN_All               ((uint16_t)0xFFFF)  /* All pins selected */

int main() {

    uint32_t maskWithOR     = GPIO_PIN_14 | GPIO_PIN_13 | GPIO_PIN_12;
    uint32_t maskInBinary   = 0b00000000000000000111000000000000;

    uint32_t data[8] = {
        //.................XXX............
        0b10010000100011110000000011111111, //0 = 000
        0b10010000100011110001000011111111, //1 = 001
        0b10010000100011110010000011111111, //2 = 010
        0b10010000100011110011000011111111, //3 = 011
        0b10010000100011110100000011111111, //4 = 100
        0b10010000100011110101000011111111, //5 = 101
        0b10010000100011110110000011111111, //6 = 110
        0b10010000100011110111000011111111, //7 = 111               
    };

    printf("maskWithOR = 0x%x\r\n", maskWithOR);
    printf("maskInBinary = 0x%x\r\n", maskInBinary);

    printf("\r\nOR MASK:\r\n");
    for(int i = 0; i < 8; i++) {
        uint8_t result = data[i] & maskWithOR;
        printf("result[%d] = %d\r\n", i, result);
    }

    printf("\r\nBINARY MASK:\r\n");
    for(int i = 0; i < 8; i++) {
        uint8_t result = data[i] & maskInBinary;
        printf("result[%d] = %d\r\n", i, result);
    }

    return 0;
}

这是我测试程序的输出:

maskWithOR = 0x7000
maskInBinary = 0x7000

OR MASK:
result[0] = 0
result[1] = 0
result[2] = 0
result[3] = 0
result[4] = 0
result[5] = 0
result[6] = 0
result[7] = 0

BINARY MASK:
result[0] = 0
result[1] = 0
result[2] = 0
result[3] = 0
result[4] = 0
result[5] = 0
result[6] = 0
result[7] = 0

我做错了什么?

2 个答案:

答案 0 :(得分:1)

您将32位操作的结果存储在8位变量中:

uint8_t result = data[i] & maskWithOR;

此操作的结果是该值被截断,使您保留原始结果的最后八位。由于您感兴趣的所有三个位都高于第12位,因此您获得的结果始终为零。

如果必须将结果拟合为8位,则将data[i] & maskWithOR的值移位最低位的索引,即12位。

答案 1 :(得分:1)

您无法将AND结果存储为8位整数...

您可以尝试强制布尔结果(1或0),如下所示:

uint8_t result = (data[i] & maskWithOR)>0;

在查看0到7之间的所需输出值之后,可以强制将32位无符号数位向右移位...向右移动12位,然后仅使用符合8位整数的位进行屏蔽以确保你得到一个8位的结果

uint8_t result = ((data[i] & maskWithOR)>>12) & 255;

虽然255掩码有点多余......你可以这样做,并可能侥幸逃脱......

uint8_t result = (data[i] & maskWithOR)>>12;

但是,正如@chux提到的AND 255uint32_t安静或取消因将结果从uint8_t缩小到{{1}}而引起的警告