1.AD7616介绍
1.1 概述:
1.2 产品特性:
1.3 引脚配置:
注: 引脚的功能配置详情需查看AD7616数据手册
1.4 时序图
本次学习只使用了AD7616硬件模式下并行接口读取数据,而对于AD7616软件模式、串行接口、并行接口写操作未作介绍。
2.解析数据手册
2.1 引脚连接
35 REFSEL | GND | DI | 使用外部基准电压 | |
36 RESET | PB11 | DI | 复位输入,低有效 | |
37 SEQEN | +3.3V | DI | 通道序列器使能 | |
38 HW_RNGSEL1 | GND | DI | 硬件模式 | 模拟输入范围±2.5V |
39 HW_RNGSEL0 | +3.3V | DI | ||
40 SER/PAR | GND | DI | 并行接口选择输入 | |
41-48 DB0-7 | PD0-PD7 | O/I | 并行输出 | |
53-60 DB8-15 | PD8-PD15 | |||
61 WR/BURST | +3.3V | DI | 突发模式使能 | |
62 SCLK/RD | PE9 | DI | 并行数据读取控制输入 | 如果CS,RD均为逻辑低电平,则使能输出总线 |
63 CS | PE10 | DI | 片选 | |
64-66 CHSEL0-2 | +3.3V | DI | ||
67 BUSY | PE12 | DO | 输出繁忙 | CONVST 上升沿之后,此引脚变为逻辑高电平,表示转换过程已开始。 BUSY 输出保持高电平,直到当前选定通道的转换过程完成为止。BUSY 下降沿表示转换数据正被锁存至输出数据寄存器,稍后便可供读取。数据必须在 BUSY 变为低电平之后读取。当 BUSY 信号为高电平时,CONVST 的上升沿不起作用。 |
68 CONVST | PE11 | DI | 通道组A/B的转换开始输入 | 在序列器模式下,当突发模式或过采样模式使能时,为了执行所需数量的转换,只需 CONVST 从低电平变为高电平一次。 |
注意:未与GPIO连接的引脚,已经与开发板焊死,写代码时不需要为其配置。
2.2工作模式
2.3数字接口
2.4复位功能
2.5 *序列器
2.6 *突发序列器
3. 驱动代码编写
3.1 配置引脚功能
配置AD7616引脚功能时需要注意,BUSY引脚类型为DO(只具备输出功能),而对于主芯片(GD32)来说,只需要配置为输入模式即可。而AD7616数据总线DB0-DB15为数字输出,对于主芯片而言并非模拟输入,而是数字输入(因为AD7616通过模拟输入引脚采集模拟数据,芯片内部已经将模拟量转换为数字量)。
//GPIO引脚初始化
void AD7616_PinInit(void)
{gpio_init(GPIOE,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_9|\GPIO_PIN_10|GPIO_PIN_11);//通用推挽输出gpio_init(GPIOE,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,GPIO_PIN_12);//浮空输入gpio_init(GPIOB,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_11);//通用推挽输出gpio_init(GPIOD,GPIO_MODE_IPU|GPIO_MODE_IPD,GPIO_OSPEED_50MHZ,GPIO_PIN_ALL);//PD所有引脚为上下拉输入
}
//配置BUSY引脚外部中断
void AD7616_BUSY_ExtiConfig(void)
{gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOE,GPIO_PIN_SOURCE_12);//选择gpio引脚中断源exti_init(EXTI_12,EXTI_INTERRUPT,EXTI_TRIG_FALLING);//下降沿触发exti_interrupt_flag_clear(EXTI_12);//清除中断标志位exti_interrupt_enable(EXTI_12);//启用中断线
}
3.2 AD7616初始化配置
本文使用的主芯片(GD32F10x)时钟频率为108MHZ,
而延时函数AD7616_Delay_9ns(uint32_t ns)只是通过while循环做空操作。
/*\brief: AD7616复位功能配置\param: mode : 复位模式AD7616_ALL_RESER :完全复位AD7616_PART_RESER :部分复位\retval: none
*/
void AD7616_Reser(uint8_t mode)
{switch(mode){case AD7616_ALL_RESER: //完全复位AD7616_RESET_0;AD7616_Delay_9ns(140);AD7616_RESET_1;delay_1ms(15);break;case AD7616_PART_RESER: //部分复位AD7616_RESET_0;delay_1us(40);AD7616_RESET_1;AD7616_Delay_9ns(5);break;default:break;}
}//AD7616初始化
void AD7616_Init(void)
{AD7616_PinInit();//引脚初始化AD7616_BUSY_ExtiConfig();//配置BUSY引脚外部中断//AD7616_RESET_1;//AD7616_Reser(AD7616_PART_RESER);//部分复位AD7616_Reser(AD7616_ALL_RESER);//完全复位//未使能输出总线AD7616_RD_1;AD7616_CS_1;AD7616_CONVST_0;//拉低CONVST电平
}
3.3启动一次转换
//AD值转换为实际温度值
float AD7616_ad_TO_temp(uint16_t i,const uint16_t ad)
{return (float)(AD7616_CH_member[i].A*ad*ad + AD7616_CH_member[i].B*ad + AD7616_CH_member[i].C);
}
/*AD7616转换函数
*/
void EXTI10_15_IRQHandler(void)
{if(RESET!=exti_interrupt_flag_get(EXTI_12)){exti_interrupt_flag_clear(EXTI_12);//清除中断标志位uint16_t i;AD7616_CONVST_0;for(i=0;i<AD7616_CHANNEL_VAL;i++){//printf("BUSY=%d\n",gpio_input_bit_get(GPIOE,GPIO_PIN_12));//启动转换后BUSY为低电平AD7616_CS_0;AD7616_RD_0; //低电平时间>30nsAD7616_Data[i]=AD7616_GET_DATA();//读取数据AD7616_RD_1; //高电平时间>10nsAD7616_CS_1;AD7616_Delay_9ns(3);}AD7616_READ_STATE=AD7616_STATE_READABLE;//可读//AD7616_CONVST_0;}
}
//启动转换
void AD7616_StartConvst(void)
{memset(AD7616_Data,0,AD7616_CHANNEL_VAL);//清空缓存//AD7616_CONVST_0;//AD7616_Delay_9ns(1);AD7616_CONVST_1;//printf("BUSY=%d\n",gpio_input_bit_get(GPIOE,GPIO_PIN_12));//未启动转换时BUSY为高电平
}
/*\brief: 启动多次转换,并求取各通道AD平均值\param: *ad 接收AD值的地址count 启动次数\retval: ERROR 超时 SUCCESS 成功转换
*/ErrStatus AD7616_Convst_Average(const uint32_t count)
{uint32_t i,j;uint32_t sum[AD7616_CHANNEL_VAL]={0};for(i=0;i<count;i++){AD7616_READ_STATE=AD7616_STATE_UNREADABLE;//不可读AD7616_StartConvst();//开始转换j=0;while(AD7616_READ_STATE!=AD7616_STATE_READABLE)//等待转换完成{AD7616_Delay_9ns(1);j++;if(j==500000) return ERROR;//超时}for(j=0;j<AD7616_CHANNEL_VAL;j++){sum[j]+=AD7616_Data[j];}}//取平均值for(i=0;i<AD7616_CHANNEL_VAL;i++){AD7616_AD[i]=sum[i]/count;AD7616_Temp[i]=AD7616_ad_TO_temp(i,AD7616_AD[i]);//转换温度}return SUCCESS;
}
3.4 头文件
#ifndef _AD7616_H_
#define _AD7616_H_#include "gd32f10x.h"
#include "flash.h"
#include <string.h>
#include <stdlib.h>
/*Pin:RD -- PE9 CS -- PE10 片选CONVST -- PE11 BUSY -- PE12 RESET -- PB11 DB0~DB15 -- PD0~PD15
*/
/* Pin define */
#define AD7616_RESET_0 gpio_bit_reset(GPIOB,GPIO_PIN_11)
#define AD7616_RESET_1 gpio_bit_set(GPIOB,GPIO_PIN_11)
#define AD7616_RD_0 gpio_bit_reset(GPIOE,GPIO_PIN_9)
#define AD7616_RD_1 gpio_bit_set(GPIOE,GPIO_PIN_9)
#define AD7616_CS_0 gpio_bit_reset(GPIOE,GPIO_PIN_10)
#define AD7616_CS_1 gpio_bit_set(GPIOE,GPIO_PIN_10)
#define AD7616_CONVST_0 gpio_bit_reset(GPIOE,GPIO_PIN_11)
#define AD7616_CONVST_1 gpio_bit_set(GPIOE,GPIO_PIN_11)
#define AD7616_BUSY_1 gpio_bit_set(GPIOE,GPIO_PIN_12)
#define AD7616_BUSY_LEVEL() gpio_input_bit_get(GPIOE,GPIO_PIN_12)
#define AD7616_INPUT_DB(x) gpio_input_bit_get(GPIOD,BIT(x))//数据引脚0-15
#define AD7616_GET_DATA() gpio_input_port_get(GPIOD) //获取PE端口值#define AD7616_CHANNEL_VAL 16#define AD7616_ALL_CH 16
#define AD7616_V0A 0
#define AD7616_V0B 1
#define AD7616_V1A 2
#define AD7616_V1B 3
#define AD7616_V2A 4
#define AD7616_V2B 5
#define AD7616_V3A 6
#define AD7616_V3B 7
#define AD7616_V4A 8
#define AD7616_V4B 9
#define AD7616_V5A 10
#define AD7616_V5B 11
#define AD7616_V6A 12
#define AD7616_V6B 13
#define AD7616_V7A 14
#define AD7616_V7B 15#define AD7616_ALL_RESER 0 //完全复位
#define AD7616_PART_RESER 1 //部分复位
#define AD7616_AD_GET_COUNT 6//转换次数
#define AD7616_STATE_UNREADABLE 0 //转换开始
#define AD7616_STATE_READABLE 1 //可读
/* parameter *//*AD7616结构体参数temp=A*x*x + B*x + C
*/
typedef struct
{uint32_t number;//通道编号float A; float B;float C;
}AD7616_parameter;
extern AD7616_parameter AD7616_CH_member[AD7616_CHANNEL_VAL];
extern uint16_t AD7616_Data[AD7616_CHANNEL_VAL];//AD值
extern uint16_t AD7616_AD[AD7616_CHANNEL_VAL];//AD平均值
extern float AD7616_Temp[AD7616_CHANNEL_VAL];//温度值/* function */
void AD7616_Init(void);
void AD7616_StartConvst(void);//启动转换
ErrStatus AD7616_Convst_Average(const uint32_t count);//启动多次转换并取平均值#endif
3.5实验结果
未接温度传感器时,所有通道输出最大值0x7FFF(第15位为符号位)。
接入一个热敏电阻时,采集到的AD值便随温度改变,可通过校准,把AD值转换为实际温度。
4.总结
本文为学习AD7616采集数据所做,数据手册很长,并不是单看时序图就能完成驱动编写,但看懂了数据手册之后,就会发现代码挺简单的。需要注意的便是BUSY引脚,它只有输出状态,不要被(手动模式)干扰。在CONVST引脚上升沿时,BUSY便会自动变为高电平,数据转换完成时,BUSY变为低电平。
本文中没有提供主函数代码,需要读取数据时,直接调用
ErrStatus AD7616_Convst_Average(const uint32_t count);启动多次转换函数,然后直接从数组中依次读取数据(AD值或温度值)即可。校准值需要自己实际测量写入。
最后,文章中可能存在着问题,欢迎各位大佬不吝赐教。
2022年11月29日