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 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 外设驱动库开发笔记40:AT25xxx外部存储器驱动 -> 正文阅读

[嵌入式]外设驱动库开发笔记40:AT25xxx外部存储器驱动

??我们在前面开发过AT24CXX系列EEPROM存储器,它使用的是I2C接口。不过有时候我们也会使用SPI接口的EEPROM存储器。在这一篇我们将来讨论AT25XXX系列EEPROM存储器的驱动设计、实现及使用。

1、功能概述

??AT25XXX系列EEPROM存储器采用SPI接口,因其操作简单且性价比高,常用于数据保存。出于开发面向AT25XXX系列EEPROM存储器操作的驱动目标,我们先来了解一下AT25XXX系列EEPROM存储器的基本情况。

1.1、硬件描述

??AT25XXX系列EEPROM存储器拥有从1K到2M的多种容量。AT25XXX系列EEPROM存储器采用SPI通讯接口。尽管容量跨度很大,但都采用相同的封装形式。具体的引脚排布及定义如下:

??为了更好地理解AT25XXX系列EEPROM存储器的操作过程,我们对CS、WP以及HOLD引脚做一个简单说明。
??首先来看一看CS引脚,CS为芯片选择引脚,低电平有效,AT25XXX系列EEPROM存储器被选中。当设备未被选中时,串行数据输入(SI)引脚将不接受数据,串行输出(SO)引脚将保持高阻抗状态。为了确保稳定的操作,CS引脚应在电源启动时跟随VCC。因此建议使用小于或等于10 kΩ的上拉电阻器连接到VCC。在电源启动后,要实现对AT25XXX系列EEPROM存储器的任何操作,都需要先将CS下拉到低电平。
??接下来我们看一看WP引脚,WP引脚为AT25XXX系列EEPROM存储器的写保护引脚。当写保护(WP)引脚保持高电位时,AT25XXX系列EEPROM存储器允许正常的读/写操作。当写保护(WP)引脚为低电平时,WPEN位设置为逻辑“1”时,所有对状态寄存器的写操作都被禁止。但如果内部写周期已经启动,那么写保护(WP)引脚变为低电平对状态寄存器的任何写操作都没有影响。当状态寄存器中的WPEN位设置为逻辑“0”时,写保护(WP)引脚的功能被屏蔽。
??最后我们来看一看HOLD引脚,暂停串行输入(HOLD)引脚低电平有效。暂停串行输入(HOLD)引脚与芯片选择(CS)引脚一起使用来暂停AT25XXX系列EEPROM存储器。当设备被选中,一个串行序列正在进行中,HOLD可以用来暂停与主设备的串行通信,而不需要重新设置串行序列。此时,串行数据输入(SI)引脚的输入将被忽略,而串行数据输出(SO)引脚将处于高阻抗状态。

1.2、通讯接口

??AT25XXX系列EEPROM存储器采用SPI通讯接口。AT25XXX系列EEPROM存储器由主机控制器(通常称为SPI主机)发送的一组指令控制。与AT25XXX系列EEPROM存储器的通信必须由SPI主设备(如微控制器)发起。SPI主设备必须在串行数据时钟(SCK)引脚上为AT25XXX系列EEPROM存储器生成串行时钟。AT25XXX系列EEPROM存储器总是作为一个从属操作,因为SCK总是一个输入。主机与AT25XXX系列EEPROM存储器通讯的拓扑图如下所示:

??SPI主机通过SPI总线与AT25XXX系列EEPROM存储器通信,SPI总线由四条信号线组成:芯片选择(CS)、串行数据时钟(SCK)、串行数据输入(SI)和串行数据输出(SO)。SPI协议定义了总共四种操作模式(模式0、模式1、模式2或模式3),每种模式在SCK极性和相位以及极性和相位如何控制SPI总线上的数据流方面有所不同。AT25XXX系列EEPROM存储器支持两种最常见的模式,SPI模式0和3。

1.3、命令操作

??AT25XXX系列EEPROM存储器被设计成直接与同步串行外围接口(SPI)接口。AT25XXX系列EEPROM存储器使用一个8位指令寄存器。所有的指令、地址和数据首先由高位开始传送,然后由高到低依次进行。指令列表及其操作代码如下:

??从上表我们知道,除了操作存储区域外,还可以操作状态寄存器。AT25XXX系列EEPROM存储器包括一个8位状态寄存器。状态寄存器位调节设备的各种特性。这些位可以通过指令进行更改。具体的结构如下:

