⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iap_sstmcu.c

📁 用SST89系列单片机存储超过64K的数据的一个例子,可节省外部的24C512,24C16,24C02等EEPROM,既省出了I/O的口,又增加了数据的保密性.
💻 C
字号:
/***********************************************************************************************************
* IAP_SSTMCU.c - SST89X564/554 SST89X516/58/54/52RD2的IAP在使用中编程的常用函数
*            弘微科技(SPAC)  田伯运    
*  	WEB: www.spacltd.com.cn 		TEL:0755-26010579   E-MAIL:andy.tian@spacltd.com.cn
* 功能介绍: 
*  SST的MCU内部FLASH的基本操作函数,包括扇区擦除,字节编程,字节校验等常用基本函数,
*   还有三个外部常用到的数据存储的函数(不用考虑具体FLASH的操作命令,注意要将IAP_SSMCU.C文件加入到你的项目中即可):
*		1. modify_single_byte_flash(ADDR,DATA)函数便可对指定的FLASH单元的内容进行改写;
*		2. modify_multi_byte_flash(begin_ADDR,counter,DATA_array)函数便可对指定起始地址的多个FLASH单元的内容进行改写;
*       3. Flash_byte_read(Address); 读FLASH地址单元内容的函数
*          从而很简单的实现数据存储等功能.
***********************************************************************************************************/

#include <SST89x5xxRD2.H>		//加入SST MCU单片机的头文件,这样就剩去了许多的特殊寄存器的声明
#include <stdio.h>
/***********************************************************************************************************
* 设置SST单片机的型号:是52-58,还是516/564?因其BLOCK1的地址是不同的
***********************************************************************************************************/
#define SST89X5XRD	0				//判断MCU的容量,SST89X5XRD=1:是52-58RD的,BLOCK1的地址:0E000H-0FFFFH
									//SST89X5XRD=0:是516/564RD的,BLOCK1的地址:01000H-01FFFH
#define DATAFLASH_BLOCK1	1		//DATAFLASH_BLOCK1=1:选择是DATA存放在BLOCK1存储区域
									//DATAFLASH_BLOCK1=0:选择是DATA存放在BLOCK0存储区域

/***********************************************************************************************************
* 定义 SST单片机的各种IAP命令
***********************************************************************************************************/
#define SFCM_SE 0x0B; /* 扇区擦除命令字(Sector-Erase)为0X0B */
#define SFCM_VB 0x0C; /* 字节校验命令字(Byte-Verify)为0X0C */
#define SFCM_PB 0x0E; /* 字节校验命令字(Byte-Program)为0X0E */

/***********************************************************************************************************
* Function Prototype,用到的函数声明
***********************************************************************************************************/
void Flash_sector_erase(unsigned short int dataAddr);	//扇区擦除函数,擦除的地址为dataAddr
void Flash_byte_program(unsigned short int dataAddr, unsigned char dataByte);//字节编程函数
bit modify_single_byte_flash(unsigned short int dataAddr,unsigned char dataByte);//修改一个FLASH地址单元的内容
bit modify_multi_byte_flash(unsigned int Begin_Addr, unsigned char counter, unsigned int array[]);//修改多个FLASH地址单元的内容
unsigned char Flash_byte_read(unsigned short int dataAddr); //字节校验函数
unsigned char ready();		//检查是否擦除或编程的操作是否已经完成
void error();		//超时错误
/**************************** SST单片机的IAP函数  **********************************************/

