初始化寄存器
#一人分享一道面试手撕题#为一个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; // 成功
}
#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; // 成功
}
全部评论
相关推荐
查看5道真题和解析 点赞 评论 收藏
分享
不知道怎么取名字_:技术这个东西,太杂了,而且要下功夫的
查看5道真题和解析 点赞 评论 收藏
分享
飞屋一号:碰到这样的mt可以直接托付终生了
点赞 评论 收藏
分享
点赞 评论 收藏
分享
