8. EBF-AD7192

8.1. 模块简介

EBF-AD7192 模块是野火科技推出的一款可配置为两路差分输入或四路伪差分输入的 24 位 Σ-Δ型模数转换模块。 本模块使用亚德诺半导体的 AD7192 芯片作为转换芯片,使用 4.9152MHz 的外部晶振提供外部时钟。本模块使用多层 PCB 设计, 搭配高精度电阻,测量范围可调, 最高可达 19 位分辨率 (实测最后五位有波动,适合取高19位)。

本模块使用 SPI 通信协议,供电电压为 5V。

AD7192模块

8.2. 参数特性

EBF-AD7192模块产品特性

特性

说明

电压

5V

电流

10mA

时钟

外部 4.9152MHz 晶振/片内 4.92MHz 时钟

测量范围

默认 ±3.3V(可通过修改分压电阻的值来修改测量范围)

输出速率

4.7Hz 至 4.8kHz

可选增益

1-128

工作温度

-40℃-85℃

结构尺寸

565mmx455mm×124mm(包含插件原件引脚高度)

输入通道

2 个差分 / 4 个伪差分输入通道

通信方式

三线式串行接口,与 SPI、QSPI、MICROWIRE 和 DSP 兼容

应用领域

压力测量、温度测量、数据采集等

8.3. 模块接口说明

本模块配套 STM32 驱动程序,可直接使用野火 STM32 系列开发板进行测试和使用,按照说明连接模块和开发板, 下载程序后可使用野火多功能调试助手连接开发板串口,查看串口输出信息。

EBF-AD7192模块接口说明

接口

说明

GND

电源地

SYNC

逻辑输入

CS

片选输入引脚。

SCLK

串行时钟输入。

DOUT

串行数据输出/数据就绪输出引脚。

DIN

ADC 输入移位寄存器的串行数据输入。

5V

电源 5V

AGND

模拟输入引脚 GND

AIN1

模拟输入引脚,结合 AGND 使用, 配置为伪差分输入;结合 AIN2 使用,作为全差分输入的正输入。

AIN2

模拟输入引脚,结合 AGND 使用, 配置为伪差分输入;结合 AIN1 使用,作为全差分输入的负输入。

AIN3

模拟输入引脚,结合 AGND 使用, 配置为伪差分输入;结合 AIN4 使用,作为全差分输入的正输入。

AIN4

模拟输入引脚,结合 AGND 使用, 配置为伪差分输入;结合 AIN3 使用,作为全差分输入的负输入。

8.4. 硬件连接

配套开发板硬件连接方式如下,

EBF-AD7192模块硬件连接

模块引脚

GND

CS

SCLK

DOUT

DIN

5V

F103MINI

GND

PA4

PA5

A6

A7

5V

F103 指南者

GND

PA4

PA5

A6

A7

5V

F103 霸道

GND

PA4

PA5

A6

A7

5V

F407 霸天虎

GND

PA3

PB3

PB4

PB5

5V

F407 骄阳

GND

PI0

PI1

PI2

PI3

5V

F429 挑战者

GND

PF6

PF7

PF8

PF9

5V

F767 挑战者

GND

PF6

PF7

PF8

PF9

5V

H743 挑战者

GND

PF6

PF7

PF8

PF9

5V

H743_PRO

GND

PD12

PC10

PC11

PD6

5V

H743 繁星

GND

PI0

PI1

PI2

PI3

5V

H750_PRO

GND

PD12

PC10

PC11

PD6

5V

8.5. 两路差分连续转换输出

8.5.1. 实验现象

这里以 STM32F103霸道开发板 为例,根据上面的硬件连接信息,将模块与开发板进行连接,再用USB线连接开发板与电脑,上电后打开野火多功能调试助手, 选择与开发板连接的端口号打开后将 AD7192-2路差分连续转换输出 例程编译下载至开发板。

上位机会打印如下信息:

adc_2

8.5.2. 例程介绍

本例程采用的硬件SPI,硬件SPI在《SPI基础知识》一文已经介绍,不再赘述,这里主要分析代码框架。

在编写AD7192模块驱动时,也要考虑更改硬件环境的情况。我们把AD7192模块引脚相关的宏定义到”bsp_ad7182.h”文件中, 在更改或移植的时候只用改宏定义就可以。

这里采用的SPI1,片选引脚为PA4,时钟引脚为PA5,MISO(主机输入从机输出)引脚为PA6,MOSI(主机输出从机输入)引脚为PA7,具体定义如下。

