【嵌入式】HC32F定时器PWM捕获+APC芯片实现模拟AD采样

文章介绍了使用客益电子的APC芯片GP9101代替TI的ADC(ADS1018)进行模拟量4-20mA/0-20mA采样的方案。通过APC将模拟信号转换为PWM,然后利用MCU的定时器进行捕获,实现模拟量到数字信号的转换。虽然精度不如原ADC,但方案简化了设计且适用于精度要求不高的场景。
摘要由CSDN通过智能技术生成

目录

一 项目背景

二 原理说明

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

四 设计实现——PWM捕获

五 梳理总结


一 项目背景

        目前使用了TI的ADC采样芯片ADS1018实现模拟量4-20mA/0-20mA的采样,原理是将外部输入的模拟量信号4-20mA,经由并联的两个100Ω电阻,转换为0.2-1V的电压信号传递到模数转换芯片的入口,再由ADS1018(全量程设置为FS=±1.024V,对应码为0x7FF)将0.2-1V电压信号转换为数据码0x190-0x7D0(400-2000),即可以将外部输入4-20mA与内部采集数据400-2000对应上,如下图所示:

        但是限于成本和货期的问题,考虑将该款ADC换成国产的其他方案。

        又因为这边AD采样的是DCS或者PLC发出来的4-20mA/0-20mA信号,必须需要外加隔离,所以不能采用MCU自带的ADC外设直接采样的方案(MCU的ADC外设没有隔离功能,必须外接隔离芯片才行),所以该方案舍弃。

        找到一款客益电子(http://www.guestgood.com/)的APC/PAC芯片,可以将输入的模拟信号转化为PWM波的占空比输出,这边选用的APC芯片为GP9101。

二 原理说明

【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】芯片特性:

        这边采用的芯片GP9101将输入0-VCC的信号转化为占空比0-100%,频率默认为1KHz的PWM波输出

【3】采样原理:

        参考上面ADC采样的思路,将外部输入的模拟量信号4-20mA,经由并联的两个400Ω电阻,转换为0.8-4V的电压信号传递到APC芯片的入口,再由GP9101(供电Vcc=5V)将0.8-4V电压信号转换为占空比为16-80%的PWM交由MCU进行捕获,即可以将外部输入4-20mA与内部采集数据对应上,如下图所示:

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

        由上面的方案,首先需要实现的是定时器捕获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)
/* 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_APC_Config(void)  //APC测试,采样0.8V-4V电压,APC输出16%-80%占空比,经过64分频定时器捕获,输出比较值为420-2100(输入K/B需要调整为2100/400)
{
    stc_timer6_basecnt_cfg_t         stcTIM6BaseCntCfg;
    stc_timer6_port_input_cfg_t      stcTIM6CapxCfg;
    
    MEM_ZERO_STRUCT(stcTIM6BaseCntCfg);
    MEM_ZERO_STRUCT(stcTIM6CapxCfg);
    
    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/64(256分频也可以试一试)
    Timer6_Init(TIMER6_UNIT1, &stcTIM6BaseCntCfg);                          //timer6 PWM frequency, count mode and clk config

    Timer6_SetPeriod(TIMER6_UNIT1, Timer6PeriodA, 0xFFFFu);               //Period set

    stcTIM6CapxCfg.enPortSel  = Timer6xCHB;                            //Capture Input Port: PWM B port
    stcTIM6CapxCfg.enPortMode = Timer6ModeCaptureInput;                //Capture input function
    stcTIM6CapxCfg.bFltEn     = true;                                  //Input filter enable
    stcTIM6CapxCfg.enFltClk   = Timer6FltClkPclk0Div16;                //Filter clock
    Timer6_PortInputConfig(TIMER6_UNIT1, &stcTIM6CapxCfg);                 //Input config

    Timer6_ConfigHwCaptureB(TIMER6_UNIT1, Timer6HwTrigPWMBRise);       //HW Capture: Timer6 PWMB port rise trig

    Timer6_ConfigHwClear(TIMER6_UNIT1, Timer6HwTrigPWMBFall);          //HW Clear: Timer6 PWMB port fall trig
    Timer6_EnableHwClear(TIMER6_UNIT1);
    
    /*start timer6*/
    Timer6_StartCount(TIMER6_UNIT1);
}

【注】也可以使用中断进行捕获:

/* TIMER6 unit and clock definition */
#define TIMER6_UNIT1                    (M4_TMR61)
#define TIMER6_UNIT1_CLOCK              (PWC_FCG2_PERIPH_TIM61)
/* 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)

uint16_t u16CaptureA;
void Timer61_CapInputCallBack(void)
{
    u16CaptureA = Timer6_GetGeneralCmpValue(TIMER6_UNIT1, TIMER6_UNIT1_CHB);
}

void Timer6_APC_Config(void)  //APC测试,采样0.8V-4V电压,APC输出16%-80%占空比,经过64分频定时器捕获,输出比较值为420-2100(输入K/B需要调整为2100/400)
{
    stc_timer6_basecnt_cfg_t         stcTIM6BaseCntCfg;
    stc_timer6_port_input_cfg_t      stcTIM6CapxCfg;
    stc_irq_regi_conf_t              stcIrqRegiConf;
    
    MEM_ZERO_STRUCT(stcTIM6BaseCntCfg);
    MEM_ZERO_STRUCT(stcTIM6CapxCfg);
    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/64(256分频也可以试一试)
    Timer6_Init(TIMER6_UNIT1, &stcTIM6BaseCntCfg);                          //timer6 PWM frequency, count mode and clk config

    Timer6_SetPeriod(TIMER6_UNIT1, Timer6PeriodA, 0xFFFFu);               //Period set

    stcTIM6CapxCfg.enPortSel  = Timer6xCHB;                            //Capture Input Port: PWM B port
    stcTIM6CapxCfg.enPortMode = Timer6ModeCaptureInput;                //Capture input function
    stcTIM6CapxCfg.bFltEn     = true;                                  //Input filter enable
    stcTIM6CapxCfg.enFltClk   = Timer6FltClkPclk0Div16;                //Filter clock
    Timer6_PortInputConfig(TIMER6_UNIT1, &stcTIM6CapxCfg);                 //Input config

    Timer6_ConfigHwCaptureB(TIMER6_UNIT1, Timer6HwTrigPWMBRise);       //HW Capture: Timer6 PWMB port rise trig

    Timer6_ConfigHwClear(TIMER6_UNIT1, Timer6HwTrigPWMBFall);          //HW Clear: Timer6 PWMB port fall trig
    Timer6_EnableHwClear(TIMER6_UNIT1);

    /*config interrupt*/
    Timer6_ConfigIrq(TIMER6_UNIT1, Timer6INTENB, true);

    stcIrqRegiConf.enIRQn = Int003_IRQn;                    //Register INT_TMR61_GUDF Int to Vect.No.002
    stcIrqRegiConf.enIntSrc = INT_TMR61_GCMB;               //Select Event interrupt function
    stcIrqRegiConf.pfnCallback = &Timer61_CapInputCallBack; //Callback function
    enIrqRegistration(&stcIrqRegiConf);                     //Registration IRQ

    NVIC_ClearPendingIRQ(stcIrqRegiConf.enIRQn);            //Clear Pending
    NVIC_SetPriority(stcIrqRegiConf.enIRQn, DDL_IRQ_PRIORITY_04);//Set priority
    NVIC_EnableIRQ(stcIrqRegiConf.enIRQn);                   //Enable NVIC

    /*start timer6*/
    Timer6_StartCount(TIMER6_UNIT1);
}

四 设计实现——PWM捕获

        因为输入到MCU的PWM频率为1KHz,所以捕获定时器的周期值为:

Period = 168000000 / 2 / 64 / (1000 / 2) = 2625

        捕获到的PWM比较值即为:

Compare = Period * Duty

        所以由上面方案中采样到的4-20mA对应的占空比16-80%,计算得到的比较值即为:

Compare4mA = Period*Duty=2625*16%=420

Compare20mA = Period*Duty=2625*80%=2100

        程序中的PWM捕获采用Timer6_GetGeneralCmpValue接口:

/**************************************************************************
* 函数名称: analogInputHandle
* 功能描述: 模拟量输入处理
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
**************************************************************************/
float analogInputHandle(STRU_ANALOG_IO_CTRL *p_analog_ctrl)
{
    //...
    //这边捕获到的比较值是根据输入进来的PWM计算得到的
    remote_ctrl.AI1_read = Timer6_GetGeneralCmpValue(TIMER6_UNIT1, TIMER6_UNIT1_CHB);
    //...
}

        采集得到的remote_ctrl.AI1_read再经过公式(本例中,K=2100,B=420),对应得到4-20:

y=(x-B)*\frac{16}{K-B}+4

五 梳理总结

        这个APC替代ADC用于采样模拟量输入的方案,使用比较简单方便,但是精度并没有之前使用的ADS1018(12位精度)那么好,适用于对精度要求不高的场景。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值