ADC(一)—AD7683/AD7684/ADS8317

1.写在前面

项目需要用到模拟信号转换(ADC),由于精度、速度及准确度都要求比较高,故选择外设独立ADC芯片。外置独立ADC价格上都比较贵,首先考虑的是ADI的器件,经过综合价格、性能、采购渠道等,最终选择AD7683/AD7684。AD7683和AD7684的区别是前者是伪差分输入,后者是真差分输入,其他性能基本一致,程序兼容。ADS8317是德州仪器(TI)产的,与AD7684兼容,都是真差分输入,程序三者都兼容。

2.器件特点

主要特点:

1)转换精度:16bit

2)转换速率:100kSPS

3)独立供电和参与源

4)伪差分输入/真差分输入

5)3线spi控制接口

6)使用简单,无复杂的寄存器配置,直接通过spi获取转换数据

7)8 pin msop封装

3.驱动程序

通过芯片数据手册可以知道,对于驱动程序,只需将spi总线实现,即是成功了90%。上一篇博客中我有写到spi的封装过程和相关代码,那么这次使用起来应该非常方便和易理解,也体现下这样做的好处,具体查看上一篇文章:“spi抽象/硬件spi

1)驱动一个器件,首先是查看器件时序图,AD7683的spi时序图如图:

具体分析

a)读取一个完整的16bit数据,至少需要24个时钟周期;

b)有效数据为中间16bit,注意前后无效bit数据。

ADI的器件特别喜欢这样的非标spi(避专利?),很多人第一想法就是用模拟spi去读取,ADI官方一些例程大部分也是模拟spi,其实都是可以用硬件spi去实现,取其中有效数据即可。当然用模拟spi也很容易实现。下面是以stm32f1单片机为硬件平台,利用上一文章“spi模型/硬件spi”中的spi总线模型驱动AD7683。

#include "spi_hw.h"

//spi bus device
static struct spi_dev_device	ad7684_spi_dev[3];
struct spi_bus_device           spi_bus1;

static void ad7684_spi_cs0(unsigned char state)
{
        if (state)
                GPIO_SetBits(GPIOC, GPIO_Pin_6);
        else
                GPIO_ResetBits(GPIOC, GPIO_Pin_6);
}


static void ad7684_spi_cs1(unsigned char state)
{
        if (state)
                GPIO_SetBits(GPIOC, GPIO_Pin_8);
        else
                GPIO_ResetBits(GPIOC, GPIO_Pin_8);
}


static void ad7684_spi_cs2(unsigned char state)
{
        if (state)
                GPIO_SetBits(GPIOA, GPIO_Pin_11);
        else
                GPIO_ResetBits(GPIOA, GPIO_Pin_11);
}
//init
void ad7684_init(void)
{	
	GPIO_InitTypeDef GPIO_InitStructure;
	
	//spi cs 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC |RCC_APB2Periph_GPIOA ,ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_8;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(GPIOC, &GPIO_InitStructure);
	GPIO_SetBits(GPIOC,GPIO_Pin_6);
	GPIO_SetBits(GPIOC,GPIO_Pin_8);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_SetBits(GPIOA,GPIO_Pin_11);
	/*device init*/
	stm32f1xx_spi_init(0,0,&spi_bus1,8);
	//device 0
	ad7684_spi_dev[0].spi_cs 	= ad7684_spi_cs0;
	ad7684_spi_dev[0].spi_bus	= &spi_bus1;
	//device 1
	ad7684_spi_dev[1].spi_cs 	= ad7684_spi_cs1;
	ad7684_spi_dev[1].spi_bus	= &spi_bus1;
	//device 2
	ad7684_spi_dev[2].spi_cs 	= ad7684_spi_cs2;
	ad7684_spi_dev[2].spi_bus	= &spi_bus1;
}

/**
  * @brief  read ad data from ad7684.
  * @param  \index ad7684 device,1 or 2 or 3
  * @retval None
  */

u16 ad7684_read(u8 index)
{
	u8 send_buff[3] = {0},recv_buff[3] = {0};

	if(index < 1 || index > 3)
		return 0;
	spi_send_recv(&ad7684_spi_dev[index-1],send_buff,recv_buff,3);
	return ((((recv_buff[0] << 16) | (recv_buff[1] << 8) | recv_buff[2])>>2)&0xffff);
}

spi的配置模式:

a)速率:SPI_BaudRatePrescaler_8分频;

b)模式:L 1或者 H 3;

c)方向:全双工;

d)其他查看上一文章源码。

具体分析:

a)源码是之前AD7684程序,命名没有修改,程序百分百兼容;

b)上面是一根spi总线挂了3片AD7683,定义了3个spi设备结构体和一个spi总线结构体;初始化了3个片选;总线初始化由“spi_core.h”及“spi_hw.c”实现,无需再调试修改;

c)初始化函数是片选IO设置及指针赋值;

d)读函数,用的API是“spi_send_recv”,从时序图也可看出;此时的“发送”动作并不是真正的发送,只是用来产生接收数据的时钟信号;

——第一个参数即为前面初始化的3个设备之一

——send_buff:“发送”3个字节,产生24个时钟信号(非真正发送)

——recv_buff:接收3个字节的返回值,高位在前

e)返回值,“return ((((recv_buff[0] << 16) | (recv_buff[1] << 8) | recv_buff[2])>>2)&0xffff)”通过移位(<</>>)和与(&)动作获取16位有效的数据。

4.总结

1)主要是体现上一文章中,spi封装的好处,驱动一个新的spi器件,或者多个spi器件时,可以非常方便地实现;

2)学会看器件时序图,非标准spi大部分情况都可以用标准spi实现;

3)摆脱重复调试spi的无用工作;

4)方便移植驱动程序到新的平台。

5.相关源码

[1]  https://github.com/Prry/drivers-for-mcu

6.参考

[1]  http://blog.csdn.net/qq_20553613/article/details/78998617

 

posted @ 2018-01-12 14:47  Acuity  阅读(968)  评论(0)    收藏  举报