??状态寄存器除了反应当前的状态外,实际上有些位还有配置功能。关于致谢为的属性及具体含义如下:

??通过写状态寄存器(WRSR)指令可以配置写保护使能和写保护的区域。块写保护位(BP1、BP0)决定了存储阵列的写保护区域。两位决定了阵列保护的四个级别,分别是:没有一个内存阵列被保护;上四分之一地址范围内存阵列被保护;上半部分地址范围内存阵列被保护;所有的内存阵列都是写保护的,这意味着所有的地址位都是只读的。块写保护级别和相应的状态寄存器控制位关系如下:

??而写保护使能 (WPEN)位用于启用或禁用写保护 (WP) 引脚。当WPEN位设置为逻辑“0”时,写入EEPROM数组的能力取决于块写保护(BP1、BP0)位的值。写入状态寄存器的权限是由WEL位控制的。当WPEN位设置为逻辑“1”时,状态寄存器是只读的。当WP引脚低且WPEN位设置为逻辑“1”时,硬件写保护就启用了。当设备被硬件写保护时,对状态寄存器的写操作,包括块写保护、WEL和WPEN位,以及对块写保护位所选择的内存阵列中的段的写操作被禁用。当启用硬件写保护时,只允许对未受块保护的内存段进行写。当WP引脚为高电平或WPEN位逻辑为“0”时,硬件写保护被禁用。当硬件写保护被禁用时,只允许对未被块保护的内存段进行写。当WPEN位被硬件写保护时,只要WP引脚保持低,它就不能被设置回逻辑“0”。写保护的关系如下所示:

??AT25XXX系列EEPROM存储器拥有从1K到2M的不同容量,寻址范围的不同所需的地址位数也不相同。地址位数根据容量从7位到18位不等,分别对应1到3个字节。具体的容量与地址位关系如下:

??需要注意的是,4K(512x8)容量的AT25XXX系列EEPROM存储器需要9为地址,但在实际操作时只用了1个字节来装载地址,最高位(第9位)地址借用了操作码的第4位来传送。

2、驱动设计与实现

??我们已经了解了AT25XXX存储器的基本功能及读写方式,接下来我们将开发操作AT25XXX系列EEPROM存储器的驱动程序。

2.1、对象定义

??在使用一个对象之前我们需要获得一个对象。同样的我们想要AT25XXX系列EEPROM存储器就需要先定义AT25XXX系列EEPROM存储器的对象。

2.1.1、对象的抽象

??我们要得到AT25XXX系列EEPROM存储器对象,需要先分析其基本特性。一般来说,一个对象至少包含两方面的特性:属性与操作。接下来我们就来从这两个方面思考一下AT25XXX系列EEPROM存储器的对象。
??先来考虑属性,作为属性肯定是用于标识或记录对象特征的东西。我们来考虑AT25XXX系列EEPROM存储器对象属性。首先AT25XXX系列EEPROM存储器有多种型号,不同型号在容量、地址位数等方面都有较大差异。为了区别不同类型的AT25XXX系列EEPROM存储器,我们将类型作为对象的属性。另外每一个AT25XXX对象都有一个状态寄存器,它标识了AT25XXX对象的当前状态,所以我们也将它作为对象的属性。
??接着我们还需要考虑AT25XXX系列EEPROM存储器对象的操作问题。我们总是要对AT25XXX对象进行数据读写,但读写操作使用SPI接口依赖于具体的硬件平台,所以我们将数据读写作为对象的操作。片选信号、写保护以及hold信号均依赖于具体的硬件定义来实现,所以我们将其作为对象的操作。还有用于时序控制的延时,其也要根据具体的软硬件平台来实现,所以我们也将其定义为对象的操作。
??根据上述我们对AT25XXX系列EEPROM存储器的分析,我们可以定义AT25XXX系列EEPROM存储器的对象类型如下:

/*定义AT25XXX对象类型*/
typedef struct At25Object {
	uint8_t status;				//状态寄存器
	At25ModeType mode;		//设备类型
	void (*Read)(uint8_t *rData,uint16_t rSize);       //读数据操作指针
	void (*Write)(uint8_t *wData,uint16_t wSize);    //写数据操作指针
	void (*Delayms)(volatile uint32_t nTime);       //毫秒延时操作指针
	void (*ChipSelect)(AT25xxxCSType cs);	//使用SPI接口时,片选操作
	void (*WP)(AT25WPType wp);						//写保护操作
	void (*Hold)(AT25HoldType hold);			//保持信号
}At25ObjectType;

