Flash保存GPS经纬度信息
flash简介
快闪存储器(英语:flash memory),是一种电子式可清除程序化只读存储器的形式,允许在操作中被多次擦或写的存储器。这种科技主要用于一般性资料存储,以及在电脑与其他数字产品间交换传输资料,如储存卡与U盘。闪存是一种特殊的、以宏块抹写的 EEPROM 。单片机的代码都存储在内部 flash ,mm32f3277 属于中容量产品, 其flash被划分为128个扇区,每个扇区四页,每页 1K 字节,共 512K Flash, 完全可以用于存储 GPS 坐标点信息。
程序设计思路
- 连续采集 GPS 信息
- 利用按键将需要的 GPS 坐标点存入转存数组
- 将数组写入 FLASH
- 读取 FLASH 中的坐标点信息用于导航
技术要点
一、浮点数写入 FLASH
GPS 信息中的经纬度坐标进行度分秒格式转换后为浮点型数据,而官方提供的 FLASH 写入函数传参是三十二位无符号整型数据,所以坐标经纬度无法直接写入 FLASH 中,因此参照网络上大多数算法后决定使用 c 语言中的共用体进行数据类型变换,具体实现过程如下。
unsigned long ex_float2int(float value)
{
union{
float float_value;
unsigned long int_value;
}c;
c.float_value = value;
return c.int_value;
}
共用体是一种特殊的数据类型,有时也被称为联合或者联合体,共用体允许在相同的内存位置存储不同的数据类型。用户可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同的内存位置的有效方式。 简单点讲也就是共用体的所有成员占用一个内存,修改一个成员会影响其余所有成员,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉,其内存大小取决于最长的成员占用的内存,如上述程序的联合体占用大小为四个字节( 32 bits ) 当我们将函数的传入参数 value 赋值给联合体中的成员变量 float_value 时,相当于是向联合体所占的内存空间中写入了 value 的二进制表达形式。
运行如下图: 虽然以整型读出和以浮点型读出的数值不同,但二者在内存空间中的二进制组合形式是相同的。 所以,不管是以无符号长整型变量读出,还是以浮点型变量读出,联合体的内存空间中保存的二进制组合都是不变的。所以我们只需把浮点型数据存入共用体中,之后再以无符号长整型将数据读出并交给转存数组保存,就成功绕过强制类型转换,可以直接写入 FLASH 了。
二、FLASH 写入及读取
FLASH 的存储特点在于,必须先将需要写入的扇区全部擦除才能写入数据,即使只想改变其中一个值,也得把整片扇区全部擦除,才能把新内容写入,所以每次更改数据记得先校验有无数据,并将需要的数据保存后再擦除并写入。这里可直接调用逐飞提供的 FLASH 操作函数实现擦除,写入及读取。注意写入的扇区尽量靠后,靠前的扇区可能保存着程序代码。
uint8 flash_check (FLASH_SECTION_enum sector_num, FLASH_PAGE_enum page_num)
{
uint16 temp_loop;
uint32 flash_addr = ((FLASH_BASE_ADDR+FLASH_SECTION_SIZE*sector_num+FLASH_PAGE_SIZE*page_num));
for(temp_loop = 0; temp_loop < FLASH_PAGE_SIZE; temp_loop+=4)
{
if( (*(__IO u32*) (flash_addr+temp_loop)) != 0xffffffff )
return 1;
}
return 0;
}
uint8 flash_erase_page (FLASH_SECTION_enum sector_num, FLASH_PAGE_enum page_num)
{
static volatile FLASH_Status gFlashStatus = FLASH_COMPLETE;
uint32 flash_addr = ((FLASH_BASE_ADDR+FLASH_SECTION_SIZE*sector_num+FLASH_PAGE_SIZE*page_num));
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
gFlashStatus = FLASH_ErasePage(flash_addr);
FLASH_ClearFlag(FLASH_FLAG_EOP );
FLASH_Lock();
if(gFlashStatus != FLASH_COMPLETE)
return 1;
return 0;
}
void flash_page_read (FLASH_SECTION_enum sector_num, FLASH_PAGE_enum page_num, uint32 *buf, uint16 len)
{
uint16 temp_loop;
uint32 flash_addr = ((FLASH_BASE_ADDR+FLASH_SECTION_SIZE*sector_num+FLASH_PAGE_SIZE*page_num));
for(temp_loop = 0; temp_loop < len; temp_loop++)
{
*buf++ = *(__IO u32*)(flash_addr+temp_loop*4);
}
}
uint8 flash_page_program (FLASH_SECTION_enum sector_num, FLASH_PAGE_enum page_num, const uint32 *buf, uint16 len)
{
static volatile FLASH_Status gFlashStatus = FLASH_COMPLETE;
uint32 flash_addr = ((FLASH_BASE_ADDR+FLASH_SECTION_SIZE*sector_num+FLASH_PAGE_SIZE*page_num));
if(flash_check(sector_num, page_num))
flash_erase_page(sector_num, page_num);
FLASH_Unlock();
while(len--)
{
gFlashStatus = FLASH_ProgramWord(flash_addr, *buf++);
if(gFlashStatus != FLASH_COMPLETE)
return 1;
flash_addr += 4;
}
FLASH_Lock();
return 0;
}
将采集到的数据写入并读出的效果如下: 其中每行前四位为经度, 后四位为维度信息, 一行就是一个坐标点,由此可得一个扇区每页最多可写入128个坐标点信息,容量足够。
三、将读取回来的值转化为浮点型经纬度
这一步比较简单,只需要仿照浮点型转换整型的步骤即可。
float ex_int2float(unsigned long value)
{
union{
float float_value;
unsigned long int_value;
}c;
c.int_value = value;
return c.float_value;
}
运行效果如下:
|