这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【LAUNCHXL-F280049C】③eCAP、PWM模块测试及电机测速小试牛

共1条 1/1 1 跳转至

【LAUNCHXL-F280049C】③eCAP、PWM模块测试及电机测速小试牛刀

菜鸟
2025-07-13 23:00:04     打赏

【LAUNCHXL-F280049C】②初试driverlib驱动串口-电子产品世界论坛



接上回,体验到TI 基于sysconfig图形化参数设定,以及基于driverlib库函数程序编写方式,感觉TI终于找对了方向(就像ST那样)。


如果有一两句话就能搞定的功能,谁还去研究复杂的寄存器。


本篇进入到TI C2000的核心功能,也就是关于电机控制方向的eCAP及PWM模块。


PWM,顾名思义,脉冲宽度调制,主要用于电机调速。


eCAP,可能稍微陌生一点,(Enhanced Capture)模块是TI C2000系列DSP中极具特色的外设,在应用中扮演着精密时间测量的关键角色。它不仅能实现传统捕获功能,还支持APWM模式,在电机控制、电源管理等领域应用广泛。


本例主要用于精密时间测量,也就是捕获功能。


首先,新建功能,选择ecap_ex2_capture_pwm这个官方例程:

image.png


首先看ecap_ex2_capture_pwm.c程序

在介绍环节介绍得很清楚。

ePWM3A(GPIO4)产生PWM信号————>eCAP1(GPIO16)捕获信号并计时

image.png



我们打开sysconfig图形化设置界面,打开eCAP:

仔细阅读其中设定,主要关注以下

eCAP mode:Capture(捕获)

EVENT1/2/3/4 上升沿、下降沿、上升沿、下降沿捕获。

如eCAP模块介绍:

image.png


image.png



下面得设置很关键:


eCAP input(捕获输入源,最关键参数):GPIO crossbar Signal-7,这是个什么东西?

image.png



crossbar(交叉开关)

可以通过X-BAR将一个外设的输出信号发送给另一个系统外设(例如将ePWM的输出发送给eCAP并进行频率测量的工作)

简单理解就是一个万能导线,可以将任意一个IO连接至任意一个模块,实现了灵活的引脚复用。

如下图所示:

image.png

回到本例:我们看到INPUTXBAR INPUT设定

明确有 INPUT:XBAR_INPUT7(呼应上面的eCAP输入设定)

INPUT Source:GPIO16,这样就将GPIO16作为eCAP输入引脚连接起来。

image.png


回到程序:

main函数就是基本的初始化。

void main(void)
{
    //
    // Initialize device clock and peripherals
    //
    Device_init();

    //
    // Disable pin locks and enable internal pullups.
    //
    Device_initGPIO();

    //
    // Initialize PIE and clear PIE registers. Disables CPU interrupts.
    //
    Interrupt_initModule();

    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    //
    Interrupt_initVectorTable();

    //
    // Configure GPIO4/5 as ePWM3A/3B
    //
    GPIO_setPadConfig(4,GPIO_PIN_TYPE_STD);
    GPIO_setPinConfig(GPIO_4_EPWM3_A);
    GPIO_setPadConfig(5,GPIO_PIN_TYPE_STD);
    GPIO_setPinConfig(GPIO_5_EPWM3_B);

    //
    // Board initialization
    // Configure GPIO 16 as eCAP input
    // Enable interrupts required for this example
    //
    Board_init();
    
    //
    // Configure ePWM
    //
    initEPWM();

    //
    // Initialize counters:
    //
    cap2Count = 0U;
    cap3Count = 0U;
    cap4Count = 0U;
    ecap1IntCount = 0U;
    ecap1PassCount = 0U;
    epwm3PeriodCount = 0U;

    //
    // Enable Global Interrupt (INTM) and Real time interrupt (DBGM)
    //
    EINT;
    ERTM;

    //
    // Loop forever. Suspend or place breakpoints to observe the buffers.
    //
    for(;;)
    {
       NOP;
    }
}


initEPWM是PWM的设定函数,本例设定PWM3A(GPIO4为PWM输出引脚)。

//
// initEPWM - Configure ePWM
//
void initEPWM()
{
    //
    // Disable sync(Freeze clock to PWM as well)
    //
    SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);

    //
    // Configure ePWM
    //       Counter runs in up-count mode.
    //       Action qualifier will toggle output on period match
    //
    EPWM_setTimeBaseCounterMode(EPWM3_BASE, EPWM_COUNTER_MODE_UP);
    EPWM_setTimeBasePeriod(EPWM3_BASE, PWM3_TIMER_MIN);
    EPWM_setPhaseShift(EPWM3_BASE, 0U);
    EPWM_setActionQualifierAction(EPWM3_BASE,
                                  EPWM_AQ_OUTPUT_A,
                                  EPWM_AQ_OUTPUT_TOGGLE,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
    EPWM_setClockPrescaler(EPWM3_BASE,
                           EPWM_CLOCK_DIVIDER_1,
                           EPWM_HSCLOCK_DIVIDER_2);

    epwm3TimerDirection = EPWM_TIMER_UP;

    //
    // Enable sync and clock to PWM
    //
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
}


最关键的函数或者功能是INT_myECAP0_ISR 中断函数。


