【嵌入式】HC32F定时器PWM输出+PAC芯片实现模拟DA输出

目录

一 项目背景

二 原理说明

三 设计实现——定时器初始化

四 设计实现——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)。 

【嵌入式】HC32F定时器PWM输出+PAC芯片实现模拟DA输出_第1张图片

【2】芯片特性:

        这边采用的芯片GP8301将输入占空比0-100%信号线性转化为0-20mA模拟电流输出:

【嵌入式】HC32F定时器PWM输出+PAC芯片实现模拟DA输出_第2张图片

         电流公式为:

IOUT=Duty*5V*10/Rset

        相比4-20mA,我这边需要一个更大范围的输出,然后通过两点校准获得精准的4-20mA的信号,所以选择Rset为2KΩ 0.1%,这样的话,输入占空比0-100%对应输出为0-25mA,其中当输入为16%占空比时,对应输出4mA,当输入为80%占空比时,对应输出20mA,并且支持两点校准,满足设想

【3】输出原理:

        做好定时器PWM输出初始化,预设周期值为:

Timer6CountOverflow = 168000000/2/64/(100/2)=26250

        这样,在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,所以输出的精度也在需求的范围之内。

你可能感兴趣的:(嵌入式,c语言,单片机,DAC,PWM,嵌入式硬件)