bsp_ad7192.h(霸道开发板例程)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
 // ... ...

 #define AD7192_SPIx                SPI1
 #define AD7192_SPIx_CLK_ENABLE()   __HAL_RCC_SPI1_CLK_ENABLE()
 #define AD7192_GPIO_CLK_ENABLE()   __HAL_RCC_GPIOA_CLK_ENABLE()
 #define AD7192_CS_Pin              GPIO_PIN_4   //CS
 #define AD7192_CS_GPIO_Port        GPIOA
 #define AD7192_SCK_Pin             GPIO_PIN_5   //SCLK
 #define AD7192_SCK_GPIO_Port       GPIOA
 #define AD7192_MISO_Pin            GPIO_PIN_6   //DOUT
 #define AD7192_MISO_GPIO_Port      GPIOA
 #define AD7192_MOSI_Pin            GPIO_PIN_7   //DIN
 #define AD7192_MOSI_GPIO_Port      GPIOA


 #define AD7192_SCLK_H              HAL_GPIO_WritePin(AD7192_SCK_GPIO_Port,AD7192_SCK_Pin,GPIO_PIN_SET)
 #define AD7192_SCLK_L              HAL_GPIO_WritePin(AD7192_SCK_GPIO_Port,AD7192_SCK_Pin,GPIO_PIN_RESET)

 #define AD7192_CS_ENABLE()         HAL_GPIO_WritePin(AD7192_CS_GPIO_Port,AD7192_CS_Pin,GPIO_PIN_RESET)
 #define AD7192_CS_DISABLE()        HAL_GPIO_WritePin(AD7192_CS_GPIO_Port,AD7192_CS_Pin,GPIO_PIN_SET)

 // ... ...

AD7192_Init函数为AD7192的初始化函数,将SCLK、MISO、MOSI均设置为复用推挽输出,将CS设置为推挽输出,再对SPI结构体进行配置。

bsp_ad7192.c(霸道开发板例程)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 void AD7192_Init(void)
 {
     GPIO_InitTypeDef GPIO_InitStruct;
     /* 使能SPI外设以及SPI引脚时钟 */
     AD7192_SPIx_CLK_ENABLE();
     AD7192_GPIO_CLK_ENABLE();

     GPIO_InitStruct.Pin = AD7192_SCK_Pin;                   // SCLK
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;                 // 复用推挽
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
     HAL_GPIO_Init(AD7192_SCK_GPIO_Port, &GPIO_InitStruct);

     GPIO_InitStruct.Pin = AD7192_MISO_Pin|AD7192_MOSI_Pin;  // MISO、 MOSI
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;                 // 复用推挽
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
     HAL_GPIO_Init(AD7192_MISO_GPIO_Port, &GPIO_InitStruct);

     GPIO_InitStruct.Pin = AD7192_CS_Pin;                    // CS
     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;             // 推挽输出
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
     HAL_GPIO_Init(AD7192_CS_GPIO_Port, &GPIO_InitStruct);

     /* SPI外设配置 */
     hspi_AD7192.Instance = AD7192_SPIx;
     hspi_AD7192.Init.Mode = SPI_MODE_MASTER;             //主模式
     hspi_AD7192.Init.Direction = SPI_DIRECTION_2LINES;   //全双工
     hspi_AD7192.Init.DataSize = SPI_DATASIZE_8BIT;       //数据位为8位
     hspi_AD7192.Init.CLKPolarity = SPI_POLARITY_HIGH;    //CPOL=1,HIGH
     hspi_AD7192.Init.CLKPhase = SPI_PHASE_2EDGE;         //CPHA为数据线的第二个变化沿
     hspi_AD7192.Init.NSS = SPI_NSS_SOFT;                 //软件控制NSS
     hspi_AD7192.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32; //32分频
     hspi_AD7192.Init.FirstBit = SPI_FIRSTBIT_MSB;        //最高位先发送
     hspi_AD7192.Init.TIMode = SPI_TIMODE_DISABLE;        //TIMODE模式关闭
     hspi_AD7192.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;  //CRC关闭
     hspi_AD7192.Init.CRCPolynomial = 7;                  //默认值,无效
     HAL_SPI_Init(&hspi_AD7192);                          //初始化

     /* 片选使能 */
     AD7192_CS_ENABLE();
 }

最后来看一下main函数的逻辑结构,先初始化一下系统时钟,HAL 库初始化,LED 端口初始化,串口1初始化, 按键初始化,然后初始化 AD7192 后将模块软件复位一下,再使用 ReadFromAD7192ViaSPI 函数对模块连接状态检测, 最后在 difference_continuous_conversion_voltage 中差分连续读取数据。

