实现对一个数据(int)指定位置0或置1

本文详细介绍了C++中位操作符的使用方法及应用案例,包括位设置、位清零、位翻转等常见操作,通过实例帮助读者理解并掌握C++位运算的基本技巧。

   


/**********************************************************************  
 * RightMove.cpp   
 * Compiler: GCC,VS,VC6.0  win32  
 * Author:WK 
 * Time: 2015 3 29
 ************************************************************************/  
#include<stdio.h>
void bit_set(unsigned int *p_data, 
			 unsigned int position, bool flag)
{
	if(flag)
	{
		*p_data |= (0x01<<(position-1));
	} 
	else
	{
		int c=(0x01<<(position-1));
		*p_data &= ~c;
	
	}		
}
void main()
{
	              
	//unsigned int ch = 'A';
	unsigned int ch=3;
	bit_set(&ch,3,false);
	//	bit_set(&ch,1,true);
    printf("%d\n",ch);
}


<think>我们使用STM32F407ZGT6的内部FLASH存储一个32位整int32_tuint32_t)。由于FLASH写入前需要先擦除(擦除单位为扇区),且写入以64位(双字)为单位,因此我们需要将32位整转换为64位格式进行存储,者存储两个32位整(占用一个64位空间)。以下为具体步骤: ### 、存储32位整的步骤 1. **选择存储位置** 使用扇区11(最后一个扇区)的末尾部分(避免与程序冲突): ```c #define FLASH_USER_START_ADDR 0x080E0000 // Sector 11起始地址 (128KB) #define FLASH_USER_END_ADDR 0x080FFFFF // Sector 11结束地址 #define DATA_ADDRESS 0x080FF000 // 示例地址(扇区内偏移) ``` 2. **擦除FLASH扇区**(仅需在首次写入需要重新写入时执行) 使用HAL库的FLASH擦除函: ```c #include "stm32f4xx_hal.h" HAL_StatusTypeDef Flash_EraseSector(uint32_t sector) { HAL_FLASH_Unlock(); // 解锁FLASH FLASH_EraseInitTypeDef eraseConfig = { .TypeErase = FLASH_TYPEERASE_SECTORS, .Sector = sector, // 选择扇区11(STM32F407中扇区11对应地址0x080E0000-0x080FFFFF) .NbSectors = 1, // 擦除1个扇区 .VoltageRange = FLASH_VOLTAGE_RANGE_3 // 电压范围3.3V }; uint32_t sectorError; HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&eraseConfig, &sectorError); HAL_FLASH_Lock(); // 重新上锁 return status; } ``` 3. **写入32位整** 由于HAL库要求64位写入,我们将32位整扩展为64位(高位补0): ```c HAL_StatusTypeDef Flash_WriteU32(uint32_t address, uint32_t data) { // 将32位数据转换为64位(高位补0) uint64_t data64 = (uint64_t)data; HAL_FLASH_Unlock(); // 使用双字写入模式 HAL_StatusTypeDef status = HAL_FLASH_Program( FLASH_TYPEPROGRAM_DOUBLEWORD, address, data64 ); HAL_FLASH_Lock(); return status; } ``` 4. **读取32位整** 直接读取指定地址的32位数据: ```c uint32_t Flash_ReadU32(uint32_t address) { // 注意:实际存储的是64位,但我们只取低32位 uint64_t data64 = *(__IO uint64_t*)address; return (uint32_t)(data64 & 0xFFFFFFFF); } ``` ### 二、完整示例代码 ```c // 步骤1:定义地址(确保64位对齐) #define FLASH_SECTOR_11 11 #define FLASH_USER_ADDR 0x080FF000 // 扇区11内的地址(需满足 address % 8 == 0) // 步骤2:擦除扇区(初始化时执行次) void Init_FlashStorage(void) { // 检查是否已写入过数据(可选) if (Flash_ReadU32(FLASH_USER_ADDR) == 0xFFFFFFFF) { Flash_EraseSector(FLASH_SECTOR_11); } } // 步骤3:保存和读取数据 void Save_Value(uint32_t value) { Flash_WriteU32(FLASH_USER_ADDR, value); } uint32_t Load_Value(void) { return Flash_ReadU32(FLASH_USER_ADDR); } // 主函测试 int main(void) { HAL_Init(); SystemClock_Config(); Init_FlashStorage(); // 初始化FLASH(必要时擦除) uint32_t testValue = 0x12345678; Save_Value(testValue); // 保存数据 uint32_t readValue = Load_Value(); // 读取数据 // 此时 readValue 应等于 testValue while(1); } ``` ### 三、关键注意事项 1. **地址对齐** 写入地址必须是8的倍(64位对齐),否则会导致硬件错误。 2. **擦除限制** 每次修改数据前需擦除整个扇区(128KB),因此建议: - 批量写入数据(例如存储组配) - 使用磨损均衡算法(记录写入位置索引) 3. **中断处理** FLASH操作期间应禁用中断: ```c __disable_irq(); Flash_WriteU32(FLASH_USER_ADDR, 0xABCD1234); __enable_irq(); ``` 4. **数据验证** 建议添加写入后读取验证: ```c HAL_StatusTypeDef Flash_WriteU32_WithVerify(uint32_t addr, uint32_t data) { Flash_WriteU32(addr, data); uint32_t read = Flash_ReadU32(addr); return (read == data) ? HAL_OK : HAL_ERROR; } ``` ### 四、替代方案(外接EEPROM) 对于需要频繁修改的单个整,建议使用外接EEPROM(如AT24C02): ```c // 通过I2C写入一个32位整 HAL_I2C_Mem_Write(&hi2c1, 0xA0, memAddr, I2C_MEMADD_SIZE_16BIT, (uint8_t*)&data, 4, 100); // 读取 HAL_I2C_Mem_Read(&hi2c1, 0xA0, memAddr, I2C_MEMADD_SIZE_16BIT, (uint8_t*)&data, 4, 100); ``` 优点:字节级擦写,无需整块擦除,寿命更长(100万次)[^3]。 > **总结**:内部FLASH适合存储不常修改的数据(如校准参),频繁修改的数据建议使用外EEPROMFRAM[^3][^4]。 §§相关问题§§ 1. 如何检测FLASH存储器的寿命状态? 2. STM32F4的备份寄存器(BKP)能否用于存储数据?有什么限制? 3. 使用内部FLASH存储数据时如何避免程序崩溃?</think>### 在STM32F407ZGT6中使用Flash存储32位整实现指南 #### 、核心步骤 1. **选择存储位置** STM32F407ZGT6的Flash分为12个扇区,推荐使用最后一个扇区(扇区11)存储数据: ```c #define FLASH_USER_START_ADDR 0x080E0000 // 扇区11起始地址 #define DATA_ADDRESS 0x080FF000 // 数据存储地址(扇区11内) ``` **注意**:地址必须8字节对齐(地址 % 8 == 0)[^5] 2. **擦除Flash扇区**(必须优先执行) ```c #include "stm32f4xx_hal.h" HAL_StatusTypeDef Flash_Erase(void) { HAL_FLASH_Unlock(); // 解锁Flash FLASH_EraseInitTypeDef eraseConfig = { .TypeErase = FLASH_TYPEERASE_SECTORS, .Sector = FLASH_SECTOR_11, // 选择扇区11 .NbSectors = 1, // 擦除1个扇区 .VoltageRange = FLASH_VOLTAGE_RANGE_3 }; uint32_t sectorError; HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&eraseConfig, &sectorError); HAL_FLASH_Lock(); // 重新上锁 return status; } ``` 3. **写入32位整** ```c HAL_StatusTypeDef Flash_WriteU32(uint32_t address, uint32_t data) { HAL_FLASH_Unlock(); // 将32位数据转换为64位格式(高位补0) uint64_t data64 = (uint64_t)data; HAL_StatusTypeDef status = HAL_FLASH_Program( FLASH_TYPEPROGRAM_DOUBLEWORD, // 64位写入模式 address, data64 ); HAL_FLASH_Lock(); return status; } ``` 4. **读取32位整** ```c uint32_t Flash_ReadU32(uint32_t address) { // 读取64位数据后取低32位 uint64_t data64 = *(__IO uint64_t*)address; return (uint32_t)(data64 & 0xFFFFFFFF); } ``` #### 二、完整使用示例 ```c // 存储数据 void Save_IntValue(void) { uint32_t myValue = 0x12345678; // 待存储的32位整 // 1. 擦除扇区(首次写入需要重新写入时) if(Flash_Erase() != HAL_OK) { // 错误处理 } // 2. 写入数据 if(Flash_WriteU32(DATA_ADDRESS, myValue) != HAL_OK) { // 错误处理 } } // 读取数据 void Load_IntValue(void) { uint32_t savedValue = Flash_ReadU32(DATA_ADDRESS); printf("读取的值: 0x%08X\n", savedValue); } ``` #### 三、关键注意事项 1. **擦除要求** Flash写入前**必须擦除**整个扇区(128KB),擦除后所有位变为`1`,写入只能将`1`改为`0`[^5]。 2. **中断处理** 在擦除/写入期间禁用中断: ```c __disable_irq(); // 开始操作前禁用中断 Flash_WriteU32(...); __enable_irq(); // 操作完成后启用中断 ``` 3. **写入限制** - 每次写入至少64位(8字节) - 同地址只能写入次(需擦除后才能再次写入) - 最大擦写次1万次[^3] 4. **数据保护** 添加CRC校验防止数据损坏: ```c // 写入时添加CRC uint32_t crc = HAL_CRC_Calculate(&hcrc, &myValue, 1); Flash_WriteU32(DATA_ADDRESS + 4, crc); // 读取时验证 uint32_t readCRC = Flash_ReadU32(DATA_ADDRESS + 4); if(HAL_CRC_Calculate(&hcrc, &savedValue, 1) != readCRC) { // 数据损坏处理 } ``` #### 四、替代方案对比 | **方法** | **优点** | **缺点** | **适用场景** | |----------|----------|----------|--------------| | **内部Flash** | 无需外设,成本 | 擦除单位大(128KB) | 不常修改的数据 | | **备份寄存器** | 无需擦除,字节写入 | 仅20字节容量 | 关键配数据[^4] | | **外接EEPROM** | 字节级擦写,寿命长 | 需I²C接口 | 频繁修改的小数据[^3] | > **推荐场景**: > - 存储设备序列号、校准参等不常修改的数据 → **内部Flash** > - 存储系统配、运行计器等常修改数据 → **外接EEPROM** > - 存储RTC备份数据 → **备份寄存器**[^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值