//
// myECAP0 ISR
//
__interrupt void INT_myECAP0_ISR(void)
{
    //
    // Get the capture counts. Each capture should be 2x the ePWM count
    // because of the ePWM clock divider.
    //
    cap2Count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_2);
    cap3Count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_3);
    cap4Count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_4);

    //
    // Compare the period value with the captured count
    //
    epwm3PeriodCount = EPWM_getTimeBasePeriod(EPWM3_BASE);

    if(cap2Count > ((epwm3PeriodCount *2) + 2U) ||
       cap2Count < ((epwm3PeriodCount *2) - 2U))
    {
        error();
    }

    if(cap3Count > ((epwm3PeriodCount *2) + 2U) ||
       cap3Count < ((epwm3PeriodCount *2) - 2U))
    {
        error();
    }

    if(cap4Count > ((epwm3PeriodCount *2) + 2U) ||
       cap4Count < ((epwm3PeriodCount *2) - 2U))
    {
        error();
    }

    ecap1IntCount++;

    //
    // Keep track of the ePWM direction and adjust period accordingly to
    // generate a variable frequency PWM.
    //
    if(epwm3TimerDirection == EPWM_TIMER_UP)
    {
        if(epwm3PeriodCount < PWM3_TIMER_MAX)
        {
           EPWM_setTimeBasePeriod(EPWM3_BASE, ++epwm3PeriodCount);
        }
        else
        {
           epwm3TimerDirection = EPWM_TIMER_DOWN;
           EPWM_setTimeBasePeriod(EPWM3_BASE, ++epwm3PeriodCount);
        }
    }
    else
    {
        if(epwm3PeriodCount > PWM3_TIMER_MIN)
        {
            EPWM_setTimeBasePeriod(EPWM3_BASE, --epwm3PeriodCount);
        }
        else
        {
           epwm3TimerDirection = EPWM_TIMER_UP;
           EPWM_setTimeBasePeriod(EPWM3_BASE, ++epwm3PeriodCount);
        }
    }

    //
    // Count correct captures
    //
    ecap1PassCount++;

    //
    // Clear interrupt flags for more interrupts.
    //
    ECAP_clearInterrupt(myECAP0_BASE,ECAP_ISR_SOURCE_CAPTURE_EVENT_4);
    ECAP_clearGlobalInterrupt(myECAP0_BASE);

    //
    // Start eCAP
    //
    ECAP_reArm(myECAP0_BASE);

    //
    // Acknowledge the group interrupt for more interrupts.
    //
    Interrupt_clearACKGroup(INT_myECAP0_INTERRUPT_ACK_GROUP);
}


通过阅读程序,大概意思应该明白了,首先是对ePWM的脉冲进行捕获CAP2/CAP3/CAP4。


然后将其(*2)跟PWM的周期进行对比。如果异常则进入error。

然后就进行PWM可变周期环节。

根据PWM波形的方向:epwm3TimerDirection 以及他的Count的最大值PWM3_TIMER_MAX、最小值PWM3_TIMER_MIN,通过

EPWM_setTimeBasePeriod(EPWM3_BASE, ++epwm3PeriodCount);

EPWM_setTimeBasePeriod(EPWM3_BASE, --epwm3PeriodCount);

从而动态调制PWM周期。


我们用一根杜邦线将GPIO4与GPIO16连接起来。另外用逻辑分析仪的钩子接在GPIO16实测PWM波形。


41be41ab0ef9534236aa31508c02975.jpg





逻辑分析仪截图如下:

image.png



image.png


image.png



可以看到周期的明显变化。WATCH窗口可以读取精准的测值(cap2就是一个脉冲的持续时长,需要乘以1/100MHZ,算出来大约36us,跟上述逻辑分析仪截图测值相当:52us》注意:不是同一时刻)。



接下来重点介绍本篇的电机测速小试牛刀

这里介绍下我使用的硬件:

淘宝上淘来的编码电机。


电机.jpg



电机输出轴转一圈AB相各输出1152个脉冲。这个很关键。

实际本例只使用A相。

将编码相机的A相接在GPIO16(eCAP输入),同时接逻辑分析仪查看波形。

978753d612e1518122690249db0db1b.jpg

程序在上述官方例程的基础上进行了修改。

加入了波形时间检测:将计数Conut*(1/100MHz)转化为时间.

在根据电机转一圈输出1152个脉冲,计算电机转一圈所需时间。


__interrupt void INT_myECAP0_ISR(void)
{
    //
    // Get the capture counts. Each capture should be 2x the ePWM count
    // because of the ePWM clock divider.
    //
    cap2Count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_2);
    cap3Count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_3);
    cap4Count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_4);

    motor_cycle1=cap2Count/100;  //单个编码脉冲时间 单位us 
    motor_cycle2=cap3Count/100;
    motor_cycle3=cap4Count/100;

    motor_cycle = motor_cycle1*2*1152/1000; //电机转一圈时间 单位ms (电机输出轴转一圈输出1152个脉冲)


    
    epwm3PeriodCount = EPWM_getTimeBasePeriod(EPWM3_BASE);

    

    ecap1IntCount++;

    //
    // Keep track of the ePWM direction and adjust period accordingly to
    // generate a variable frequency PWM.
    //
    
    //
    // Count correct captures
    //
    ecap1PassCount++;

    //
    // Clear interrupt flags for more interrupts.
    //
    ECAP_clearInterrupt(myECAP0_BASE,ECAP_ISR_SOURCE_CAPTURE_EVENT_4);
    ECAP_clearGlobalInterrupt(myECAP0_BASE);

    //
    // Start eCAP
    //
    ECAP_reArm(myECAP0_BASE);

    //
    // Acknowledge the group interrupt for more interrupts.
    //
    Interrupt_clearACKGroup(INT_myECAP0_INTERRUPT_ACK_GROUP);
}


运行如下:

image.png

也就是电机转一圈2.1秒,跟我用秒表计时几乎一样,实验成功。

再用逻辑分析仪检测下波形。脉冲时间893us,跟上图的motor_cycle1完全一致。

image.png

测试成功!


电机测速.gif





关键词: C2000    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]