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的上升沿禁用(三态)引脚。例如,要读回数据寄存器,实施如下序列:

  1. 将0x020001写入输入寄存器。这采用选定数据寄存器配
    置用于读取模式的器件。
  2. 然后进行第二次写入:一个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原理图:
在这里插入图片描述

以下是一个电压电流双环控制的DSP程序的示例,供您参考: ```c #include <stdio.h> #include <stdlib.h> #include <math.h> #include "DSP2833x_Device.h" #include "DSP2833x_Examples.h" // 定义采样周期 #define Ts 0.0001 // 定义电压电流采样AD最大值 #define Vmax 4096 #define Imax 4096 // 定义PID参数 #define Kp_v 0.1 #define Ki_v 0.01 #define Kp_i 0.2 #define Ki_i 0.02 // 定义电压电流变量 int16 V, I; // 定义PID控制变量 float error_v, error_i; float integral_v, integral_i; float output_v, output_i; float setpoint_v, setpoint_i; // 定义DAC输出变量 int16 DAC_v, DAC_i; // 定义函数原型 void Init_ADC(); void Init_DAC(); void Init_PWM(); void Init_PID(); void ADC_ISR(); void PWM_ISR(); void main(void) { // 初始化系统 InitSysCtrl(); // 初始化ADC、DAC、PWM、PID等模块 Init_ADC(); Init_DAC(); Init_PWM(); Init_PID(); // 启用全局中断 EINT; ERTM; // 进入主循环 while(1) { // 获取电压电流采样值 V = AdcRegs.ADCRESULT0; I = AdcRegs.ADCRESULT1; // 计算电压电流PID控制量 error_v = setpoint_v - V; integral_v += Ki_v * error_v * Ts; output_v = Kp_v * error_v + integral_v; if(output_v > 1.0) output_v = 1.0; if(output_v < 0.0) output_v = 0.0; error_i = setpoint_i - I; integral_i += Ki_i * error_i * Ts; output_i = Kp_i * error_i + integral_i; if(output_i > 1.0) output_i = 1.0; if(output_i < 0.0) output_i = 0.0; // 输出DAC控制信号 DAC_v = output_v * Vmax; DAC_i = output_i * Imax; DacaRegs.DACVALS.all = DAC_v; DacbRegs.DACVALS.all = DAC_i; } } // 初始化ADC模块 void Init_ADC() { // 初始化ADC时钟 AdcRegs.ADCTRL2.bit.PRESCALE = 6; AdcRegs.ADCTRL3.bit.ADCCLKPS = 5; // 初始化ADC采样周期 AdcRegs.ADCCTL1.bit.ADCPWDN = 1; AdcRegs.ADCCTL1.bit.ADCBGPWD = 1; AdcRegs.ADCCTL1.bit.ADCREFPWD = 1; AdcRegs.ADCCTL1.bit.ADCENABLE = 1; AdcRegs.ADCCTL1.bit.ADCREFSEL = 0; AdcRegs.ADCCTL1.bit.INTPULSEPOS = 1; AdcRegs.ADCSOC0CTL.bit.TRIGSEL = 5; AdcRegs.ADCSOC0CTL.bit.CHSEL = 0; AdcRegs.ADCSOC0CTL.bit.ACQPS = 15; AdcRegs.ADCSOC1CTL.bit.TRIGSEL = 5; AdcRegs.ADCSOC1CTL.bit.CHSEL = 1; AdcRegs.ADCSOC1CTL.bit.ACQPS = 15; // 初始化ADC中断 PieCtrlRegs.PIEIER1.bit.INTx6 = 1; IER |= M_INT1; } // 初始化DAC模块 void Init_DAC() { // 初始化DAC时钟 DacaRegs.DACCTL.bit.DACREFSEL = 0; DacaRegs.DACCTL.bit.LOADMODE = 0; DacaRegs.DACOUTEN.bit.DACOUTEN = 1; DacbRegs.DACCTL.bit.DACREFSEL = 0; DacbRegs.DACCTL.bit.LOADMODE = 0; DacbRegs.DACOUTEN.bit.DACOUTEN = 1; } // 初始化PWM模块 void Init_PWM() { // 初始化PWM时钟 CpuSysRegs.PCLKCR2.bit.EPWM1ENCLK = 1; EPwm1Regs.TBCTL.bit.CTRMODE = 2; EPwm1Regs.TBPRD = 1500; EPwm1Regs.TBCTL.bit.PHSEN = 1; EPwm1Regs.TBPHS.half.TBPHS = 0; EPwm1Regs.TBCTL.bit.SYNCOSEL = 3; EPwm1Regs.CMPA.half.CMPA = 750; EPwm1Regs.AQCTLA.bit.CAU = 1; EPwm1Regs.AQCTLA.bit.CAD = 2; EPwm1Regs.CMPB.half.CMPB = 750; EPwm1Regs.AQCTLB.bit.CBU = 1; EPwm1Regs.AQCTLB.bit.CBD = 2; } // 初始化PID模块 void Init_PID() { // 初始化PID变量 setpoint_v = 500; setpoint_i = 200; error_v = 0; error_i = 0; integral_v = 0; integral_i = 0; output_v = 0; output_i = 0; } // ADC采样中断服务程序 interrupt void ADC_ISR() { AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; } // PWM中断服务程序 interrupt void PWM_ISR() { PieCtrlRegs.PIEACK.all = PIEACK_GROUP3; } ``` 以上是一个简单的电压电流双环控制的DSP程序示例,具体实现方式可能因硬件平台和控制算法不同而有所差异。程序的基本思路是通过ADC采集电压电流值,经过PID控制计算后输出控制信号到DAC模块,通过PWM模块控制电压电流输出到负载。需要注意的是,程序中的PID参数需要根据实际应用场景进行调整,以达到最佳的控制效果。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值