TI-C2000-捕獲模塊ECAP應用-以歐姆龍E6B2-CWZ6C測速編碼器爲例

基於TI的F28379D的捕獲模塊應用

文章信息

撰寫日期 2018.12.20
完稿日期
最近維護
本文作者 multimicro
聯繫方式 [email protected]
GitHub https://github.com/wifialan
本文地址 https://blog.csdn.net/multimicro/article/details/85112066

開發環境

環境說明 詳細信息 備註信息
操作系統 Win10_x64
CCS版本 Code Composer Studio v8 官網地址
controlSUITE controlSUITE for C2000 MCUs 官網地址
F28379D C2000 Delfino MCU F28379D LaunchPad™ development kit 官網地址
歐姆龍E6B2編碼器 E6B2-CWZ6C 1000 P/R

捕獲模塊簡介

F28379D的Ecap模塊捕獲過程如下
在這裏插入圖片描述

該定時器是捕獲模塊專用定時器,在設定好捕獲事件後,每捕獲一個事件,對應的各級捕獲寄存器就會把時間記錄在捕獲寄存器裏面,通過這些時間信息即可計算出速度信息。
Ecap模塊中比較重要的寄存器

  • eCAP控制寄存器ECCTL1
    用於配置觸發捕獲事件的條件和對應的計數器(一共四級,詳見程序註釋)
  • eCAP控制寄存器ECCTL2
    用於配置eCAP的工作模式,包括進入中斷的方式等
  • eCAP捕獲寄存器eCAPx
    用於記錄各級捕獲事件發生時的時間
  • 其餘寄存器在代碼中查看其作用

詳細代碼

/*
 * ecap.c
 *
 *  Created on: 2018年12月14日
 *      Author: multimicro
 */


#include "project.h"

void InitECapture()
{
    InitECapture1();
    InitECapture2();
    InitECapture3();
}

void InitECapture1()
{
    ECap1Regs.ECEINT.all = 0x0000;             // Disable all capture interrupts
    ECap1Regs.ECCLR.all = 0xFFFF;              // Clear all CAP interrupt flags
    ECap1Regs.ECCTL1.bit.CAPLDEN = 0;          // Disable CAP1-CAP4 register loads
    ECap1Regs.ECCTL2.bit.TSCTRSTOP = 0;        // Make sure the counter is stopped

    // Configure peripheral registers
    ECap1Regs.ECCTL2.bit.CONT_ONESHT = 1;      // 單次模式
    ECap1Regs.ECCTL2.bit.STOP_WRAP = 3;        // Stop at 4 events
    ECap1Regs.ECCTL2.bit.SWSYNC = 1;            //同步所有的Ecap時鐘
    //以下CAP1POL是配置捕獲單元的極性
    /*
     *      ____      ____      ____
     *     |    |    |    |    |    |
     * ____|    |____|    |____|    |____
     *     ↑    ↓    ↑    ↓
     *     A    B    C    D
     *
     * */
    ECap1Regs.ECCTL1.bit.CAP1POL = 0;          // Rising edge  0
    ECap1Regs.ECCTL1.bit.CAP2POL = 1;          // Falling edge 1
    ECap1Regs.ECCTL1.bit.CAP3POL = 0;          // Rising edge  0
    ECap1Regs.ECCTL1.bit.CAP4POL = 1;          // Falling edge 1
    ECap1Regs.ECCTL1.bit.CTRRST1 = 0;          // 完成此次捕獲後不重置計數器
    ECap1Regs.ECCTL1.bit.CTRRST2 = 0;          // 完成此次捕獲後不重置計數器
    ECap1Regs.ECCTL1.bit.CTRRST3 = 0;          // 完成此次捕獲後不重置計數器
    ECap1Regs.ECCTL1.bit.CTRRST4 = 1;          // 完成此次捕獲後重置計數器
    ECap1Regs.ECCTL2.bit.SYNCI_EN = 1;         // Enable sync in
    ECap1Regs.ECCTL2.bit.SYNCO_SEL = 0;        // Pass through
    ECap1Regs.ECCTL1.bit.CAPLDEN = 1;          // Enable capture units


    ECap1Regs.ECCTL2.bit.CAP_APWM = 0;          //工作在CAP捕獲模式
    ECap1Regs.ECCTL2.bit.REARM = 1;            // arm one-shot
    ECap1Regs.ECCTL1.bit.CAPLDEN = 1;          // Enable CAP1-CAP4 register loads
//    ECap1Regs.ECEINT.bit.CEVT4 = 1;            // 4 events = interrupt

//    ECap1Regs.ECCTL2.bit.TSCTRSTOP = 1;        // Start Counter
}

