F28379D烧写双核程序(在线&离线)
@
文章信息
| 撰写日期 | 2018.12.20
---|:--😐---
| 完稿日期 | 2018.12.20
| 最近维护 |2019.07.14
| 本文作者 | multimicro
| 联系方式 | multimicro@qq.com
| GitHub | https://github.com/wifialan
| 本文地址 | https://www.cnblogs.com/multimicro/p/9997615.html
开发环境
环境说明 | 详细信息 | 备注信息 |
---|---|---|
操作系统 | Win10_x64 | |
CCS版本 | Code Composer Studio v8 | 官网地址 |
controlSUITE | controlSUITE for C2000 MCUs | 官网地址 |
F28335 | 硬汉F28335开发板(150MHz时钟频率) | |
欧姆龙E6B2编码器 | E6B2-CWZ6C 1000 P/R |
捕获模块简介
F28335的Ecap模块捕获过程如下
该定时器是捕获模块专用定时器,在设定好捕获事件后,每捕获一个事件,对应的各级捕获寄存器就会把时间记录在捕获寄存器里面,通过这些时间信息即可计算出速度信息。
Ecap模块中比较重要的寄存器
- eCAP控制寄存器ECCTL1
用于配置触发捕获事件的条件和对应的计数器(一共四级,详见程序注释) - eCAP控制寄存器ECCTL2
用于配置eCAP的工作模式,包括进入中断的方式等 - eCAP捕获寄存器eCAPx
用于记录各级捕获事件发生时的时间 - 其余寄存器在代码中查看其作用
对与F2837xD,其配置捕获模块的程序和F28335的程序完全一样,唯一的不同就是配置Ecap输入引脚方式不同,F28335有固定的Ecap输入引脚,而F2837xD的捕获输入因为加入了Crossbar(X-BAR)机制,使得配置输入引脚其他C2000系列DSP更加灵活,可以使用任何一个GPIO口作为捕获输入,在TI官方的F2837xD文档Technical Reference Manual上面可以看到如下配置捕获引脚的说明(P1955):
F2837xD配置捕获输入的GPIO口的程序就两行:
若想进一步了解X-BAR,参考上面提到的文档P1151页。
详细代码
/*
* 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;
}
维护日志
| 维护日期 | 维护内容
---|:--😐---
| 2019.07.14 | 增加了F2837xD系列DSP上的配置捕获输入GPIO的介绍