main.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 int main(void)
 {
     /* 系统时钟初始化成72MHz */
     SystemClock_Config();

     /* HAL 库初始化 */
     HAL_Init();

     /* LED 端口初始化 */
     LED_GPIO_Config();

     /* 配置串口1为:115200 8-N-1 */
     DEBUG_USART_Config();

     /* 按键初始化 */
     Key_GPIO_Config();

     /* AD7192初始化 */
     AD7192_Init();

     /* 软件复位 AD7192 */
     AD7192SoftwareReset();

     /* 延时10ms*/
     HAL_Delay(10);

     /* 通过SPI对AD7192执行一次读操作函数 */
     ReadFromAD7192ViaSPI(REG_ID, 1, AD7192Registers, REG_ID);

     if ((AD7192Registers[REG_ID] & 0x0F) != 0)
     {
         printf("AD7192 初始化失败请检查连接!\r\n");
         while(1);
     }
     printf("AD7192_ID = 0x%X\r\n", AD7192Registers[REG_ID]);

     /* 两路差分连续读实验 */
     difference_continuous_conversion_voltage();

     while (1)
     {
     }
 }

我们在主函数中用到了 ReadFromAD7192ViaSPI 和 difference_continuous_conversion_voltage 这两个函数, 首先我们先讲解一下 ReadFromAD7192ViaSPI 函数,这个函数的功能是读取 AD7192 内部寄存器的内容,我们可以看到它的第一个输入参数 RegisterStartAddress 指的就是寄存器地址。 其他输入参数的意思在代码里已经注明里,在这里主要讲解一下这个函数的整体思路。

该函数首先定义两个读写缓存数组 WriteBuf 和 ReadBuf,它们都是4个字节32位的,根据AD7192数据手册等资料我们知道,AD7192 片内有一个8位的通信寄存器和其他8个长度不一的寄存器, 而读取这8个长度不一的寄存器当中的那个最长的寄存器需要32位也就是4个字节的空间来保存读取到的数据,所以这两个数组的大小都是4个字节。

然后,写入通信寄存器,这是必要的步骤,因为与 AD7192 的所有通信都必须以对通信寄存器的写操作开始,写入通信寄存器的数据决定了下一个操作是对哪一个寄存器进行读操作还是写操作。 接着因为该函数是读寄存器数据,不需要写入数据,所以将 WriteBuf 数组的全部4个字节都赋值为NOP,也就是0。在 switch 语句里面判断要读取的是哪一个寄存器, 因为这8个寄存器长度不一,所以实际上要根据寄存器长度分成三种情况:8位寄存器(REG_ID、REG_COM_STA、REG_GPOCON)、24位寄存器(REG_MODE、REG_CONF、REG_OFFSET、REG_FS)、 还有数据寄存器(REG_DATA),数据寄存器本是24位的寄存器,但在使用多通道的时候读取时会附加上状态寄存器的内容来指定是哪个通道的数据,所以读取时可能读取到的不止是24位的数据。 具体请参考数据手册里的相关内容。

