我们在前面开发过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验证等。

欢迎关注:

外设驱动库开发笔记40:AT25xxx外部存储器驱动相关推荐

  1. 外设驱动库开发笔记13:MLX90614红外温度传感器驱动

    红外温度传感器一般用于非接触式的温度检测.在我们的系统中经常会有这样的需求.所以我们将其设计为通用的驱动库以备复用.这一篇我们将讲述MLX90614红外温度传感器驱动的设计与实现. 1.功能概述 ML ...

  2. 外设驱动库开发笔记9:SHT1x系列温湿度传感器驱动

    在我们的产品中,经常需要检测温湿度数据.有很多检测温湿度的方法和模块,其中SHT1x系列温湿度传感器就是一种成本较低使用方便的温湿度检测模块.下面我们就来说一说如何实现SHT1x系列温湿度传感器的驱动 ...

  3. 外设驱动库开发笔记0:EPD总体设计

    在产品开发过程中,不可避免需要使用很多外部的元件及传感器,这些元器件也许是板载的,也许是板外的,但不管怎样,为其开发驱动程序都是必须的.每次都需要为这些元器件编写驱动程序.但每次重复编写调试很麻烦,于 ...

  4. python实现sht驱动_【技术】外设驱动库开发笔记9:SHT1x系列温湿度传感器驱动

    在我们的产品中,经常需要检测温湿度数据.有很多检测温湿度的方法和模块,其中SHT1x系列温湿度传感器就是一种成本较低使用方便的温湿度检测模块.下面我们就来说一说如何实现SHT1x系列温湿度传感器的驱动 ...

  5. 外设驱动库开发笔记29:DS17887实时时钟驱动

    一些时候,在我们的嵌入式产品中需要记录时间,所以我们就需要获取时钟,当然实现的方式多种多样,有的MCU本身就有这一功能,不过精度较低.当我们的应用要求较高时就需要使用专门的实时时钟芯片,如DS1788 ...

  6. 外设驱动库开发笔记22:ADXL345三轴数字加速度计驱动

    移动设备的广泛应用增加对移动过程中各种参数的检测需求.ADXL345三轴数字加速度计可以用来检测加速度.进而测量倾斜角度等.在这一篇中,我们将讨论ADXL345三轴数字加速度计驱动程序的设计与实现. ...

  7. 外设驱动库开发笔记33:LCD1602液晶显示屏驱动

      LCD1602是一种工业字符型液晶,能够同时显示16x02即32个字符.LCD1602液晶显示的原理是利用液晶的物理特性,通过电压对其显示区域进行控制,即可以显示出图形.在这一章我们就来讨论LCD ...

  8. 外设驱动库开发笔记54:外设库驱动设计改进的思考

      不知不觉中我们已经发布了五十多篇外设驱动的文章.前段时间有一位网友提出了一些非常中肯的建议,这也让我们开始考虑怎么优化驱动程序设计的问题.在这一篇中我们将来讨论这一问题. 1.问题分析   首先我 ...

  9. 外设驱动库开发笔记35:迪文触摸屏驱动

      有些时候嵌入式系统也需要显示更为复杂的图形,需要更丰富的数据展示.为此,我们需要更大,色彩更丰富,带触屏的显示屏,当然性价比更高就最好了.在我们的项目中遇到此类需求,我们有时会选择DWIN触摸屏. ...

最新文章

  1. 接口测试——postman
  2. 一个奇葩的网络问题,把技术砖家搞蒙了
  3. Nginx安装手册(摘自入云龙老师教案,亲测可用)
  4. VS2015下载地址和安装教程(图解)
  5. 微信分享只有链接没有图标和标题正文
  6. 虚拟机无法查询ip地址的解决方案
  7. 为你的简书和 GitHub 设定个性域名 1
  8. 使用apicloud开发app
  9. 草木有本心,何求美人折
  10. java开发的公文管理系统源代码_基于jsp的公文管理系统-JavaEE实现公文管理系统 - java项目源码...
  11. Arduino定义数组,求数组长度,
  12. [python][Bug记录]特殊16进制转成对应的语言
  13. day35 数据库的初步认识
  14. mac m1 office卸载重装(学校官方正版)
  15. unity+steamVR+VRTK开发环境的搭建
  16. linux 动态图片制作,Ubuntu 17.10下使用kazam制作gif动态图片
  17. oracle添加外键约束的方法
  18. axios实现excel文件下载
  19. 百度移动应用安卓_安卓车牌识别应用于移动警务通提高使用体验度
  20. VirtualBox 中 Ubuntu 16.04 虚拟机与主机之间复制粘贴文本

热门文章

  1. 什么是高防服务器,高防服务器的原理
  2. JAVA入门_继承与重载_饲养员喂养动物
  3. 【转】 中兴OLT-C300常用命令
  4. 11-散列1 电话聊天狂人 (25分)
  5. Node-RED使用指南:6:配置与设定总结:运行环境配置
  6. C/C++笔试题(13)
  7. 数据交易相关法规比较研究
  8. java 时区 不正确_Java中的时区不匹配
  9. android webview应用,Android WebView简单应用
  10. Page Life Expectancy判断服务器运行SQLSERVER时内存是否充足