1. 指针类型与地址计算

c

volatile uint16_t *p_flash = (volatile uint16_t *)(USER_SYSTEM_DATA_ADDR + offset);

地址计算规则:

  • USER_SYSTEM_DATA_ADDR + offset 是字节地址

  • 但 p_flash 是 uint16_t * 类型指针

  • 指针的算术运算与指针类型相关

2. 指针运算规则

c

// 示例代码演示
uint32_t base_addr = 0x0800F000;  // 字节地址

// 情况1:字节指针
volatile uint8_t *p_byte = (volatile uint8_t *)base_addr;
// p_byte + 1 → 地址加1字节 → 0x0800F001

// 情况2:半字指针(16位)
volatile uint16_t *p_halfword = (volatile uint16_t *)base_addr;
// p_halfword + 1 → 地址加2字节 → 0x0800F002

// 情况3:字指针(32位)
volatile uint32_t *p_word = (volatile uint32_t *)base_addr;
// p_word + 1 → 地址加4字节 → 0x0800F004

3. 您的具体情况分析

c

// 您的代码:
p_flash = (volatile uint16_t *)(USER_SYSTEM_DATA_ADDR + offset);

// 假设:
// USER_SYSTEM_DATA_ADDR = 0x0800F000
// offset = 0

// 那么:
p_flash + 0 → 指向地址 0x0800F000-0x0800F001 (2字节)
p_flash + 1 → 指向地址 0x0800F002-0x0800F003 (2字节)
p_flash + 2 → 指向地址 0x0800F004-0x0800F005 (2字节)

// 访问数据:
uint16_t data1 = p_flash[0];    // 读取 0x0800F000-0x0800F001
uint16_t data2 = p_flash[1];    // 读取 0x0800F002-0x0800F003

4. 实际使用示例

c

// 错误使用示例(常见错误)
void incorrect_usage(void) {
    volatile uint16_t *p_flash = (volatile uint16_t *)USER_SYSTEM_DATA_ADDR;
    
    // 错误:以为可以按字节递增
    for(int i = 0; i < 10; i++) {
        uint16_t data = p_flash[i];  // 实际是每2字节取一次
        // 这不是按字节读取!
    }
}

// 正确使用示例:按半字读取
void read_halfwords(void) {
    volatile uint16_t *p_flash = (volatile uint16_t *)USER_SYSTEM_DATA_ADDR;
    
    // 读取5个半字(10字节)
    uint16_t buffer[5];
    for(int i = 0; i < 5; i++) {
        buffer[i] = p_flash[i];  // 每次读取2字节
    }
}

// 正确使用示例:按字节读取(使用字节指针)
void read_bytes(void) {
    volatile uint8_t *p_byte = (volatile uint8_t *)USER_SYSTEM_DATA_ADDR;
    
    // 读取10个字节
    uint8_t buffer[10];
    for(int i = 0; i < 10; i++) {
        buffer[i] = p_byte[i];  // 每次读取1字节
    }
}

5. 与Flash编程函数结合

c

// 示例:将字节数组转换为半字数组进行Flash编程
flash_status_type write_with_halfword_ptr(uint32_t offset, uint8_t *data, uint32_t size) {
    // 检查size是否为偶数(半字对齐)
    if(size % 2 != 0) {
        return FLASH_ALIGN_ERROR;
    }
    
    volatile uint16_t *p_flash = (volatile uint16_t *)(USER_SYSTEM_DATA_ADDR + offset);
    uint16_t *p_data = (uint16_t *)data;  // 将字节指针转换为半字指针
    
    flash_unlock();
    
    // 按半字数量编程
    uint32_t halfword_count = size / 2;
    for(uint32_t i = 0; i < halfword_count; i++) {
        status = flash_halfword_program(
            (uint32_t)&p_flash[i],  // 注意:这里是计算地址
            p_data[i]
        );
        
        if(status != FLASH_OPERATE_DONE) {
            flash_lock();
            return status;
        }
        
        while(flash_flag_get(FLASH_BUSY_FLAG) == SET);
    }
    
    flash_lock();
    return FLASH_OPERATE_DONE;
}

6. 重要提醒:地址计算

c

// 正确获取绝对地址的方式
uint32_t get_actual_address(uint32_t offset) {
    // 方法1:直接计算
    uint32_t byte_addr = USER_SYSTEM_DATA_ADDR + offset;
    
    // 方法2:通过指针转换(不推荐用于计算)
    volatile uint16_t *p = (volatile uint16_t *)(USER_SYSTEM_DATA_ADDR);
    uint32_t addr_from_ptr = (uint32_t)(p + offset);  // 错误!这是加 offset*2
    
    // 正确:如果要使用指针运算
    uint32_t addr_correct = (uint32_t)(p + (offset / 2));  // 需要除以2
    
    return byte_addr;  // 使用方法1最简单
}

7. 实际应用建议

c

// 建议:使用明确的函数进行不同精度的访问
uint8_t flash_read_byte(uint32_t offset) {
    volatile uint8_t *p = (volatile uint8_t *)(USER_SYSTEM_DATA_ADDR);
    return p[offset];
}

uint16_t flash_read_halfword(uint32_t offset) {
    // 确保offset是2的倍数
    if(offset % 2 != 0) {
        return 0xFFFF;  // 错误值
    }
    
    volatile uint16_t *p = (volatile uint16_t *)(USER_SYSTEM_DATA_ADDR);
    uint32_t halfword_index = offset / 2;
    return p[halfword_index];
}

uint32_t flash_read_word(uint32_t offset) {
    // 确保offset是4的倍数
    if(offset % 4 != 0) {
        return 0xFFFFFFFF;  // 错误值
    }
    
    volatile uint32_t *p = (volatile uint32_t *)(USER_SYSTEM_DATA_ADDR);
    uint32_t word_index = offset / 4;
    return p[word_index];
}

总结回答您的直接问题:

是的,对于 volatile uint16_t *p_flashp_flash + 1 会使地址增加2字节,而不是1字节。

这是因为:

  1. C语言的指针运算会自动考虑类型大小

  2. uint16_t 类型占用2字节

  3. 指针加1实际上是指向下一个同类型元素,而不是下一个字节

如果您需要按字节递增访问,应该使用 uint8_t * 类型的指针

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