AD7606与STM32F103ZET6的串行通信

  本文是AD7606与STM32的串行通信的学习心得,可帮助你快速入门AD7606。

时序图的理解

  图一

 图二

 图三

 图四

 根据图一,一些引脚在置高或置低时的上升或下降沿会受时间影响,因此在编写代码时,一些对引脚的操作需要放在一起,且延时函数不能随意使用。
 图二是整体的一个时序框图,大体的逻辑就是在使用AD7606之前要先复位一下,复位信号是高电平有效,时间至少为50ns。然后就是对采样速率和量程的配置,也就是对OS0,OS1,OS2和RANGE脚的配置,然后再对一些引脚进行一些初始化(也可以直接在GPIO配置的时候进行初始化)。之后就是发送启动信号,也就是将CVA,CVB同时拉低至少25ns后再拉高(启动信号上升沿有效)。之后AD7606开始转换,BUSY信号线自动拉高,如果BUSY信号线拉低则表明转换已经完成。转换完成后将CS片选信号线拉低才可以进行数据读取,读取完成后将CS片选信号线拉高即可。(还有一种是在转换时进行数据读取的,由于对于采样速率要求并不是特别的高,所以也没有深入研究)
 图三是串行通讯对数据进行读取的时序框图,讲的是在AD7606转换完成后将CS片选信号拉低后的操作。转换完成后CS片选信号拉低,开始读取数据。由于是16位8通道ADC,一次读取一个字节,所以一个通道需要读取两次数据。因为是高位在前低位在后所以就是先读取的是MSB,后读取的LSB,数据需要SCLK下降沿有效。经过16*8 = 128个SCLK读取后已经全部将ADC转换的数据全部读取完了,之后就可以将CS片选信号拉高了(由于串行通讯FRSTDATA数据线可以不接,所以并没有用到这个脚)。
 图四是对一个字节的读取,顺序也就是现将时钟线拉高后拉低然后读取一下当前的值然后拉高,重复八次就是一个字节的读取。(MSB的最高位为符号位,若为1则数据为负数,若为0则数据为正数)

计算公式的理解


 图上为计算公式,VIN为输入量,REF为ADC所选择的基准电压,一般使用内部基准电压REF=2.5V。上下两公式的选择,是由J2所接量程所决定。
 在程序中的计算公式:

 DB data[i]为AD所输出的二进制补码,可通过此方式计算出输入电压。

硬件电路连接

  串行工作方式:

 串行模式工作时,相关引脚连接方式:

rst复位引脚
convstB可以接在一起,当同时置低时 进行模拟量采样并处理
convstA
STby控制工作模式,正常工作时一般直接接高电平
OS12用于选择过采样倍率
OS11
OS10
busy标志位,标志AD正在进行模拟量采样并处理
cs片选信号,置低后标志可以开始输出模拟量
rdCS置低后的每一个上升沿输出每一位模拟量
DoutA(DB7)数据输出线
D15直接接地
SER连接3.3 ,用于设定ADC为串行工作模式
5V
GND
RANGEJ2用于选择输入电压的范围,影响计算公式
PB7数据口,ADC最终通过此口给单片机发送数据

实物连接图

软件设计

  部分参数的定义

uint8_t read_flag=1;s16 DB_data[8]={0};u8 i;int32_t line=0;int32_t reminder[32][32]={0};uint8_ttemp;

  初始化函数

void AD7606_Init(void){convstA_Set;//同时拉高convstB_Set;delay_ms(1);STby_Set;//一直置高clk1_Set;//针对CLK和CS的操作尽可能地放在一起cs1_Set;clk2_Set;//根据自己的需求连接几个CS和CLK 这里使用了四个ADCcs2_Set;clk3_Set;cs3_Set;clk4_Set;cs4_Set; OS10_Reset;//过采样模式的初始化OS11_Reset;OS12_Reset;AD7606_reset();delay_ms(1);AD7606_startconvst();}

  开始转化函数
 COA 与COB均是上升沿触发,因此需要同时拉低再拉高。

void AD7606_startconvst(void){convstA_Reset;convstB_Reset;delay_us (1);convstA_Set;convstB_Set;}

  复位函数
 REST是上升沿触发,因此先拉低再拉高再拉低。

void AD7606_reset(void) { rst_Reset;delay_us (1);rst_Set; delay_us(1);rst_Reset; }

  读数据函数,此处定义STM32的CO口与单片机的PB7数据线相连,读取AD转换的数据。

voidAD7606_read_data1(s16 * DB_data) {u8 i,j; for(i=0;i<8;i++)//循环8次是因为有8个通道{u16 DB_data1 = 0;//用于存储读出引脚的值cs1_Reset; //CS和CLK的引脚控制函数尽量放在一起delay_us(1);for(j=0;j<16;j++)//循环16次是因为寄存器可以存16位{clk1_Reset;//CLK拉低开始输出delay_us(1);DB_data1 = ((u16)(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_0))<< (15-j)) + DB_data1 ;//AD输出为二级制补码,此处涉及部分寄存器的知识clk1_Set;delay_us(1);}cs1_Set;DB_data[i] = (u16)DB_data1;//此处大致意思为将AD通道输出的值赋给一个存储内容为8的数组}read_flag++;//多ADC使用时的标志位} 

  遍历ADC函数
 注:1.此处的函数是使用一块STM32驱动四块AD7606,read_flag的使用是为了使相应的AD7606工作,如果你使用一块AD7606那么你看一个if里的函数就足够了。
 2.函数中包含的部分变量为全局变量,因此没有在函数的局部进行定义。

void throught_all(void){AD7606_startconvst();temp = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5);//判断BUSY线的反馈的值来决定对AD的操作while(temp == 0){delay_us(1);temp = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5);}if(read_flag==1){AD7606_read_data1(DB_data); //此函数返回一个数组,此数组的每一位中存放着相应通道采样的值,之后对该数组进行相应操作即可for(i=0;i<8;i++){delay_us(100);line=2*i+1;/if(flag==0){column=m+1;}if(flag==1){column=m+17;}reminder[line-1][column-1]=(DB_data[i]*10000.0/32768);//计算公式的体现}}if(read_flag==2)//以下为其他3个AD的操作程序{AD7606_read_data2(DB_data);for(i=0;i<8;i++){delay_us(100);line=2*i+17;if(flag==0){column=m+1;}if(flag==1){column=m+17;}reminder[line-1][column-1]=(DB_data[i]*10000.0/32768);}}if(read_flag==3){AD7606_read_data3(DB_data); for(i=0;i<8;i++){delay_us(100);line=2*i+2;if(flag==0){column=m+1;}if(flag==1){column=m+17;}reminder[line-1][column-1]=(DB_data[i]*10000.0/32768);}}if(read_flag==4){AD7606_read_data4(DB_data); for(i=0;i<8;i++){delay_us(100);line=2*i+18;if(flag==0){column=m+1;}if(flag==1){column=m+17;}reminder[line-1][column-1]=(DB_data[i]*10000.0/32768);}}}