void InitECapture2()
{
    ECap2Regs.ECEINT.all = 0x0000;             // Disable all capture interrupts
    ECap2Regs.ECCLR.all = 0xFFFF;              // Clear all CAP interrupt flags
    ECap2Regs.ECCTL1.bit.CAPLDEN = 0;          // Disable CAP1-CAP4 register loads
    ECap2Regs.ECCTL2.bit.TSCTRSTOP = 0;        // Make sure the counter is stopped

    // Configure peripheral registers
    ECap2Regs.ECCTL2.bit.CONT_ONESHT = 1;      // 單次模式
    ECap2Regs.ECCTL2.bit.STOP_WRAP = 3;        // Stop at 4 events
    ECap2Regs.ECCTL2.bit.SWSYNC = 1;            //同步所有的Ecap時鐘
    //以下CAP2POL是配置捕獲單元的極性
    /*
     *      ____      ____      ____
     *     |    |    |    |    |    |
     * ____|    |____|    |____|    |____
     *     ↑    ↓    ↑    ↓
     *     A    B    C    D
     *
     * */
    ECap2Regs.ECCTL1.bit.CAP1POL = 0;          // Rising edge  0
    ECap2Regs.ECCTL1.bit.CAP2POL = 1;          // Falling edge 1
    ECap2Regs.ECCTL1.bit.CAP3POL = 0;          // Rising edge  0
    ECap2Regs.ECCTL1.bit.CAP4POL = 1;          // Falling edge 1
    ECap2Regs.ECCTL1.bit.CTRRST1 = 0;          // 完成此次捕獲後不重置計數器
    ECap2Regs.ECCTL1.bit.CTRRST2 = 0;          // 完成此次捕獲後不重置計數器
    ECap2Regs.ECCTL1.bit.CTRRST3 = 0;          // 完成此次捕獲後不重置計數器
    ECap2Regs.ECCTL1.bit.CTRRST4 = 1;          // 完成此次捕獲後重置計數器
    ECap2Regs.ECCTL2.bit.SYNCI_EN = 1;         // Enable sync in
    ECap2Regs.ECCTL2.bit.SYNCO_SEL = 0;        // Pass through
    ECap2Regs.ECCTL1.bit.CAPLDEN = 1;          // Enable capture units


    ECap2Regs.ECCTL2.bit.CAP_APWM = 0;          //工作在CAP捕獲模式
    ECap2Regs.ECCTL2.bit.REARM = 1;            // arm one-shot
    ECap2Regs.ECCTL1.bit.CAPLDEN = 1;          // Enable CAP1-CAP4 register loads
//    ECap2Regs.ECEINT.bit.CEVT4 = 1;            // 4 events = interrupt

//    ECap2Regs.ECCTL2.bit.TSCTRSTOP = 1;        // Start Counter
}

void InitECapture3()
{
    ECap3Regs.ECEINT.all = 0x0000;             // Disable all capture interrupts
    ECap3Regs.ECCLR.all = 0xFFFF;              // Clear all CAP interrupt flags
    ECap3Regs.ECCTL1.bit.CAPLDEN = 0;          // Disable CAP1-CAP4 register loads
    ECap3Regs.ECCTL2.bit.TSCTRSTOP = 0;        // Make sure the counter is stopped

    // Configure peripheral registers
    ECap3Regs.ECCTL2.bit.CONT_ONESHT = 0;      // 連續模式
    ECap3Regs.ECCTL2.bit.STOP_WRAP = 1;        // Stop at 2 events
    ECap3Regs.ECCTL2.bit.SWSYNC = 1;            //同步所有的Ecap時鐘
    //以下CAP3POL是配置捕獲單元的極性
    /*
     *        ________
     *       |        |
     *  _____|        |________________________
     *       ↑        ↓
     *       A        B
     *
     * */
    ECap3Regs.ECCTL1.bit.CAP1POL = 0;          // Rising edge  0
    ECap3Regs.ECCTL1.bit.CAP2POL = 1;          // Falling edge 1
    ECap3Regs.ECCTL1.bit.CTRRST1 = 0;          // 完成此次捕獲後不重置計數器
    ECap3Regs.ECCTL1.bit.CTRRST2 = 1;          // 完成此次捕獲後重置計數器

    ECap3Regs.ECCTL2.bit.SYNCI_EN = 1;         // Enable sync in
    ECap3Regs.ECCTL2.bit.SYNCO_SEL = 0;        // Pass through
    ECap3Regs.ECCTL1.bit.CAPLDEN = 1;          // Enable capture units


    ECap3Regs.ECCTL2.bit.CAP_APWM = 0;          //工作在CAP捕獲模式
    ECap3Regs.ECCTL2.bit.REARM = 1;            // arm one-shot
    ECap3Regs.ECCTL1.bit.CAPLDEN = 1;          // Enable CAP1-CAP4 register loads
    ECap3Regs.ECEINT.bit.CEVT2 = 1;            // 2 events = interrupt

    ECap3Regs.ECCTL2.bit.TSCTRSTOP = 1;        // Start Counter
}


