【LAUNCHXL-F280049C】②初试driverlib驱动串口-电子产品世界论坛
接上回,体验到TI 基于sysconfig图形化参数设定,以及基于driverlib库函数程序编写方式,感觉TI终于找对了方向(就像ST那样)。
如果有一两句话就能搞定的功能,谁还去研究复杂的寄存器。
本篇进入到TI C2000的核心功能,也就是关于电机控制方向的eCAP及PWM模块。
PWM,顾名思义,脉冲宽度调制,主要用于电机调速。
eCAP,可能稍微陌生一点,(Enhanced Capture)模块是TI C2000系列DSP中极具特色的外设,在应用中扮演着精密时间测量的关键角色。它不仅能实现传统捕获功能,还支持APWM模式,在电机控制、电源管理等领域应用广泛。
本例主要用于精密时间测量,也就是捕获功能。
首先,新建功能,选择ecap_ex2_capture_pwm这个官方例程:

首先看ecap_ex2_capture_pwm.c程序
在介绍环节介绍得很清楚。
ePWM3A(GPIO4)产生PWM信号————>eCAP1(GPIO16)捕获信号并计时

我们打开sysconfig图形化设置界面,打开eCAP:
仔细阅读其中设定,主要关注以下
eCAP mode:Capture(捕获)
EVENT1/2/3/4 上升沿、下降沿、上升沿、下降沿捕获。
如eCAP模块介绍:

、

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

crossbar(交叉开关)
可以通过X-BAR将一个外设的输出信号发送给另一个系统外设(例如将ePWM的输出发送给eCAP并进行频率测量的工作)
简单理解就是一个万能导线,可以将任意一个IO连接至任意一个模块,实现了灵活的引脚复用。
如下图所示:

回到本例:我们看到INPUTXBAR INPUT设定
明确有 INPUT:XBAR_INPUT7(呼应上面的eCAP输入设定)
INPUT Source:GPIO16,这样就将GPIO16作为eCAP输入引脚连接起来。

回到程序:
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波形。

逻辑分析仪截图如下:



可以看到周期的明显变化。WATCH窗口可以读取精准的测值(cap2就是一个脉冲的持续时长,需要乘以1/100MHZ,算出来大约36us,跟上述逻辑分析仪截图测值相当:52us》注意:不是同一时刻)。
接下来重点介绍本篇的电机测速小试牛刀
这里介绍下我使用的硬件:
淘宝上淘来的编码电机。

电机输出轴转一圈AB相各输出1152个脉冲。这个很关键。
实际本例只使用A相。
将编码相机的A相接在GPIO16(eCAP输入),同时接逻辑分析仪查看波形。

程序在上述官方例程的基础上进行了修改。
加入了波形时间检测:将计数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);
}运行如下:

也就是电机转一圈2.1秒,跟我用秒表计时几乎一样,实验成功。
再用逻辑分析仪检测下波形。脉冲时间893us,跟上图的motor_cycle1完全一致。

测试成功!


 
					
				
 
			
			
			
						
			 我要赚赏金
 我要赚赏金 STM32
STM32 MCU
MCU 通讯及无线技术
通讯及无线技术 物联网技术
物联网技术 电子DIY
电子DIY 板卡试用
板卡试用 基础知识
基础知识 软件与操作系统
软件与操作系统 我爱生活
我爱生活 小e食堂
小e食堂

