stm32F1输入捕获详解
1、问题:什么叫输入捕获
回答:举个例子,比如一个信号由低电平变成高电平时,cpu保存定时器的值,信号再由高电平变成低电平时,cpu又保存一次定时器的值,那么通过这两次定时器的值就可以计算出脉冲宽度
问:可否具体?
答:简单的说就是通过检测 TIMx_CHx 上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA 等。
2、输入捕获框图
3、输入捕获相关寄存器
需要用到的寄存器有:TIMx_ARR、TIMx_PSC、TIMx_CCMR1、TIMx_CCER、TIMx_DIER、TIMx_CR1、TIMx_CCR1
(1)捕获/比较模式寄存器 1:TIMx_CCMR1
TIMx_CCMR1 是对 2 个通道的配置,低八位[7:0]用于捕获/比较通道 1 的控制,而高八位[15:8]则用于捕获/比较通道 2 的控制,因为 TIMx 还有 CCMR2 这个寄存器,所以可以知道CCMR2 是用来控制通道 3 和通道 4
IC1S[1:0]=01,也就是配置 IC1 映射在 TI1 上,即 CC1 对应 TIMx_CH1。
输入捕获 1 预分频器 IC1PSC[1:0],如果是 1 次边沿就触发 1 次捕获,选择 00 。
输入捕获 1 滤波器 IC1F[3:0],这个用来设置输入采样频率和数字滤波器长度。其中,fCK_INT是定时器的输入频率(TIMxCLK),一般为 72Mhz,而 fDTS 则是根据 TIMx_CR1 的 CKD[1:0]的设置来确定的,如果 CKD[1:0]设置为 00,那么 fDTS = fCK_INT,N 值就是滤波长度。
如果IC1F[3:0]=0000,只要采集到上升沿,就触发捕获。
如果IC1F[3:0]=0011,捕获到上升沿的时候,以fCK_INT的频率,连续采样8次通道 1 的电平,如果都是高电平,则说明却是一个有效的触发,就会触发输入捕获中断(如果开启了的话)。
(2)捕获/比较使能寄存器:TIMx_CCER
Bit 1 CC1P: Capture/Compare 1 output polarity
CC1 channel configured as output:
0: OC1 active high.
1: OC1 active low.
CC1 channel configured as input:
This bit selects whether IC1 or IC1 is used for trigger or capture operations.
0: non-inverted: capture is done on a rising edge of IC1. When used as external trigger, IC1
is non-inverted.
1: inverted: capture is done on a falling edge of IC1. When used as external trigger, IC1 is
inverted.
Bit 0 CC1E: Capture/Compare 1 output enable
CC1 channel configured as output:
0: Off - OC1 is not active.
1: On - OC1 signal is output on the corresponding output pin.
CC1 channel configured as input:
This bit determines if a capture of the counter value can actually be done into the input
capture/compare register 1 (TIMx_CCR1) or not.
0: Capture disabled.
1: Capture enabled.
(3)DMA/中断使能寄存器:TIMx_DIER
如果需要用到中断来处理捕获数据,必须开启通道 1 的捕获比较中断,即 CC1IE 设置为 1。
(4)捕获/比较寄存器 1:TIMx_CCR1
该寄存器用来存储捕获发生时,TIMx_CNT
的值,我们从 TIMx_CCR1 就可以读出通道 1 捕获发生时刻的 TIMx_CNT 值,通过两次捕获(一次上升沿捕获,一次下降沿捕获)的差值,就可以计算出高电平脉冲的宽度。
4、相关函数
(1)输入捕获通道初始化函数:
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
1
2
3
4
5
6
7
8
9
10typedef 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;
1
2
3
4
5
6
7
8
9TIM_ICInitTypeDef TIM5_ICInitStructure; TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择输入端 IC1 映射到 TI1 上 TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获 TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到 TI1 上 TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频 TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波 TIM_ICInit(TIM5, &TIM5_ICInitStructure);
(2)通道极性设置独立函数:
void TIM_OCxPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
(3)获取通道捕获值
uint32_t TIM_GetCapture1(TIM_TypeDef* TIMx);
5、输入捕获的一般配置步骤:
① 初始化定时器和通道对应IO的时钟。
② 初始化IO口,模式为输入:GPIO_Init();
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 输入
③初始化定时器ARR,PSC
TIM_TimeBaseInit();
④初始化输入捕获通道
TIM_ICInit();
⑤如果要开启捕获中断,
TIM_ITConfig( TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断和捕获中断
NVIC_Init();
⑥使能定时器:TIM_Cmd();TIM_Cmd(TIM5,ENABLE ); //使能定时器 5
⑦编写中断服务函数:TIMx_IRQHandler();
if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET){}//判断是否为更新中断
if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET){}//判断是否发生捕获事件
TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update);//清除中断和捕获标志位
6、程序
(1)timer.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71//定时器 5 通道 1 输入捕获配置 TIM_ICInitTypeDef TIM5_ICInitStructure; void TIM5_Cap_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //①使能 TIM5 时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //①使能 GPIOA 时钟 //初始化 GPIOA.0 ① GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA0 设置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 输入 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.0 GPIO_ResetBits(GPIOA,GPIO_Pin_0); //PA0 下拉 //②初始化 TIM5 参数 TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //预分频器 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上计数模式 TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //初始化 TIMx //③初始化 TIM5 输入捕获通道 1 TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择输入端 IC1 映射到 TI1 上 TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获 TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到 TI1 上 TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频 TIM5_ICInitStructure.TIM_ICFilter = 0x00; //IC1F=0000 配置输入滤波器 不滤波 TIM_ICInit(TIM5, &TIM5_ICInitStructure); //初始化 TIM5 输入捕获通道 1 //⑤初始化 NVIC 中断优先级分组 NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; //TIM3 中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级 2 级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级 0 级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道被使能 NVIC_Init(&NVIC_InitStructure); //初始化 NVIC TIM_ITConfig( TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//④允许更新中断捕获中断 TIM_Cmd(TIM5,ENABLE ); //⑥使能定时器 5 } u8 TIM5CH1_CAPTURE_STA=0; //输入捕获状态 u16 TIM5CH1_CAPTURE_VAL;//输入捕获值 //⑤定时器 5 中断服务程序 void TIM5_IRQHandler(void) { if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获 { if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET) {if(TIM5CH1_CAPTURE_STA&0X40) //已经捕获到高电平了 { if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了 { TIM5CH1_CAPTURE_STA|=0X80; //标记成功捕获了一次 TIM5CH1_CAPTURE_VAL=0XFFFF; }else TIM5CH1_CAPTURE_STA++; } } if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET) //捕获 1 发生捕获事件 { if(TIM5CH1_CAPTURE_STA&0X40) //捕获到一个下降沿 { TIM5CH1_CAPTURE_STA|=0X80; //标记成功捕获到一次上升沿 TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5); TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //设置为上升沿捕获 }else //还未开始,第一次捕获上升沿 { TIM5CH1_CAPTURE_STA=0; //清空 TIM5CH1_CAPTURE_VAL=0; TIM_SetCounter(TIM5,0); TIM5CH1_CAPTURE_STA|=0X40; //标记捕获到了上升沿 TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //设置为下降沿捕获 } } } TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位 }
(2)main 函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26extern u8 TIM5CH1_CAPTURE_STA; //输入捕获状态 extern u16 TIM5CH1_CAPTURE_VAL; //输入捕获值 int main(void) { u32 temp=0; delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置 NVIC 中断分组 2 uart_init(115200); //串口初始化波特率为 115200 LED_Init(); //LED 端口初始化 TIM3_PWM_Init(899,0); //不分频。PWM 频率=72000/(899+1)=80Khz TIM5_Cap_Init(0XFFFF,72-1); //以 1Mhz 的频率计数 while(1) { delay_ms(10); TIM_SetCompare2(TIM3,TIM_GetCapture2(TIM3)+1); if(TIM_GetCapture2(TIM3)==300) TIM_SetCompare2(TIM3,0); if(TIM5CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿 { temp=TIM5CH1_CAPTURE_STA&0X3F; temp*=65536;//溢出时间总和 temp+=TIM5CH1_CAPTURE_VAL;//得到总的高电平时间 printf("HIGH:%d usrn",temp); //打印总的高点平时间 TIM5CH1_CAPTURE_STA=0; //开启下一次捕获 } } }
7、完整程序包
来源于网络的输入捕获实验
最后
以上就是大方小伙最近收集整理的关于嵌入式单片机基础篇(九)之通用定时器(三)输入捕获stm32F1输入捕获详解的全部内容,更多相关嵌入式单片机基础篇(九)之通用定时器(三)输入捕获stm32F1输入捕获详解内容请搜索靠谱客的其他文章。
发表评论 取消回复