
AD5422的使用(控制输出不同范围的电压电流值)
AD5422可以控制输出不同的电压、电流值。使用最基本的通信就是单片机对其读写数据,在此基础上进行如下操作进行驱动。1.复位2.初始化配置,例如电压、电流输出范围。3.根据要输出的电流值转换成给到AD5422的值,配置数据寄存器,从而输出电流。4.根据需要选择读取寄存器,检测故障等。
AD5422的使用
AD5422
一、AD5422简介
- AD5422是低成本、精密、完全集成、12/16位数模转换器(DAC),内置可编程电流源和可编程电压输出。
- 输出电流范围可编程设置为4 mA至20 mA、0 mA至20 mA或者超量程的0 mA至24 mA。
- 电压输出由一个独立引脚提供,该引脚可配置成提供0 V至5 V、0 V至10 V、±5 V或±10 V输出范围;所有范围均提供10%的超量程。
- 含有一个异步清零引脚(CLEAR),它可将输出设置为零电平/中间电平电压输出或将输出设置为选定电流范围的低端。
- 灵活的串行接口为SPI和MICROWIRE兼容型,可以采用三线式模式工作,从而极大地降低隔离应用的数字隔离要求。
简言之,就是可以控制输出不同的电流和电压,以匹配我们的需求。
可应用于在检测到不同信号时,调整不同输出。
二、AD5422的使用
AD5422通过一个多功能三线式串行接口受控,该接口以最高30 MHz的时钟速率工作,与SPI、QSPI™、MICROW-IRE和DSP标准兼容。
本文AD5422的使用主要通过SPI进行数据的读写传输。而后在不同寄存器中写值,来完成不通的操作。也可通过读数据来获取寄存器中写入的值。
书写代码时,最重要的就是写数据和读数据的操作。
1.写数据
下图为写入数据的时序图:
读数据完成输入移位寄存器操作。
输入移位寄存器为24位宽。数据在串行时钟输入SCLK的控制下首先作为24位字载入器件MSB中。数据在SCLK的上升沿逐个输入。输入寄存器包括8个地址位和16个数据位,如下表所示。
该24位字在LATCH引脚的上升沿无条件锁存。数据继续逐个输入,与LATCH的状态无关。在LATCH的上升沿,锁存输入寄存器中存在的数据;换言之,要在LATCH的上升沿之前逐个输入的最后24位是锁存的数据。上图给出了这种操作的时序图。
匹配上面时序图可以书写写数据的代码:
void WriteToAD5422(unsigned char count,unsigned char *buf)
{
unsigned char ValueToWrite = 0;
unsigned char i = 0;
unsigned char j = 0;
CLR_LATCH();
for ( i=count;i>0;i-- )
{
ValueToWrite = *(buf+i-1);
for (j=0; j<8; j++)
{
CLR_SCLK();
if(0x80 == (ValueToWrite & 0x80))
{
SET_SDIN(); //Send one to SDIN pin of AD5422
}
else
{
CLR_SDIN(); //Send zero to SDIN pin of AD5422
}
ad54x2_delay(1);
SET_SCLK();
ad54x2_delay(1);
ValueToWrite <<= 1; //Rotate data
}
}
CLR_SCLK();
ad54x2_delay(1);
SET_LATCH();
ad54x2_delay(20);
}
使用示例如下:
buf[2] = 0x56; //reset复位
buf[1] = 0x00;
buf[0] = 0x01;
WriteToAD5422(3,buf);
说明: 代码WriteToAD5422(3,buf)
中3
表示写入3个数据,buf
为写入数据地址。数据从buf[2]
开始写,依次次是buf[1]
和buf[0]
。使用时,buf[2]
放操作寄存器的地址,buf[1]
和buf[0]
为写入的数据。
2.读数据
下图为回读数据的时序图:
回读操作
通过在写入输入寄存器时设置地址字节和读取地址(见表9和表11)可调用回读模式。接下来AD5422的应该是一个NOP命令,该命令从先前寻址的寄存器逐个输出数据,如图3所示。寻址AD5422进行读取操作之后SDO引脚默认禁用;LATCH的上升沿使能SDO引脚预测逐个输出的数据。数据在SDO上逐个输出后,LATCH的上升沿禁用(三态)引脚。例如,要读回数据寄存器,实施如下序列:
- 将0x020001写入输入寄存器。这采用选定数据寄存器配
置用于读取模式的器件。 - 然后进行第二次写入:一个NOP条件,即0x000000。在
此写入期间,来自寄存器的数据在SDO线路上逐个输出。
匹配上面时序图可以书写读数据的代码:
void ReadFromAD5422(unsigned char count,unsigned char *buf)
{
unsigned char i = 0;
unsigned char j = 0;
unsigned char iTemp = 0;
unsigned char RotateData = 0;
CLR_LATCH();
for(j=count; j>0; j--)
{
for(i=0; i<8; i++)
{
CLR_SCLK();
RotateData <<= 1; //Rotate data
ad54x2_delay(1);
CLR_SDIN(); //Write a nop condition when read the data.
iTemp = GET_SDO(); //Read SDO of AD5422
SET_SCLK();
if(iTemp == 1)
{
RotateData |= 1;
}
ad54x2_delay(1);
}
*(buf+j-1)= RotateData;
}
CLR_SCLK();
ad54x2_delay(1);
SET_LATCH();
ad54x2_delay(20);
}
使用示例如下:
Temp[2] = 0x02; //读状态寄存器 Iout故障、压摆、过热
Temp[1] = 0x00;
Temp[0] = 0x00;
WriteToAD5422(3,Temp); //准备读状态寄存器
ReadFromAD5422(3,Temp); //Read STATUS REGISTER
说明:Temp[2]
写0x02
表示需要读取,后面Temp[1]
和Temp[0]
一起表示要读取的寄存器 ,如表9所示。00为读取状态寄存器,01为读取数据寄存器,10读取控制寄存器。 而后进行读数据操作。读到16位数据,分别放入Temp[1]
(高八位)和Temp[0]
(低八位)。
3.AD5422操作流程
1.操作复位
2.初始化配置控制寄存器
3.在数据寄存器中写入值,控制输出电流
4.可以读取寄存器的值,判断数据是否正确写入,例如读取状态寄存器检测故障。
下图是操作流程图:
(1)操作复位寄存器
写0x560001操作复位寄存器进行复位。复位寄存器描述如下:
如上图可知,只需操作复位寄存器D0位(复位),因此后16位输入0x0001。
示例代码:
/**
* 函数描述: 复位AD5422
* 参 数: 无
* 返 回 值: 无
*/
void RstAD5422(void)
{
unsigned char buf[4] = {0,0,0,0};
buf[2] = 0x56; //reset复位
buf[1] = 0x00;
buf[0] = 0x01;
WriteToAD5422(3,buf);
ad54x2_delay(100);
}
(2)操作控制寄存器进行初始化。
控制寄存器通过将输入移位寄存器的地址字设置为0x55寻址。要写入控制寄存器的数据输入D15至D0位置中,如表14所示。控制寄存器功能如表15所示。
写REXT设置此位可选择外部电流设置电阻,通过后三位更改范围。写OUTEN使能输出,写入后三位R1、R2、R3控制电流电压输出范围选择。
示例代码:
/**
* 函数描述: 初始化AD5422
* 参 数: u32CConfData: 工作模式
0x553000 -> 0V~5V
0x553001 -> 0V~10V
0x553002 -> -5V~+5V
0x553003 -> -10V~+10V
0x553005 -> 4mA~20mA
0x553006 -> 0mA~20mA
0x553007 -> 0mA~24mA
pDaModPin: 模块引脚
* 返 回 值: 无
*/
void ad5422Init(unsigned int u32CConfData)
{
unsigned char Temp[4] = {0,0,0,0};
RstAD5422();
Temp[2]=(u32CConfData>>16)&0xFF;//高位
Temp[1]=(u32CConfData>>8)&0xFF;
Temp[0]= u32CConfData&0xFF;//低位
WriteToAD5422(3,Temp);;
// printf("u32ConfData = 0x%X\n",u32ConfData);
}
(3)操作数据寄存器 控制输出电流值
数据寄存器通过将输入移位寄存器的地址字设置为0x01寻址。对于AD5412,要写入至数据寄存器的数据输入D15至D4位置中,而对于AD5422,输入D15至D0位置。
数据寄存器写入的值匹配输出的电压或是电流,存在一个计算公式如下:
电压输出
对以下公式进行变换,求出我们需要的D,也就是我们给到数据寄存器的值。其中DAC分辨率为16。VREFIN一般要求输入5V。REFOUT输出5V,一般直接连接到REFIN。
电流输出
电流输出同上,计算出我们需要的D值。其中DAC分辨率为16。
示例代码:
输出电流处理:
/**
* 函数描述: 初始化AD5422
* 参 数: current_type: 电流模式(可选以下值)
IOUT_4_20
IOUT_0_20
IOUT_0_24
output_current: 要输出的电流
* 返 回 值: 无
*/
uint16_t CurrentToData(unsigned char current_type, unsigned char output_current)
{
uint16_t data;
switch (current_type)
{
case IOUT_4_20: data = ((output_current-4)*65536)/16;break;
case IOUT_0_20: data = ((output_current)*65536)/20;break;
case IOUT_0_24: data = ((output_current)*65536)/24;break;
default: break;
}
return data;
}
/**
* 函数描述: 设置电流输出
* 参 数: current_type: 电流输出范围
可选:IOUT_4_20
IOUT_0_20
IOUT_0_24
output_current: 要输出的电流值
* 返 回 值:
* 备 注:
*/
void setCurrentOut(unsigned char current_type, unsigned char output_current)
{
unsigned char Temp[4] = {0,0,0,0};
uint16_t u16DaValue = 0u;
u16DaValue = CurrentToData(current_type,output_current);
Temp[2] = 0x01;
Temp[1] = (uint8_t)(u16DaValue>>8);
Temp[0] = (uint8_t)(u16DaValue);
WriteToAD5422(3,Temp);
}
输出电压处理:
uint16_t VoltageToData(unsigned char voltage_type, unsigned char output_voltage)
{
uint16_t data;
switch (voltage_type)
{
case VOUT_0_5: data = ((output_voltage)*65536)/(5*1);break;
case VOUT_0_10: data = ((output_voltage)*65536)/(5*2);break;
case VOUT_P_OR_M_5: data = ((output_voltage-(2*5/2))*65536)/(5*1);break;
case VOUT_P_OR_M_10: data = ((output_voltage-(4*5/2))*65536)/(5*1);break;
default: break;
}
return data;
}
/**
* 函数描述: 设置电压输出
* 参 数: voltage_type: 电流输出范围
可选: VOUT_0_5: 0 V至5 V电压范围
VOUT_0_10: 0 V至10 V电压范围
VOUT_P_OR_M_5: ±5 V电压范围
VOUT_P_OR_M_10: ±10 V电压范围
output_voltage: 要输出的电流值
* 返 回 值:
* 备 注:
*/
void setVoltageOut(unsigned char voltage_type, unsigned char output_voltage)
{
unsigned char Temp[4] = {0,0,0,0};
uint16_t u16DaValue = 0u;
u16DaValue = CurrentToData(voltage_type,output_voltage);
Temp[2] = 0x01;
Temp[1] = (uint8_t)(u16DaValue>>8);
Temp[0] = (uint8_t)(u16DaValue);
WriteToAD5422(3,Temp);
}
(4)读取寄存器写入值
例如读状态寄存器,读寄存器类似不再说明。
示例代码:
先写要读哪个寄存器,再进行读值,读到16位数据,分别放入Temp[1]
(高八位)和Temp[0]
(低八位)。
/**
* 函数描述: 检查 Iout故障、过热
* 参 数: 空
* 返 回 值: NO_FAULT 0 //无错
IOUT_FAULT 1 //过热
TEMP_FAULT 2 //Iout故 障
ALL_FAULT 3 //均有误
* 备 注:
*/
uint8_t CheckFault(void)
{
unsigned char Temp[4] = {0,0,0,0};
unsigned char IoutState=0;
unsigned char tempState=0;
Temp[2] = 0x02; //读状态寄存器 Iout故障、压摆、过热
Temp[1] = 0x00;
Temp[0] = 0x00;
WriteToAD5422(3,Temp); //准备读状态寄存器
ReadFromAD5422(3,Temp); //Read STATUS REGISTER
IoutState=(Temp[1])&0x01;
tempState=(Temp[1]>>2)&0x01;
if(!IoutState&&!tempState)
{
return NO_FAULT;
}
else if(IoutState&&!tempState)
{
return IOUT_FAULT;
}
else if(!IoutState&&tempState)
{
return TEMP_FAULT;
}
else
{
return ALL_FAULT;
}
}
也可以通过读寄存器反过来算以下,你写入的要输出的电压、电流值,但意义不太。如下:
uint16_t CheckCurrentOut(void)
{
unsigned char buf[4] = {0,0,0,0};
unsigned char IoutRange=0;
uint16_t data;
uint16_t output_current;
buf[2] = 0x02;
buf[1] = 0x00;
buf[0] = 0x02;
WriteToAD5422(3,buf);
ReadFromAD5422(3,buf); //读控制寄存器
IoutRange=(buf[1])&0x07;
ad54x2_delay(100);
buf[2] = 0x02; //读数据寄存器
buf[1] = 0x00;
buf[0] = 0x01;
WriteToAD5422(3,buf);
ReadFromAD5422(3,buf); //Read data REGISTER
data=(uint16_t) (buf[2] << 8) | buf[1];
switch (IoutRange)
{
case IOUT_0_20: output_current=(20/65536)*data;break;
case IOUT_0_24: output_current=(24/65536)*data;break;
case IOUT_4_20: output_current=(16/65536)*data+4;break;
default: break;
}
return output_current;
}
uint16_t CheckVoltageOut(void)
{
unsigned char buf[4] = {0,0,0,0};
unsigned char VoltageRange=0;
uint16_t data;
uint16_t output_voltage;
buf[2] = 0x02;
buf[1] = 0x00;
buf[0] = 0x02;
WriteToAD5422(3,buf);
ReadFromAD5422(3,buf);
VoltageRange=(buf[1])&0x07;
ad54x2_delay(100);
buf[2] = 0x02; //读数据寄存器
buf[1] = 0x00;
buf[0] = 0x01;
WriteToAD5422(3,buf);
ReadFromAD5422(3,buf); //Read data REGISTER
data=(uint16_t) (buf[2] << 8) | buf[1];
switch (VoltageRange)
{
case VOUT_0_5: output_voltage=5*1*(data/65536);break;
case VOUT_0_10: output_voltage=5*2*(data/65536);break;
case VOUT_P_OR_M_5: output_voltage=5*1*(data/65536)-(2*5/2);break;
case VOUT_P_OR_M_10: output_voltage=5*1*(data/65536)-(4*5/2);break;
default: break;
}
return output_voltage;
}
(5)总体代码调用
1.复位
2.初始化配置,例如电压、电流输出范围。
3.根据要输出的电流值转换成给到AD5422的值,配置数据寄存器,从而输出电流。
4.根据需要选择读取寄存器,检测故障等。
示例代码:
int main(void)
{
unsigned char buf[4] = {0,0,0,0};
Init_All_Periph();//初始化时钟、GPIO口等
RstAD5422();
ad5422Init(0x553005);//4-20mA
ad54x2_delay(100);
while(1)
{
setCurrentOut(IOUT_4_20,20);
AD5422_fault = CheckFault();
CheckCurrent = CheckCurrentOut();
}
}
另外不要忘记对时钟、GPIO口进行配置。
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*管脚配置说明:
PA8->CLEAR
PA3->LATCH
PA2->SCLK
PA1->SDIN
PA0->SDO
更改管脚时注意在ad5422_IO.c文件中更改相关宏定义
*/
/*设置SPI输出*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_8 ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*设置SPI输入*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
//配置系统时钟,使能各外设时钟
void RCC_Configuration(void)
{
SystemInit();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC
| RCC_APB2Periph_GPIOD /*| RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG| RCC_APB2Periph_AFIO*/
, ENABLE);
}
//配置所有外设
void Init_All_Periph(void)
{
RCC_Configuration();
GPIO_Configuration();
NVIC_Configuration();
}
总结
AD5422可以控制输出不同的电压、电流值。使用最基本的通信就是单片机对其读写数据,在此基础上进行如下操作进行驱动。
1.复位
2.初始化配置,例如电压、电流输出范围。
3.根据要输出的电流值转换成给到AD5422的值,配置数据寄存器,从而输出电流。
4.根据需要选择读取寄存器,检测故障等。
附ADC原理图:
更多推荐
所有评论(0)