2.1.2、对象初始化

??我们知道,一个对象仅作声明是不能使用的,我们需要先对其进行初始化,所以这里我们来考虑AT25XXX系列EEPROM存储器对象的初始化函数。一般来说,初始化函数需要处理几个方面的问题。一是检查输入参数是否合理;二是为对象的属性赋初值;三是对对象作必要的初始化配置。据此我们设计AT25XXX系列EEPROM存储器对象的初始化函数如下:

/* 初始化AT25XXX对象 */
void At25xxxInitialization(At25ObjectType *at,	//AT25XXX对象实体
					At25ModeType mode,		//AT25XXX对象类型
					AT25Read read,				//读AT25XXX对象操作指针
					AT25Write write,			//写AT25XXX对象操作指针
					AT25Delayms delayms,		//延时操作指针
					AT25ChipSelect cs			//片选操作函数指针
				)
{
	if((at==NULL)||(read==NULL)||(write==NULL)||(delayms==NULL))
	{
		return;
	}
	at->Read=read;
	at->Write=write;
	at->Delayms=delayms;
	
	if(cs!=NULL)
	{
		at->ChipSelect=cs;
	}
	else
	{
		at->ChipSelect=AT25ChipSelectDefault;
	}

	if(mode>=AT25Number)
	{
		return;
	}
	at->mode=mode;
	
	if(mode<AT25080B)
	{
		at->memAddLength=AT258BitMemAdd;
	}
	else if(mode<AT25M01)
	{
		at->memAddLength=AT2516BitMemAdd;
	}
	else
	{
		at->memAddLength=AT2524BitMemAdd;
	}
	
	ReadStatusForAT25xxx(at);
	
	//写允许
	SetWriteEnableLatchForAT25xxx(at);
	
	uint8_t cmd;
	//使能写保护,保护全部区域
	cmd=at->status|AT25_WPEN|AT25_BPALL;
	WriteStatusForAT25xx(at,cmd);
	
	ReadStatusForAT25xxx(at);
}

2.2、对象操作

??我们已经完成了AT25XXX系列EEPROM存储器对象类型的定义和对象初始化函数的设计。但我们的主要目标是获取对象的信息,接下来我们还要实现面向AT25XXX系列EEPROM存储器的各类操作。

2.2.1、读数据操作

??读取AT25XXX系列EEPROM存储器需要先将CS线拉低以选择设备,尔后发送READ(0x03)指令,在后发送要读的寄存器地址。一旦接收完寄存器地址,后续的信号将被忽略。然后返回指定地址的数据。读AT25XXX系列EEPROM存储器数据的操作时序如下:

??根据上述时序图,我们可以编写读AT25XXX系列EEPROM存储器数据的程序如下:

/*从AT25xxx读取数据*/
void ReadDatasFromAT25xxx(At25ObjectType *at,uint32_t regAddress,uint8_t *rData,uint16_t rSize)
{
  uint8_t data[4];
	uint16_t index=0;
	uint8_t temp;
	uint16_t size=0;
	
	data[index++]=AT25_READ;
	
	if(at->memAddLength==AT258BitMemAdd)
	{
		data[index++]=(uint8_t)regAddress;
		
		if(at->mode==AT25040B)
		{
			temp=(uint8_t)(regAddress>>8);
			data[0]|=((temp&0x01)<<3);
		}
	}
	else if(at->memAddLength==AT2516BitMemAdd)
	{
		data[index++]=(uint8_t)(regAddress>>8);
		data[index++]=(uint8_t)regAddress;
	}
	else
	{
		data[index++]=(uint8_t)(regAddress>>16);
		data[index++]=(uint8_t)(regAddress>>8);
		data[index++]=(uint8_t)regAddress;
	}

	temp=(uint8_t)(regAddress&regAddMask[at->mode]);
	if((rSize<=pageBytes[at->mode])&&(rSize<=(pageBytes[at->mode]-temp)))
	{
		size=rSize;
	}
	else
	{
		size=pageBytes[at->mode]-temp;
	}
	
	at->ChipSelect(AT25CS_Enable);
	at->Write(data,index);
	at->Delayms(1);
	at->Read(rData,size);
	at->ChipSelect(AT25CS_Disable);
}

