Chenyj Space
返回博客
·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 架构,包括中断机制、低功耗模式和系统启动流程等内容。