糖尿病康复,内容丰富有趣,生活中的好帮手!
糖尿病康复 > 【STM32】标准库与HAL库对照学习教程十--输入捕获实验

【STM32】标准库与HAL库对照学习教程十--输入捕获实验

时间:2022-09-29 02:36:13

相关推荐

【STM32】标准库与HAL库对照学习教程十--输入捕获实验

【STM32】标准库与HAL库对照学习教程十--输入捕获实验

一、前言二、准备工作三、输入捕获介绍1、简介2、原理 四、输入捕获结构1、通道映射表2、结构图 五、输入捕获寄存器位(1)ICF[3:0](2)CC1S[1:0](3)ICPS[1:0](4)CC1P(5)CC1E 六、硬件电路七、标准库配置输入捕获1、配置步骤2、配置工程3、实验程序4、实验效果 八、HAL库配置输入捕获1、使用cubemx生成工程2、相关函数3、实验程序4、实验效果

一、前言

二、准备工作

STM32F103开发板(我用的是普中的STM32F103ZE开发板)cubemx软件、keil 5(MDK)开发板原理图

有关于定时器不了解的可以看这篇文章:【STM32】标准库与HAL库对照学习教程七–定时器中断

三、输入捕获介绍

1、简介

定时器章节我们了解到通用定时器具有多种功能,输入捕获就是其中一种。

STM32F1除了基本定时器TIM6和TIM7其他定时器都具有输入捕获功能

输入捕获可以对输入的信号上升沿,下降沿或者双边沿进行捕获,通常用于测量输入信号的脉宽、测量 PWM 输入信号的频率及占空比。

与输出比较一样,每个定时器的输入捕获有4个通道,分别映射到四个引脚上

2、原理

在输入捕获模式下,捕获中断定时器中断是打开的。

①输入捕获初始化②检测到边沿电平变化,触发捕获中断,在中断函数里,清空计算器TIMx_CNT的值③计算期间,可能会达到重装载值ARR触发定时器中断,在中断函数里,记录定时器计算溢出的次数为N④再次检测到边沿电平变化,触发中断,在中断函数里,得到计算器TIMx_CNT的值,记录到一个变量里(CCR)⑤高电平持续时间=(CCR+N*ARR)*计算周期 。.,ARR为定时器重装载值。

在拿一个对比图形

四、输入捕获结构

1、通道映射表

图片来源于STM32F1xx中文参考手册 116页

2、结构图

可以看到,捕获与比较的通道是相同的,所以在捕获与比较只能用一种,并且在图中可以看出通道1与通道2的捕获是可以互通的。

五、输入捕获寄存器位

由上面的图2,可以知道,控制输入捕获的比较重要的几个位,分别是来自TIMx_CCMR1寄存器的ICF[3:0]、CC1S[1:0]、ICPS[1:0]位TIMx_CCER寄存器的CC1P、CC1E位

(1)ICF[3:0]

数字滤波器由一个事件计数器组成,假设我们是检测高电平,滤波N次,当连续N次采样检测,如果都是高电平,则说明这是一个有效的电平信号,这样便可以过滤掉那些因为某些而干扰产生的一些信号 。

输入捕获滤波器IC1F[3:0],这个用于设置采样频率和数字滤波器长度

(2)CC1S[1:0]

因为通道1与通道2是可以互通的,所以要使用这个位选择映射位置

(3)ICPS[1:0]

捕获预分频器,表示遇到N个边沿时捕获一次

(4)CC1P

配置通道是输入捕获还是输出比较

(5)CC1E

捕获使能位。

图片来源于STM32F1xx中文参考手册 282页

六、硬件电路

本篇使用输入捕获检测按键引脚高电平的持续时间

按键电路请参考自己开发板的原理图。

七、标准库配置输入捕获

1、配置步骤

(1)使能定时器及端口时钟,并设置引脚复用器映射和引脚模式等(2)初始化定时器参数,包含自动重装值,分频系数,计数方式等(3)设置通用定时器的输入捕获参数,开启输入捕获功能(4)开启捕获和定时器溢出(更新)中断(5)设置定时器中断优先级,使能定时器中断通道(6)编写定时器中断服务函数(7)使能定时器

2、配置工程

标准库

(1)复制上一章的工程,并重命名为10、输入捕获实验