/*******************************************************************************************************
 *  Ecap 的基準時鐘在150MHz的主頻下約爲6.67ns
 *  也就是說每過6.67ns ECap1Regs.CAPx的值就會遞增1,通過CAP1和CAP3的時間差可以計算出速度
 *******************************************************************************************************
 *  1. 該 E6B2-CWZ6C 的分辨率爲 1000 P/R 即改編碼器每轉一圈,固定輸出1000個脈衝
 *  2. 若1s內轉一圈,則每個脈衝的週期爲: 1s/1000 = 1ms (下圖中A→C的時間 , 從  A → C 爲一個完整的脈衝)
 *  3. 由 E6B2-CWZ6C 技術文檔可知,輸出一共有三相A、B、Z相輸出,其中Z相爲同步相
 *  4. 計算轉速時只需要A相或者B相一個即可。但計算轉動方向時,需要配合A相和B相,必須用到Z相,下面會解釋
 *
 *     ____      ____      ____      ____
 *         |    |    |    |    |    |    |
 *         |____|    |____|    |____|    |____
 *         ↓    ↑    ↓    ↑
 *         A    B    C    D
 *
 *  當  A 事件(捕獲第一個下降沿)發生時 Ecap模塊把當前時間記錄在 ECap1Regs.CAP1中
 *  當  B 事件(捕獲第一個上升沿)發生時 Ecap模塊把當前時間記錄在 ECap1Regs.CAP2中
 *  當  C 事件(捕獲第二個下降沿)發生時 Ecap模塊把當前時間記錄在 ECap1Regs.CAP3中
 *  當  D 事件(捕獲第二個上升沿)發生時 Ecap模塊把當前時間記錄在 ECap1Regs.CAP4中
 *******************************************************************************************************
 *   下面說明一下正轉和反轉時的三相輸出波形
 *
 *   捕獲器1和2配置的
 *
 *   1. 正轉(forward)
 *           _____       _____       _____
 *  A       |     |     |     |     |     |
 *     _____|     |_____|     |_____|     |_____...
 *          ↑     ↓     ↑     ↓
 *          A1    B1    C1    D1
 *
 *      以下變量可在函數中查看
 *      A1: Ecap1_TS1
 *      C1: Ecap1_TS3
 *               _____       _____       _____
 *  B           |     |     |     |     |     |
 *       _______|     |_____|     |_____|     |_____...
 *              ↑     ↓     ↑     ↓
 *              A2    B2    C2    D2
 *
 *      以下變量可在函數中查看
 *      A2: Ecap2_TS1
 *      B2: Ecap2_TS2
 *
 *          ___________
 *  Z      |           |
 *    _____|           |____________________________...
 *         ↑           ↓
 *         A3          B3
 *
 *      沒用到Ecap3的計數寄存器
 *
 *   2. 反轉(backward)
 *   標註見上
 *             _____       _____       _____
 *  A         |     |     |     |     |     |
 *       _____|     |_____|     |_____|     |_____...
 *            ↑     ↓     ↑     ↓
 *            A1    B1    C1    D1
 *          _____       _____       _____
 *  B      |     |     |     |     |     |
 *     ____|     |_____|     |_____|     |_____...
 *                     ↑     ↓     ↑     ↓
 *                     A2    B2    C2    D2
 *          ___________
 *  Z      |           |
 *    _____|           |____________________________
 *         ↑           ↓
 *         A3          B3
 *
 *
 *    需要注意,此種狀態捕獲模塊捕獲 B 相的上升沿如上圖所示,而不是同步信號到來時的第一個上升沿
 *    應該是因爲延時的原因,不影響測向。
 *
 *    同步相到來時,纔會啓動捕獲模塊1和2來捕獲A相和B相的脈衝,捕獲器完成一次捕獲事件後就停止工作
 *    等待下一次的同步信號再一次啓動捕獲
 */