/***********************************************************************************************************
*  扇区擦除函数--Flash_sector_erase(unsigned short int dataAddr)
*  输入参数:     dataAddr---擦除的扇区地址
***********************************************************************************************************/
void Flash_sector_erase(unsigned short int dataAddr)
{
unsigned short int Dest_Addr = dataAddr;
	SFCF = SFCF | 0x40; // SFCF.6=1: IAP功能使能
	SFAH = Dest_Addr>>8; // 将扇区地址的高8位装入FLASH的高8位地址寄存器(SFAH)中
	SFAL = Dest_Addr; 	// 将扇区地址的低8位装入FLASH的低8位地址寄存器(SFAL)中
	SFCM = SFCM_SE; 	// 在FLASH的命令寄存器(SFCM)中填入扇区擦除命令--SFCM_SE=0X0B
	SFAL = Dest_Addr; 	// 将扇区地址的低8位装入FLASH的低8位地址寄存器(SFAL)中
	if(!ready())		// 等待擦除完毕
		error();		// 等待超时--错误
	SFCF = SFCF & ~0x40; // SFCF.6=0: IAP功能禁止
	return;
}
/***********************************************************************************************************
* 字节编程函数---Flash_byte_program()
* 输入参数:     dataAddr---编程的字节地址
* 输入参数:     dataByte---编程的数据
***********************************************************************************************************/
void Flash_byte_program(unsigned short int dataAddr, unsigned char dataByte)
{
unsigned short int Dest_Addr = dataAddr;
	SFCF = SFCF | 0x40; // SFCF.6=1: IAP功能使能
	SFAH = Dest_Addr>>8; // 将扇区地址的高8位装入FLASH的高8位地址寄存器(SFAH)中
	SFAL = Dest_Addr; 	// 将扇区地址的低8位装入FLASH的低8位地址寄存器(SFAL)中
	SFDT = dataByte; 	// 在FLASH的数据寄存器(SFDT)中填入编程的数据--dataByte
	SFCM = SFCM_PB; 	// 在FLASH的命令寄存器(SFCM)中填入字节编程命令--SFCM_PB=0X0E
	if(!ready())		// 等待编程完毕
		error();		// 等待超时--错误
	SFCF = SFCF & ~0x40; // SFCF.6=0: IAP功能禁止
	return;
}
/***********************************************************************************************************
* 字节校验读函数---Flash_byte_read()
* 输入参数:     dataAddr---校验读的字节地址
* 返回参数:		readByte---读出的单元数值
***********************************************************************************************************/
unsigned char Flash_byte_read(unsigned short int dataAddr)
{
unsigned short int Dest_Addr = dataAddr;
unsigned char readByte;
	SFCF = SFCF | 0x40; // SFCF.6=1: IAP功能使能
	SFAH = Dest_Addr>>8; // 将扇区地址的高8位装入FLASH的高8位地址寄存器(SFAH)中
	SFAL = Dest_Addr; 	// 将扇区地址的低8位装入FLASH的低8位地址寄存器(SFAL)中
	SFCM = SFCM_VB; 	// 在FLASH的命令寄存器(SFCM)中填入字节校验命令--SFCM_PB=0X0E
	readByte = SFDT;	// 取得读到的单元数据
	SFCF = SFCF & 0xBF; // SFCF.6=0: 关闭IAP功能
	SFDT = 0;	
	return readByte;	//返回读到的数据
}
/***********************************************************************************************************
* 检查IAP操作是否完成函数---ready()
* 输入参数:  	无
* 返回参数:  	1--IAP操作(FLASH擦除或字节编程)完成成功标志
*				0--IAP操作超时错误退出
***********************************************************************************************************/
unsigned char ready()
{
	unsigned int TimeOut = 0;
	
	while (TimeOut < 10000)			//要设的等待时间足够长,否则有些芯片的擦除时间可能不够,引起错误的编程信息.
		{
			if ((SFST&4) == 0) 		//SFST.2=0:IAP操作完成
			{ 
				SFCF = SFCF & 0xBF; //IAP操作完成,关闭IAP功能--SFCF.6=0 
				SFDT = 0; 			
				return 1; 			//返回成功标志--1
			}
			TimeOut++;
		}
		
	SFCF = SFCF & 0xBF; 			//时间超时,关闭IAP功能--SFCF.6=0
	SFDT = 0; 						/*any value other than 0x55*/
	return 0; 						//返回失败标志--0
}

