·20 分钟
嵌入式 C 语言编程技巧:位操作、内存管理与代码优化
嵌入式C语言位操作内存管理代码优化嵌入式
位操作技巧
位操作是嵌入式编程中最常用的技巧之一,用于配置寄存器、控制外设等。
1. 基本位操作
c
// 位操作基本函数
#define SET_BIT(reg, bit) ((reg) |= (bit)) // 置位
#define CLR_BIT(reg, bit) ((reg) &= ~(bit)) // 清位
#define TOG_BIT(reg, bit) ((reg) ^= (bit)) // 翻转
#define GET_BIT(reg, bit) ((reg) & (bit)) // 读位
// 使用示例
uint32_t reg = 0x00;
SET_BIT(reg, 0x01); // 设置 bit0
SET_BIT(reg, 0x04); // 设置 bit2
CLR_BIT(reg, 0x01); // 清除 bit0
TOG_BIT(reg, 0x04); // 翻转 bit2
if(GET_BIT(reg, 0x04)) {
// bit2 为 1
}
2. 位域操作
c
// 定义位域结构
typedef struct {
uint32_t enable : 1; // bit0
uint32_t mode : 2; // bit1-2
uint32_t priority : 3; // bit3-5
uint32_t reserved : 26; // bit6-31
} ControlReg_t;
// 使用位域
volatile ControlReg_t *ctrl = (ControlReg_t *)0x40021000;
ctrl->enable = 1;
ctrl->mode = 2;
ctrl->priority = 5;
3. 位掩码技巧
c
// 提取特定位段
uint32_t reg_value = 0x12345678;
// 提取 bit8-15
uint8_t byte1 = (reg_value >> 8) & 0xFF;
// 提取 bit16-19
uint8_t nibble = (reg_value >> 16) & 0x0F;
// 设置特定位段
uint32_t new_value = (reg_value & ~(0xFF << 8)) | (0xAB << 8);
内存管理
1. 内存对齐
c
// 结构体对齐
typedef struct {
uint8_t a; // 1 byte
uint32_t b; // 4 bytes, 对齐到 4 字节边界
uint8_t c; // 1 byte
} AlignedStruct_t; // 大小 = 12 bytes
// 使用 packed 属性避免对齐
typedef struct __attribute__((packed)) {
uint8_t a; // 1 byte
uint32_t b; // 4 bytes
uint8_t c; // 1 byte
} PackedStruct_t; // 大小 = 6 bytes
// 对齐的重要性
// 1. 性能:对齐访问更快
// 2. 硬件要求:某些外设必须对齐访问
// 3. 网络协议:字节序和对齐
2. 内存池管理
c
// 简单内存池实现
#define POOL_SIZE 1024
#define BLOCK_SIZE 32
static uint8_t memory_pool[POOL_SIZE];
static uint8_t pool_bitmap[POOL_SIZE / BLOCK_SIZE / 8];
void* pool_alloc(void) {
for(int i = 0; i < POOL_SIZE / BLOCK_SIZE; i++) {
int byte_idx = i / 8;
int bit_idx = i % 8;
if(!(pool_bitmap[byte_idx] & (1 << bit_idx))) {
pool_bitmap[byte_idx] |= (1 << bit_idx);
return &memory_pool[i * BLOCK_SIZE];
}
}
return NULL; // 内存池已满
}
void pool_free(void *ptr) {
if(ptr == NULL) return;
uint32_t offset = (uint8_t*)ptr - memory_pool;
int block_idx = offset / BLOCK_SIZE;
int byte_idx = block_idx / 8;
int bit_idx = block_idx % 8;
pool_bitmap[byte_idx] &= ~(1 << bit_idx);
}
3. DMA 内存管理
c
// DMA 缓冲区必须对齐
#define DMA_BUFFER_SIZE 256
// 使用 aligned 属性
__attribute__((aligned(4))) uint8_t dma_buffer[DMA_BUFFER_SIZE];
// 或者使用特定段
#pragma section = "DMA_BUFFER"
uint8_t dma_buffer[DMA_BUFFER_SIZE] @ "DMA_BUFFER";
代码优化技巧
1. 查表法
c
// 使用查表法替代复杂计算
// 计算 sin 值
const uint16_t sin_table[360] = {
0, 17, 35, 53, 71, 89, 107, 125, 143, 161,
// ... 预计算的 sin 值
};
uint16_t fast_sin(uint16_t angle) {
return sin_table[angle % 360];
}
// 字符串转数字
uint32_t fast_atoi(const char *str) {
uint32_t result = 0;
while(*str >= '0' && *str <= '9') {
result = result * 10 + (*str - '0');
str++;
}
return result;
}
2. 编译器优化
c
// 使用 likely/unlikely 提示编译器
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
void process_data(uint8_t data) {
if(unlikely(data == 0xFF)) {
// 错误处理(很少发生)
handle_error();
} else {
// 正常处理
normal_process(data);
}
}
// 使用 inline 减少函数调用开销
static inline uint32_t min(uint32_t a, uint32_t b) {
return a < b ? a : b;
}
// 使用 restrict 优化指针访问
void copy_array(uint8_t *restrict dst, const uint8_t *restrict src, uint32_t len) {
for(uint32_t i = 0; i < len; i++) {
dst[i] = src[i];
}
}
3. 循环优化
c
// 循环展开
void fill_array(uint8_t *arr, uint32_t len, uint8_t value) {
uint32_t i;
// 处理前 4 的倍数
for(i = 0; i < len - 3; i += 4) {
arr[i] = value;
arr[i + 1] = value;
arr[i + 2] = value;
arr[i + 3] = value;
}
// 处理剩余元素
for(; i < len; i++) {
arr[i] = value;
}
}
// 使用寄存器变量
void fast_copy(uint8_t *dst, const uint8_t *src, uint32_t len) {
register uint32_t i;
for(i = 0; i < len; i++) {
dst[i] = src[i];
}
}
调试技巧
1. 断言宏
c
// 调试断言
#ifdef DEBUG
#define ASSERT(cond) \
do { \
if(!(cond)) { \
printf("Assertion failed: %s, file %s, line %d\n", \
#cond, __FILE__, __LINE__); \
while(1); \
} \
} while(0)
#else
#define ASSERT(cond) ((void)0)
#endif
// 使用断言
void process_buffer(uint8_t *buf, uint32_t len) {
ASSERT(buf != NULL);
ASSERT(len > 0 && len <= MAX_BUFFER_SIZE);
// 处理逻辑
}
2. 调试输出
c
// 调试日志宏
#ifdef DEBUG
#define LOG_DEBUG(fmt, ...) \
printf("[DEBUG] %s:%d: " fmt "\n", __func__, __LINE__, ##__VA_ARGS__)
#define LOG_INFO(fmt, ...) \
printf("[INFO] " fmt "\n", ##__VA_ARGS__)
#define LOG_ERROR(fmt, ...) \
printf("[ERROR] %s:%d: " fmt "\n", __func__, __LINE__, ##__VA_ARGS__)
#else
#define LOG_DEBUG(fmt, ...) ((void)0)
#define LOG_INFO(fmt, ...) ((void)0)
#define LOG_ERROR(fmt, ...) ((void)0)
#endif
// 使用日志
void init_peripheral(void) {
LOG_DEBUG("Initializing peripheral...");
if(config.error) {
LOG_ERROR("Configuration failed: %d", config.error);
return;
}
LOG_INFO("Peripheral initialized successfully");
}
3. 性能分析
c
// 使用 DWT 周期计数器测量时间
#define DWT_CYCCNT *((volatile uint32_t *)0xE0001004)
#define DWT_CTRL *((volatile uint32_t *)0xE0001000)
void dwt_init(void) {
DWT_CTRL |= 1; // 使能周期计数器
}
uint32_t dwt_get_cycles(void) {
return DWT_CYCCNT;
}
// 测量函数执行时间
void measure_function(void) {
uint32_t start, end, cycles;
start = dwt_get_cycles();
// 被测函数
function_to_measure();
end = dwt_get_cycles();
cycles = end - start;
printf("Function took %lu cycles\n", cycles);
}
防御性编程
1. 参数检查
c
// 返回错误码
typedef enum {
ERR_NONE = 0,
ERR_INVALID_PARAM,
ERR_TIMEOUT,
ERR_OVERFLOW
} ErrorCode_t;
ErrorCode_t process_data(uint8_t *data, uint32_t len) {
if(data == NULL) {
return ERR_INVALID_PARAM;
}
if(len > MAX_BUFFER_SIZE) {
return ERR_OVERFLOW;
}
// 处理数据
// ...
return ERR_NONE;
}
2. 看门狗保护
c
// 看门狗初始化
void watchdog_init(uint32_t timeout_ms) {
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
IWDG_SetPrescaler(IWDG_Prescaler_64);
IWDG_SetReload(timeout_ms * 64 / 1000);
IWDG_ReloadCounter();
IWDG_Enable();
}
// 喂狗
void watchdog_feed(void) {
IWDG_ReloadCounter();
}
// 主循环中的看门狗
int main(void) {
watchdog_init(1000); // 1 秒超时
while(1) {
// 主任务
main_task();
// 喂狗
watchdog_feed();
}
}
下一篇
接下来我们将深入探讨 ARM Cortex-M 架构,包括中断机制、低功耗模式和系统启动流程等内容。