初始化寄存器

#一人分享一道面试手撕题#为一个32位控制寄存器(地址为0x40021000)设计一个初始化函数。该寄存器包含多个位域,其布局如下表所示。函数需要根据配置参数,安全、高效地初始化该寄存器。

#include <stdint.h>
#include <stddef.h>

// 定义寄存器地址
#define CTRL_REG_ADDR (*(volatile uint32_t *)0x40021000)

// 定义位域掩码和偏移量(更清晰、可维护性更强的方式)
#define MODE_MASK        0x00000003UL
#define MODE_OFFSET      0
#define CLK_SRC_MASK     0x0000000CUL
#define CLK_SRC_OFFSET   2
#define PRESCALER_MASK   0x00000030UL
#define PRESCALER_OFFSET 4
#define EN_INT_MASK      0x00000100UL
#define EN_INT_OFFSET    8
#define DIV_MASK         0xFFFF0000UL
#define DIV_OFFSET       16

// 保留位的掩码,用于确保这些位被清零
#define RESERVED_MASK    0x0000FE00UL // 位15:9

int register_init(const struct reg_config *config) {
    // 1. 参数基础校验
    if (config == NULL) {
        return -1;
    }

    // 2. 详细的参数值合法性校验
    if (config->mode > 2) {
        return -1; // MODE值非法
    }
    if (config->clk_src > 2) {
        return -1; // CLK_SRC值非法
    }
    if (config->prescaler > 3) {
        return -1; // PRESCALER值非法
    }
    if (config->en_int > 1) {
        return -1; // EN_INT值非法
    }
    // DIV 是16位无符号整数,其取值范围0-65535都是合法的,无需额外校验

    // 3. 组装寄存器值
    uint32_t reg_value = 0; // 从0开始构建

    reg_value |= ((uint32_t)(config->mode) & 0x3) << MODE_OFFSET;
    reg_value |= ((uint32_t)(config->clk_src) & 0x3) << CLK_SRC_OFFSET;
    reg_value |= ((uint32_t)(config->prescaler) & 0x3) << PRESCALER_OFFSET;
    reg_value |= ((uint32_t)(config->en_int) & 0x1) << EN_INT_OFFSET;
    reg_value |= ((uint32_t)(config->div) & 0xFFFF) << DIV_OFFSET;

    // 注意:由于我们是从0开始按位或,并且保留位对应的值始终为0,所以自然就保证了保留位为0。
    // 这是一种更安全的方法。

    // 4. 写入寄存器
    CTRL_REG_ADDR = reg_value;

    return 0; // 成功
}
全部评论

相关推荐

Edgestr:没项目地址就干脆把那一栏删了呗
点赞 评论 收藏
分享
2025-12-31 14:19
门头沟学院 产品经理
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务