STM32TIM定时器(3)

2024-02-06 21:12
文章标签 定时器 stm32tim

本文主要是介绍STM32TIM定时器(3),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 前言
  • 一、介绍部分
    • 输入捕获简介
    • 频率测量
    • 捕获比较通道
    • 主从模式
    • 输入捕获基本结构
    • PWMI基本结构
  • 二、代码部分
    • 使用输入捕获捕获另一个端口的PWM输入
      • 线路连接
      • 代码内容
    • PWMI获取频率占空比
      • 线路连接与上个案例一致
      • 代码实现
  • 总结
    • 相关函数
    • PSC、ARR都有1的误差


前言

这部分主要介绍输入捕获,通过输入捕获捕获定时器的计数器的值,通过频率检测来获取波形频率。简单介绍主从模式,实现硬件自动化检测。


一、介绍部分

输入捕获简介

在这里插入图片描述
也就是定时器框图的这部分
在这里插入图片描述

频率测量

都是计次数越大误差越小,所以使用N相等时得到中界频率。

在这里插入图片描述

捕获比较通道

在这里插入图片描述

主从模式

通过触发触发源自动运行从模式的内容
在这里插入图片描述

输入捕获基本结构

在这里插入图片描述

PWMI基本结构

在这里插入图片描述

二、代码部分

使用输入捕获捕获另一个端口的PWM输入

使用TIM2、PA0端口用于输出PWM波形,使用TIM3、PA6端口来接收这段波形频率。使用的是测周法

线路连接

在这里插入图片描述

代码内容

PWM.c

#include "stm32f10x.h"                  // Device headervoid PWM_Init(void){// 初始化时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;		// 复用推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 50Hz翻转速度GPIO_Init(GPIOA, &GPIO_InitStructure);// 使用内部时钟(默认)TIM_InternalClockConfig(TIM2);// 配置事间基础(时基单元)TIM_TimeBaseInitTypeDef TIM_InitStructure;// 时钟分频TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;// 计算模式TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;// 重载值(有1的偏差)<计数值> ARRTIM_InitStructure.TIM_Period = 100-1;// 预分频(有1的偏差)<频率> PSCTIM_InitStructure.TIM_Prescaler = 720-1;// 重复计数器(不使用)TIM_InitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2,&TIM_InitStructure);//初始化输出比较TIM_OCInitTypeDef TIM_OCInitStruct;// 初始这个结构体,以免因为没有配置高级定时器相关的值而产生问题TIM_OCStructInit(&TIM_OCInitStruct);// PWM1模式TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;// PWM高电平时有效TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;// 输出使能TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;// CCR,用于控制占空比的值TIM_OCInitStruct.TIM_Pulse = 0;TIM_OC1Init(TIM2,&TIM_OCInitStruct);// 启动定时器TIM_Cmd(TIM2,ENABLE);}// 设置CCR
void PWM_SetCCR(uint16_t Compare){TIM_SetCompare1(TIM2,Compare);}// 设置PSC
void PWM_SetPSC(uint16_t Prescaler){// 单独修改TIM2的预分频,立即生效,不使用影子寄存器TIM_PrescalerConfig(TIM2,Prescaler,TIM_PSCReloadMode_Immediate);
}

封装输入捕获,IC.c内容:

#include "stm32f10x.h"                  // Device headervoid IC_Init(void){// 开启时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;		// 上拉输入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 50Hz翻转速度GPIO_Init(GPIOA, &GPIO_InitStructure);// 使用内部时钟(默认)TIM_InternalClockConfig(TIM3);// 配置事间基础(时基单元)TIM_TimeBaseInitTypeDef TIM_InitStructure;// 时钟分频TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;// 计算模式TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;// 重载值(有1的偏差)<计数值> ARRTIM_InitStructure.TIM_Period = 65536-1;// 预分频(有1的偏差)<频率> PSCTIM_InitStructure.TIM_Prescaler = 72-1;// 重复计数器(不使用)TIM_InitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM3,&TIM_InitStructure);//初始化输入捕获TIM_ICInitTypeDef TIM_ICInitStructure;// 选择CH1通道TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;// 滤波频率,设置高点过使人耳听不见噪音,不会影响频率TIM_ICInitStructure.TIM_ICFilter = 0xF;// 上升沿触发TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;// 分频器不分频TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;// 选择直连通道TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;TIM_ICInit(TIM3,&TIM_ICInitStructure);		// 四个通道一个函数// 设置输入触发源TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);// 选择从模式,重置TIM3的计数器TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);// 启动定时器TIM_Cmd(TIM3,ENABLE);
}uint32_t IC_GetFreq(void){// 72000000/73/获取的ARRreturn 1000000 / (TIM_GetCapture1(TIM3)+1);
}

