外设驱动库开发笔记3:AD527x系列数字电位器驱动

在一些时候我们需要使用精度更高的数字电位器来实现我们的应用。我们经常使用AD527x系列数字电位器来实现这类应用。在通常情况下,AD527x系列数字电位器完全能够满足要求。为了减少重复工作,在这里我们将分系并实现AD527x系列数字电位器的驱动。

1、功能概述

我们在这里讨论的AD527x系列数字电位器包括:AD5270、AD5271、AD5272和AD5724,他们的功能是相同的,主要在数字位或通讯接口上有写差别。

AD527x系列数字电位器集业界领先的可变电阻性能与非易失性存储器(NVM)于一体,这些器件的端到端电阻容差误差小于1%,并提供50次可编程(50-TP)存储器。将电阻值编程写入50-TP存储器之前,可进行无限次调整。这些器件不需要任何外部电压源来帮助熔断熔丝,并提供50次永久编程的机会。在50-TP激活期间,一个永久熔断熔丝指令会将游标位置固定。

对于AD527x系列数字电位器,皆有一个16位宽的移位寄存器,一切对AD527x系列数字电位器的操作都是同过这个以为寄存器完成的。移位寄存器的格式如下所示。

该16位移位寄存器由两个应设为0的未用位、四个控制位和10个RDAC数据位组成,并且数据以MSB优先方式加载。对于AD5271和AD5274只有8位数据,则最后两位会被忽略。四个控制位决定软件命令的功能,具体的功能码如下所示:

我们对AD527x系列数字电位器的操作就是以这10个命令为基础的,事实上NOP命令是可以忽略的,因为它不会有任何操作发生。其中有命令5和命令7需要说一下。

命令7则用于设置控制寄存器。控制寄存器仅后4为有效。C0用于设置50-TP的编程使能。C1用于设置RDAC的写保护。C2用于电阻容差校准。C3则是指示50-TP的编程状态。具体结构如下:

而命令5用于设置读出的50-TP的内容。就是说这条命令用于设置我下次读取50-TP时究竟是那一条的类容,因为总共有50条。具体的取值如下:

共50条需要50个编码,使用了D0到DF5位,编号1开始一一对应50个编程位置。

2、驱动设计与实现

我们已经了解了AD527x系列数字电位器的基本情况,接下来我们就设计并实现AD527x系列数字电位器的驱动。 

2.1、对象定义

同样的我们将基于对象操作的思想来设计AD527x系列数字电位器的驱动。既如此,我们首先必须要定义AD527x系列数字电位器对象。

2.1.1、抽象对象类型

在抽象出AD527x系列数字电位器对象类型之前,我们先来分析一下AD527x系列数字电位器。一个对象最起码包含属性和操作两个特性,我们来分析一下AD527x系列数字电位器对象包含有那些属性和操作。

对于AD527x系列数字电位器包含有多种器件,不同的器件在通讯接口和档位等方面会有差别,所以我们将设备的类型作为其属性以分辩究竟是哪种器件,进而分辨接口和档位差异。游标的当前位置以及控制寄存器的值我们也将其设置为属性以确定设备当前的状态。当设备时I2C接口时,需要有一个设备地址,所以我们将设备地址设置为属性,这个属性只在I2C接口模式时才起作用。而在使用SPI接口的器件时,需要一个片选信号,所以我们将操作片选信号作为AD527x系列数字电位器的一个操作,这个操作只在使用SPI接口的器件时才起作用。此外,AD527x系列数字电位器对象还需要实现数据的发送与接收以及操作过程中必要的延时函数,我们均将其作为对象的操作。据上述分析我们可以抽象出AD527x系列数字电位器对象类型如下:

/*定义用于SPI接口的对象类型*/
typedef struct AD527xObject {AD527xType type; //设备类型uint8_t devAddress; //设备地址,用于I2C接口uint8_t conreg; //控制寄存器uint16_t rdac; //游标寄存器现值void (*ChipSelcet)(AD527xCSType en); //片选信号,用于SPI接口void (*Receive)(struct AD527xObject *rx,uint8_t *rData,uint16_t rSize);void (*Transmit)(struct AD527xObject *rx,uint8_t *wData,uint16_t wSize);void (*Delayms)(volatile uint32_t nTime);       //ms延时操作指针
}AD527xObjectType;

2.1.2、对象的初始化

