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

我们的经常需要采集一些精度要求较高的模拟信号,使用MCU集成的ADC难以达到要求、所以我们需要独立的ADC芯片。这一节我们就来设计并实现AD7705芯片的驱动、并探讨驱动的使用方法。

1、功能概述

AD7705/AD7706是用于低频测量的完整模拟前端。可以直接从传感器接收低电平输入信号,并产生串行数字输出。

1.1、硬件结构

AD7705AD7706均为完整16位、低成本、Σ-ΔADC,适合直流和低频交流测量应用。其具有低功耗(3 V时最大值为1 mW)特性,因而可用于环路供电、电池供电或本地供电的应用中。片内可编程增益放大器提供从1128的增益设置,无需使用外部信号调理硬件便可接受低电平和高电平模拟输入。

AD7705拥有两个差分通道,而AD7706则拥有一个差分通道和两个伪差分通道。在定制比率应用器件时,差分基准电压输入还能提供极大的灵活性。采用16引脚封装,具体的定义及结构如下:

AD7705/AD7706设备的工作电压从2.7 V3.3 V4.75 V5.25 V不等。在VDD5v和参考电压为2.5 V的情况下,输入信号范围从0 mV20 mV,从0 V2.5 V,都可以在这两种设备上使用。在VDD3v和参考电压为1.25 V的情况下,可以处理0 mV10 mV0 V1.225 V的单极输入信号范围。

1.2、片上寄存器

AD7705/AD7706每个包含8个片上寄存器,可以通过串口访问。第一个是通信寄存器,第二个是配置寄存器,第三个是时钟寄存器,第四个是数据寄存器,余下的是校准寄存器。具体如下:

需要说明的是测试寄存器,不要改变此寄存器中的任何位的状态,这个寄存器用于设备测试。

1.2.1、通信寄存器

通信寄存器用于控制通道选择,并决定下一个操作是读操作还是写操作,并决定下一个读操作或写操作访问哪个寄存器。通讯寄存器各位含义如下:

所有到AD7705/AD7706的通信都必须从通信寄存器的写操作开始。写入该寄存器的数据决定下一个操作是读操作还是写操作,以及该操作发生在哪个寄存器。其中RS2–RS0三位决定下一操作是针对哪一个寄存器进行的。

CH1 CH0两位决定是针对哪一通道的操作。

1.2.2、配置寄存器

配置寄存器是一个8位寄存器,可以从中读取或写入数据,用于确定校准模式、增益设置、双极/单极操作和缓冲模式。

1.2.3、时钟寄存器

时钟寄存器是一个8位寄存器,可以从中读取或写入数据,,并包含筛选器选择位和时钟控制位。

1.2.4、数据寄存器

数据寄存器是一个16位的只读寄存器,它包含来自AD7705/AD7706的最新转换结果。如果通信寄存器为该寄存器的写操作设置了部件,则必须执行写操作才能将部件返回到其默认状态。然而,写入该部分的16位数据将被AD7705/AD7706忽略。

1.2.5、校准寄存器

校准寄存器是一系列的寄存器对,用于存储通道校准数据。每对包括一个零标度校准寄存器和一个满标度校准寄存器,并对应一个通道。当开启系统零点或量程校准时,将根据对应通道上的数据来校准。当然如果有必要,也可以通过数字接口来读写这些寄存器。

2、驱动设计与实现

我们已经了解了AD7705模数转换器的结构及内部寄存器配置,接下来我们将根据我们的了解设计并实现AD7705模数转换器的驱动。

2.1、对象定义

我们对AD7705模数转换器的操作依然是基于对象的,所以我们要先得到对象。首先的工作当然是抽象得到对象的特性进而得到我们需要的对象。

2.1.1、抽象对象类型

一个对象最起码包含属性和操作两方面内容,我们先来分析一下AD7705模数转换器对象需要包含哪些属性和操作。

对于AD7705模数转换器来说,总共有8个寄存器,这些寄存器是实现操作的基础,我们要配置并了解这些寄存器的状态,所以我们将这些寄存器抽象为对象的属性,以便随时掌握操作的目标。

进而我们考虑AD7705模数转换器对象的操作。首先我们要操作AD7705模数转换器就是向其发送命令和读取数据,所以我们将向AD7705模数转换器发送命令和读取数据作为对象的一个操作。AD7705模数转换器采用SPI通讯接口,有时需要在软件中对片选信号进行操作,所以我们将片选型号的操作作为对象的另一个操作。在一些情况下,有些针对对象的活动需要延时进行,而在不同的平台中采取的延时方式不尽相同,为了操作方便我们将延时操作作为对象的一个操作。此外AD7705模数转换器有一个转换数据就绪检测的功能,我们将读取就绪信号作为它的另一个操作。

