输入捕获实验
输入捕获模式可以用来测量脉冲宽度或者测量频率。STM32的定时器,除了TIM6和TIM7,其他定时器都有输入捕获功能。
输入捕获工作过程
一句话总结工作过程:通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。
(以通道一为例)
步骤一:设置输入捕获滤波器
步骤二:设置输入捕获极性
步骤三:设置输入捕获映射通道
步骤四:设置输入捕获分频器
步骤五:捕获到有效信号可以开启中断
定时器通道
对应引脚TIM5为例:
输入捕获相关寄存器
捕获/比较模式寄存器TIMx_CCMR1/2
当在输入捕捉模式下使用的时候,对应上图的第二行描述。 低八位[7:0]用于捕获/比较通道1的控制,而高八位[15:8]则用于捕获/比较通道2的控制,由此也可以知道TIMx_CCMR2寄存器是用来控制通道3和4的。
TIMx_CCMR1的[7:0]位的详细描述如下:
捕获/比较使能寄存器TIMx_CCER
要使能输入捕获,必须设置CC1E=1,而CC1P则根据自己的需要来配置。
DMA/中断使能寄存器TIMx_DIER
本文中需要用到中断来处理捕获数据,所以必须开启通道1的捕获比较中断,即CC1IE设置为1,此外更新中断也需要开启,UIE设置为1。
控制寄存器1 TIMx_CR1
最低位,使能寄存器。
状态寄存器TIMx_SR
输入捕获相关库函数
输入捕获通道初始化函数
void TIM_ICInit(TIM_TypeDef TIMx, TIM_ICInitTypeDef TIM_ICInitStruct);
typedef struct
{
uint16_t TIM_Channel; //捕获通道1~4
uint16_t TIM_ICPolarity; //捕获极性
uint16_t TIM_ICSelection; //映射关系
uint16_t TIM_ICPrescaler; //分频系数
uint16_t TIM_ICFilter; //滤波器
} TIM_ICInitTypeDef;
示例:
TIM_ICInitTypeDef* TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter=0x00;
TIM_ICInit(TIM5,&TIM5_ICInitStructure);
通道极性设置独立函数
void TIM_OCxPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
获取通道捕获值
uint32_t TIM_GetCapture1(TIM_TypeDef* TIMx);
输入捕获的一般配置步骤
①. 初始化定时器和通道对应IO的时钟。
②. 初始化IO口,模式为输入:GPIO_Init();
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;//PA0输入
③. 初始化定时器ARR,PSC
TIM_TimeBaseInit();
④. 初始化输入捕获通道
TIM_ICInit();
⑤. 如果要开启捕获中断
TIM_ITConfig();
NVIC_Init();
⑥. 使能定时器
TIM_Cmd();
⑦. 编写中断服务函数
TIMx_IRQHandler();
输入捕获实验
实验目的
测量信号的脉冲宽度。
by库函数
TIM5_CAP_Init()
//定时器5通道1输入捕获配置
void TIM5_CAP_Init(u16 arr, u16 psc)
{
//定义结构体
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitSturc;
TIM_ICInitTypeDef TIM_ICInitStructure;
NVIC_InitTypeDef NVIC_InitStucture;
//使能时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);//使能定时器5时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能PA时钟
//GPIOA.0初始化
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;//PA.0上拉输入
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//PA.0
GPIO_Init(GPIOA,&GPIO_InitStructure);//GPIOA.0初始化
GPIO_ResetBits(GPIOA,GPIO_Pin_0);//将PA.0初始化为低电平
//TIM5定时器初始化
TIM_TimeBaseInitSturc.TIM_Period=arr;//重装载值
TIM_TimeBaseInitSturc.TIM_Prescaler=psc;//预分频系数
TIM_TimeBaseInitSturc.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseInitSturc.TIM_ClockDivision=TIM_CKD_DIV1;//时钟分频因子为1
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitSturc);
//初始化TIM5输入捕获参数
TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;//选择输入端IC1映射到TT1上
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//上升沿捕获
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//映射到TT1上
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;//配置输入分频,不分频
TIM_ICInitStructure.TIM_ICFilter=0x00;//配置输入滤波器,不滤波
TIM_ICInit(TIM5,&TIM_ICInitStructure);
//中断分组初始化
NVIC_InitStucture.NVIC_IRQChannel=TIM5_IRQn;//TIM5中断通道
NVIC_InitStucture.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级2
NVIC_InitStucture.NVIC_IRQChannelSubPriority=2;//响应优先级2
NVIC_InitStucture.NVIC_IRQChannelCmd=ENABLE;//中断使能
NVIC_Init(&NVIC_InitStucture);
//允许TIM5的更新中断和捕获中断
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);
//使能定时器5
TIM_Cmd(TIM5,ENABLE);
}
TIM5_IRQHandler()
u8 TIM5CH1_CAPTURE_STA=0; //输入捕获状态
u16 TIM5CH1_CAPTURE_VAL; //输入捕获值
void TIM5_IRQHandler(void)
{
if((TIM5CH1_CAPTURE_STA&0x80)==0)
{
if(TIM_GetITStatus(TIM5,TIM_IT_Update)==SET)
{
if(TIM5CH1_CAPTURE_STA&0x40)//已经捕获到了高电平
{
if((TIM5CH1_CAPTURE_STA&0x3f)==0x3f)//不是等于1,此代表高电平时间太长
{
TIM5CH1_CAPTURE_STA|=0x80;//标记成功捕获了一次
TIM5CH1_CAPTURE_VAL=0xffff;
}else TIM5CH1_CAPTURE_STA++;//捕获次数加一
}
}
if(TIM_GetITStatus(TIM5,TIM_IT_CC1)==SET)
{
if(TIM5CH1_CAPTURE_STA&0x40)//已经捕获到了上升沿,此为捕获下降沿
{
TIM5CH1_CAPTURE_STA|=0x80;//标记成功捕获到一次高电平脉宽
TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);//获取TIM5当前计数值
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising);//设置为捕获上升沿
}else//还未开始时,捕获上升沿
{
TIM5CH1_CAPTURE_STA=0;
TIM5CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM5,0);//TIM5从0开始计数
TIM5CH1_CAPTURE_STA|=0x40;//标记捕获了上升沿
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);//设置为捕获下降沿
}
}
}
TIM_ClearITPendingBit(TIM5,TIM_IT_Update|TIM_IT_CC1);//清除更新和捕获中断标志位
}
main.c
#include "stm32f10x.h"
#include "timer.h"
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "usart.h"
extern u8 TIM5CH1_CAPTURE_STA;//输入捕获状态
extern u16 TIM5CH1_CAPTURE_VAL;//输入捕获值
int main(void)
{
u32 temp=0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//NVIC中断优先级分组
delay_init();//延时函数初始化
LED_Init();//LED初始化函数
uart_init(115200);//串口初始化
TIM5_CAP_Init(0xffff,72-1);//以1MHz的频率计数
while(1)
{
if(TIM5CH1_CAPTURE_STA&0x80)//成功捕获一次脉宽
{
temp=TIM5CH1_CAPTURE_STA&0x3f;//捕获次数取出
temp*=65536;//0xffff=65536
temp+=TIM5CH1_CAPTURE_VAL;//脉宽持续时间
printf("HIGH:%d us\r\n",temp);//打印总的高点平时间
TIM5CH1_CAPTURE_STA=0;//清零,准备下一次输入捕获
}
}
}
by寄存器
TIM5_CAP_Init()
//TIM5通道1输入捕获初始化
void TIM5_CAP_Init(u16 arr, u16 psc)
{
//使能时钟
RCC->APB2ENR|=1<<2;//PA口时钟使能
RCC->APB1ENR|=1<<3;//TIM5时钟使能
//GPIOA.0初始化
GPIOA->CRL&=0XFFFFFFF0;
GPIOA->CRL|=0X00000008;//PA.0下拉输入,默认下拉
//TIM5时钟初始化
TIM5->ARR=arr;//TIM3自动重装载值
TIM5->PSC=psc;//设置预分频值
//TIM5通道1中断初始化
TIM5->CCMR1|=1<<0;//无滤波,无预分频,IC1映射在TI1上
//中断分组初始化
MY_NVIC_Init(2,2,TIM5_IRQn,2);//抢占2,响应2,中断优先级分组2
TIM5->CCER|=1<<0; //CC1E=1 允许捕获计数器的值到捕获寄存器中
//使能捕获和更新中断
TIM5->DIER|=1<<0;//使能更新中断
TIM5->DIER|=1<<1;//使能捕获中断
//使能定时器5
TIM5->CR1|=1<<0;
}
TIM5_IRQHandler()
u8 TIM5CH1_CAPTURE_STA=0; //输入捕获状态
u16 TIM5CH1_CAPTURE_VAL; //输入捕获值
void TIM5_IRQHandler(void)
{
if((TIM5CH1_CAPTURE_STA&0x80)==0)//还未成功捕获
{
if(TIM5->SR&0x01)
{
if(TIM5CH1_CAPTURE_STA&0x40)//已经捕获到高电平了
{
if((TIM5CH1_CAPTURE_STA&0x3f)==0x3f)
{
TIM5CH1_CAPTURE_STA|=0x80;//标记成功捕获了一次
TIM5CH1_CAPTURE_VAL=0xffff;
}else TIM5CH1_CAPTURE_STA++;
}
}
if(TIM5->SR&0x02)//捕获1发生捕获时间
{
if(TIM5CH1_CAPTURE_STA&0x40)//已经捕获到上升沿了,此为下降沿
{
TIM5CH1_CAPTURE_STA|=0x80;//标记捕获到一次高电平脉宽
TIM5CH1_CAPTURE_VAL=TIM5->CCR1;
TIM5->CCER&=~(1<<1);//设置为捕获上升沿
}else//还未开始时,捕获上升沿
{
TIM5CH1_CAPTURE_STA=0;
TIM5CH1_CAPTURE_VAL=0;
TIM5->CNT=0;//计数器清空
TIM5CH1_CAPTURE_STA|=0x40;//标记捕获了上升沿
TIM5->CCER|=1<<1;//设置为捕获下降沿
}
}
}
TIM5->SR&=~(1<<0);//清除更新中断标志位
TIM5->SR&=~(1<<1);//清除捕获中断标志位
//可以直接TIM5->SR=0;
}
main.c
#include "sys.h"
#include "delay.h"
#include "timer.h"
#include "led.h"
#include "usart.h"
extern u8 TIM5CH1_CAPTURE_STA; //输入捕获状态
extern u16 TIM5CH1_CAPTURE_VAL; //输入捕获值
int main(void)
{
u32 temp=0;
Stm32_Clock_Init(9);//系统时钟设置
delay_init(72);//延时初始化
uart_init(72,115200);//串口初始化
LED_Init(); //初始化与LED连接的硬件 接口
TIM5_CAP_Init(0XFFFF,72-1); //以1MHz的时钟频率计数
while(1)
{
if(TIM5CH1_CAPTURE_STA&0x80)
{
temp=TIM5CH1_CAPTURE_STA&0x3f;
temp*=65536;
temp+=TIM5CH1_CAPTURE_VAL;
printf("HIGH: %d us\r\n",temp);//左下划线
TIM5CH1_CAPTURE_STA=0;
}
}
}