??如果只需要读取一个字节,那么在读取一个字节后CS信号需在读取后恢复高电平。如果想读取多个字节,那么CS信号必须持续低电平,在存储器内部字节地址将自动递增,数据将继续移位。当到达最高地址时,地址计数器将滚动到最低阶地址,从而允许在一个连续的读取循环中读取整个内存,而不管起始地址是什么。

2.2.2、写数据操作

??写AT25XXX系列EEPROM存储器,必须执行两条单独的指令。首先,必须通过写使能(WREN)指令使设备能够写。然后,可以执行写序列。如果设备没有启用写(WREN),设备将忽略写指令。在内部写周期中,除了RDSR指令外,所有命令都将被忽略。写AT25XXX系列EEPROM存储器的时序如下:

??根据上述时序图,我们可以编写写AT25XXX系列EEPROM存储器数据的程序如下:

/*向AT25xxx写入数据*/
void WriteDatasToAT25xxx(At25ObjectType *at,uint16_t regAddress,uint8_t *wData,uint16_t wSize)
{
  uint8_t data[wSize+4];
	uint16_t index=0;
	uint8_t temp;
	uint16_t size=0;
	
	data[index++]=AT25_WRITE;
	
	if(at->memAddLength==AT258BitMemAdd)
	{
		data[index++]=(uint8_t)regAddress;
		
		if(at->mode==AT25040B)
		{
			temp=(uint8_t)(regAddress>>8);
			data[0]|=((temp&0x01)<<3);
		}
	}
	else if(at->memAddLength==AT2516BitMemAdd)
	{
		data[index++]=(uint8_t)(regAddress>>8);
		data[index++]=(uint8_t)regAddress;
	}
	else
	{
		data[index++]=(uint8_t)(regAddress>>16);
		data[index++]=(uint8_t)(regAddress>>8);
		data[index++]=(uint8_t)regAddress;
	}

	temp=(uint8_t)(regAddress&regAddMask[at->mode]);
	if((wSize<=pageBytes[at->mode])&&(wSize<=(pageBytes[at->mode]-temp)))
	{
		size=wSize;
	}
	else
	{
		size=pageBytes[at->mode]-temp;
	}

	for(int i;i<size;i++)
	{
		data[index++]=wData[i];
	}
	
	if(((at->status)&0x02)!=0x02)
	{
		SetWriteEnableLatchForAT25xxx(at);
	}
	
	if(((at->status)&0x0C)!=0x00)
	{
		WriteStatusForAT25xx(at,at->status|AT25_BPNONE);
	}
	
	at->ChipSelect(AT25CS_Enable);
	at->Write(data,index);
	at->ChipSelect(AT25CS_Disable);
	
	WriteStatusForAT25xx(at,at->status|AT25_BPALL);
}

2.2.3、状态寄存器操作

??前面我们已经详细描述过状态寄存器的格式以及每一位的定义。有一些位是只读的,有一些位是可读写的,记下来我们实现针对状态寄存器中的操作。

(1)、读状态寄存器

??读状态寄存器(RDSR)指令提供对状态寄存器的访问。RDSR指令可以确定设备的状态以及块写保护(BP1, BP0)位表示所使用的内存阵列保护的范围。读取状态寄存器的方法是拉低CS信号,然后发送0x05操作码。操作码完成后,设备将返回8位状态寄存器值。具体时序如下:

??根据上述时序图,我们可以编写读AT25XXX系列EEPROM存储器状态寄存器的程序如下:

/*读AT25xxx状态寄存器*/
void ReadStatusForAT25xxx(At25ObjectType *at)
{
  uint8_t opCode=AT25_RDSR;
	uint8_t status;
	
	at->ChipSelect(AT25CS_Enable);
	at->Write(&opCode,1);
	at->Delayms(1);
	at->Read(&status,1);
	at->ChipSelect(AT25CS_Enable);
	
	at->status=status;
}

(2)、写状态寄存器

??写状态寄存器(WRSR)指令使SPI主机能够更改状态寄存器的选定位。在WRSR指令开始之前,必须执行一条WREN指令,将WEL位设置为逻辑“1”。WREN指令完成后,可以执行WRSR指令。在WRSR指令之后,AT25XXX系列EEPROM存储器将不会响应除RDSR以外的命令,直到自动计时的内部写周期完成。写周期结束后,状态寄存器中的WEL位复位为逻辑“0”。具体的时序图如下:

??根据上述时序图,我们可以编写写AT25XXX系列EEPROM存储器状态寄存器的程序如下:

/*写AT25xxx状态寄存器*/
void WriteStatusForAT25xx(At25ObjectType *at,uint8_t cmd)
{
  uint8_t data[2];
	
	data[0]=AT25_WRSR;
	data[1]=cmd;
	
	if(((at->status)&0x02)!=0x02)
	{
		SetWriteEnableLatchForAT25xxx(at);
	}
	
	if((((at->status)&AT25_WPEN)!=AT25_WPEN)&&(at->WP!=NULL))
	{
		at->WP(AT25WP_Disable);
	}
	
	at->ChipSelect(AT25CS_Enable);
	at->Write(data,2);
	at->ChipSelect(AT25CS_Disable);
	
	ReadStatusForAT25xxx(at);
	
	if(at->WP!=NULL)
	{
		at->WP(AT25WP_Enable);
	}
}

??WRSR指令对状态寄存器的第6位、第5位、第4位、第1位和第0位没有影响。只有第7位、第3位和第2位可以通过WRSR指令进行更改。这些可修改的位是写保护使能(WPEN)和块保护(BP1, BP0)位。这三个位元是非易失性位元,具有与常规EEPROM单元相同的特性和功能。当电源从设备中移除时,它们的值被保留。

2.2.4、写操作使能与失能操作

??通过写使能(WREN)指令和写失能(WRDI)指令实现对状态寄存器和EEPROM阵列的写操作的启用和禁用。这些功能改变了状态寄存器中WEL位的状态。

(1)写操作启用

??状态寄存器的写能门闩(WEL)位必须在每个写状态寄存器(WRSR)和写入内存阵列(Write)指令之前设置为逻辑“1”。这是通过向AT25XXX系列EEPROM存储器发送一条WREN(0x06)指令来完成的。首先,CS引脚被拉低以选择设备,然后发送WREN指令。然后CS信号被拉高,并将状态寄存器中的WEL位更新为逻辑“1”。具体的操作时序如下:

??根据上述时序图,我们可以编写AT25XXX系列EEPROM存储器操作启用的程序如下:

/* AT25XXX设置写使能所存器*/
void SetWriteEnableLatchForAT25xxx(At25ObjectType *at)
{
	uint8_t opCode=AT25_WREN;
	
	at->ChipSelect(AT25CS_Enable);
	at->Write(&opCode,1);
	at->ChipSelect(AT25CS_Enable);
	
	ReadStatusForAT25xxx(at);
}

(2)、写操作禁用

??为了防止误写,写禁用(WRDI)指令(0x04)通过将WEL位设置为逻辑“0”来禁用所有编程模式。WRDI指令与WP引脚的状态无关。具体的操作时序如下图所示:

??根据上述时序图,我们可以编写AT25XXX系列EEPROM存储器操作禁用的程序如下:

/* AT25XXX复位写使能所存器*/
void ResetWriteEnableLatchForAT25xxx(At25ObjectType *at)
{
	uint8_t opCode=AT25_WRDI;
	
	at->ChipSelect(AT25CS_Enable);
	at->Write(&opCode,1);
	at->ChipSelect(AT25CS_Enable);
	
	ReadStatusForAT25xxx(at);
}

3、驱动的使用

??在上一节我们设计并实现了AT25XXX系列EEPROM存储器的驱动程序,而这一节我们将设计一个简单的应用来验证这一驱动程序。

3.1、声明并初始化对象

??使用基于对象的操作我们需要先得到这个对象,所以我们先要使用前面定义的AT25XXX系列EEPROM存储器对象类型声明一个AT25XXX系列EEPROM存储器对象变量,具体操作格式如下:
??At25ObjectType at25;
??声明了这个对象变量并不能立即使用,我们还需要使用驱动中定义的初始化函数对这个变量进行初始化。这个初始化函数所需要的输入参数如下:

At25ObjectType *at,AT25XXX对象实体
At25ModeType mode,AT25XXX对象类型
AT25Read read,读AT25XXX对象操作指针
AT25Write write,写AT25XXX对象操作指针
AT25Delayms delayms,延时操作指针
AT25ChipSelect cs,片选操作函数指针

