当前位置:   article > 正文

stm32 AD7606 芯片驱动 hal库 spi通讯_spi ad7606 rtos

spi ad7606 rtos

         这两天用来个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,所以我挑核心部分来讲解,以免混淆。 

  1. #define AD7606Cs1_High() HAL_GPIO_WritePin(CARD1_CS_GPIO_Port, CARD1_CS_Pin, GPIO_PIN_SET)
  2. #define AD7606Cs1_Low() HAL_GPIO_WritePin(CARD1_CS_GPIO_Port, CARD1_CS_Pin, GPIO_PIN_RESET)
  3. #define AD7606Rst_High(GPIO,GPIO_PIN) HAL_GPIO_WritePin(GPIO, GPIO_PIN, GPIO_PIN_SET)
  4. #define AD7606Rst_Low(GPIO,GPIO_PIN) HAL_GPIO_WritePin(GPIO, GPIO_PIN, GPIO_PIN_RESET)
  5. #define AD7606CONVST_High(GPIO,GPIO_PIN) HAL_GPIO_WritePin(GPIO, GPIO_PIN, GPIO_PIN_SET)
  6. #define AD7606CONVST_LOW(GPIO,GPIO_PIN) HAL_GPIO_WritePin(GPIO, GPIO_PIN, GPIO_PIN_RESET)
  7. typedef enum
  8. {
  9. AD7606_OS_0 = 0,
  10. AD7606_OS_1,
  11. AD7606_OS_2,
  12. AD7606_OS_4,
  13. AD7606_OS_8,
  14. AD7606_OS_16,
  15. AD7606_OS_32,
  16. AD7606_OS_64,
  17. AD7606_OS_NULL,
  18. }AD7606_OS;
  19. static void AD7606_Set_Os(AD7606_OS os_type)
  20. {
  21. GPIO_TypeDef *GPIO_OS0;
  22. GPIO_TypeDef *GPIO_OS1;
  23. GPIO_TypeDef *GPIO_OS2;
  24. uint16_t GPIO_PIN_OS0;
  25. uint16_t GPIO_PIN_OS1;
  26. uint16_t GPIO_PIN_OS2;
  27. uint8_t type = (uint8_t)os_type;
  28. GPIO_OS0 = MCU_OS0_card1_GPIO_Port;
  29. GPIO_OS1 = MCU_OS1_card1_GPIO_Port;
  30. GPIO_OS2 = MCU_OS2_card1_GPIO_Port;
  31. GPIO_PIN_OS0 = MCU_OS0_card1_Pin;
  32. GPIO_PIN_OS1 = MCU_OS1_card1_Pin;
  33. GPIO_PIN_OS2 = MCU_OS2_card1_Pin;
  34. HAL_GPIO_WritePin(GPIO_OS0,GPIO_PIN_OS0,(GPIO_PinState)(type&0x01));
  35. type = type>>1;
  36. HAL_GPIO_WritePin(GPIO_OS1,GPIO_PIN_OS1,(GPIO_PinState)(type&0x01));
  37. type = type>>1;
  38. HAL_GPIO_WritePin(GPIO_OS2,GPIO_PIN_OS2,(GPIO_PinState)(type&0x01));
  39. type = type>>1;
  40. }

配置采样频率

  1. typedef enum
  2. {
  3. AD7606_5V = 0,
  4. AD7606_10V,
  5. }AD7606_RANGE;
  6. static void AD7606_Set_Range(AD7606_RANGE RANGE)
  7. {
  8. GPIO_TypeDef *GPIO_RAGE;
  9. uint16_t GPIO_PIN_RAGE;
  10. GPIO_RAGE = MCU_RANGE_card1_GPIO_Port;
  11. GPIO_PIN_RAGE = MCU_RANGE_card1_Pin;
  12. HAL_GPIO_WritePin(GPIO_RAGE,GPIO_PIN_RAGE,(GPIO_PinState)RANGE);
  13. }

配置采样范围

  1. void AD7606Reset()
  2. {
  3. GPIO_TypeDef *GPIO_RST;
  4. uint16_t GPIO_PIN_RST;
  5. GPIO_RST = MCU_RESET_card1_GPIO_Port;
  6. GPIO_PIN_RST = MCU_RESET_card1_Pin;
  7. AD7606Rst_Low(GPIO_RST,GPIO_PIN_RST);
  8. AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
  9. AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
  10. AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
  11. AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
  12. AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
  13. AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
  14. AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
  15. AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
  16. AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
  17. AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
  18. AD7606Rst_High(GPIO_RST,GPIO_PIN_RST);
  19. AD7606Rst_Low(GPIO_RST,GPIO_PIN_RST);
  20. }

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

  1. void AD7606Init(AD7606_CARD drv)
  2. {
  3. AD7606_Set_Os(AD7606_OS_0,drv);
  4. AD7606_Set_Range(AD7606_5V,drv);
  5. AD7606Cs1_High();
  6. AD7606CONVST_High(MCU_CONVST_card2_GPIO_Port,MCU_CONVST_card2_Pin);
  7. AD7606Reset(drv);
  8. }

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

  1. void AD7606Start(AD7606_CARD drv)
  2. {
  3. GPIO_TypeDef *GPIO_CONVST;
  4. uint16_t GPIO_PIN_CONVST;
  5. GPIO_CONVST = MCU_CONVST_card1_GPIO_Port;
  6. GPIO_PIN_CONVST = MCU_CONVST_card1_Pin;
  7. AD7606CONVST_High(GPIO_CONVST,GPIO_PIN_CONVST);
  8. AD7606CONVST_LOW(GPIO_CONVST,GPIO_PIN_CONVST);
  9. AD7606CONVST_LOW(GPIO_CONVST,GPIO_PIN_CONVST);
  10. AD7606CONVST_LOW(GPIO_CONVST,GPIO_PIN_CONVST);
  11. AD7606CONVST_LOW(GPIO_CONVST,GPIO_PIN_CONVST);
  12. AD7606CONVST_LOW(GPIO_CONVST,GPIO_PIN_CONVST);
  13. AD7606CONVST_LOW(GPIO_CONVST,GPIO_PIN_CONVST);
  14. AD7606CONVST_LOW(GPIO_CONVST,GPIO_PIN_CONVST);
  15. AD7606CONVST_High(GPIO_CONVST,GPIO_PIN_CONVST);
  16. }

启动芯片采样转换

  1. uint16_t AD7606_values[8];
  2. void AD7606BusyIrqCallback(uint16_t *ad7606Val,uint8_t ad7606Chl)
  3. {
  4. AD7606Cs1_Low();
  5. HAL_SPI_Receive(&hspi5,(uint8_t *)ad7606Val,ad7606Chl,0x100);
  6. AD7606Cs1_High();
  7. AD7606Start(drv);
  8. }

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

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

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

Vin =  RANGE * ADC_NUM / 32768;

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

避坑

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/551792
推荐阅读
相关标签
  

闽ICP备14008679号