寄存器位域、位操作等示例

嵌入式中,与外设打交道较多,其实大部分的设置是直接操作寄存器的,而寄存器又被当成一个内存地址来使用。每个寄存器有不同的字段,表示不同的含义。常常使用的方法有移位和位域。我一般常用的移位,这是当年搞AVR单片机时留下的纪念,我也自认为移位方式十分好用。另外的位域,其实我没实际使用过。

本文就虚拟一个寄存器(其实是一个变量而已)及其字段,当然,仅具有演示意义,不代表实际的场合。

使用位操作时,就是通过左移、右移来组装不同字段的数据,在移位时一定要记得使用掩码,否则数据有可能会错乱。见代码的test_1函数示例。

使用位域时,就是设置好各个字段的位域,然后一一赋值,再利用联合体的特性来对寄存器赋值,位域最好用联合体,方便很多。见代码的test_2函数示例。

两种方法各有优点,看个人取舍吧。我是偏向使用移位的方式。

#include <stdio.h>

/*
测试结果:
struct test
register_value: 0x0000fead
enable: 1 type: 6 id: a value: fe
union test
register_value: 0x0000fead
enable: 0 type: 6 id: a value: fe

*/
/**
虚拟的寄存器,各字段:

0: enable
1~3: type
4~7: id
8~15:value
16~31: reserve 
*/

unsigned int register_value = 0;

// 结构体式
typedef struct {
    unsigned int enable;
    unsigned int type;
    unsigned int id;
    unsigned int value;
}DEV_IO_ARG;

int test_1(void)
{
    DEV_IO_ARG io_arg_tmp;
    DEV_IO_ARG *io_arg = &io_arg_tmp;
    // 组装
    io_arg->enable = 0x1;
    io_arg->type = 0x6;
    io_arg->id = 0xa;
    io_arg->value = 0xfe;

    register_value = (io_arg->value << 8) | (io_arg->id << 4) | (io_arg->type << 1) | (io_arg->enable << 0);

    printf("register_value: 0x%08x\n", register_value);

    // 分解
    io_arg->enable = (register_value >> 0) & 0x01;
    io_arg->type = (register_value >> 1) & 0x07;
    io_arg->id = (register_value >> 4) & 0x0f;
    io_arg->value = (register_value >> 8) & 0xff;
    printf("enable: %x type: %x id: %x value: %x\n", 
    io_arg->enable,
    io_arg->type,
    io_arg->id,
    io_arg->value);
}

// 联合体式
typedef struct {
    unsigned int enable: 1;
    unsigned int type: 3;
    unsigned int id: 4;
    unsigned int value: 8;
    unsigned int reserve: 16;
}DEV_IO_ARG_1;

typedef union {
    unsigned int tmp;
    DEV_IO_ARG_1 arg;
}DEV_IO_ARG_UNION;

void test_2(void)
{
    DEV_IO_ARG_UNION io_arg_tmp = {0};
    io_arg_tmp.arg.enable = 1;
    io_arg_tmp.arg.type = 0x6;
    io_arg_tmp.arg.id = 0xa;
    io_arg_tmp.arg.value = 0xfe;
    
    register_value = 0;
    register_value = io_arg_tmp.tmp;
    printf("register_value: 0x%08x\n", register_value);
    
    // 前面enable为1,这里减去1,理论上enable应该为0。
    io_arg_tmp.tmp = register_value - 1; 
    printf("enable: %x type: %x id: %x value: %x\n", 
    io_arg_tmp.arg.enable,
    io_arg_tmp.arg.type,
    io_arg_tmp.arg.id,
    io_arg_tmp.arg.value);
}

int main(void)
{
    printf("struct test\n");
    test_1();
    
    printf("union test\n");
    test_2();
}


注:本文内容简单,起因也很简单,公司某部门某些人员可能没搞过嵌入式,没见过位域的用法,但又要搞那一堆代码,不懂了,就问我们部门的人。该同事(和我十分好的那种)和我聊了,于是就有此文。有时想想,想不明白凭什么别人不懂的问题就可以找我们,我们不懂的问题就要自己查。

 

李迟记于2014年6月7日

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值