文章信息
撰寫日期 | 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;
}