/***********************************************************************************************************
* IAP操作失败指示函数,
***********************************************************************************************************/
void error()
{
	//ErrorCode=1; 	//置IAP失败标志--ErrorCode=1
	//LED_ERR=0;		//点亮错误灯,关闭成功灯,表示编程出错失败.
	//LED_OK=1;
	while(1) 		//程序停止
	{}
}
/***********************************************************************************************************
* 字节编程函数---modify_single_byte_flash()
* 输入参数:     dataAddr---编程的字节地址
* 输入参数:     dataByte---编程的数据
***********************************************************************************************************/
bit modify_single_byte_flash(unsigned  int dataAddr, unsigned char dataByte)
{
	unsigned  int xdata Flash_addr;	// = dataAddr+DATAFLASH_ADDR_START;	//将FLASH的DATA存储地址由原来的相对地址转换为具体芯片的FLASH绝对地址
	unsigned  int xdata Addr_Sector;	// = Dest_Addr & 0xff80;			//要修改数据所站的扇区的起始地址
	unsigned char xdata temp,counter=0x80;								//作为计数器,一个扇区
	unsigned  char xdata Sector_Buffer[0x80];					//定义内部扩展RAM的0x80个单元作为一个扇区数据的缓冲区

	#if SST89X5XRD 									//如果是SST89X52-58,BLOCK1在0XE000--0XFFFF区间
	    Flash_addr = dataAddr+0xe000;				//且当前的BOOT CODE处于BLOCK0,IAP编程的范围只能在BLOCK1的0xe000-0xffff范围内
	#else				 							//如果是SST89X516/564,BLOCK1在0X1000--0X1FFF区间
	    Flash_addr = dataAddr+0x0000;				//且当前的BOOT CODE处于BLOCK0,IAP编程的范围只能在BLOCK1的0x1000-0x1fff范围内
	#endif


	if(dataByte==(dataByte&(Flash_byte_read(Flash_addr))))		//如果要写的单元原来内容只需1->0的过程,而没有0->1的过程,
		{													//就不用擦除整个扇区,而只需使用字节编程命令即可,减少FLASH的擦写次数,延长FLASH的使用寿命
			Flash_byte_program(Flash_addr,dataByte);				
			if (dataByte==Flash_byte_read(Flash_addr)) return 1;	//读出的数据等于要写的数据,返回1
				else return 0;								//读出的数据不等于要写的数据,返回0
			}
	else 										//如果有0->1的过程,就必须进行扇区擦除,将整个扇区的内容,重新写一遍.

	temp = AUXR;								//暂存AUXR辅助寄存器.以便用完128个RAM的BUFFER后恢复.
	AUXR  = 0x00;								//使用SST89E516内部的768 RAM,EXRAM=0,
	Addr_Sector = Flash_addr & 0xff80;			//计算出要修改数据所站的扇区的起始地址
	counter=0x80;								//一个扇区有128个存储单元,
	for (counter=0;counter<0x80;counter++)		//读一个扇区(128个字节)的内容到扩展RAM缓冲区中
		{
			Sector_Buffer[counter]=Flash_byte_read(Addr_Sector);
			Addr_Sector++;
			}
	Sector_Buffer[Flash_addr&0x007f]=dataByte;		//在RAM缓冲区中写入新的修改后数据
	Addr_Sector=Flash_addr&0xff80;				//重新置要修改扇区的首地址
	Flash_sector_erase(Addr_Sector);					//将这个要修改单元所在的扇区进行全部擦除
	for (counter=0;counter<0x80;counter++)		//将修改后的扇区内容重新写回到这个扇区内
		{
			Flash_byte_program(Addr_Sector,Sector_Buffer[counter]);	//对扇区中的单元写入一个扇区更改后的内容
			Addr_Sector++;									//指向下一个地址单元
			}
	AUXR = temp;								//恢复为占用前的AUXR
	if (dataByte==Flash_byte_read(Flash_addr)) return 1;	//读出的数据等于要写的数据,返回1
	else return 0;									//读出的数据不等于要写的数据,返回0
}

