1. 引言
在嵌入式系统中,有时候我们需要精确测量外部信号的变化,比如一个脉冲信号的频率或周期。这就像是在拍摄视频时,我们需要捕捉每一个关键帧一样。STM32定时器的输入捕获功能就是这样一个工具,它可以帮我们在信号变化时记录下那一刻的时间点。本文将带你从硬件层面理解输入捕获1(IC1)的工作原理。
2. 输入捕获1的基本原理
想象一下,你正在拍摄一段视频,每当视频中有重要的动作发生时,你就按下暂停键,记录下这一刻的画面。输入捕获1(IC1)就是这样一个“暂停键”,它可以在检测到外部信号变化时记录下当前的时间点。
3. 关键寄存器及其作用
实现输入捕获功能主要涉及到以下几个寄存器,就像是电影拍摄过程中的一些关键道具:
1. TIMx_CR1(控制寄存器1)
- 就像导演的剧本,决定了整个拍摄的过程。这里配置定时器的基本操作模式。
2. TIMx_SMCR(从模式控制寄存器)
- 类似于导演的指令手册,当定时器需要与其他设备同步时,这个寄存器就派上了用场。
3. TIMx_ARR(自动装载寄存器)
- 就像电影的总长度,决定了计数器的最大值。
4. TIMx_PSC(预分频寄存器)
- 类似于剪辑的速度调节器,用于调整计数频率。
5. TIMx_EGR(事件生成寄存器)
- 就像导演的喊话筒,用于软件触发更新事件或生成中断请求。
6. TIMx_CCMR1/2(捕获/比较模式寄存器1/2)
- 就像摄像机的设置菜单,用于配置捕获/比较通道的工作模式和极性。
7. TIMx_CCRx(捕获/比较寄存器x)
- 类似于电影的剪辑片段存储器,用于存储捕获值或比较值。
8. TIMx_DIER(DMA/中断使能寄存器)
- 就像导演的通知列表,用于配置DMA请求和中断请求。
9. TIMx_SR(状态寄存器)
- 类似于电影的进度条,用于指示定时器的状态和发生的事件。
4. 寄存器配置流程
4.1 初始化定时器
1. 配置定时器控制寄存器(TIMx_CR1)
- 就像设定电影的类型,设置定时器模式为向上计数模式(`TIM_CR1_DIR=0`)。
2. 配置预分频寄存器(TIMx_PSC)
- 就像调整电影的播放速度,设置预分频系数,以调整计数频率。
3. 配置自动装载寄存器(TIMx_ARR)
- 就像设定电影的总长度,设置最大计数值,即定时器计数器的上限。
4. 配置捕获/比较模式寄存器(TIMx_CCMRx)
- 就像调整摄像机的设置,设置IC1为输入捕获模式,并配置IC1的极性(上升沿、下降沿或双边沿)。
5. 配置DMA/中断使能寄存器(TIMx_DIER)
- 就像导演的通知设置,使能与IC1相关的中断(`TIM_DIER_CC1IE=1`)。
4.2 使能捕获功能
1. 使能捕获/比较通道(TIMx_CCER)
- 就像启动摄像机,设置捕获/比较通道1为有效状态(`TIM_CCER_CC1E=1`)。
2. 使能捕获/比较模块(TIMx_CCMRx)
- 就像确认摄像机的设置,使能输入捕获功能(`TIM_CCMRx_CCxS=0`)。
4.3 使能定时器
1. 使能定时器计数器(TIMx_CR1)
- 就像导演说“开始”,设置定时器使能位(`TIM_CR1_CEN=1`)。
4.4 处理捕获事件
1. 配置中断优先级(NVIC)
- 就像导演的优先级列表,设置与定时器相关的中断优先级。
2. 编写中断服务程序
- 就像导演的剪辑室,处理捕获事件,读取捕获寄存器中的值,并进行后续处理。
5. 工作流程
1. 初始化配置
- 就像导演准备拍摄前的准备工作,配置定时器的控制寄存器、预分频寄存器、自动装载寄存器等。
2. 使能捕获
- 就像导演确认摄像机已经准备好,通过配置捕获/比较模式寄存器使能输入捕获功能。
3. 使能中断
- 就像导演安排好中断通知,使能与捕获相关的中断,并配置中断优先级。
4. 捕获事件发生
- 就像导演喊“咔”,当输入信号发生边沿变化时,定时器会自动记录当前计数值到捕获寄存器。
5. 处理捕获事件
- 就像导演剪辑视频,中断发生时,进入中断服务程序处理捕获事件,读取捕获寄存器的值并进行后续处理。
6. 示例代码
include "stm32f1xx.h"
// 定义使用的定时器
define TIMx TIM3
void TIM_Config(void);
void NVIC_Config(void);
int main(void)
{
// 开启定时器时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
// 配置定时器
TIM_Config();
// 配置中断
NVIC_Config();
// 启动定时器
TIM_Cmd(TIMx, ENABLE);
// 主循环
while (1)
{
// 可以在此处添加代码来处理捕获的数据
}
}
void TIM_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_BaseInitStruct;
TIM_ICInitTypeDef TIM_ICInitStruct;
// 初始化定时器
TIM_BaseInitStruct.TIM_Prescaler = 71; // 调整预分频系数
TIM_BaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_BaseInitStruct.TIM_Period = 65535; // 设置自动重载值
TIM_BaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_BaseInitStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIMx, &TIM_BaseInitStruct);
// 初始化捕获通道
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; // 检测上升沿
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStruct.TIM_ICFilter = 0;
TIM_ICInit(TIMx, &TIM_ICInitStruct);
// 启用捕获中断
TIM_ITConfig(TIMx, TIM_IT_CC1, ENABLE);
// 启用捕获功能
TIM_ICCmd(TIMx, TIM_Channel_1, ENABLE);
}
void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStruct;
// 设置中断优先级
NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIMx, TIM_IT_CC1) != RESET)
{
// 获取捕获值
uint32_t captureValue = TIM_GetCaptureValue(TIMx, TIM_Channel_1);
// 计算频率
float frequency = SystemCoreClock / captureValue;
// 处理结果
// 这里可以打印频率或其他处理
TIM_ClearITPendingBit(TIMx, TIM_IT_CC1); // 清除中断标志位
}
}
```
7. 结论
通过上述寄存器配置流程,可以实现STM32定时器输入捕获1(IC1)功能,用于测量外部信号的变化。