一个对象我们需要对其初始化才能使用,初始化函数至少包含有2方面内容:一是为对象变量赋必要的初值;二是检查这些初值是否是有效的。特别是一些操作指针错误的话可能产生严重的后果。基于这一原则,我们设计AD527x系列数字电位器的对象初始化函数如下:

/* 初始化AD527x对象,I2C接口必须初始化devAddress,SPI接口必需初始化void (*ChipSelcet)(bool) */
void AD527xInitialization(AD527xObjectType *rx,uint8_t address,AD527xType type,AD527xReceive recieve,AD527xTransmit transmit,AD527xChipSelcet cs,AD527xDelayms delayms)
{if((rx==NULL)||(recieve==NULL)||(transmit==NULL)||(delayms==NULL)){return;}if((type==AD5270)||(type==AD5271)) //使用SPI接口{if(cs==NULL) //硬件电路实现片选{rx->ChipSelcet=DefaultChipSelcet;}else{rx->ChipSelcet=cs;}rx->devAddress=0x00;}else //使用I2C接口{if((address==0x58)||(address==0x5C)||(address==0x5E)){rx->devAddress=address;}else if((address==0x2C)||(address==0x2E)||(address==0x2F)){rx->devAddress=(address<<1);}else{rx->devAddress=0x00;}rx->ChipSelcet=NULL;}rx->type=type;rx->conreg=0x00;rx->rdac=0x0000;rx->Receive=recieve;rx->Transmit=transmit;rx->Delayms=delayms;ReadControlRegister(rx);SetSoftShutMode(rx,SOFT_NORMAL_MODE);
}

2.2、对象操作

前面我们已经描述过,对AD527x系列数字电位器的操作命令有9个。这9个命令皆是对寄存器进行读写操作的,所以我们这里将这些操作分为读寄存器操作和写寄存器操作,并以此设计驱动程序。

2.2.1、写寄存器操作

首先我们需要说明写寄存器操作是针对对象的操作函数,而不是对象变量包含的操作,因为我们只在对象变量中放入依赖于外界平台的基本操作。写寄存器操作会以回调的方式调用对象变量包含的基本操作。

因为AD527x系列数字电位器对象包括不同接口和不同档位的器件,所以我们设计写寄存器操作时需要考虑AD527x系列数字电位器对象的类型。而这个类型已在初始化时赋予了对象变量。据此我们设计写寄存器操作函数如下:

/* 写寄存器操作 */
static void AD527xWriteRegister(AD527xObjectType *rx,uint16_t cmd)
{uint8_t tData[2];tData[0]=(uint8_t)(cmd>>8);tData[1]=(uint8_t)cmd;if((rx->type==AD5270)||(rx->type==AD5271)) //SPI接口{rx->ChipSelcet(AD527xCS_ENABLE);rx->Delayms(1);}rx->Transmit(rx,tData,2);if((rx->type==AD5270)||(rx->type==AD5271)) //SPI接口{rx->Delayms(1);rx->ChipSelcet(AD527xCS_DISABLE);}
}

2.2.2、读寄存器操作

与写寄存器操作一样,读寄存器操作一样要考虑到AD527x系列数字电位器对象的类型。在使用SPI接口的对象类型种需要考虑片选信号的处理。我们设计读寄存器操作如下:

/* 读寄存器操作 */
static void AD527xReadRegister(AD527xObjectType *rx,uint16_t cmd,uint8_t *rData)
{uint8_t tData[2];if((rx->type==AD5270)||(rx->type==AD5271)) //SPI接口{rx->ChipSelcet(AD527xCS_ENABLE);rx->Delayms(1);}rx->Transmit(rx,tData,2);rx->Receive(rx,rData,2);if((rx->type==AD5270)||(rx->type==AD5271)) //SPI接口{rx->Delayms(1);rx->ChipSelcet(AD527xCS_DISABLE);}
}

2.2.3、面向命令的操作

我们已经实现了对继存存其的读操作和写操作,但我们并不想通过调用这两个函数并传递命令来实现我们的应用。所以我们将不同的操作命令所要完成的功能封装成函数,在这些函数中调用读写寄存器操作函数来完成。这样使用驱动就变得更为简便。例如我们设计读写RDAC的函数如下:

/* 设置AD527x游标位置 */
void SetRDACForAd527x(AD527xObjectType *rx,uint16_t data)
{uint16_t temp=0;if((rx->type==AD5271)||(rx->type==AD5274)) //256档{temp=data>255?255:data;}else if((rx->type==AD5270)||(rx->type==AD5272)) //1024档{temp=data>1023?1023:data;}temp=COMMAND_W_RDAC|temp;if(((rx->conreg)&0x02)!=0x02){SetControlRegister(rx,PROGRAM_RDAC_ENABLE|rx->conreg);}AD527xWriteRegister(rx,temp);
}/* 读取RDAC游标寄存器的内容 */
uint16_t ReadRDACFromAd527x(AD527xObjectType *rx)
{uint8_t rData[2];uint16_t cmd=COMMAND_R_RDAC;AD527xReadRegister(rx,cmd,rData);rx->rdac=(rData[0]<<8)+rData[1];return rx->rdac;
}

3、驱动的使用

我们已经实现了AD527x系列数字电位器的驱动。接下来我们来考虑如何使用这一驱动实现我们的应用。

3.1、声明并初始化对象

我们已经定义了AD527x系列数字电位器对象类型。所以我们先要使用对象类型声明一个AD527x系列数字电位器对象变量。形式如下:

AD527xObjectType ad527x;

当然,这里定义的这个对象变量还不能直接使用。我们需要使用初始化函数对这个对象变量进行初始化。初始化函数前面已经说过,传递的参数皆是与对象变量相关的。初始化函数的参数如下:

AD527xObjectType *rx,待初始化的对象变量。

uint8_t address,采用I2C接口通讯是的设备地址。

AD527xType type,对象的设备类型。

AD527xReceive recieve,数据接收函数指针。

AD527xTransmit transmit,数据发送函数指针。

AD527xChipSelcet cs,使用SPI接口通讯时,片选操作函数指针。

AD527xDelayms delayms,毫秒延时操作函数指针。

对于这些参数,对象变量我们已经定义了。对象类型根据实际器件输入即可。而设备地址在使用I2C接口时按要求输入即可,如果是SPI接口则任意uint8_t类型的值均可。最主要的是我们需要定义几个函数,并将函数指针作为参数。这几个函数的类型图下:

/*定义片选信号函数指针类型*/
typedef void (*AD527xChipSelcet)(AD527xCSType en);/*定义接收数据函数指针类型*/
typedef void (*AD527xReceive)(struct AD527xObject *rx,uint8_t *rData,uint16_t rSize);/*定义发送数据函数指针类型*/
typedef void (*AD527xTransmit)(struct AD527xObject *rx,uint8_t *wData,uint16_t wSize);/*定义ms延时操作指针*/
typedef void (*AD527xDelayms)(volatile uint32_t nTime);

对于这几个函数我们根据样式定义就可以了,具体的操作可能与使用的硬件平台有关系。片选操作函数只在使用SPI接口是需要定义,否则可以传入NULL即可。具体函数定义如下:

/*定义片选信号函数*/
void AD527xCS(AD527xCSType en)
{if(AD527xCS_ENABLE==en){HAL_GPIO_WritePin(GPIOF, GPIO_PIN_4, GPIO_PIN_RESET);}else{HAL_GPIO_WritePin(GPIOF, GPIO_PIN_4, GPIO_PIN_SET);}
}/*定义接收数据函数*/
void AD527xReceiveData(struct AD527xObject *rx,uint8_t *rData,uint16_t rSize)
{HAL_SPI_Receive (&hspi, rData, rSize, 1000);
}/*定义发送数据函数*/
void AD527xTransmitData(struct AD527xObject *rx,uint8_t *wData,uint16_t wSize)
{HAL_SPI_Transmit (&hspi, wData, wSize, 1000);
}

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

AD527xInitialization(&ad527x,0x00,AD5270,AD527xReceiveData,AD527xTransmitData,AD527xCS,HAL_Delay);

这是使用SPI接口器件的初始化操作,使用I2C接口的初始化操作类似次操作即可。

3.2、基于对象进行操作

我们已经定义了对象变量并对其进行了初始化。接下来我们就要看看如何操作对象得到我们想要的结果。

我们在前面已经根据操作命令做了封装,所以我们需要什么养的功能只需要调用相应的函数就可以了。如我们想要设置RDAC为最大值则:

SetValueToAd5270(&ad527x,1023);

其中第1个参数为要操作的对象指针,第2个参数为要设置的游标位置值。

4、应用总结

我们已经实现AD527x系列数字电位器的驱动及基于此驱动的应用,得到了与我们预期一致的结果,说明驱动的设计时符合需求的。

在使用驱动时需注意,采用I2C接口的器件需要考虑设备地址的问题。设备地址由ADDR引脚的状态决定。由三种取值如下:

在使用驱动时需注意,采用SPI接口的器件需要考虑片选操作的问题。如果片选信号是通过硬件电路来实现的,我们在初始化时给其传递NULL值。如果是软件操作片选则传递我们编写的片选操作函数。

源码地址GitHub:https://github.com/foxclever/ExPeriphDriver

欢迎关注:

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

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

相关文章

PID控制器改进笔记之一:改进PID控制器之参数动态调整

前面我们发布了一系列PID控制器相关的文章&#xff0c;包括经典PID控制器以及参数自适应的PID控制器。这一系列PID控制器虽说实现了主要功能&#xff0c;也在实际使用中取得了良好效果&#xff0c;但还有很多的细节部分可以改进以提高性能和灵活性。所以在这篇中我们来讨论改进…

外设驱动库开发笔记4:AD9833函数发生器驱动

很多时候我们需要输出某种函数信号&#xff0c;如方波、三角波、正弦波等&#xff0c;但想要获得这样的函数信号&#xff0c;不论是硬件电路还是软件实现&#xff0c;却并不是一件简单的事情。不过AD9833这类函数生成芯片可以简化这方面的操作&#xff0c;这一节我们就来设计并…

PID控制器改进笔记之二:改进PID控制器之手自动切换

前面我们发布了一系列PID控制器相关的文章&#xff0c;包括经典PID控制器以及参数自适应的PID控制器。这一系列PID控制器虽说实现了主要功能&#xff0c;也在实际使用中取得了良好效果&#xff0c;但还有很多的细节部分可以改进以提高性能和灵活性。所以在这篇中我们来讨论改进…

外设驱动库开发笔记5:AD7705系列ADC驱动

我们的经常需要采集一些精度要求较高的模拟信号&#xff0c;使用MCU集成的ADC难以达到要求、所以我们需要独立的ADC芯片。这一节我们就来设计并实现AD7705芯片的驱动、并探讨驱动的使用方法。 1、功能概述 AD7705/AD7706是用于低频测量的完整模拟前端。可以直接从传感器接收低…

PID控制器改进笔记之三:改进PID控制器之正反作用

前面我们发布了一系列PID控制器相关的文章&#xff0c;包括经典PID控制器以及参数自适应的PID控制器。这一系列PID控制器虽说实现了主要功能&#xff0c;也在实际使用中取得了良好效果&#xff0c;但还有很多的细节部分可以改进以提高性能和灵活性。所以在这篇中我们来讨论改进…

PID控制器改进笔记之四:改进PID控制器之设定值响应

前面我们发布了一系列PID控制器相关的文章&#xff0c;包括经典PID控制器以及参数自适应的PID控制器。这一系列PID控制器虽说实现了主要功能&#xff0c;也在实际使用中取得了良好效果&#xff0c;但还有很多的细节部分可以改进以提高性能和灵活性。所以在这篇中我们来讨论改进…

PID控制器改进笔记之五:改进PID控制器之串级设定

前面我们发布了一系列PID控制器相关的文章&#xff0c;包括经典PID控制器以及参数自适应的PID控制器。这一系列PID控制器虽说实现了主要功能&#xff0c;也在实际使用中取得了良好效果&#xff0c;但还有很多的细节部分可以改进以提高性能和灵活性。所以在这篇中我们来讨论改进…

滤波器开发之一:基于算数平均的平滑滤波器

信号采集是非常常见的需求&#xff0c;我们也总是希望采集到的数据是纯净而真实的&#xff0c;但这只是我们的希望。环境中存在太多的干扰信号&#xff0c;为了让我们得到的数据尽可能地接近实际值&#xff0c;我们需要降低这些干扰信号的影响&#xff0c;于是就有了滤波器的用…

外设驱动库开发笔记6:AD719x系列ADC驱动

前面我们讨论了AD7705这种ADC器件的驱动开发&#xff0c;在实际中我们使用更多的是AD719x系列的ADC芯片、包括有AD7191、AD7192和AD7193等。接下来我们就来设计并开发AD719x的驱动程序。 1、功能概述 AD7192是一款适合高精密测量应用的低噪声完整模拟前端&#xff0c;内置一个…

滤波器开发之二:基于算数平均的带阻平滑滤波器

信号采集是非常常见的需求&#xff0c;我们也总是希望采集到的数据是纯净而真实的&#xff0c;但这只是我们的希望。环境中存在太多的干扰信号&#xff0c;为了让我们得到的数据尽可能地接近实际值&#xff0c;我们需要降低这些干扰信号的影响&#xff0c;于是就有了滤波器的用…