bsp_ad7192.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
 /**
   * @brief   通过SPI对AD7192执行一次读操作函数
   * @param   RegisterStartAddress :要读寄存器的起始地址(取值范围是从0x00——0x07)
   * @param   NumberOfRegistersToRead : 要读寄存器的个数
   * @param   DataBuffer : 要读入的值
   * @param   OffsetInBuffer : 缓存内偏移
   * @retval
   */
 unsigned char ReadFromAD7192ViaSPI(const unsigned char RegisterStartAddress, const unsigned char NumberOfRegistersToRead, uint32_t *DataBuffer, const unsigned char OffsetInBuffer)
 {
 //形参包括要读寄存器的起始地址RegisterStartAddress(取值范围是从0x00——0x07),要读取寄存器的个数,指向将读取AD7192寄存器数据存入的数组的指针(DataBuffer才是要读入的值其他是中间变量),
 //一般指向AD7192Registers[8],
 //const unsigned char OffsetInBuffer,字面意思是缓存内偏移,是指AD7192Registers[8]数组内部偏移,注意是数组哦,之前我们说过AD7192Registers[8]之所以定义8个元素,
 //一个寄存器对应AD7192Registers[8]数组的一个元素,互不干扰。

   unsigned char WriteBuf[4]={0,0,0,0}; //定义有4个元素的写缓存数组,每个数组元素占1个字节。
   unsigned char ReadBuf[4]={0,0,0,0};  //定义有4个元素的读缓存数组,每个数组元素占1个字节。
   unsigned char i;


   //Delay(0xFFFF);
   for(i=0; i < NumberOfRegistersToRead; i++)
   {
     WriteBuf[0] = WEN|RW_R|((RegisterStartAddress + i)<<3)|CREAD_DIS;        //写入通信寄存器;8位数据;下一个操作是对指定寄存器执行读操作。CREAD_DIS表示不使能连续读。
     //确定下一步进行寄存器读操作,那么写操作自然无效喽。
     AD7192readdata(WriteBuf, ReadBuf, 1);//首先通过写入通信寄存器来选定下一步要读取的寄存器
                                                 //然后再将WriteBuf清空
     WriteBuf[0] = NOP;
     WriteBuf[1]     = NOP;
     WriteBuf[2]     = NOP;
     WriteBuf[3]     = NOP;

     switch(RegisterStartAddress + i)
     {
       case REG_ID              :     //ID寄存器(0x04,8位寄存器)
       case REG_COM_STA :     //状态寄存器(0x00,8位寄存器)
       case REG_GPOCON  :     //通用数字输出控制寄存器(0x05,8位寄存器)
         AD7192readdata(WriteBuf, ReadBuf, 1);    //此3种情况是读取一个字节
         DataBuffer[OffsetInBuffer + i ] =  ReadBuf[0];
         break;

       case REG_MODE   :     //模式寄存器(0x01,24位)
       case REG_CONF   :     //配置寄存器(0x02,24位)
       case REG_OFFSET :     //失调寄存器(0x06,24位)
       case REG_FS             :     //满量程寄存器(0x07,24位)
         AD7192readdata(WriteBuf, ReadBuf, 3);             //此4种情况是读取3个字节
         DataBuffer[OffsetInBuffer + i ] = ReadBuf[0];
         DataBuffer[OffsetInBuffer + i ] = (DataBuffer[OffsetInBuffer + i ]<<8) + ReadBuf[1];
         DataBuffer[OffsetInBuffer + i ] = (DataBuffer[OffsetInBuffer + i ]<<8) + ReadBuf[2];
         break;

       case REG_DATA  :     //数据寄存器(0x03,24位或32位)
         if (AD7192Registers[REG_MODE] & DAT_STA_EN)       //多通道使能,将状态寄存器的内容附加到数据寄存器24位的数据上,所以是32位数据
           {
           AD7192readdata(WriteBuf, ReadBuf, 4);         //所以此情况是读4个字节
           DataBuffer[OffsetInBuffer + i ] = ReadBuf[0];
           DataBuffer[OffsetInBuffer + i ] = (DataBuffer[OffsetInBuffer + i ]<<8) + ReadBuf[1];
           DataBuffer[OffsetInBuffer + i ] = (DataBuffer[OffsetInBuffer + i ]<<8) + ReadBuf[2];
           DataBuffer[OffsetInBuffer + i ] = (DataBuffer[OffsetInBuffer + i ]<<8) + ReadBuf[3];
           break;
           }
         else
           {
           AD7192readdata(WriteBuf, ReadBuf, 3);        //do not transfer the status contents after read data register
           DataBuffer[OffsetInBuffer + i ] = ReadBuf[0];
           DataBuffer[OffsetInBuffer + i ] = (DataBuffer[OffsetInBuffer + i ]<<8) + ReadBuf[1];
           DataBuffer[OffsetInBuffer + i ] = (DataBuffer[OffsetInBuffer + i ]<<8) + ReadBuf[2];
           break;
           }

       default                        :
           break;

     }
   }

   return 0;
 }

接下来再看 difference_continuous_conversion_voltage 函数。这个函数其实非常简单。 它的功能是对2路差分通道:“AIN1_AIN2” 和 “AIN3_AIN4” 进行连续地AD转换,转换完成之后读取这两通道ADC转换结果并打印出来。 进入该函数里面首先会读取并打印8个 AD7192 片内寄存器的值,方便查看和调试,然后调用 ad7192_mode_cfg_reg 函数配置模式寄存器和配置寄存器, 进行内部校准,最后启动连续转换,开启连续读模式,在 while 循环里不断读取和打印两路差分通道的 ADC 电压值。

