目录
主控芯片:STM32F103RCT6、ADS8866转换芯片、使用HAL库进行开发。
ADS8866是一款16位、100kSPS单端输入模数转换器(ADC)。ADS8866是一款16位,100kSPS,单端输入,模数转换器 (ADC)。此器件以2.5V至5V的外部基准运行,从而在无需额外的信号调节情况下提供宽信号范围。此基准电压设置独立于,并且可超过,模拟电源电压(AVDD)。此器件提供一个SPI兼容串口,此串口也支持菊花链操作以实现多个器件级联。 此器件支持-0.1V至VREF + 0.1V范围的单极单端模拟输入。器件运行针对极低功耗运行进行了优化。功耗直接与速度成比例。这个特性使得ADS8866非常适合于低速应用。
以下链接是其详细的数据手册:
https://download.csdn.net/download/qq_45143522/89216266
我这边是使用STM32F103RCT6的SPI3与ADS8866进行通讯的。引脚对应如下: stm32f103引脚 ADS8866引脚 PA15 CONVST作为片选引脚使用 PB3 SCLK时钟引脚 PB4 DOUT(MISO) PB5 DIN(MOSI) 由于ADS8866分为三线模式和四线模式,我这边使用的是三线模式,即不使用DIN(MISO),硬件设计时可以根据ads8866的datesheet手册根据三线模式的要求将DIN引脚直接和DVDD相连使其保持高电平即可。
这里如何使用STM32CubeMX配置SPI3的驱动,可以自己查找相关的资料进行配置,这里不再配置,直接看程序框架及驱动代码。
主函数main程序架构: uint8_t ads8866_buf[2]; //用来存储ads8866发送来的数据 int main() { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); //初始化GPIO,片选引脚CONVST MX_SPI3_Init(); //初始化SPI3的相关引脚及配置SPI3 while(1) { get_ads8866_data(&hspi3,ads8866_buf); //stm32读取ads8866转换数据接口函数 HAL_Delay(2000); } } MX_GPIO_Init函数主要内容如下: MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLDOWN; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA,&GPIO_InitStruct); //这里将CONVST初始化为低电平是由ADS8866的通讯时序决定的,后面会说。 HAL_GPIO_WritePin(GPIOA,GPIO_PIN_15,GPIO_PIN_RESET); } MX_SPI3_Init函数主要内容如下: void MX_SPI3_Init(void) { hspi3.Instance = SPI3; hspi3.Init.Mode = SPI_MODE_MASTER; //主模式 hspi3.Init.Direction = SPI_DIRECTION_2LINES; hspi3.Init.DataSize = SPI_DATASIZE_8BIT; //8位帧结构 hspi3.Init.CLKPolarity = SPI_POLARITY_LOW; //SCLK的空闲状态为低电平 hspi3.Init.CLKPhase = SPI_PHASE_2EDGE; //在SCLK的第2个跳变沿开始传输数据 hspi3.Init.NSS = SPI_NSS_SOFT; hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; //4分频值 频率为36MHz/4 = 9MHz hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB; //数据传输从MSB位开始 hspi3.Init.TIMode = SPI_TIMODE_DISABLE; hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; hspi3.Init.CRCPolynomial = 7; if(HAL_SPI_Init(&hspi3) != HAL_OK) { Error_Handler(); } __HAL_SPI_ENABLE(&hspi3); } 其中: 时钟极性CPOL和时钟相位CPHA两项的设置依然是和ADS8866芯片的通讯时序有关,后面会说到。 HAL_SPI_MspInit(SPI_HandleTypeDef * spiHandle)函数的主要内容如下: void HAL_SPI_MspInit(SPI_HandleTypeDef * spiHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(spiHandle->Instance == SPI3) { __HAL_RCC_SPI3_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); //PB3--SCLK PB4--DOUT(MISO) PB5--DIN(MOSI) GPIO_InitStruct.Pin = GPIO_PIN_3 | GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB,&GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_4; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOB,&GPIO_InitStruct); } }
至此,SPI3的HAL库驱动就基本完成了,接着需要与ADS8866芯片进行通讯,来获取adc采集的数据。
在进行ADS8866驱动开发前,我们需要阅读芯片的datesheet手册来确定通讯的时序。如下图是数据手册里的三线模式的通讯时序图:
根据数据手册及时序图,我们可以知道: 1、在三线模式下,CONVST引脚与DVDD引脚相连,并且将CONVST引脚作为片选引脚使用。 2、CONVST引脚的上升沿会使得DOUT进入三态的状态,并且开始与ads8866建立会话。 3、CONVST引脚由低变高后最少要持续t_conv-max的时间,这个参数为8.8微秒。 4、当建立会话的过程结束之后就进入传输数据的阶段。 5、在CONVST的下降沿,DOUT退出三态状态,ADS8866开始向外传输数据,数据传输从最高位开始。 6、之后的数据传输都是在SCLK的下降沿到来时进行传输。数据在SCLK的双边沿均有效。 7、将片选信号CONVST拉高或者在第16次SCLK时钟的下降沿到来之后DOUT将重新回到三态的状态。 除了以上信息,我们根据时序图还可以知道: CONVST片选信号的初始状态为低电平。 SCLK时钟线的空闲状态为低电平。即时钟极性CPOL = 0。 在SCLK的第2个跳变沿(下降沿)开始传输数据,即时钟相位CPHA为1。 这三点对我们编写程序非常重要。
经过以上对ADS8866芯片的时序分析之后,我们想要通过SPI通讯读取ADS8866芯片采集转换后的adc数据将十分简单。 具体程序代码如下:
//使用到的微秒级延时函数 void delay_us(uint32_t us) { uint8_t i = 0; while(us--) { i = 12; while(i--); } } //获取ADS8866的转换数据 void get_ads8866_data(SPI_HandleTypeDef *hspi,uint8_t *buf) { //建立会话 ADC_CS3_HIGH; //片选信号初始化为低,在DIN为高的时候,片选信号给个上升沿开始与adc芯片建立会话 delay_us(10); //片选信号拉高后的持续时间要超过8.8微秒 //传输数据 ADC_CS3_LOW; //片选信号拉低开始传输数据 HAL_SPI_Receive(hspi,buf,2,100); //接收ADS8866发送的2字节数据到buf缓存中 }