据以上的分析我们可以抽象AD7705模数转换器的对象类型如下:

/* 定义AD7705对象类型 */
typedef struct AD7705Object {uint8_t registers[3];                      //用于存储通讯、配置和时钟寄存器uint8_t (*ReadWriteByte)(uint8_t data);    //读写操作uint8_t (*CheckDataIsReady)(void);         //就绪信号检测void (*ChipSelect)(AD7705CSType cs);       //实现片选void (*Delayms)(volatile uint32_t nTime);  //实现ms延时操作void (*Delayus)(volatile uint32_t nTime);  //实现us延时操作
}AD7705ObjectType;

2.1.2、对象初始化

我们虽然得到了是对象,但对象不能直接使用,我们需要对其进行初始化方能使用。所以接下来我们考虑AD7705模数转换器对象的初始化函数。

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

/* AD7705对象初始化函数 */
void AD7705Initialization(AD7705ObjectType *ad,AD7705GainType gain,AD7705MclkType mclk,AD7705OutRateType rate,AD7705ReadWriteByteType spiReadWrite,AD7705CheckDataIsReadyType checkReady,AD7705ChipSelect cs,AD7705Delay msDelay,AD7705Delay usDelay)
{if((ad==NULL)||(spiReadWrite==NULL)||(checkReady==NULL)||(msDelay==NULL)||(usDelay==NULL)){return;}ad->CheckDataIsReady=checkReady;ad->ReadWriteByte=spiReadWrite;ad->Delayms=msDelay;ad->Delayus=usDelay;if(cs==NULL)     //硬件电路实现片选{ad->ChipSelect=DefaultChipSelect;}else{ad->ChipSelect=cs;}//设置成单极性、无缓冲、增益为1、滤波器工作、自校准ad->registers[REG_SETUP]=SelfCalibration|Unipolar|BufferDisable|FSYNCEnable|gains[gain];ad->registers[REG_CLOCK]=CLKEnable; //默认主时钟输出if((mclk==Mclk4915200)||(mclk==Mclk2000000)){ad->registers[REG_CLOCK]|=CLKDIVEnable;}else{ad->registers[REG_CLOCK]|=CLKDIVDisable;}if(((mclk<=Mclk4915200)&&(rate<=Rate200Hz))||((mclk>=Mclk1000000)&&(rate>=Rate50Hz))){ad->registers[REG_CLOCK]|=updateRate[rate];}else{ad->registers[REG_CLOCK]=0x00;return;}    
}

2.2、对象操作

我们获取对象的目的就是希望通过对象来得到我们想要的数据。对于AD7705模数转换器来说,我们想要得到的就是各个通道的输入信号。所以我们对AD7705模数转换器对象的操作就是得到通道的模数转换值。据此我们设计读取AD7705模数转换器单个通道的值的函数如下:

//读取AD7705单个通道的值
uint16_t GetAD7705ChannelValue(AD7705ObjectType *ad,AD7705ChannelType channel)
{ad->ChipSelect(AD7705CS_Enable);//初始化通道AD7705ChannelConfig(ad,channel);ad->Delayms(20);ad->registers[REG_COMM]=DataRegister|ReadOperation|OperatingMode|channels[channel];ad->ReadWriteByte(ad->registers[REG_COMM]);//等待数据准备好while(ad->CheckDataIsReady()==1)   {}uint16_t dataLowByte;uint16_t dataHighByte;dataHighByte = ad->ReadWriteByte(0xFF);        //读数据寄存器ad->Delayus(200);dataLowByte = ad->ReadWriteByte(0xFF);        //读数据寄存器ad->Delayus(200);dataHighByte = dataHighByte << 8;uint16_t value;value  =  dataHighByte | dataLowByte; ad->ChipSelect(AD7705CS_Disable);return value;
}

其中设置寄存器和时钟寄存器的值,在初始化函数中已经记录下来,在配置时,我们只需要下发数据就好了。

3、驱动的使用

我们已经设计并实现了AD7705模数转换器的驱动,接下来我们考虑如何使用这一驱动程序实现AD7705模数转换器的应用。

3.1、声明并初始化对象

应用的设计一如既往,我们需要使用AD7705模数转换器对象类型声明一个对象变量。形式如下:

AD7705ObjectType ad7705;

声明了这个对象变量并不能用于操作AD7705模数转换器,我们还需要使用初始化函数对对象变量进行初始化。初始换函数所需参数如下:

AD7705ObjectType *ad,要初始化的AD7705对象

AD7705GainType gain,增益系数

AD7705MclkType mclk,主时钟频率

AD7705OutRateType rate,输出更新速率

AD7705ReadWriteByteType spiReadWriteSPI口读写操作函数