ad7192_test.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
 /**
   * @brief  2路差分连续转换电压实验
   * @param  无
   * @retval 无
   */
 void difference_continuous_conversion_voltage(void)
 {
   uint32_t ad_data = 0;
   float v = 0.0;
   uint32_t mode = 0, cfg = 0;

   printf("野火 AD9172 2路 差分连续转换读电压实验\r\n");

   /* 读 AD7192 寄存器 */
   ReadFromAD7192ViaSPI(REG_COM_STA, 8, AD7192Registers, REG_COM_STA);
   for(int i=0; i < 8; i++)
   {
     printf("AD7192Register[%d] = 0x%06X \r\n", i+REG_COM_STA , AD7192Registers[i+REG_COM_STA]);
   }

       /* 单次转换|使能状态传输|外部时钟|sinc4滤波器|禁用奇偶校验|时钟不分频|禁用单周期转换|禁用60Hz陷波|128 */
   mode = MODE_SING|DAT_STA_EN|EXT_XTAL|SINC_4|ENPAR_DIS|CLK_DIV_DIS|SINGLECYCLE_DIS|REJ60_DIS|1023;
   cfg  = CHOP_DIS|REF_IN1|AIN1_AIN2|BURN_DIS|REFDET_DIS|BUF_DIS|UB_BI|GAIN_1;
       /*禁用斩波|外部基准电压1|12差分通道(单)|禁用激励电流|禁用基准电压检测|禁用模拟输入缓冲|双极性模式|增益为128 */

   ad7192_mode_cfg_reg(mode, cfg);    // 配置模式寄存器和配置寄存器

   /* 校准 */
   AD7192InternalZeroScaleCalibration();
   AD7192InternalFullScaleCalibration();

   AD7192StartContinuousConvertion(AIN1_AIN2|AIN3_AIN4);    // 启动连续转换
   AD7192StartContinuousRead();
   while(1)
   {
     ad_data = AD7192ReadConvertingData();

     switch(ad_data & 7)
     {
       case 0:
         v = ((ad_data >> 8) / 8388608.0 - 1)*3.3;
         printf("AIN1_AIN2 = %fV\n", v);
       break;

       case 1:
         v = ((ad_data >> 8) / 8388608.0 - 1)*3.3;
         printf("AIN3_AIN4 = %fV\n", v);
       break;

     }
   }
 }

8.6. 四路单端连续转换输出

8.6.1. 实验现象

这里以 STM32F103霸道开发板 为例, 确认模块正确连接到开发板后打开模块配套例程的 AD7192-4路单端连续转换输出 , 使用MDK编译并下载该程序到对应开发板,复位开发板让程序运行。

打开野火多功能调试助手,配置串口为波特率115200、无校验、8数据位、1停止位,连接相应端口。 我们用一根杜邦线一头连接开发板的电位器插针,另一头依次连接模块的AIN1、AIN2、AIN3、AIN4并旋转电位器, 随后可以从串口调试助手看到电压值的变化。

改变 AIN1 通道电压:

实验现象

改变 AIN1-4 通道电压:

实验现象

注解

对于没有电位器的开发板,可直接将AIN1、AIN2、AIN3、AIN4连接到3V3或GND测量引脚电压。 模块在使用时要与被测设备做共地处理。

警告

请勿将模块输入通道的GND错误地与VCC相连,此操作会损坏模块和被测设备。

8.6.2. 例程介绍

本例程main函数的逻辑结构与 “AD7192-2路差分连续转换输出” 例程的是差不多的,就是先初始化一下系统时钟、HAL 库初始化,LED、串口1、按键初始化, 再初始化 AD7192 模块,然后软件复位一下 AD7192,再使用 ReadFromAD7192ViaSPI 函数对模块连接状态检测, 最后在 continuous_conversion_voltage 中连续读取数据。

main.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 int main(void)
 {
   /* 系统时钟初始化成168MHz */
   SystemClock_Config();

   /* HAL 库初始化 */
   HAL_Init();

   /* LED 端口初始化 */
   LED_GPIO_Config();

   /* 配置串口1为:115200 8-N-1 */
   DEBUG_USART_Config();

   /* 按键初始化 */
   Key_GPIO_Config();

   /* AD7192初始化 */
   AD7192_Init();

   /* 软件复位 AD7192 */
   AD7192SoftwareReset();

   HAL_Delay(10);
   ReadFromAD7192ViaSPI(REG_ID, 1, AD7192Registers, REG_ID);

   if ((AD7192Registers[REG_ID] & 0x0F) != 0)
   {
     printf("AD7192 初始化失败请检查连接!\r\n");
     while(1);
   }
   printf("AD7192_ID = 0x%X\r\n", AD7192Registers[REG_ID]);

   /* 4路ADC连续读实验 */
   continuous_conversion_voltage();

   while (1)
   {
   }
 }

