外设驱动库开发笔记23:AT24Cxx外部存储器驱动

在我们的应用开发过程中,经常会使用到外部的EEPROM外部存储器来保存一些参数和配置数据等。而比较常用的就是AT24Cxx系列产品,这一节我们来开发用于操作AT24Cxx系列产品的驱动。

1、功能概述

AT24Cxx系列EEPROM包括从1Kbit2Mbit的各种容量。AT24Cxx系列产品采用I2C总线数据传送协议。尽管容量跨度很大,但它们都拥有相同的封装和引脚排布,具体的引脚分配如下:

由于A0A1A2可以组成000~111八种情况,即通过器件地址输入端A0A1A2可以实现将最多8个器件连接到同一条总线上,通过不同的配置进行器件的选择。

对于AT24Cxx系列EEPROM不同的容量对地址的分配有较大差异,这涉及到设备地址和寄存器地址。从1K容量到2M容量寄存器地址分别采用718位来表示。16K及以下容量的EEPROM采用一个字节的寄存器地址配合设备地址段实现711位的寄存器地址寻址。而32k及以上的EEPROM采用两个字节的寄存器地址配合设备地址段实现1218位的寄存器地址寻址。具体的地址分配如下:

从上表我们很容易明白,设备地址的低3位的定义决定了在同一条I2C总线上,最多可以挂载多少个AT24Cxx设备。有3位用于设备地址则最多可挂载8个设备;有2位用于设备地址则最多可挂载4个设备;有1位用于设备地址则最多可挂载2个设备;有0位用于设备地址则最多可挂载1个设备。需要注意的是,不同定义的位的设备混用于同一总线时,相同的定义位必须一样,否则用作寄存器地址的位可能让总线上的总线无法识别。

在一些AT24Cxx系列EEPROM型号中,带有序列号的专用存储单元。这些存储单元不占用存储器的存储单元。序列号为128位,读取序列号的设备地址以0xB0开头,以区别于EEPROM存储区域的读取。

在一些AT24Cxx系列EEPROM型号中,除了带有序列号的专用存储单元外,还有带有48位或者64位的MAC地址,固定在专用的存储单元。这些单元不占用存储器的存储单元。读取序列号和读取MAC地址采用同样的设备地址,均以0xB0开头。有一些型号该区域并未用于MAC定制可用于用户操作。

需要注意的是有些型号的AT24Cxx系列EEPROM存储器的设备地址是固化的,需通过型号的后缀标识来识别。

2、驱动设计与实现

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

2.1、对象定义

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

2.1.1、对象的抽象

我们要得到AT24Cxx系列EEPROM存储器对象,需要先分析其基本特性。一般来说,一个对象至少包含两方面的特性:属性与操作。接下来我们就来从这两个方面思考一下AT24Cxx系列EEPROM存储器的对象。

先来考虑属性,作为属性肯定是用于标识或记录对象特征的东西。我们来考虑AT24Cxx系列EEPROM存储器对象属性。首先AT24Cxx系列EEPROM存储器采用的是I2C接口,对于每一个I2C接口元件都有一个设备地址用于区别总线上的设备,所以我们将I2C设备地址作为对象的属性用以区别总线设备。AT24Cxx系列EEPROM存储器存在多个型号对应不同的容量和特性,所以我们将其型号设置为对象的属性以区别对象的类型。前面我们也说过,不同容量的AT24Cxx系列EEPROM存储器由于寻址空间不同,所以寄存器地址长度也是不同的,所以我们将其地址长度作为属性以区分处理。

接着我们还需要考虑AT24Cxx系列EEPROM存储器对象的操作问题。我们需要对AT24Cxx系列EEPROM存储器进行数据读写操作,无论读写其实都依赖于对I2C接口的操作,而这些操作基本都会依赖于具体的硬件平台,所以我们将读写操作作为对象的操作。

根据上述我们对AT24Cxx系列EEPROM存储器的分析,我们可以定义AT24Cxx系列EEPROM存储器的对象类型如下:

typedef struct At24cObject {uint8_t devAddress;          //设备地址At24cModeType mode;           //设备类型At24cMemAddLengthType memAddLength;           //寄存器地址长度void (*Read)(struct At24cObject *at,uint16_t regAddress,uint8_t *rData,uint16_t rSize);       //读数据操作指针void (*Write)(struct At24cObject *at,uint16_t regAddress,uint8_t *wData,uint16_t wSize);    //写数据操作指针void (*Delayms)(volatile uint32_t nTime);       //毫秒延时操作指针
}At24cObjectType;

