IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> Flash保存GPS经纬度信息 -> 正文阅读

[嵌入式]Flash保存GPS经纬度信息

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 的二进制表达形式。

运行如下图:
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;
}

将采集到的数据写入并读出的效果如下:
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;//以浮点型返回
}

运行效果如下:
在这里插入图片描述

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-03-30 18:41:35  更:2022-03-30 18:44:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:46:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码