__interrupt void ecap1_isr(void)
{
    // 參考鏈接:https://blog.csdn.net/chenjiayu938/article/details/81349866
    ecap1_count = (++ ecap1_count) % 5;

    Ecap1_TS1 = ECap1Regs.CAP1;
    Ecap1_TS3 = ECap1Regs.CAP3;

    calc_pulse = Ecap1_TS3 - Ecap1_TS1;
    // calc_time unit is millseconds
    // 因爲計數器每6.67ns遞增一次,所以 ( 一個脈衝時間間隔內的計數器數值 ÷ 6.67 ) 就是一個脈衝持續的時間(ns),然後在除以1000000就換算得到ms
    // 此編碼器的分辨率爲 1000 P/R 轉一圈固定輸出1000個脈衝,1s轉一圈輸出的脈衝週期爲1ms,因此可用   ( 1(ms) / 當前的脈衝週期(ms) )  來求得轉速(r/s)
    calc_time = calc_pulse * 667.0 / 100.0 / 1000000.0;
    speed = 1 / calc_time;


    if(ecap1_count == 3)//降低刷新率,減小中斷內部開銷
    {
        memset(speed_char,'\0',8);
        doubleTochar(speed,speed_char,2);        //將浮點型speed數值轉化爲char型,用於LCD顯示
        strcat(speed_char," r/s");
        memset(lcd_second_line,'\0',20);
        strcat(lcd_second_line," Speed:");
        strcat(lcd_second_line,speed_char);             //在"Speed:"後增添速度信息 最終信息格式爲 "Speed:xx.xx r/s"
        if (Direction_flag == FORWARD) {
            Display_LCD1602(" Dire:forward",lcd_second_line);   //LCD1206顯示速度和方向信息
        } else {
            Display_LCD1602(" Dire:backward",lcd_second_line);   //LCD1206顯示速度和方向信息
        }
    }

    ECap1Regs.ECCLR.bit.CEVT4 = 1;      //使能第四級捕獲事件發生後進入中斷
    ECap1Regs.ECCLR.bit.INT = 1;        //清除Ecap全局中斷標誌位
    ECap1Regs.ECCTL1.bit.CAPLDEN = 1;   //使能在捕獲事件中加載CAP1-4寄存器事件

    // Acknowledge this interrupt to receive more interrupts from group 4
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP4;
}


__interrupt void ecap2_isr(void)
{

    Ecap2_TS1 = ECap2Regs.CAP1;
    Ecap2_TS2 = ECap2Regs.CAP2;

    Ecap2_gap_A_B = Ecap2_TS1 - Ecap1_TS1;
    Ecap2_gap_pulse = Ecap2_TS2 - Ecap2_TS1;

    //判斷方向
    if ( Ecap2_gap_A_B < Ecap2_gap_pulse) {
        Direction_flag = FORWARD;
    } else {
        Direction_flag = BACKWARD;
    }

    ECap2Regs.ECCLR.bit.CEVT4 = 1;
    ECap2Regs.ECCLR.bit.INT = 1;
    ECap2Regs.ECCTL1.bit.CAPLDEN = 1;          // Enable capture units

    // Acknowledge this interrupt to receive more interrupts from group 4
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP4;
}

__interrupt void ecap3_isr(void)
{

    if (Z_frist_flag == 0) {
        //Z相檢測到同步信號,啓動A相和B相的檢測
        ECap1Regs.ECCTL2.bit.TSCTRSTOP = 1;//啓動Ecap1定時器
        ECap2Regs.ECCTL2.bit.TSCTRSTOP = 1;//啓動Ecap2定時器
        ECap1Regs.ECEINT.bit.CEVT4 = 1;// 4 events = interrupt
        ECap2Regs.ECEINT.bit.CEVT4 = 1;// 4 events = interrupt
        Z_frist_flag = 1;
    } else {
        //同步開啓Ecap1和Ecap2
        ECap1Regs.ECCTL2.bit.REARM = 1;
        ECap2Regs.ECCTL2.bit.REARM = 1;
    }


    ECap3Regs.ECCLR.bit.CEVT2 = 1;
    ECap3Regs.ECCLR.bit.INT = 1;
    ECap3Regs.ECCTL2.bit.REARM = 1;
    ECap3Regs.ECCTL1.bit.CAPLDEN = 1;          // Enable capture units

    // Acknowledge this interrupt to receive more interrupts from group 4
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP4;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章