AD7705CheckDataIsReadyType checkReady,就绪检测函数

AD7705ChipSelect cs,片选操作函数

AD7705Delay msDelay,毫秒延时函数

AD7705Delay usDelay,微秒延时函数

对于这些参数,对象变量我们已经定义了。采用的增益倍数根据实际情况选择,为枚举。AD7705采用的数字时钟则根据我们的实际使用情况输入,为枚举。而输出更新速率根据需要选择,为枚举。主要的是我们需要定义几个函数,并将函数指针作为参数。这几个函数的类型如下:

/*定义读写AD7705函数指针类型*/
typedef uint8_t (*AD7705ReadWriteByteType)(uint8_t data);/*定义就绪检测函数指针类型*/
typedef uint8_t (*AD7705CheckDataIsReadyType)(void);/*定义片选信号函数指针类型*/
typedef void (*AD7705ChipSelect)(AD7705CSType cs);/*定义延时操作函数指针类型*/
typedef void (*AD7705Delay)(volatile uint32_t nTime);

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

/*定义片选信号函数*/
void AD7705CS(AD7705CSType en)
{if(AD7705CS_Enable==en){HAL_GPIO_WritePin(GPIOF, GPIO_PIN_4, GPIO_PIN_RESET);}else{HAL_GPIO_WritePin(GPIOF, GPIO_PIN_4, GPIO_PIN_SET);}
}/* 定义就绪信号读取函数 */
uint8_t AD7705CheckReady(void)
{return HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_0);
}/*定义发送数据函数*/
uint8_t AD7705WriteReadData(uint8_t wData)
{uint8_t rxData=0;HAL_SPI_TransmitReceive(&ad7705hspi,&wData,&rxData,1,1000);return rxData;
}

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

AD7705Initialization(&ad7705Gain_1Mclk2457600Rate200HzAD7705WriteReadDataAD7705CheckReadyAD7705CSHAL_DelayDelayus);

3.2、基于对象进行操作

我们定义了对象变量并使用初始化函数给其作了初始化。接着我们就来考虑操作这一对象获取我们想要的数据。在驱动中我们已经封装了获取某一通道模数转换数据的函数,这里我们将调用这一函数获取AD7705两个通道的模数转换值。

/*获取通道数据*/
void GetChannelValue(void)
{uint16_t dataCode[2];dataCode[0]=GetAD7705ChannelValue(&ad7705,Channel1);dataCode[1]=GetAD7705ChannelValue(&ad7705,Channel2);
}

获取了ADC的数据后就可以根据每个通道所对应的物理量量程范围计算得到物理量值。

4、应用总结

我们实现了AD7705模数转换器的驱动并使用驱动实现了简单的应用,得到了AD7705两个通道的模数转换数据,结果与预期一致。

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

​完整的源代码可在GitHub下载:https://github.com/foxclever/ExPeriphDriver

欢迎关注:

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

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

相关文章

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系列温湿度传感器是适用于各种应用的高品质湿度传感…

LwIP应用开发笔记之十:LwIP带操作系统基本移植

现在&#xff0c;TCP/IP协议的应用无处不在。随着物联网的火爆&#xff0c;嵌入式领域使用TCP/IP协议进行通讯也越来越广泛。在我们的相关产品中&#xff0c;也都有应用&#xff0c;所以我们结合应用实际对相关应用作相应的总结。 1、技术准备 我们采用的开发平台是STM32F407…

ThreadX应用开发笔记之一:移植ThreadX到STM32平台

现在一些小型系统中也往往有多任务处理的需求&#xff0c;这就为实时操作系统提供了用武之地。事实上国内外各种各样的RTOS有很多&#xff0c;而且基本都在走开源的路线&#xff0c;ThreadX也不例外&#xff0c;在这一篇中我们就来学习ThreadX初步应用并将其移植到STM32平台中。…

外设驱动库开发笔记12:TSEV01CL55红外温度传感器驱动

有时候我们需要检测一些无法直接接触的器件的温度。为了实现这一需求&#xff0c;我们通常会选择红外温度传感器来实现这一功能。考虑到复用的问题&#xff0c;我们一般会将操作元器件的代码抽象为驱动函数以备调用。这里我们就来设计并实现TSEV01CL55红外温度传感器的驱动。 …

FreeRTOS应用开发笔记之一:FreeRTOS在STM32的移植

FreeRTOS是如今在小型嵌入式领域应用比较广泛的一种实时操作系统。它是一种开源且免费的操作系统&#xff0c;而且移植和使用都非常的简单。在这里我们将学习并移植FreeRTOS。 1、必要的准备 工欲善其事&#xff0c;必先利其器&#xff0c;在开始学习和移植之前&#xff0c;相…