这两天用来个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是否共地;文章来源:https://www.toymoban.com/news/detail-859148.html
感谢大家看到这里,祝大家生活愉快。文章来源地址https://www.toymoban.com/news/detail-859148.html
到了这里,关于stm32 AD7606 芯片驱动 hal库 spi通讯的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!