滤波器开发之三:基于算数平均的阶进平滑滤波器

信号采集是非常常见的需求&#xff0c;我们也总是希望采集到的数据是纯净而真实的&#xff0c;但这只是我们的希望。环境中存在太多的干扰信号&#xff0c;为了让我们得到的数据尽可能地接近实际值&#xff0c;我们需要降低这些干扰信号的影响&#xff0c;于是就有了滤波器的用…

外设驱动库开发笔记7:LTC2400系列ADC驱动

有些时候我们需要对高精度的ADC来处理一些要求较高的模拟量采集。在处理温控器的过程中我们就使用到了LTC2400这款ADC。接下来我们就来设计并实现LTC2400的驱动。 1、功能概述 LTC2400是一个供电电压2.7V到5.5V的微功率24位转换器&#xff0c;集成了振荡器、4ppm INL和0.3ppm…

外设驱动库开发笔记8:GPIO模拟I2C驱动

I2C总线简单方便&#xff0c;是我们经常使用的一种总线。但有时候我们的MCU没有足够多的I2C控制器来实现我们的应用&#xff0c;所幸我可以使用普通的GPIO引脚来模拟低速的I2C总线通信。这一节我们就来实现使用软件通过普通GPIO操作I2C设备的驱动。 1、功能概述 I2C总线使用两…

嵌入式IAP开发笔记之一:面向STM32的BootLoader程序

对于很多人来说&#xff0c;BootLoader并不是一个陌生的词&#xff0c;甚至会经常用到它。因为在很多情况下我们都需要BootLoader程序&#xff0c;比如我们需要对系统在线升级时就需要它&#xff0c;还有当我们需要在外部存储器中运行程序时也需要用到它。在这里我们就来设计一…

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

在我们的产品中&#xff0c;经常需要检测温湿度数据。有很多检测温湿度的方法和模块&#xff0c;其中SHT1x系列温湿度传感器就是一种成本较低使用方便的温湿度检测模块。下面我们就来说一说如何实现SHT1x系列温湿度传感器的驱动。 1、功能概述 SHT1x包括 SHT10&#xff0c; S…

Modbus协议栈应用实例之一:Modbus RTU主站应用

自从开源了我们自己开发的Modbus协议栈之后&#xff0c;有很多朋友建议我针对性的做几个示例。所以我们就基于平时我们的应用整理了几个简单但可以说明基本的应用方法的示例&#xff0c;在这一篇中我们先来使用协议栈实现Modbus RTU主站的示例。 1、何为RTU主站 Modbus协议是…

uCOS-III应用开发笔记之一:uCOS-III在STM32的移植

uCOS-III实时操作系统在MCU平台被广泛使用&#xff0c;在这里我们将简单的记录如何将uCOS-III实时操作系统移植到目标平台上并运行。 1、必要的准备 在开始uCOS-III实时操作系统的移植前&#xff0c;我们还需要做一些必要的准备&#xff0c;如确定目标板、准备目标工程及uCOS…

外设驱动库开发笔记10:SHT2x系列温湿度传感器驱动

温湿度检测是嵌入式编程中经常应用到的一项功能。在我们的产品中亦经常使用。SHT2x系列温湿度传感器作为一种高精度低成本的集成模块&#xff0c;一直应用于我们的产品中。在这里我们讨论如何封装SHT2x系列温湿度传感器的驱动。 1、功能概述 SHT20配有一个全新设计的CMOSens芯…

Modbus协议栈应用实例之二:Modbus RTU从站应用

自从开源了我们自己开发的Modbus协议栈之后&#xff0c;有很多朋友建议我针对性的做几个示例。所以我们就基于平时我们的应用整理了几个简单但可以说明基本的应用方法的示例&#xff0c;这一篇中我们将使用协议栈实现一个Modbus RTU从站应用。 1、何为RTU从站 Modbus协议是一…

外设驱动库开发笔记11:SHT3x系列温湿度传感器驱动

在我们的产品中经常会遇到温湿度检测的需求。可以用于检测温湿度的传感器元件也有很多。我们经常使用的SHT各系列数字温湿度传感器来实现应用需求。在这里我们将设计并实现SHT3x系列温湿度传感器的驱动。 1、功能概述 SHT3x系列温湿度传感器是适用于各种应用的高品质湿度传感…