??对于这些参数,对象变量我们已经定义了。而对象类型为枚举,根据实际使用的AT25XXX系列EEPROM存储器来选择就好了。主要的是我们需要定义几个函数,并将函数指针作为参数。这几个函数的类型如下:

/* 定义读数据操作函数指针类型 */
typedef void (*AT25Read)(uint8_t *rData,uint16_t rSize);
/* 定义写数据操作函数指针类型 */
typedef void (*AT25Write)(uint8_t *wData,uint16_t wSize);
/* 定义延时操作函数指针类型 */
typedef void (*AT25Delayms)(volatile uint32_t nTime);
/* 定义使用SPI接口时,片选操作函数指针类型 */
typedef	void (*AT25ChipSelect)(AT25xxxCSType cs);

??对于这几个函数我们根据样式定义就可以了,具体的操作可能与使用的硬件平台有关系。片选操作函数用于多设备需要软件操作时,如采用硬件片选可以传入NULL即可。具体函数定义如下:

/*读AT25寄存器值*/
static void ReadDataFromAT25(uint8_t *rData,uint16_t rSize)
{
	HAL_SPI_Receive (&at25hspi,rData,rSize,1000);
}

/*写AT25寄存器值*/
static void WriteDataToAT25(uint8_t *wData,uint16_t wSize)
{
  HAL_SPI_Transmit (&at25hspi,wData,wSize,1000);
}

/*片选操作*/
void ChipSelectForAT25(AT25xxxCSType cs)
{
	if(cs==AT25CS_Enable)
  {
    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
  }
  else
  {
    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
  }
}

??对于延时函数我们可以采用各种方法实现。我们采用的STM32平台和HAL库则可以直接使用HAL_Delay()函数。于是我们可以调用初始化函数如下:

At25xxxInitialization(&at25,		//AT25XXX对象实体
					AT25M01,	//AT25XXX对象类型
					ReadDataFromAT25,		//读AT25XXX对象操作指针
					WriteDataToAT25,		//写AT25XXX对象操作指针
					HAL_Delay,		//延时操作指针
					ChipSelectForAT25		//片选操作函数
						   );

3.2、基于对象进行操作

??我们定义了对象变量并使用初始化函数给其作了初始化。接着我们就来考虑操作这一对象获取我们想要的数据。我们在驱动中已经将获取数据并转换为转换值的比例值,接下来我们使用这一驱动开发我们的应用实例。

/*AT25XXX数据读写操作*/
void AT25ReadWriteData(void)
{
	uint16_t regAddress=0x02;
	uint8_t readByte;
	uint8_t writeByte=0x0A;
	uint8_t rData[2];
	uint16_t rSize=2;
	uint8_t wData[]={0x5A,0xA5};
	uint16_t wSize=2;
	
	/*从AT25XXX读取单个字节,从随机地址读取*/
	readByte=ReadByteFromAT25xxx(&at25,regAddress);

	/*向AT25XXX写入单个字节*/
	WriteByteToAT25xxx(&at25,regAddress,writeByte);

	/*从AT25XXX读取多个字节,从指定地址最多到所在页的结尾*/
	ReadBytesFromAT25xxx(&at25,regAddress,rData,rSize);

	/*向AT25XXX写入多个字节,从指定地址最多到所在页的结尾*/
	WriteBytesToAT25xxx(&at25,regAddress,wData,wSize);
}

4、应用总结

??在本片中我们讨论并设计了AT25XXX系列EEPROM存储器的驱动程序,并据此设计了一个简单的验证应用。无论是写数据还是读数据均可顺利执行,说明我们的驱动设计是正确的。
??需要注意的是,4K(512x8)容量的AT25XXX系列EEPROM存储器需要9为地址,但在实际操作时只用了1个字节来装载地址,最高位(第9位)地址借用了操作码的第4位来传送。
??在使用驱动时需注意,采用SPI接口的器件需要考虑片选操作的问题。如果片选信号是通过硬件电路来实现的,我们在初始化时给其传递NULL值。如果是软件操作片选则传递我们编写的片选操作函数。
??在这一驱动设计的过程中我们并未验证读写数据的正确性,事实上如果是比较重要的数据我们可以为其添加验证,如CRC验证等。

欢迎关注:

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-04-06 23:22:24  更:2022-04-06 23:24:32 
 
开发: 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 4:42:23-

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