Flash保存GPS经纬度信息

Flash保存GPS经纬度信息

文章目录

  • Flash保存GPS经纬度信息
    • flash简介
    • 程序设计思路
    • 技术要点
      • 一、浮点数写入 FLASH
      • 二、FLASH 写入及读取
      • 三、将读取回来的值转化为浮点型经纬度


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保存GPS经纬度信息_第1张图片
虽然以整型读出和以浮点型读出的数值不同,但二者在内存空间中的二进制组合形式是相同的。
所以,不管是以无符号长整型变量读出,还是以浮点型变量读出,联合体的内存空间中保存的二进制组合都是不变的。所以我们只需把浮点型数据存入共用体中,之后再以无符号长整型将数据读出并交给转存数组保存,就成功绕过强制类型转换,可以直接写入 FLASH 了。

二、FLASH 写入及读取

FLASH 的存储特点在于,必须先将需要写入的扇区全部擦除才能写入数据,即使只想改变其中一个值,也得把整片扇区全部擦除,才能把新内容写入,所以每次更改数据记得先校验有无数据,并将需要的数据保存后再擦除并写入。这里可直接调用逐飞提供的 FLASH 操作函数实现擦除,写入及读取。注意写入的扇区尽量靠后,靠前的扇区可能保存着程序代码。

//-------------------------------------------------------------------------------------------------------------------
// @brief		校验FLASH是否有数据
// @param		sector_num		需要写入的扇区编号	参数范围 FLASH_SECTION_0-FLASH_SECTION_127
// @param		page_num		当前扇区页的编号	参数范围 FLASH_PAGE_0-FLASH_PAGE_3
// @return						返回1有数据 返回0没有数据 如果需要对有数据的区域写入新的数据则应该对所在扇区进行擦除操作
// @since		v1.0
// Sample usage:				flash_check(FLASH_SECTION_127,FLASH_PAGE_3);
//-------------------------------------------------------------------------------------------------------------------
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));		// 提取当前 Flash 地址

	for(temp_loop = 0; temp_loop < FLASH_PAGE_SIZE; temp_loop+=4)										// 循环读取 Flash 的值
	{
		if( (*(__IO u32*) (flash_addr+temp_loop)) != 0xffffffff )										// 如果不是 0xffffffff 那就是有值
			return 1;
	}
	return 0;
}

//-------------------------------------------------------------------------------------------------------------------
// @brief		擦除扇区
// @param		sector_num		需要写入的扇区编号	参数范围 FLASH_SECTION_0-FLASH_SECTION_127
// @param		page_num		当前扇区页的编号	参数范围 FLASH_PAGE_0-FLASH_PAGE_3
// @return						返回1有表示失败		返回0表示成功
// @since		v1.0
// Sample usage:				flash_erase_page(FLASH_SECTION_127, FLASH_PAGE_3);
//-------------------------------------------------------------------------------------------------------------------
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 地址

	FLASH_Unlock();																						// 解锁 Flash
	FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);							// 清除操作标志
	gFlashStatus = FLASH_ErasePage(flash_addr);															// 擦除
	FLASH_ClearFlag(FLASH_FLAG_EOP );																	// 清楚操作标志
	FLASH_Lock();																						// 锁定 Flash
	if(gFlashStatus != FLASH_COMPLETE)																	// 判断操作是否成功
		return 1;
	return 0;
}

//-------------------------------------------------------------------------------------------------------------------
// @brief		读取一页
// @param		sector_num		需要读取的扇区编号   参数范围 FLASH_SECTION_0-FLASH_SECTION_127
// @param		page_num		当前扇区页的编号     参数范围 FLASH_PAGE_0-FLASH_PAGE_3
// @param		buf				需要读取的数据地址   传入的数组类型必须为uint32
// @param		len				需要写入的数据长度   参数范围 1-256
// @return						返回1有表示失败  返回0表示成功
// @since		v1.0
// Sample usage:				flash_page_read(FLASH_SECTION_127, FLASH_PAGE_3, data_buffer, 256);
//-------------------------------------------------------------------------------------------------------------------
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));		// 提取当前 Flash 地址

	for(temp_loop = 0; temp_loop < len; temp_loop++)													// 根据指定长度读取
	{
		*buf++ = *(__IO u32*)(flash_addr+temp_loop*4);													// 循环读取 Flash 的值
	}
}

//-------------------------------------------------------------------------------------------------------------------
// @brief		编程一页
// @param		sector_num		需要写入的扇区编号   参数范围 FLASH_SECTION_0-FLASH_SECTION_127
// @param		page_num		当前扇区页的编号     参数范围 FLASH_PAGE_0-FLASH_PAGE_3
// @param		buf				需要写入的数据地址   传入的数组类型必须为uint32
// @param		len				需要写入的数据长度   参数范围 1-256
// @return						返回1有表示失败  返回0表示成功
// @since		v1.0
// Sample usage:				flash_page_program(FLASH_SECTION_127, FLASH_PAGE_3, data_buffer, 256);
//-------------------------------------------------------------------------------------------------------------------
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));		// 提取当前 Flash 地址

	if(flash_check(sector_num, page_num))																// 判断是否有数据 这里是冗余的保护 防止有人没擦除就写入
		flash_erase_page(sector_num, page_num);															// 擦除这一页

	FLASH_Unlock();																						// 解锁 Flash
	while(len--)																						// 根据长度
	{
		gFlashStatus = FLASH_ProgramWord(flash_addr, *buf++);											// 按字 32bit 写入数据
		if(gFlashStatus != FLASH_COMPLETE)																// 反复确认操作是否成功
			return 1;
		flash_addr += 4;																				// 地址自增
	}
	FLASH_Lock();																						// 锁定 Flash
	return 0;
}

将采集到的数据写入并读出的效果如下:
Flash保存GPS经纬度信息_第2张图片
其中每行前四位为经度, 后四位为维度信息, 一行就是一个坐标点,由此可得一个扇区每页最多可写入128个坐标点信息,容量足够。

三、将读取回来的值转化为浮点型经纬度

这一步比较简单,只需要仿照浮点型转换整型的步骤即可。

float ex_int2float(unsigned long value)       //长整型转换为浮点型
{
//	定义共用体
	union{
		float float_value;
		unsigned long int_value;
	}c;
//	存储数据转换
	c.int_value = value;//以长整型存入共用体
	return c.float_value;//以浮点型返回
}

运行效果如下:
Flash保存GPS经纬度信息_第3张图片

你可能感兴趣的:(智能车调试日记,单片机,arm)