(2)进入工程文件,进入APP文件,新建Input用来存放与输入捕获相关的文件。

(3)打开工程,新建文件,并命名为input.h与input.c

(4)添加文件到目录,并添加头文件路径

3、实验程序

input.h

#ifndef INPUT_H_#define INPUT_H_#include "stm32f10x.h"extern volatile u16 TIM_Exceed; //定时器计数溢出次数extern volatile u8 TIM_IC_Edge; //边沿检测计数extern volatile u16 TIM_IC_VAL; //存放计数器CNT的值void TIM5_CH1_Input_Init(u16 Psc,u16 Per);#endif

input.c

#include "input.h"volatile u16 TIM_Exceed = 0; //定时器计数溢出次数volatile u8 TIM_IC_Edge = 0; //边沿检测计数volatile u16 TIM_IC_VAL = 0; //存放计数器CNT的值/**************************************************函数名: TIM5_CH1_Input_Init*函数功能:定时器5通道1输入捕获初始化函数*输入: Psc:定时器分频,Per:自动重装载值*返回值: 无**************************************************/void TIM5_CH1_Input_Init(u16 Psc,u16 Per){GPIO_InitTypeDef GPIO_InitStruct;TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_ICInitTypeDef TIM_ICInitStruct;NVIC_InitTypeDef NVIC_InitStruct;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //使能定时器时钟RCC_APB1PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能引脚时钟//引脚配置GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; //PA0GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD; //下拉输入GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStruct); ///初始化引脚//定时器配置TIM_TimeBaseInitStruct.TIM_Prescaler = Psc; //时钟分频TIM_TimeBaseInitStruct.TIM_Period = Per; //重装载数TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //系统1分频TIM_TimeBaseInit(TIM5, &TIM_TimeBaseInitStruct); //初始化时钟//捕获通道设置TIM_ICInitStruct.TIM_Channel = TIM_Channel_1; //选择通道1TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; //预分频器的值设置为1TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; //设置极性为上升沿捕获TIM_ICInitStruct.TIM_ICFilter = 0; //不进行滤波TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; //选择直接映射到TI1TIM_ICInit(TIM5, &TIM_ICInitStruct); //输入捕获初始化TIM_ITConfig(TIM5, TIM_IT_Update|TIM_IT_CC1, ENABLE); //开启捕获中断与定时器中断NVIC_InitStruct.NVIC_IRQChannel = TIM5_IRQn; //定时器中断通道NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; //抢占式优先级NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3; //响应式优先级NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //中断通道使能NVIC_Init(&NVIC_InitStruct); //中断通道初始化TIM_Cmd(TIM5, ENABLE); //定时器5使能}/**************************************************函数名:TIM5_IRQHandler*函数功能: 定时器5的中断函数*输入: 无*返回值:无**************************************************/void TIM5_IRQHandler(){if(TIM_GetITStatus(TIM5, TIM_IT_Update)) //计数器溢出产生的中断{if(TIM_IC_Edge == 1) //高电平状态{TIM_Exceed++; //定时器计数溢出次数加1}}if(TIM_GetITStatus(TIM5, TIM_IT_CC1)) //捕获中断{if(TIM_IC_Edge == 0) //捕获的上升沿{TIM_Cmd(TIM5, DISABLE); //定时器5失能TIM_OC1PolarityConfig(TIM5, TIM_OCPolarity_Low); //设置极性为下升沿捕获TIM_Exceed = 0; //定时器计数溢出次数清零TIM_SetCounter(TIM5, 0); //定时器5的CNT清零TIM_IC_Edge++; //下个状态为下降沿捕获TIM_Cmd(TIM5, ENABLE); //定时器5使能}else //捕获的是下降沿{TIM_Cmd(TIM5, DISABLE); //定时器5失能TIM_IC_VAL = TIM_GetCapture1(TIM5); //获取定时器5的计数值TIM_OC1PolarityConfig(TIM5, TIM_OCPolarity_High); //设置极性为上升沿捕获TIM_IC_Edge++; //下个状态到主函数}}TIM_ClearITPendingBit(TIM5, TIM_IT_Update|TIM_IT_CC1); //清空标志位}

main.c