调用的 continuous_conversion_voltage 函数其实也与2路差分连续转换电压实验中的 difference_continuous_conversion_voltage 函数时差不多的。 只不过本实验启动的是 4 个通道的伪差分信号输入转换。

ad7192_test.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
 /**
   * @brief  4路单端连续转换电压实验
   * @param  无
   * @retval 无
   */
 void continuous_conversion_voltage(void)
 {
   uint32_t ad_data = 0;
   float v = 0.0;
   uint32_t mode = 0, cfg = 0;

   printf("野火 AD9172 4 路连续转换读电压实验\r\n");

   /* 读 AD7192 寄存器 */
   ReadFromAD7192ViaSPI(REG_COM_STA, 8, AD7192Registers, REG_COM_STA);
   for(int i=0; i < 8; i++)
   {
     printf("AD7192Register[%d] = 0x%06X \r\n", i+REG_COM_STA , AD7192Registers[i+REG_COM_STA]);
   }

       /* 单次转换|使能状态传输|外部时钟|sinc4滤波器|禁用奇偶校验|时钟不分频|禁用单周期转换|禁用60Hz陷波|128 */
   mode = MODE_SING|DAT_STA_EN|EXT_XTAL|SINC_4|ENPAR_DIS|CLK_DIV_DIS|SINGLECYCLE_DIS|REJ60_DIS|1023;
   cfg  = CHOP_EN|REF_IN1|AIN1_AIN2|BURN_DIS|REFDET_DIS|BUF_DIS|UB_BI|GAIN_1;
       /*禁用斩波|外部基准电压1|12差分通道(单)|禁用激励电流|禁用基准电压检测|禁用模拟输入缓冲|双极性模式|增益为128 */

   ad7192_mode_cfg_reg(mode, cfg);    // 配置模式寄存器和配置寄存器

   /* 校准 */
   AD7192InternalZeroScaleCalibration();
   AD7192InternalFullScaleCalibration();

   AD7192StartContinuousConvertion(AIN1_COM|AIN2_COM|AIN3_COM|AIN4_COM);    // 启动连续转换

   while(1)
   {
     ad_data = AD7192ReadConvertingData();

     switch(ad_data & 7)
     {
       case 4:
         v = ((ad_data >> 8) / 8388608.0 - 1)*3.3;
         printf("AIN1_COM = %fV\n", v);
       break;

       case 5:
         v = ((ad_data >> 8) / 8388608.0 - 1)*3.3;
         printf("AIN2_COM = %fV\n", v);
       break;

       case 6:
         v = ((ad_data >> 8) / 8388608.0 - 1)*3.3;
         printf("AIN3_COM = %fV\n", v);
       break;

       case 7:
         v = ((ad_data >> 8) / 8388608.0 - 1)*3.3;
         printf("AIN4_COM = %fV\n", v);
       break;
     }
   }
 }

8.7. 补充说明

8.7.1. 如何测量高于3.3V的电压

提示

如何测量高于3.3V的电压呢?由于我们的 AD7192 模块硬件默认仅支持测量0~3.3V的电压,所以如果要测量高于3.3V的电压,需要更改模块硬件。查看模块原理图,我们需要更换输入端的分压电阻(R4, R5, R6, R7 和 R8, R9, R10, R11),尽可能换较大阻值的电阻,而且电阻精度越高越好,并且要保证测量电压经过电阻分压之后输入到 AIN1~AIN4 这四个输入端的电压不超过3.3V才行。就比如:如果需要 AIN1 这个通道测量最大为6.6V的电压,根据原理图,AIN1 = 6.6V * R8 / (R4+R8) <= 3.3V,由此可知 R4 >= R8,也就是 R8 的阻值应该小于等于 R4 的阻值,然后还要考虑流经R4和R8电流不能太大,还有考虑到电阻精度越高采样得到的电压值也就越准确,所以这两个电阻应该选用阻值尽可能高的、电阻精度也选用足够高的。另外:原理图上面 R8, R9, R10, R11 标的阻值是“NC”字样,这指的是模块板子上默认没有焊接这几个电阻,所以这个时候需要加焊合适的电阻。

8.7.2. 如何测量负电压

提示

当测量单端负电压信号,测量输出为负值到0V,该负值最大绝对值和测量单端正电压信号值相同。使用差分电压信号才能测量输出负到正值,伪差分不行。