目录
一 项目背景
二 原理说明
三 设计实现——定时器初始化
四 设计实现——PWM输出
五 梳理总结
一 项目背景
目前使用了TI的DAC芯片DAC7311,将MCU的4-20/0-20数据转化电压信号,经由一系列电路,最终输出4-20/0-20mA电流输出。
但是限于成本和货期的问题,考虑将该款DAC换成国产的其他方案。
找到一款客益电子(http://www.guestgood.com/)的APC/PAC芯片,可以将输入的PWM信号占空比转化为模拟电流输出,这边选用的PAC芯片为GP8301。(APC替代ADC的方案参考之前的一篇文章【嵌入式】HC32F定时器PWM捕获+APC芯片实现模拟AD采样)
二 原理说明
【1】APC/PAC芯片原理:
A=Analog,P=PWM,C=Convertor。
APC=Analog to PWM Convertor 是一种模拟信号转PWM信号的专用芯片,PAC=PWM to Analog Convertor是一种PWM信号转模拟信号的专用芯片。
在信号调理领域,经常需要面对模拟量信号的传输、采集、控制等问题,传统的信号链芯片包括模数转换器(ADC)、数模转换器(DAC)、运算放大器(OpAmp)、比较器(Comparator)等等,它们扮演着模数混合信号处理的主要角色。信号链芯片的功能基础而强大,经过精心的设计后能形成多种多样优秀的信号处理电路。但即便如此,在很多应用领域,传统的信号链芯片依然存在瓶颈和制约,无法达到理想的电路性能和技术指标,尤其在一些需要PWM信号的领域,传统的方法遇到许多困难。
客益电子发明了一种新型的模拟信号处理的专用芯片,它实现了模拟信号与PWM信号间的高精度转换功能,我们称它为APC(Analog to PWM Convertor)和PAC(PWM to Analog Convertor)。
【2】芯片特性:
这边采用的芯片GP8301将输入占空比0-100%信号线性转化为0-20mA模拟电流输出:
电流公式为:
相比4-20mA,我这边需要一个更大范围的输出,然后通过两点校准获得精准的4-20mA的信号,所以选择Rset为2KΩ 0.1%,这样的话,输入占空比0-100%对应输出为0-25mA,其中当输入为16%占空比时,对应输出4mA,当输入为80%占空比时,对应输出20mA,并且支持两点校准,满足设想。
【3】输出原理:
做好定时器PWM输出初始化,预设周期值为:
这样,在64分频定时器中,输出频率为50*2=100Hz的PWM,占空比根据设置的比较值确定,例如当比较值为4200时,即输出4mA需要的占空比16%。当比较值为21000时,即输出20mA需要的占空比80%。
三 设计实现——定时器初始化
由上面的方案,首先需要实现的是定时器输出PWM功能的初始化,我这边使用的主控芯片为小华的HC32F460,选用其高级控制定时器Timer6进行PWM输出,端口选用PB13,其功能是TIMER6_1_PWMB(Timer6的1单元B通道):
初始化程序如下:
/* TIMER6 unit and clock definition */
#define TIMER6_UNIT1 (M4_TMR61)
#define TIMER6_UNIT1_CLOCK (PWC_FCG2_PERIPH_TIM61)
#define TIMER6_COUNT_OVERFLOW1 (SystemCoreClock/2U/64U/50U) //100Hz
/* TIMER6 channel B Port/Pin definition */
#define TIMER6_UNIT1_CHB (Timer6GenCompareB)
#define TIMER6_UNIT1_CHB_PORT (PortB)
#define TIMER6_UNIT1_CHB_PIN (Pin13)
#define TIMER6_UNIT1_CHB_FUNC (Func_Tim6)
void Timer6_PAC_Config(void) //PAC测试,比较电阻Rset调整为2K,根据公式Iout = Duty * 5 * 10 / Rset,输出占空比0-100%对应输出0-25mA
{
stc_timer6_basecnt_cfg_t stcTIM6BaseCntCfg;
stc_timer6_port_output_cfg_t stcTIM6PWMxCfg;
stc_timer6_gcmp_buf_cfg_t stcGCMPBufCfg;
stc_port_init_t stcPortInit;
stc_irq_regi_conf_t stcIrqRegiConf;
MEM_ZERO_STRUCT(stcTIM6BaseCntCfg);
MEM_ZERO_STRUCT(stcTIM6PWMxCfg);
MEM_ZERO_STRUCT(stcGCMPBufCfg);
MEM_ZERO_STRUCT(stcPortInit);
MEM_ZERO_STRUCT(stcIrqRegiConf);
PWC_Fcg2PeriphClockCmd(TIMER6_UNIT1_CLOCK, Enable);
PORT_SetFunc(TIMER6_UNIT1_CHB_PORT, TIMER6_UNIT1_CHB_PIN, TIMER6_UNIT1_CHB_FUNC, Disable); //Timer61 PWMA
stcTIM6BaseCntCfg.enCntMode = Timer6CntSawtoothMode; //Sawtooth wave mode
stcTIM6BaseCntCfg.enCntDir = Timer6CntDirUp; //Counter counting up
stcTIM6BaseCntCfg.enCntClkDiv = Timer6PclkDiv64; //Count clock: pclk0
Timer6_Init(TIMER6_UNIT1, &stcTIM6BaseCntCfg); //timer6 PWM frequency, count mode and clk config
Timer6_SetPeriod(TIMER6_UNIT1, Timer6PeriodA, TIMER6_COUNT_OVERFLOW1); //period set
Timer6_SetGeneralCmpValue(TIMER6_UNIT1, TIMER6_UNIT1_CHB, TIMER6_COUNT_OVERFLOW1 * 4 / 5); //Set General Compare RegisterA Value
stcTIM6PWMxCfg.enPortMode = Timer6ModeCompareOutput; //Compare output function
stcTIM6PWMxCfg.bOutEn = true; //Output enable
stcTIM6PWMxCfg.enPerc = Timer6PWMxCompareLow; //PWMA port output Low level when CNTER value match PERAR
stcTIM6PWMxCfg.enCmpc = Timer6PWMxCompareHigh; //PWMA port output High level when CNTER value match with GCMAR
stcTIM6PWMxCfg.enStaStp = Timer6PWMxStateSelSS; //PWMA output status is decide by STACA STPCA when CNTER start and stop
stcTIM6PWMxCfg.enStaOut = Timer6PWMxPortOutLow; //PWMA port output set low level when CNTER start
stcTIM6PWMxCfg.enStpOut = Timer6PWMxPortOutLow; //PWMA port output set low level when CNTER stop
stcTIM6PWMxCfg.enDisVal = Timer6PWMxDisValLow;
Timer6_PortOutputConfig(TIMER6_UNIT1, Timer6PWMB, &stcTIM6PWMxCfg);
/*start timer6*/
Timer6_StartCount(TIMER6_UNIT1);
}
四 设计实现——PWM输出
通过Timer6_SetGeneralCmpValue设置比较值,即可以实现对输出PWM的占空比进行控制:
uint16_t PacPeriod = 0u, PacDuty = 0u;
unsigned short analog_output_k;
unsigned short analog_output_b;
//无符号数限值处理
#define VARIABLE_LIMIT(var, lower, upper) \
do{ \
if((var) < (lower)) \
{ \
(var) = (lower); \
} \
else if((var) > (upper)) \
{ \
(var) = (upper); \
} \
/**************************************************************************
* 函数名称: analogOutputHandle
* 功能描述: 模拟量输出处理
* 输入参数: p_analog_ctrl->output_ui为需要输出的模拟值,范围0-20mA
* 输出参数:
* 返 回 值:
* 其它说明:
**************************************************************************/
void analogOutputHandle(int dac, STRU_ANALOG_IO_CTRL *p_analog_ctrl)
{
float acc_adjust; //输出精度校准
//...
//参数acc_adjust即为输出占空比,可以通过下面公式通过analog_output_k与analog_output_b值进行校准
acc_adjust = (((float)((analog_output_k - analog_output_b) / 16.0) / 1000.0) * (p_analog_ctrl->output_ui - 4) + (float)(analog_output_b / 10000.0)) / 5;
PacDuty = PacPeriod - acc_adjust * PacPeriod;
VARIABLE_LIMIT(PacDuty, 0, PacPeriod-1); //占空比控制在0-100%。同时占空比最大值必须比周期值小,否则会出问题。这边取周期值减一。
Timer6_SetGeneralCmpValue(TIMER6_UNIT1, TIMER6_UNIT1_CHB, PacDuty);
return ;
}
五 梳理总结
这个PAC替代DAC用于输出模拟量的方案,使用比较简单方便,而且由于该PAC内置12位高精度的DAC,所以输出的精度也在需求的范围之内。