IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 【STM32】标准库与HAL库对照学习教程十--输入捕获实验 -> 正文阅读

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

一、前言

本篇文章是对定时器功能中的输入捕获功能的讲解与配置,本篇从输入捕获原理讲解开始,一步一步让您学会输入捕获的知识与配置,您可以点击目录跳转您想要看的内容。

二、准备工作

  • 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;  //PA0
	GPIO_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;  //选择通道1
	TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; //预分频器的值设置为1
	TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; //设置极性为上升沿捕获
	TIM_ICInitStruct.TIM_ICFilter = 0;   //不进行滤波
	TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; //选择直接映射到TI1
	TIM_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);   //计一个数1us
	while(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_1
  • TIM_CHANNEL_2
  • TIM_CHANNEL_3
  • TIM_CHANNEL_4
  • TIM_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); //关闭定时器5
			TIM5_CH1_Edge++;  //进入到主函数状态
			TIM5_CH1_VAL = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1); //读取捕获通道的值
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING); //设置捕获极性为上降沿
		}
	}
}

4、实验效果

在这里插入图片描述
到这里就结束啦!
在这里插入图片描述

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-11-25 08:17:11  更:2021-11-25 08:18:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/8 5:21:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码