/*-----------------------------------------------------------------------------------*/
/* 修改多个单元的Flash存储器内容, 只在同一个扇区内写,保留同一扇区中不需修改的数据	*/
/* Begin_Addr,被写数据Flash开始地址;counter,连续写多少个字节; array[],数据来源		*/
/*-----------------------------------------------------------------------------------*/
bit modify_multi_byte_flash(unsigned int Begin_Addr, unsigned char counter, unsigned int array[])
{
	unsigned  int xdata Dest_Addr,Flash_addr;	// = dataAddr+DATAFLASH_ADDR_START;	//将FLASH的DATA存储地址由原来的相对地址转换为具体芯片的FLASH绝对地址
	unsigned  int xdata Addr_Sector,Addr_Flash;	// = Dest_Addr & 0xff80;			//要修改数据所站的扇区的起始地址
	unsigned char xdata temp,i;//,counter=0x80;								//作为计数器,一个扇区
	unsigned  char xdata Sector_Buffer[0x80];					//定义内部扩展RAM的0x80个单元作为一个扇区数据的缓冲区

	#if SST89X5XRD 									//如果是SST89X52-58,BLOCK1在0XE000--0XFFFF区间
	    Flash_addr = Begin_Addr+0xe000;				//且当前的BOOT CODE处于BLOCK0,IAP编程的范围只能在BLOCK1的0xe000-0xffff范围内
	#else 											//如果是SST89X516/564,BLOCK1在0X1000--0X1FFF区间
	    Flash_addr = Begin_Addr+0x0000;				//且当前的BOOT CODE处于BLOCK0,IAP编程的范围只能在BLOCK1的0x1000-0x1fff范围内
	#endif


	if(counter > 0x80) return 0;				//只允许最大是一个扇区(0x80=128个字节)空间的数据修改
	if((Flash_addr&0x007f+counter) > 0x80) return 0;	//修改的起始地址+修改的个数也不能超过一个扇区(128字节)的数目

	temp = AUXR;								//暂存AUXR辅助寄存器.以便用完128个RAM的BUFFER后恢复.
	AUXR  = 0x00;								//使用SST89E516内部的768 RAM,EXRAM=0,
	Addr_Sector = Flash_addr & 0xff80;			//计算出要修改数据所站的扇区的起始地址

	//--------------第1步:读一个扇区(128个字节)的内容到扩展RAM缓冲区中--------------
	Addr_Flash=Flash_addr&0xff80;				//置FLASH编程的地址指针
	i=0x80;										//一个扇区有128个存储单元,
	for (i=0;i<0x80;i++)						//读一个扇区(128个字节)的内容到扩展RAM缓冲区中
		{
			Sector_Buffer[i]=Flash_byte_read(Addr_Flash);
			Addr_Flash++;
			}
	//--------------第2步:将要修改的内容写入扇区缓冲区内,共修改COUNTER个--------------
	Dest_Addr=Flash_addr&0x007f;				//转为一个扇区内的相对地址(只取低7位)	
	for (i=0;i<counter;i++)						//将要修改的内容写入扇区缓冲区内,共修改COUNTER个
		{
			Sector_Buffer[Dest_Addr]=array[i];	//将要修改的内容写入扇区缓冲区的对应地址
			Dest_Addr++;						//指向下一个缓冲地址
			}

	//-------------第3步:擦除要修改地址所在的扇区---------------------------------------
	Addr_Sector=Flash_addr&0xff80;				//重新置要修改扇区的首地址
	Flash_sector_erase(Addr_Sector);			//将这个要修改单元所在的扇区进行全部擦除

	//-------------第4步:将修改后的缓冲区内容重新写回到FLASH中--------------------------
	Addr_Flash=Flash_addr&0xff80;				//置FLASH编程的地址指针
	for (i=0;i<0x80;i++)		//将修改后的扇区内容重新写回到这个扇区内
		{
			Flash_byte_program(Addr_Flash,Sector_Buffer[i]);	//对扇区中的单元写入一个扇区更改后的内容
			if ((Flash_byte_read(Addr_Flash)) != Sector_Buffer[i]) //对刚写入的FLASH单元进行读出校验,
				return 0;									//如果不等于刚写入的内容,则错误返回
			Addr_Flash++;						//校验正确,指向下一个FLASH地址单元,继续FLASH编程
			}
	AUXR = temp;								//恢复为占用前的AUXR
	return 1;									//整个扇区128个字节全部编程成功,返回1
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -