stm32 AD7606 芯片驱动 hal库 spi通讯

         这两天用来个ad7606 的芯片,结果硬件出来个问题,花了不少时间看这个芯片手册,干脆分享一下。

        引脚定义

        OS0 OS1 OS2

        这个三个引脚用于配置芯片的采样频率,只要不设置为111即可正常采样;

CONVSTA CONVSTB 这两个引脚用于启动芯片采集转换,默认高电平,上升沿后,采样芯片开始数据采集

RESET 用于开始采样前对芯片的复位,如果没有复位,后续采集的数据可能是乱码,只需要在开机的时候复位一次即可。

RD引脚即数据通讯时钟

CS引脚通讯使用,低电平有效

BUSY引脚,默认低电平,下降沿表示数据转换成功

DOUTA,DOUTB 使用spi通信只需要这两个引脚。

RANGE引脚,低电平表示转换的是5v的电压,高电平表示转换的是10v的电压,后续电压转换时后用到。

通讯时序

该芯片支持串行通讯和并行通讯,我使用的是串行通讯,即spi,时序图如下

其通讯的时序和spi一样,其中FRSTDATA引脚在串行通讯的时候可以忽略,没有明确说明spi的配置,但是根据时序图可以判断,sclk默认高电平,在下降沿读取数据,串行读取数据有两种方式,一种是如上的一条数据线(DOUTA 或者 DOUTB),直接读取八个数据,每个数据两个字节,另外一种是DOUTA 和 DOUTB 各读取四个数据,我使用的是第一种方式。

我们再看如何驱动AD7606芯片,如上时序,首先需要复位芯片,RESET引脚保持最少50ns的高电平,之后CONVSTA /B触发一个上升沿,开始数据转换,此时busy引脚拉高,表示在采集的数据的过程中,当busy引脚拉低,表示书采集结束,之后边可以通过spi通讯获取数据

以上是芯片的基本内容,介绍一下相关配置和代码

HAL配置

spi配置如上,需要注意的两点,通信的数据为16个字节,第二个使用的MSB模式。

代码讲解

代码部分,因为我的代码是使用了两个ad7606,所以我挑核心部分来讲解,以免混淆。 


#define AD7606Cs1_High()   HAL_GPIO_WritePin(CARD1_CS_GPIO_Port, CARD1_CS_Pin, GPIO_PIN_SET)
#define AD7606Cs1_Low()    HAL_GPIO_WritePin(CARD1_CS_GPIO_Port, CARD1_CS_Pin, GPIO_PIN_RESET)

#define AD7606Rst_High(GPIO,GPIO_PIN)  		HAL_GPIO_WritePin(GPIO, GPIO_PIN, GPIO_PIN_SET)
#define AD7606Rst_Low(GPIO,GPIO_PIN)     	HAL_GPIO_WritePin(GPIO, GPIO_PIN, GPIO_PIN_RESET)

#define AD7606CONVST_High(GPIO,GPIO_PIN)    HAL_GPIO_WritePin(GPIO, GPIO_PIN, GPIO_PIN_SET)
#define AD7606CONVST_LOW(GPIO,GPIO_PIN)    	HAL_GPIO_WritePin(GPIO, GPIO_PIN, GPIO_PIN_RESET)

typedef enum
{
	AD7606_OS_0 = 0,
	AD7606_OS_1,
	AD7606_OS_2,
	AD7606_OS_4,
	AD7606_OS_8,
	AD7606_OS_16,
	AD7606_OS_32,
	AD7606_OS_64,
	AD7606_OS_NULL,

}AD7606_OS;

static void AD7606_Set_Os(AD7606_OS os_type)
{
	GPIO_TypeDef 	*GPIO_OS0;
	GPIO_TypeDef 	*GPIO_OS1;
	GPIO_TypeDef 	*GPIO_OS2;
	
	uint16_t 		GPIO_PIN_OS0;
	uint16_t 		GPIO_PIN_OS1;
	uint16_t 		GPIO_PIN_OS2;
	
	uint8_t  		type = (uint8_t)os_type;
	

    GPIO_OS0 = MCU_OS0_card1_GPIO_Port;
	GPIO_OS1 = MCU_OS1_card1_GPIO_Port;
	GPIO_OS2 = MCU_OS2_card1_GPIO_Port;
	GPIO_PIN_OS0 = MCU_OS0_card1_Pin;
	GPIO_PIN_OS1 = MCU_OS1_card1_Pin;
	GPIO_PIN_OS2 = MCU_OS2_card1_Pin;


	
	HAL_GPIO_WritePin(GPIO_OS0,GPIO_PIN_OS0,(GPIO_PinState)(type&0x01));
	type = type>>1;
	HAL_GPIO_WritePin(GPIO_OS1,GPIO_PIN_OS1,(GPIO_PinState)(type&0x01));
	type = type>>1;
	HAL_GPIO_WritePin(GPIO_OS2,GPIO_PIN_OS2,(GPIO_PinState)(type&0x01));
	type = type>>1;


}

配置采样频率


typedef enum
{
	AD7606_5V = 0,
	AD7606_10V,

}AD7606_RANGE;

static void AD7606_Set_Range(AD7606_RANGE RANGE)
{
	GPIO_TypeDef 	    *GPIO_RAGE;
	uint16_t 			GPIO_PIN_RAGE;
	

    GPIO_RAGE = MCU_RANGE_card1_GPIO_Port;
	GPIO_PIN_RAGE = MCU_RANGE_card1_Pin;

	
	HAL_GPIO_WritePin(GPIO_RAGE,GPIO_PIN_RAGE,(GPIO_PinState)RANGE);	
}

配置采样范围

void AD7606Reset()
{
	GPIO_TypeDef 	*GPIO_RST;
	uint16_t 		GPIO_PIN_RST;


	GPIO_RST = MCU_RESET_card1_GPIO_Port;
	GPIO_PIN_RST = MCU_RESET_card1_Pin;

	
    AD7606Rst_Low(GPIO_RST,GPIO_PIN_RST);
    AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
    AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
    AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
    AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
    AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
    AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
    AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
    AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
    AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
    AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
    AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
    AD7606Rst_Low(GPIO_RST,GPIO_PIN_RST);
	
}

复位芯片代码,其中的    AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);事实上只是在凑时间,如果你的芯片时钟频率很高的话,建议量一下这边RESET引脚复位时间够不够。

void AD7606Init(AD7606_CARD drv)
{
		AD7606_Set_Os(AD7606_OS_0,drv);
		AD7606_Set_Range(AD7606_5V,drv);
		AD7606Cs1_High();
		AD7606CONVST_High(MCU_CONVST_card2_GPIO_Port,MCU_CONVST_card2_Pin);
		AD7606Reset(drv);

}

初始化芯片,配置采样频率,采样范围,拉高对应的引脚,复位芯片。

void AD7606Start(AD7606_CARD drv)
{
	
	GPIO_TypeDef 	*GPIO_CONVST;
	uint16_t 		GPIO_PIN_CONVST;


	GPIO_CONVST = MCU_CONVST_card1_GPIO_Port;
	GPIO_PIN_CONVST = MCU_CONVST_card1_Pin;

	AD7606CONVST_High(GPIO_CONVST,GPIO_PIN_CONVST);
	AD7606CONVST_LOW(GPIO_CONVST,GPIO_PIN_CONVST);
	AD7606CONVST_LOW(GPIO_CONVST,GPIO_PIN_CONVST);
	AD7606CONVST_LOW(GPIO_CONVST,GPIO_PIN_CONVST);
	AD7606CONVST_LOW(GPIO_CONVST,GPIO_PIN_CONVST);
	AD7606CONVST_LOW(GPIO_CONVST,GPIO_PIN_CONVST);
	AD7606CONVST_LOW(GPIO_CONVST,GPIO_PIN_CONVST);
	AD7606CONVST_LOW(GPIO_CONVST,GPIO_PIN_CONVST);
	AD7606CONVST_High(GPIO_CONVST,GPIO_PIN_CONVST);


}

启动芯片采样转换

uint16_t 	AD7606_values[8];

void AD7606BusyIrqCallback(uint16_t *ad7606Val,uint8_t ad7606Chl)
{


	    AD7606Cs1_Low();
		HAL_SPI_Receive(&hspi5,(uint8_t *)ad7606Val,ad7606Chl,0x100);
		AD7606Cs1_High();

		
		AD7606Start(drv);

}

这边有两个注意点,ad芯片在转换期间也是可以读取数据,但是有相关的时序限制,我这边没有对busy进行判断是因为在实际使用的情况下,我是有延时的,足够芯片的数据转换,第二个注意点,我们是要读取16位的数据,所以需要定义uint16_t 类型的数组,在实际通过HAL_SPI_Receive读取的时候在强制转换成uint8类型的指针。

最后是数据转化,我简单说一下

简单来说,你采集的数值是 一个二级制补码,你需要将采集值转换成原码,再通过

Vin =  RANGE * ADC_NUM / 32768;

这个式子中,Vin是我们要采集的电压,RANGE为我们设置的数值,为5v或者10v,ADC_NUM是我们采集的数值并且转换成源码。

避坑

在实际过程中,驱动代码倒是没有说明特别大的问题,但是,我卡了好几天,因为获取的数据是0x7fff,无论怎么样都是这个数据,最后发现是硬件原理图画的有问题,并且REFGNG也不对,如果有朋友遇到类似的情况,优先检查硬件,尤其是几个GND是否共地;

感谢大家看到这里,祝大家生活愉快。

代码放在 gitee上

https://gitee.com/zxys8/ad7606_-project.git

这里面有ad7606和w5500驱动样例

代码思路本来是想用接口函数来写的,但是以前水平不够,最终写的不伦不类的,也懒的再改了,权当给大家当一个参考吧

AD7606.c中是核心代码,通过调用接口函数结构体来操作设备

drv_AD7606.c是驱动代码,需要再这里面实现对应的接口函数,主要是将对应的gpio赋值

user_AD7606.c是用户代码,调用是真真采集数据和转换数据的地方

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值