主函数main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"int main(void)
{OLED_Init();PWM_Init();IC_Init();PWM_SetPSC(720-1);			// f = 72MHz/(Prescaler+1)/(ARR+1)PWM_SetCCR(50);					// 占空比 = CRR/(ARR+1)OLED_ShowString(1,1,"Freq:       Hz");while (1){OLED_ShowNum(1,8,IC_GetFreq(),5);}
}

PWMI获取频率占空比

和PWMI基本结构一样,在上面的基础上多加一条交叉通道,用这个通道检测下降沿,来获取占空比

线路连接与上个案例一致

代码实现

PWM.c不用修改,修改IC.c的内容

#include "stm32f10x.h"                  // Device headervoid IC_Init(void){// 开启时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;		// 上拉输入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 50Hz翻转速度GPIO_Init(GPIOA, &GPIO_InitStructure);// 使用内部时钟(默认)TIM_InternalClockConfig(TIM3);// 配置事间基础(时基单元)TIM_TimeBaseInitTypeDef TIM_InitStructure;// 时钟分频TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;// 计算模式TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;// 重载值(有1的偏差)<计数值> ARRTIM_InitStructure.TIM_Period = 65536-1;// 预分频(有1的偏差)<频率> PSCTIM_InitStructure.TIM_Prescaler = 72-1;// 重复计数器(不使用)TIM_InitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM3,&TIM_InitStructure);//初始化输入捕获TIM_ICInitTypeDef TIM_ICInitStructure;// 选择CH1通道TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;// 滤波频率,设置高点过使人耳听不见噪音,不会影响频率TIM_ICInitStructure.TIM_ICFilter = 0xF;// 上升沿触发TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;// 分频器不分频TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;// 选择直连通道TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
//	TIM_ICInit(TIM3,&TIM_ICInitStructure);		// 四个通道一个函数// 自动配置另一条相反通道,下降沿触发,交叉通道TIM_PWMIConfig(TIM3,&TIM_ICInitStructure);// 设置输入触发源TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);// 选择从模式,重置TIM3的计数器TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);// 启动定时器TIM_Cmd(TIM3,ENABLE);
}uint32_t IC_GetFreq(void){// 72000000/73/获取的ARRreturn 1000000 / (TIM_GetCapture1(TIM3)+1);
}
// 获取占空比
uint32_t IC_GetDuty(void){return (TIM_GetCapture2(TIM3)+1)*100/(TIM_GetCapture1(TIM3)+1);
}

主函数main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"int main(void)
{OLED_Init();PWM_Init();IC_Init();PWM_SetPSC(7200-1);			// f = 72MHz/(Prescaler+1)/(ARR+1)PWM_SetCCR(80);					// 占空比 = CRR/(ARR+1)OLED_ShowString(1,1,"Freq:       Hz");OLED_ShowString(2,1,"Duty:       %");while (1){// 显示频率OLED_ShowNum(1,8,IC_GetFreq(),5);// 显示占空比OLED_ShowNum(2,11,IC_GetDuty(),2);}
}

总结

相关函数

