今日得以继续我的MSP432电赛速通之旅~~~
目录
基础知识:
相关库函数:
一般配置步骤:
首先定义一个初始化函数:
1.复用引脚:
2.配置连续计数结构体:
3.初始化定时器连续计数:
4.配置捕获结构体:
5.初始化定时器为捕获:
6.选择模式开始计数:
7.清除中断标志位:
8.开启定时器端口中断:
9.开启总中断:
10.编写 TIMA ISR:
11.主函数捕获的编写:
硬件电路的连接:
实验结果:
MSP432捕获模式是一种可编程的寄存器配置,
在此模式下,MSP432可以在外部事件确切发生的瞬时刻捕获一个定时器的值。
捕获模式可以用于许多应用,例如测量某个事件的时间间隔或周期,
以及检测输入脉冲的上升边、下降边或两种边缘的时间。
在MSP432上,捕获模式与定时器结合使用。
MSP432中的每个定时器都有多个捕获/比较通道可以使用,
每个通道可以独立配置为捕获模式。
在捕获模式下,每个通道可以在定时器上的不同时间点捕获一个定时器的值。
并将其存储在一个捕获寄存器中。
在定时器捕获中,我们只需关心连续计数模式就好了:
连续计数模式就是从零开始计数
直到65535,然后又从0开始计数,如此往复循环。
此处先列出定时器与通道对应引脚
以下1~7,都定义在库 timer_a.h中:
1.初始化定时器为连续计数模式:
Timer_A_configureContinuousMode(TIMER_Ax,&continuousModeConfig);
2.配置定时器的捕获模式:
Timer_A_initCapture(TIMER_Ax_BASE,&captureModeConfig);
3.选择模式开始计数:
Timer_A_startCounter(TIMER_Ax_BASE,TIMER_A_CONTINUOUS_MODE);
第一个参数选择定时器 ,第二个参数可选择填写以下模式之一:
1. TIMER_A_STOP_MODE
(TIMER_A_CTL_MC_0)`: 停止模式,计时器A停止计数并保持其当前值。
2. TIMER_A_UP_MODE
(TIMER_A_CTL_MC_1)`: 单向上计数模式,计时器A从0开始递增计数,当计数值达到最大值(根据配置而定)时,计时器将重新从0开始。
3. TIMER_A_CONTINUOUS_MODE
(TIMER_A_CTL_MC_2)`: 连续模式,计时器A从0开始递增计数,当计数值达到最大值(根据配置而定)时,计时器将自动重新从0开始。
4. TIMER_A_UPDOWN_MODE
(TIMER_A_CTL_MC_3)`: 上下计数模式,计时器A从0开始递增计数,当计数值达到最大值(根据配置而定)时,计时器将自动切换为递减模式,直到计数值回到0。这个模式可以用来产生周期性的波形。
通过选择适当的工作模式,可以根据应用的需求来配置计时器A的行为。
4.清除定时器溢出中断标志位:
Timer_A_clearInterruptFlag(TIMER_Ax_BASE);
5.清除定时器捕获中断标志位:
Timer_A_clearCaptureCompareInterrupt(TIMER_Ax,REGISTER_N);
6.获取定时器溢出中断状态:
Timer_A_getEnabledInterruptStatus(TIMER_Ax_BASE);
7.获取定时器捕获中断状态:
Timer_A_getCaptureCompareEnabledInterruptStatus(TIMER_Ax,REGISTER_N);
8.获取定时器捕获电平状态:
Timer_A_getSynchronizedCaptureCompareInput(TIMER_Ax,REGISTER_N,Setting);
返回值:
TIMER_A_OUTPUTMODE_OUTBITVALUE_LOW
TIMER_A_OUTPUTMODE_OUTBITVALUE_HIGH
以下9~10,定义在了interrupt.h中:
9.开启定时器A端口中断:
Interrupt_enableInterrupt(INT_TAx_N);
10.开启总中断:
Interrupt_enableMaster(void);
0.配置时钟
1.复用引脚
2.配置连续计数结构体
3.初始化定时器连续计数
4.配置捕获结构体
5.初始化定时器为捕获
6.选择模式开始计数
7.清除中断标志位
8.开启定时器端口中断
9.开启总中断
10.编写 TIMA ISR
本次配置TA2 通道1捕获并测量高电平持续时间为实验目标:
对应引脚为P5.6
用来封装初始化的语句:
void Timer2_Cap_Inint()
{
}
Tip: 定时器捕获是复用输入,定时器PWM是复用输出:
//1.复用引脚GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,GPIO_PIN6,GPIO_PRIMARY_MODULE_FUNCTION);
首先在timer_a.h中找到结构体:
复制内容粘贴在初始化函数中:
做以下修改:
//2.配置连续计数结构体
Timer_A_ContinuousModeConfig continuousModeConfig=
{
TIMER_A_CLOCKSOURCE_SMCLK, //时钟源
TIMER_A_CLOCKSOURCE_DIVIDER_48, //时钟分频48 分辨力为1us
TIMER_A_TAIE_INTERRUPT_ENABLE, //开启定时器溢出中断
TIMER_A_SKIP_CLEAR //Skip Clear Counter
};
定时器溢出中断要使能开启,因为如果高电平持续时间过长
恰好到定时器溢出中断了才结束,此时的捕获寄存器刚好清零
读取到的捕获值就是0了,算出来的高电平持续时间就是0了
所以要开启溢出中断,每溢出一次就中断记录一次,
最后计算的时候,在把溢出的时间加回去
填上定时器A2和结构体地址就行了
//3.初始化定时器连续计数:
Timer_A_configureContinuousMode(TIMER_A2_BASE,&continuousModeConfig);
//4.配置捕获结构体:
const Timer_A_CaptureModeConfig continuousModeConfig_TA2=
{
TIMER_A_CAPTURECOMPARE_REGISTER_1, //此处改通道引脚
TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE, //上升下降沿捕获
TIMER_A_CAPTURE_INPUTSELECT_CCIxA, //CCIxA:外部引脚输入(CCIxB:与内部ACLK连接)
TIMER_A_CAPTURE_SYNCHRONOUS //同步捕获
};
//5.初始化定时器为捕获:
Timer_A_initCapture(TIMER_A2_BASE,&continuousModeConfig_TA2);
//6.选择模式开始计数:
Timer_A_startCounter(TIMER_A2_BASE,TIMER_A_CONTINUOUS_MODE);
//7.清除中断标志位:
Timer_A_clearInterruptFlag(TIMER_A2_BASE);
Timer_A_clearCaptureCompareInterrupt(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_1);
//8.开启定时器端口中断:
Interrupt_enableInterrupt(INT_TA2_N);
该函数参数的有效值可以去interrupt.h找到声明:
我们用的是定时器A2 通道1中断,
通道1、2、3、4都是选择INT_TA2_N这个端口
只有通道0是选择INT_TA2_0这个端口
主函数初始化区域调用函数开启即可
中断服务函数,去启动文件寻找函数名并复制:
粘贴,声明作为新的函数:
开始编写捕获处理:
#define CAP_TIMA_SELECTION TIMER_A2_BASE //在这里改定时器
#define CAP_REGISTER_SELECTION TIMER_A_CAPTURECOMPARE_REGISTER_1 //在这里改定时器通道
#define CAP_CCR_NUM 1 //在这里改定时器通道
#define CAP_PORT_PIN GPIO_PORT_P5, GPIO_PIN6 //在这里改复用引脚
uint16_t TIMA2_CAP_STA = 0;
uint16_t TIMA2_CAP_VAL = 0;
//定时器A2 通道1 中断服务函数
void TA2_N_IRQHandler(void)
{
//还未成功捕获
if ((TIMA2_CAP_STA & 0X80) == 0)
{
//溢出中断
if (MAP_Timer_A_getEnabledInterruptStatus(CAP_TIMA_SELECTION))
{
//清除定时器溢出中断标志位
MAP_Timer_A_clearInterruptFlag(CAP_TIMA_SELECTION);
/*如果在未清除中断位值时,来了一次中断,COV会置位,需要软件复位,
这里没有官方库函数。具体可以参考技术手册(slau356h.pdf) P790 */
BITBAND_PERI(TIMER_A_CMSIS(CAP_TIMA_SELECTION)->CCTL[CAP_CCR_NUM], TIMER_A_CCTLN_COV_OFS) = 0;
//已经捕获到高电平了 40H = 0x 0100 0000
if (TIMA2_CAP_STA & 0X40)
{
//高电平太长了
if ((TIMA2_CAP_STA & 0X3F) == 0X3F)
{
//强制标记成功捕获完高电平 80H = 0x1000 0000
TIMA2_CAP_STA |= 0X80;
TIMA2_CAP_VAL = 0XFFFF;
}
else
//溢出次数加1
{TIMA2_CAP_STA++; }
}
}
//捕获中断
if (MAP_Timer_A_getCaptureCompareEnabledInterruptStatus(CAP_TIMA_SELECTION, CAP_REGISTER_SELECTION))
{
//清除 CCR1 更新中断标志位
MAP_Timer_A_clearCaptureCompareInterrupt(CAP_TIMA_SELECTION, CAP_REGISTER_SELECTION);
//判断是否捕获到下降沿
if (TIMA2_CAP_STA & 0X40 &&
(MAP_Timer_A_getSynchronizedCaptureCompareInput(
CAP_TIMA_SELECTION,
CAP_REGISTER_SELECTION,
TIMER_A_READ_CAPTURE_COMPARE_INPUT) == TIMER_A_CAPTURECOMPARE_INPUT_LOW))
{
//标记成功捕获完高电平
TIMA2_CAP_STA |= 0X80;
TIMA2_CAP_VAL = Timer_A_getCaptureCompareCount(CAP_TIMA_SELECTION, CAP_REGISTER_SELECTION);
}
//还未开始,第一次捕获上升沿
else
{
TIMA2_CAP_STA = 0;
TIMA2_CAP_VAL = 0;
MAP_Timer_A_clearTimer(CAP_TIMA_SELECTION); //清空定时器 重新从0计数
TIMA2_CAP_STA |= 0X40; //标记捕获到了上升沿
}
}
}
}
此处按键K1 K2分别是为了将LED点亮和熄灭
点亮时是高电平,以此模拟捕获高电平时长
并将计算好的时长通过串口发送给上位机
#include "sysinit.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "tim32.h"
#include "key.h"
#define CAP_TIMA_SELECTION TIMER_A2_BASE //在这里改定时器
#define CAP_REGISTER_SELECTION TIMER_A_CAPTURECOMPARE_REGISTER_1 //在这里改定时器通道
#define CAP_CCR_NUM 1 //在这里改定时器通道
#define CAP_PORT_PIN GPIO_PORT_P5, GPIO_PIN6 //在这里改复用引脚
uint16_t TIMA2_CAP_STA = 0;
uint16_t TIMA2_CAP_VAL = 0;
void TimA2_Cap_Init(void);
int main(void)
{
uint8_t key;
uint32_t temp;
SysInit(); // 第3讲 时钟配置
uart_init(115200); // 第7讲 串口配置
delay_init(); // 第4讲 滴答延时
LED_Init(); //第2讲 GPIO输出
KEY_Init(0); //第2讲 GPIO输入
TimA2_Cap_Init(); //第8讲 定时器A 捕获
printf("Hello,MSP432!\r\n");
MAP_Interrupt_enableMaster(); // 开启总中断
while (1)
{
key = KEY_Scan(0);
if (key == KEY1_PRES)
LED_RED_On();
else if (key == KEY2_PRES)
LED_RED_Off();
if (TIMA2_CAP_STA & 0X80) //成功捕获到了一次上升沿
{
temp = TIMA2_CAP_STA & 0X3F;
temp *= 65536; //溢出时间总和
temp += TIMA2_CAP_VAL; //得到总的高电平时间
printf("HIGH:%dus\r\n", temp); //打印总的高点平时间
TIMA2_CAP_STA = 0; //开启下一次捕获
}
}
}
别忘了将P1^0与P5^6用杜邦线相连,这样LED亮,
就送来高电平给引脚P5^6测量捕获