#include "LED.h"#include "Delay.h"#include "System.h"#include "input.h"#include "usart.h"#include "stdio.h"/**************************************************函数名: main*函数功能: 主函数*输入:无 *返回值: 无**************************************************/int main(){u32 time;SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //抢占式优先级与响应式优先级的分组LED_Init();USART1_Init(9600);TIM5_CH1_Input_Init(71,0xffff); //计一个数1uswhile(1){if(TIM_IC_Edge == 2){time = TIM_IC_VAL+TIM_Exceed*0xffff; //得到总计数值printf("高电平持续时间是 %d ms\r\n",time/1000); //打印高电平持续时间TIM_IC_Edge = 0; //边沿捕获值清零TIM_Cmd(TIM5, ENABLE); //重新使能定时器}}}

4、实验效果

八、HAL库配置输入捕获

1、使用cubemx生成工程

(1)打开cubemx,新建工程,选择自己的芯片。

(2)配置RCC,选择外部高速时钟

(3)配置时钟树

(4)配置捕获通道

上升沿捕获直接映射到引脚不分频0次滤波

③打开中断

④设置引脚为下拉

(5)配置串口

(6)工程文件配置并生成工程

2、相关函数

HAL_TIM_ReadCapturedValue() ; 获取捕获通道计数器的函数HAL_TIM_IC_Start();开启输入捕获通道HAL_TIM_IC_Stop();关闭输入捕获通道HAL_TIM_IC_Start_IT();开启输入捕获通道与中断HAL_TIM_IC_Stop_IT();关闭输入捕获通道与中断__HAL_TIM_SET_COUNTER(HANDLE,COUNTER)设置计数器CNT的值,(HANDLE:时钟,COUNTER:设置的值)TIM_RESET_CAPTUREPOLARITY(HANDLE,CHANNEL);清除通道极性TIM_SET_CAPTUREPOLARITY(HANDLE,CHANNEL,POLARITY);设置通道极性__HAL_TIM_SET_CAPTUREPOLARITY(HANDLE,CHANNEL,POLARITY);清除通道极性,并设置通道极性HAL_TIM_PeriodElapsedCallback() ;定时器中断回调函数HAL_TIM_IC_CaptureCallback();捕获中断回调函数

Channel

TIM_CHANNEL_1TIM_CHANNEL_2TIM_CHANNEL_3TIM_CHANNEL_4TIM_CHANNEL_ALL

极性TIM_ICPOLARITY_RISING-上升沿TIM_ICPOLARITY_FALLING-下降沿TIM_ICPOLARITY_BOTHEDGE-上升下降沿

3、实验程序

#include<stdio.h>

int fputc(int ch, FILE *f){HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);return ch;}

uint8_t TIM5_CH1_Edge=0; //状态变化时,计数值uint32_t TIM5_CH1_VAL=0; //储存计数器的记录值uint32_t TIM5_CH1_OVER=0; //计数器溢出的个数uint32_t time; //高电平持续时间

HAL_TIM_Base_Start_IT(&htim5);//打开定时器中断HAL_TIM_IC_Start_IT(&htim5,TIM_CHANNEL_1); //打开输入捕获

if(TIM5_CH1_Edge == 2){TIM5_CH1_Edge = 0; //重新开始捕获time = TIM5_CH1_VAL + TIM5_CH1_OVER*0xffff;printf("高电平持续时间为 %d ms\r\n", time/1000);HAL_TIM_IC_Start_IT(&htim5,TIM_CHANNEL_1); //打开输入捕获}

回调函数

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){if(htim == &htim5){if(TIM5_CH1_Edge == 1){TIM5_CH1_OVER++; //定时器溢出值增加}}}void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){if(htim == &htim5){if(TIM5_CH1_Edge == 0) //捕获到上升沿{TIM5_CH1_Edge++; //进入捕获下降沿状态TIM5_CH1_OVER = 0; //定时器溢出值清零__HAL_TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING); //设置捕获极性为下降沿__HAL_TIM_SET_COUNTER(&htim5,0); //设置定时器CNT计数器的值为0}else //捕获到下升沿{HAL_TIM_IC_Stop_IT(&htim5,TIM_CHANNEL_1); //关闭定时器5TIM5_CH1_Edge++; //进入到主函数状态TIM5_CH1_VAL = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1); //读取捕获通道的值__HAL_TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING); //设置捕获极性为上降沿}}}

4、实验效果

到这里就结束啦!

如果觉得《【STM32】标准库与HAL库对照学习教程十--输入捕获实验》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。