// 初始化输入捕获
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
// 自动配置没有配置的另一条输入捕获通道
void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
// 设置从模式
void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);
// 设置不同定时器的比较值
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);
// 设置不同定时器的预分频
void TIM_SetIC1Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC2Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC3Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC4Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
// 获取不同定时器的捕获计数器内容
uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture2(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture3(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture4(TIM_TypeDef* TIMx);

PSC、ARR都有1的误差

这篇关于STM32TIM定时器(3)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/685550

相关文章

Linux内核定时器使用及说明

《Linux内核定时器使用及说明》文章详细介绍了Linux内核定时器的特性、核心数据结构、时间相关转换函数以及操作API,通过示例展示了如何编写和使用定时器,包括按键消抖的应用... 目录1.linux内核定时器特征2.Linux内核定时器核心数据结构3.Linux内核时间相关转换函数4.Linux内核定时

使用Python实现一个优雅的异步定时器

《使用Python实现一个优雅的异步定时器》在Python中实现定时器功能是一个常见需求,尤其是在需要周期性执行任务的场景下,本文给大家介绍了基于asyncio和threading模块,可扩展的异步定... 目录需求背景代码1. 单例事件循环的实现2. 事件循环的运行与关闭3. 定时器核心逻辑4. 启动与停

Springboot如何配置Scheduler定时器

《Springboot如何配置Scheduler定时器》:本文主要介绍Springboot如何配置Scheduler定时器问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录Springboot配置Scheduler定时器1.在启动类上添加 @EnableSchedulin

【Qt】定时器事件

定时器事件 在之前学习QTimer中实现了定时器的功能,而在QTimer背后是QTimerEvent定时器事件进行支撑的。在QObject中提供了一个timeEvent这个函数。 startTimer启动定时器killTimer关闭定时器 Qt 中在进⾏窗⼝程序的处理过程中,经常要周期性的执⾏某些操作,或者制作⼀些动画效果,使⽤定 时器就可以实现。所谓定时器就是在间隔⼀定时间后,去执⾏某⼀

独立按键单击检测(延时消抖+定时器扫描)

目录 独立按键简介 按键抖动 模块接线 延时消抖 Key.h Key.c 定时器扫描按键代码 Key.h Key.c main.c 思考  MultiButton按键驱动 独立按键简介 ​ 轻触按键相当于一种电子开关,按下时开关接通,松开时开关断开,实现原理是通过轻触按键内部的金属弹片受力弹动来实现接通与断开。  ​ 按键抖动 由于按键内部使用的是机

【JavaScript】在循环体中了解定时器工作机制

for (var i = 0; i < 5; i++) {setTimeout(function() {console.log(i);}, 1000);}console.log(i);   如果我们约定,用箭头表示其前后的两次输出之间有 1 秒的时间间隔,而逗号表示其前后的两次输出之间的时间间隔可以忽略,代码实际运行的结果该如何描述?会有下面两种答案: A. :5 -> 5 -> 5 ->

WebAPI (一)DOM树、DOM对象,操作元素样式(style className,classList)。表单元素属性。自定义属性。间歇函数定时器

文章目录 Web API基本认知一、 变量声明二、 DOM1. DOM 树2. DOM对象3. 获取DOM对象(1)、选择匹配的第一个元素(2)、选择匹配多个元素 三、 操作元素1. 操作元素内容2. 操作元素属性(1)、常用属性(href之类的)(2)、通过style属性操作CSS(3)、通过类名(className)操作CSS(4)、通过classList操作控制CSS(5)、操作表单

深入理解C语言中的POSIX定时器

引言 在Unix和类Unix系统中,定时器是一种常见的机制,用于在特定时间间隔后执行某些操作。POSIX定时器因其灵活性和功能丰富而被广泛采用。本文将深入探讨POSIX定时器的工作原理、内部机制、使用方法及其在实际开发中的应用。 POSIX定时器基础 POSIX定时器是一种高级定时器接口,它允许用户创建定时器并指定定时器到期时的动作。POSIX定时器支持以下特性: 信号通知:定时器到

Android AnalogClock TextClock DigitalClock Chronometer 时钟 定时器

AnalogClock 相关属性:  android:dial="@drawable/img1" //表盘android:hand_hour="@drawable/alert_dialog_icon" //时针android:hand_minute="@drawable/alert_dialog_icon" //分针 TextClock 相关属性: android:f