最近项目调试使用到了AD7327芯片,为了防止后续忘记又得各种查资料,将自己这次调试的心得记录于此,如果错误请指正。谢谢。
开发环境:STM32F407VET6+AD7327 keil mdk 5.23
这款芯片有官方例程,代码开发起来省事儿好多。
-12位精度
- 支持软件选择量程:±10V、±5V、±2.5V,0-10V
-500ksps传输速率
-8个模拟量输入通道,既可配置为单个输入,也可配置为双路输入(传感器信号包含V+、V-两根信号线情况下)
-内置2.5V参考电压
此处可能导致后期程序配置好了寄存器,确定了量程,结果发现输入电压没到最大量程还差好远,结果已经到了fff最大值了,莫名其妙的,设计时需要注意!
硬件接线按照上图所示即可,注意以下几点:
-1. 1脚CS 片选。接mcu一个IO口即可;初始化芯片及数据转换读取时需要对该引脚输出高低电平
-2. 2脚DIN SPI通讯数据引脚,我使用STM32做主机控制AD7327芯片,因此,DIN脚接mcu的SPI_MOSI
-3. 18脚.DOUT SPI通讯数据引脚,DOUT脚接mcu的SPI_MISO
-4. 20脚SCLK SPI时钟,接SPI_SCK
-5. 17脚VDRIVE 接mcu的IO口,初始化后拉高即可。注意该引脚必须和VCC电压相同,最大也不能超过VCC+0.3V。我是用的 stm32f4芯片,因此VCC就是用的3.3V,所以该引脚直接接到stm32的一个IO口即可。
PS.注意硬件电路上的电容方向,我的板子上有个电容方向画反了,结果上电一个劲儿的发热。建议画板时一定要仔细,参考官方模板电路,焊好后通电没有发现什么问题也要摸一摸芯片和各个元器件看是不是有短路或者接错导致的发热现象出现
注意vin0-vin7,引脚号并不是按照顺序来的,我之前引脚号弄错了,还花了一番功夫,结果发现原理图上引脚号跟芯片文档对不上,还好电源引脚没有错误,不至于烧掉元器件。
AD7327包含4个寄存器,通过SPI发送一个16位的值来读写AD7237.
16位命令中,最高位第15位为写入命令,1有效
第14位与第13位用来选择对相应寄存器进行写入操作
控制寄存器注意以下几点:
1.coding 即为AD值的类型,0则输出补码,1则输出二进制原码
2.ref 电压参考。0则开启外部参考,不使用内部参考;1则使用内部参考作为AD输出值的参考
3.第12-10位,ADD2-ADD0地址选择,如下图所示。我需要8个独立输入通道,因此我配置ADD2-ADD0:111 mode1 = 0,mode0 = 0
4. Table11中电源模式选择中两个参数所示,00即为正常模式
5.sequence选择 我使用8个独立输入通道模式,并且开启sequence模式,即自动按照VIN0-VIN7顺序读取采集值并传输到总线,因此写入seq1=1,seq2=0即可
若要读取指定通道采集值,则写入seq1=0,seq2=1即可
选择相应输入采集通道值,输出到总线。我使用了8个通道,因此全选即可,VIN0-VN7全为1即可。
通过设置VinxA与VinxB,来配置相应通道的输入量程,我使用的8个通道均为±10V,因此配置为00即可。
通过向SPI总线写入0x00来读取AD值,返回的16位数据中,第15-13位为当前12位采集值的地址值,第12位为正负标志,若采用补码方式,采集到负电压,则该位为1.
具体ADD2-ADD0对应哪个通道,可以在上述4.1控制寄存器中table10中找到
官方例程中已经配置好各个寄存器地址,在ad7327.h文件中
#define AD_AUTO 1 //默认使用sequence模式,若想单独读取,改成0即可
uint8_t AD7327Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI1_Init();//SPI1初始化
SPI1_SetSpeed(SPI_BaudRatePrescaler_256);//spi速率选择
//PA4 Vdrive/PC4 CS 引脚初始化
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
AD_Vdrive_1;//Vdrive拉高
AD_CS_HIGH;//片选拉高,禁止AD读取,带配置完寄存器后拉低
delayms(20);
//量程选择
WriteToRangeRegister1 (IN10vCH0, IN10vCH1, IN10vCH2, IN10vCH3);
delayms(20);
WriteToRangeRegister2 (IN10vCH4, IN10vCH5, IN10vCH6, IN10vCH7);
delayms(20);
#if AD_AUTO //使用自动sequence模式,则初始化以下代码,否则无需执行
//我使用了8个通道,因此VIN0-VIN7全部要初始化
WriteToSequenceRegister (VIN0|VIN1|VIN2|VIN3|VIN4|VIN5|VIN6|VIN7);
delayms(20);
WriteToControlRegister(CH0|CH1|CH2|CH3|CH4|CH5|CH6|CH7, Mode0, Normal,
StraightBinary, Ref_En, Sequencer);
delayms(20);
#endif
return 0;
}
void SPI1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
GPIO_PinAFConfig(GPIOA , GPIO_PinSource5, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA , GPIO_PinSource6, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA , GPIO_PinSource7, GPIO_AF_SPI1);
//GPIOA 5 6 7
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,ENABLE);
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,DISABLE);
//SPI_I2S_DeInit(SPI1);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //空闲状态高电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //时钟第一个跳边沿数据被采样
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
}
使用sequence模式,配置完成后,系统则会按照VIN0-VIN7的顺序采集转换并送出
假如只需要读取某几个通道的数据,则初始化后选择相应通道即可。
uint16_t SPI1_ReadWriteByte(uint16_t TxData)
{
uint16_t returnData;
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){}
AD_CS_LOW;//拉低cs
SPI_I2S_SendData(SPI1, TxData); //发送命令
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){}
returnData = SPI_I2S_ReceiveData(SPI1);//读取SPI数据
AD_CS_HIGH;//拉高cs
return returnData;//返回SPI读取到的值
}
uint16_t ReadSequence (void)
{
uint16_t DataToWrite = 0x00;
uint16_t ReturnData = 0x00;
DataToWrite = 0x0000;
ReturnData = SPI1_ReadWriteByte (DataToWrite);
return ReturnData;
}
写入00命令,芯片便会按照之前的设置返回采集值
注意返回值第15-13位为通道值,第12位为正负标志
static uint16_t ReadCHx(uint16_t VINx, uint16_t CHx)
{
uint16_t value;
uint8_t i;
double sum = 0;
WriteToSequenceRegister (VINx);//读取VINx通道的值
delayms(10);
WriteToControlRegister(CHx, Mode0, Normal, StraightBinary, Ref_En, Sequencer);
delayms(10);
for(i = 0; i < N; i ++)//采集N次
{
ADValue_Original[i] = (ReadSequence() & 0X0FFF);//读取值后12位放入数组
sum += ADValue_Original[i];//N次值相加求和
}
value = (uint16_t) (sum / N);//取平均值
return value;
}
VINx与CHx为相同通道值。就是你想读通道1,就把x写1,读通道2,就把x改成2