2.1.2、对象初始化

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

/* 初始化AT24CXX对象 */
void At24cxxInitialization(At24cObjectType *at,    //AT24CXX对象实体uint8_t devAddress,   //AT24CXX设备地址At24cModeType mode,    //AT24CXX对象类型At24cMemAddLengthType length,      //寄存器地址长度At24cRead read,        //读AT24CXX对象操作指针At24cWrite write,      //写AT24CXX对象操作指针At24cDelays delayms           //延时操作指针)
{if((at==NULL)||(read==NULL)||(write==NULL)||(delayms==NULL)){return;}if((devAddress&0xF0)==0xA0){at->devAddress=devAddress;}else{at->devAddress=0x00;}at->mode=mode;at->memAddLength=length;at->Read=read;at->Write=write;at->Delayms=delayms;
}

2.2、对象操作

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

2.2.1、写单个字节

AT24Cxx系列EEPROM存储器支持单字节写数据,收到正确的设备地址和字地址字节后,EEPROM将发送一个确认。然后设备将准备接收8位数据字。在接收到8位数据字之后,EEPROM将返回一个ACK。然后,寻址设备(如总线主机)必须使用停止条件终止写操作。此时,EEPROM将进入一个内部自动定时的写周期,这个写周期将在一定时间内完成,而数据字将被编程到非易失性EEPROM中。在这个写周期中,所有的输入都是禁用的,EEPROM在写完成之前不会响应。

如果AT24Cxx对象是一个使用7位到11位地址表示寄存器地址的话,其数据格式如下图所示:

如果AT24Cxx对象是一个使用12位到18位地址表示寄存器地址的话,其数据格式如下图所示:

根据上述时序图,我们可以编写AT24Cxx系列EEPROM存储器写单个字节数据程序如下:

/*向AT24CXX写入单个字节*/
void WriteByteToAT24CXX(At24cObjectType *at,uint32_t regAddress,uint8_t data)
{uint8_t temp;uint16_t regAdd;if(at->memAddLength==AT24C8BitMemAdd){regAdd=(uint16_t)(regAddress&0xFF);temp=(uint8_t)(regAddress>>8);}else{regAdd=(uint16_t)regAddress;temp=(uint8_t)(regAddress>>16);}temp=(temp&(~(devAddMask[at->mode]>>1)))<<1;at->devAddress=(at->devAddress & devAddMask[at->mode])|temp;at->Write(at,regAdd,&data,1);
}

2.2.2、写多个字节

AT24Cxx系列EEPROM存储器支持多字节的写操作,但对于AT24Cxx对象来说最多只支持写到发送地址所在的页尾,所以资料中也称其为页写。而对于不同型号的AT24Cxx系列EEPROM存储器每页所包含的字节数是不一样的,从8个字节到256个字节不等,我们需要注意写入的字节数。

整页写的初始化方式与单字节写的初始化方式相同,但是总线主机在第一个数据字被锁定后不会发送停止条件。相反,在EEPROM承认接收到第一个数据字之后,总线主机可以传输最多到所在页结尾的数据字。EEPROM将在接收到每个数据字后返回一个ACK。一旦所有要写的数据都被发送到设备,总线主机必须发出一个停止条件此时内部的自计时写周期将开始。字地址的下四位在接收到每个数据字后进行内部递增,高阶位地址位元不会增加。整页写操作仅限于在单个物理页中写入字节,而不管实际写入的字节数。当增加的字地址到达页面边界时,地址计数器将滚动到同一页面的开头。这是必须要注意的,一旦继续写数据可能会将页面中先前加载的数据无意中更改。

如果AT24Cxx对象是一个使用7位到11位地址表示寄存器地址的话,其写多个字节的数据格式如下图所示:

如果AT24Cxx对象是一个使用12位到18位地址表示寄存器地址的话,其写多个字节的数据格式如下图所示:

根据上述时序图,我们可以编写AT24Cxx系列EEPROM存储器写多个字节数据程序如下:

/*向AT24CXX写入多个字节,从指定地址最多到所在页的结尾*/
void WriteBytesToAT24CXX(At24cObjectType *at,uint32_t regAddress,uint8_t *wData,uint16_t wSize)
{uint16_t regAdd;uint8_t size;uint8_t temp;if(at->memAddLength==AT24C8BitMemAdd){regAdd=(uint16_t)(regAddress&0xFF);temp=(uint8_t)(regAddress>>8);}else{regAdd=(uint16_t)regAddress;temp=(uint8_t)(regAddress>>16);}temp=(temp&(~(devAddMask[at->mode]>>1)))<<1;at->devAddress=(at->devAddress & devAddMask[at->mode])|temp;if((wSize<=pageBytes[at->mode])&&(wSize<=(pageBytes[at->mode]-(regAddress&regAddMask[at->mode])))){size=wSize;}else{size=pageBytes[at->mode]-(regAddress&regAddMask[at->mode]);}at->Write(at,regAdd,wData,size);
}

2.2.3、读单个字节

AT24Cxx系列EEPROM存储器支持单字节的读操作。这一方式其实有两种模式,读当前位置和读随机位置。其实读当前位置是读随机位置特例,我们考虑一般性则只考虑随机读取就可以了。随机读的开始方式与字节写操作加载新数据字地址的方式相同。这就是所谓的伪写序列;但是,必须省略数据字节和字节写的停止条件,以防止该部分进入内部写循环。一旦设备地址和字地址被锁定并被EEPROM确认,总线主机必须生成另一个启动条件。总线主机现在通过发送一个启动条件来初始化一个读取的当前地址,接着是一个有效的设备地址字节,其R/W位设置为逻辑“1”。之后EEPROM将对设备地址进行ACK处理,并在SDA线路上连续地输出数据字。如果总线主机在第9个时钟周期内没有响应ACK,则所有类型的读操作都将终止。在NACK响应之后,主进程可以发送一个停止条件来完成协议。

如果AT24Cxx对象是一个使用7位到11位地址表示寄存器地址的话,其读单个字节的数据格式如下图所示:

如果AT24Cxx对象是一个使用12位到18位地址表示寄存器地址的话,其读单个字节的数据格式如下图所示:

根据上述时序图,我们可以编写AT24Cxx系列EEPROM存储器随机读取一个字节数据程序如下:

/*从AT24CXX读取单个字节,从随机地址读取*/
uint8_t ReadByteFromAT24CXX(At24cObjectType *at,uint32_t regAddress)
{uint8_t rData;uint16_t regAdd;uint8_t temp;if(at->memAddLength==AT24C8BitMemAdd){regAdd=(uint16_t)(regAddress&0xFF);temp=(uint8_t)(regAddress>>8);}else{regAdd=(uint16_t)regAddress;temp=(uint8_t)(regAddress>>16);}temp=(temp&(~(devAddMask[at->mode]>>1)))<<1;at->devAddress=(at->devAddress & devAddMask[at->mode])|temp;at->Read(at,regAdd,&rData,1);return rData;
}

2.2.4、读多个字节

AT24Cxx系列EEPROM存储器支持多字节的读操作,类似于单字节读取,可以从当前位置开始读也可以从指定地址开始读。多字节读取也称为顺序读取由当前地址读取或随机读取启动。总线主接收到一个数据字后,它以ACK应答。只要EEPROM接收到ACK,它就会继续增加字地址,并连续地计时输出连续的数据字。当达到最大内存地址时,数据字地址将滚动,顺序读取将从内存数组的开头开始。如果总线主机在第9个时钟周期内没有响应ACK,则所有类型的读操作都将终止。在NACK响应之后,主进程可以发送一个停止条件来完成协议。

如果AT24Cxx对象是一个使用7位到11位地址表示寄存器地址的话,其读多个字节的数据格式如下图所示:

如果AT24Cxx对象是一个使用12位到18位地址表示寄存器地址的话,其读多个字节的数据格式如下图所示:

根据上述时序图,我们可以编写AT24Cxx系列EEPROM存储器顺序读取多个字节数据程序如下:

/*从AT24CXX读取多个字节,从指定地址最多到所在页的结尾*/
void ReadBytesFromAT24CXX(At24cObjectType *at,uint32_t regAddress,uint8_t *rData,uint16_t rSize)
{uint16_t regAdd;uint16_t size;uint8_t temp;if(at->memAddLength==AT24C8BitMemAdd){regAdd=(uint16_t)(regAddress&0xFF);temp=(uint8_t)(regAddress>>8);}else{regAdd=(uint16_t)regAddress;temp=(uint8_t)(regAddress>>16);}temp=(temp&(~(devAddMask[at->mode]>>1)))<<1;at->devAddress=(at->devAddress & devAddMask[at->mode])|temp;if((rSize<=pageBytes[at->mode])&&(rSize<=(pageBytes[at->mode]-(regAddress&regAddMask[at->mode])))){size=rSize;}else{size=pageBytes[at->mode]-(regAddress&regAddMask[at->mode]);}at->Read(at,regAdd,rData,size);
}

3、驱动的使用

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

3.1、声明并初始化对象

使用基于对象的操作我们需要先得到这个对象,所以我们先要使用前面定义的AT24Cxx系列EEPROM存储器对象类型声明一个AT24Cxx系列EEPROM存储器对象变量,具体操作格式如下:

At24cObjectType at24c;

声明了这个对象变量并不能立即使用,我们还需要使用驱动中定义的初始化函数对这个变量进行初始化。这个初始化函数所需要的输入参数如下:

At24cObjectType *atAT24CXX对象实体

uint8_t devAddressAT24CXX设备地址

At24cModeType modeAT24CXX对象类型

At24cMemAddLengthType length,寄存器地址长度

At24cRead read,读AT24CXX对象操作指针

At24cWrite write,写AT24CXX对象操作指针

At24cDelayms delayms,延时操作指针

对于这些参数,对象变量我们已经定义了。对象类型与寄存器地址长度为枚举,根据实际情况选择就好了。设备地址根据我们的实际使用情况设置就可以了。主要的是我们需要定义几个函数,并将函数指针作为参数。这几个函数的类型如下:

/* 定义读数据操作函数指针类型 */
typedef void (*At24cRead)(struct At24cObject *at,uint16_t regAddress,uint8_t *rData,uint16_t rSize);      /* 定义写数据操作函数指针类型 */
typedef void (*At24cWrite)(struct At24cObject *at,uint16_t regAddress,uint8_t *wData,uint16_t wSize);   /* 定义延时操作函数指针类型 */
typedef void (*At24cDelayms)(volatile uint32_t nTime);      

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

/*读AT24C寄存器值*/
static void ReadDataFromAT24C(At24cObjectType *at24c,uint16_t regAddress,uint8_t *rData,uint16_t rSize)
{uint16_t cSize;uint8_t cmd[2];if(at24c->memAddLength==AT24C8BitMemAdd){cSize=1;cmd[0]=(uint8_t)regAddress;}else{cSize=2;cmd[0]=(uint8_t)(regAddress>>8);cmd[1]=(uint8_t)regAddress;}HAL_I2C_Master_Transmit(&at24chi2c,at24c->devAddress,cmd,cSize,1000);HAL_I2C_Master_Receive(&at24chi2c,at24c->devAddress+1,rData, rSize, 1000);
}/*写AT24C寄存器值*/
static void WriteDataToAT24C(At24cObjectType *at24c,uint16_t regAddress,uint8_t *wData,uint16_t wSize)
{uint8_t tData[wSize+2];uint16_t tSize;if(at24c->memAddLength==AT24C8BitMemAdd){tSize=wSize+1;tData[0]=(uint8_t)regAddress;}else{tSize=wSize+2;tData[0]=(uint8_t)(regAddress>>8);tData[1]=(uint8_t)regAddress;}for(int i=0;i<wSize;i++){tData[i+2]=wData[i];}HAL_I2C_Master_Transmit(&at24chi2c,at24c->devAddress,wData,wSize,1000);
}

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

At24cxxInitialization(&at24c,       //AT24CXX对象实体0xAE,           //AT24CXX设备地址AT24C01C,        //AT24CXX对象类型AT24C8BitMemAdd,       //寄存器地址长度ReadDataFromAT24C,    //读AT24CXX对象操作指针WriteDataToAT24C, //写AT24CXX对象操作指针HAL_Delay //延时操作指针);

3.2、基于对象进行操作

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

/*AT24XXX数据操作*/
void AT24CReadWriteData(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;/*从AT24CXX读取单个字节,从随机地址读取*/readByte=ReadByteFromAT24CXX(&at24c,regAddress);/*向AT24CXX写入单个字节*/WriteByteToAT24CXX(&at24c,regAddress,writeByte);/*从AT24CXX读取多个字节,从指定地址最多到所在页的结尾*/ReadBytesFromAT24CXX(&at24c,regAddress,rData,rSize);/*向AT24CXX写入多个字节,从指定地址最多到所在页的结尾*/WriteBytesToAT24CXX(&at24c,regAddress,wData,wSize);
}

4、应用总结

这一篇中,我们设计了AT24Cxx系列EEPROM存储器的读写驱动,而且设计了一个简单的应用验证了驱动程序,读写操作都能按预期要求完成,而且操作也很稳定。

在使用驱动时我们需要注意,因为不同容量的AT24Cxx系列EEPROM存储器的每一页的字节数数不一样的。在多字节读写时,最多支持到所在页尾。到页尾后,EEPROM存储器的内部指针将回到页首,此时执行读则得到的是错误数据,若执行写则会覆盖原有数据造成错误。所以在程序中若读写的范围超越了一页的范围将会被舍弃。

在使用驱动时还需注意,因为不同容量的AT24Cxx系列EEPROM存储器的寻址范围是不一样的,所以用于表示寄存器地址的寄存器地址位数有1个字节和2个字节的差别,为了便于区分需要在对AT24Cxx系列EEPROM存储器对象进行初始化时指定。

源码下载:https://github.com/foxclever/ExPeriphDriver

欢迎关注:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/499336.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

外设驱动库开发笔记24:FM24xxx系列FRAM存储器驱动

虽然说使用EEPROM保存参数很有效&#xff0c;但操作及使用次数均有一下限制。当我们的一些参数需要不定时修改或存储时&#xff0c;使用FRAM就更为方便一点。这一节我们就来设计并实现FM24xxx系列FRAM的驱动。 1、功能概述 我们首先说一下铁电随机存取存储器&#xff0c;F-RA…

外设驱动库开发笔记25:FM25xxx FRAM存储器驱动

在我们的项目中&#xff0c;时常会有参数或数据需要保存。铁电存储器的优良性能和操作方便常常被我们选用。FM25xxx FRAM存储器就是我们经常使用到的一系列铁电存储器&#xff0c;这一篇我们将讨论FM25xxx FRAM存储器的驱动设计、实现及使用。 1、功能概述 FM25xxx FRAM存储器…

步进电机驱动技术1:基于TMC2660的步进电机驱动

步进电机的应用非常广泛&#xff0c;在各种设备中经常会遇到&#xff0c;而步进电机的驱动则是使用步进电机必不可少的部分&#xff0c;可以有多种方式来实现步进电机的驱动&#xff0c;在这里我们来考虑一下基于TMC2660驱动芯片的步进电机驱动。 1、功能概述 TMC2660是德国T…

外设驱动库开发笔记26:nRF24L01无线通讯驱动

现在无线在我们的生活中无处不在。而我们开发的物联网产品也大量使用无线通讯。在这一篇文章中&#xff0c;我们将讨论nRF24L01无线通讯模块驱动程序的开发与实现。 1、功能概述 nRF24L01是一款工作在2.4~2.5GHz世界通用ISM 频段的单片无线收发器芯片无线收发器包括&#xff…

外设驱动库开发笔记27:ESP8266无线通讯驱动

我们的物联网产品所使用的平台都支持无线通讯&#xff0c;而且无线通讯本身更的成本较低&#xff0c;受到大家的欢迎。在本篇文章中&#xff0c;我们将详细讨论并实现ESP8266无线通讯模块的驱动。 1、功能概述 ESP8266是由乐鑫公司出品的一款物联网芯片&#xff0c;因为价格较…

外设驱动库开发笔记28:W5500以太网控制器

以太网通讯是一种被广泛使用的数据通讯方式。在嵌入式应用中也经常使用&#xff0c;但协议栈的实现并不是一件容易的事。不过有些以太网控制器就带有协议栈&#xff0c;如W5500。在本篇中我们将讨论如何设计并实现W5500以太网控制器的驱动。 1、功能概述 W5500是WIZnet开发的…

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

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

外设驱动库开发笔记30:宇电AI-BUS通讯驱动

嵌入式系统通常都会与外部设备进行通讯&#xff0c;这就涉及到通讯协议的问题。这些通讯协议有的是标准协议有的厂家自定义的协议&#xff0c;如宇电的AI-BUS。在本篇中&#xff0c;我们将讨论AI-BUS的驱动&#xff0c;以便于与宇电设备的通讯。 1、功能概述 宇电的设备使用基…

步进电机驱动技术3:基于ULN2003的步进电机驱动

在我们的项目中&#xff0c;经常使用到低电压小功率的步进电机&#xff0c;此类步进电机若采用驱动器控制不断成本高也过于复杂&#xff0c;我们可以直接使用场效应管或者达林顿管来实现对其的驱动。在本篇中&#xff0c;我们就来讨论一下基于ULN2003A达林顿管实现对步进电机的…

通讯接口应用笔记2:MAX3160实现多协议通讯

在一些应用需求中&#xff0c;我们需要对外部提供串行通讯端口&#xff0c;但这些端口所通讯的目标设备各有不同&#xff0c;接口协议也有RS232以及RS485和RS422多种。面对这种情况&#xff0c;我们当然可以同时设计多个串口以适应不同需要&#xff0c;但无疑对硬件资源是一种浪…

电机速度曲线规划1:梯形速度曲线设计与实现

电机驱动是很常见的应用&#xff0c;在很多系统中我们都会碰到需要改变电机的速度以实现相应的控制功能&#xff0c;这就涉及到电机速度曲线规划的问题。在这篇中我们就来简单讨论一下电机的梯形曲线规划的问题。 1、基本原理 梯形速度曲线控制算法是工业控制领域应用最为广泛…

文件系统应用笔记之一:FatFS在STM32F4上的移植

在实现如U盘文件读写&#xff0c;SD卡的文件读写等工作时&#xff0c;我们往往需要一个文件系统来支持我们的工作。特别在一些MCU应用中&#xff0c;文件系统的加入能明显改善系统交互的友好性。在这一篇中&#xff0c;我们就来讨论FatFS文件系统在STM32F4上的移植和应用。 1、…

通讯接口应用笔记3:使用W5500实现Modbus TCP服务器

前面我们设计实现了W5500的驱动程序&#xff0c;也讲解了驱动的使用方式。在最近一次的项目应用中&#xff0c;正好有一个使用W5500实现TCP通讯的需求&#xff0c;所以我们就使用该驱动程序轻松实现。这一篇中我们就来说一说基于我们W5500通讯驱动程序实现TCP通讯的过程。 1、…

电机速度曲线规划2:S形速度曲线设计与实现

电机驱动是很常见的应用&#xff0c;在很多系统中我们都会碰到需要改变电机的速度以实现相应的控制功能&#xff0c;这就涉及到电机速度曲线规划的问题。在这篇中我们就来简单讨论一下电机的S型曲线规划的问题。 1、基本原理 S型速度曲线控制算法是工业控制领域另一种常用的加…

USB应用开发笔记之一:STM32上实现USB主机读写U盘

在项目应用中&#xff0c;经常会有对外交换数据的需求。USB接口读写U盘无疑是一种颇为方便的选择。在这一篇中&#xff0c;我们就来讨论如何在STM32上实现USB主机读写U盘文件的方法。 1、应用概述 在我们的产品上有这样一个需求&#xff0c;希望通过大容量的U盘存取数据。我们…

Modbus协议栈综合实例设计

自我们开源了我们的Modbus协议栈之后&#xff0c;就一直有朋友来信说希望提供示例。这次我们整理了几个例子以供参考。 1、应用实例规划 在这次的实例中&#xff0c;我们使用的目标板拥有一个以太网接口、一个RS232串行接口和一个RS485串行接口&#xff0c;所以我们规划实现&a…

ThreadX应用开发笔记之二:移植ThreadX到STM32H7平台

前面我们将ThreadX成功移植到了STM32F4平台&#xff0c;但这只是我们的部分应用。我们希望将ThreadX的优势发挥到我们的更多应用中&#xff0c;所以在这一篇中我们就来实现将ThreadX移植到STM32H7平台中。 1、前期准备 在开始将ThreadX移植到STM32H7平台之前&#xff0c;我们需…

外设驱动库开发笔记31:S-Modlue远红外气体传感器驱动

在气体分析类产品中&#xff0c;我们经常会用到远红外气体传感器。我们就在碳氢类气体成分分析中使用了S-Modlue远红外气体传感器。接下来&#xff0c;我们将讨论S-Modlue远红外气体传感器驱动的设计与实现。 1、功能概述 S-MODULE EVO 使用非分散红外检测技术NDIR&#xff0c…

外设驱动库开发笔记32:HLPM025K3 PM2.5传感器驱动

现在人们对大气环境及室内环境都比较关注。PM2.5在生活中也是常见的词汇。在有些产品中就要求检测PM2.5的数值。检测PM2.5的手段多种多样&#xff0c;在要求不高时我们通常可以采用激光模块。在这一篇中&#xff0c;我们将讨论HLPM025K3 PM2.5传感器驱动的设计与实现。 1、功能…

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

LCD1602是一种工业字符型液晶&#xff0c;能够同时显示16x02即32个字符。LCD1602液晶显示的原理是利用液晶的物理特性&#xff0c;通过电压对其显示区域进行控制&#xff0c;即可以显示出图形。在这一章我们就来讨论LCD1602液晶显示屏驱动的设计与实现。 1、功能概述 LCD1602液…