32单片机基础:输入捕获测频率

news2024/11/19 7:42:20

 接线图如下图所示:

我们复制之前写过的代码6-3 PWM驱动LED呼吸灯

在PWM模块中,执行的逻辑是,初始化TIM2的通道1,产生一个PWM波形,输出引脚是PA0,通过SetCompare1的函数,可以调节CCR1寄存器的值,从而控制PWM的占空比。目前PWM的频率是在初始化里面写好了的,是固定的,运行时调节不太方便,所以我们在最后加一个函数,用来快捷调节PWM的频率。

我们知道PWM频率=更新频率=72M/(PSC+1)/(ARR+1)所以PSC和ARR都可以调节频率,但是占空比等于CRR/(ARR+1),所以通过ARR调节频率,还同时会影响到占空比,而通过PSC调节频率,不会影响占空比,显然比较方便,所以我们计划是,固定ARR为100-1.通过调节PSC来改变PWM频率,另外,ARR为100-1,CCR的数值直接就是占空比

void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode); 

这个函数就是单独写入PSC的函数

我们写一个函数单独改变PSC的值。

void PWM_SetPrescaler(uint16_t Prescaler)
{
	TIM_PrescalerConfig(TIM2,Prescaler, TIM_PSCReloadMode_Immediate);
}

在主函数写入这些代码,就可以输出频率为1Khz,占空比为50%的波形了

    PWM_SetPrescaler(720-1);    //Freq=72M/(PSC+1)/(ARR+1)
	PWM_SetCompare1(50);         //Duty=CCR/(ARR+1)

建立输入捕获的.c,.h文件

首先对IC(输入捕获)初始化,怎么初始化呢?目前我们需要配置电路连接成下图所示的这个样子

 第一步:RCC开启时钟,把GPIO和TIM的时钟打开

第二步:GPIO初始化,把GPIO配置成输入模式,一般选择上拉输入和浮空输入

第三步:配置时基单元,让CNT计数器在内部时钟的驱动下自增运行。

第四步:配置输入捕获单元,包括滤波器,直连通道还是交叉通道,分频器这些参数。用一个结构体就可以统一配置了。

第五步:选择从模式的触发源,触发源选择为TI1FP1,这里调用一个库函数,给一个参数就OK了。

第六步:选择触发之后执行的操作,执行Reset操作,这里也是调用一个库函数就OK了。

最后,当这些电路都配置好了,调用TIM_Cmd函数,开启定时器。

这样所有的电路就能配合起来,按照我们之前的要求工作了。当我们需要读取最新一个周期的频率时,直接读取CCR寄存器,然后按照fc/N,计算一下就行了。

我们了解一下需要的库函数:

void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);

这个是用结构体配置输入捕获单元的函数,另外注意,输入捕获和输出比较都有四个通道,ICInit是共用一个函数的,所以在结构体里会额外有一个参数,可以选择具体配置哪个通道。因为可能有交叉通道的配置,所以函数合在一起比较方便。

void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);

这个函数与上一个函数类似。都是用于初始化输入捕获单元的,上一个函数只是单一的配置一个通道,而这个函数,可以快速配置两个通道,把外设电路结构配置成PWMI模式

void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct);

可以给输入捕获结构体赋一个初始值。

void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);

选择输入触发源TRGI,对应下图所示:调用这个函数,就能选择从模式触发源了。

void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource);

选择输出触发源TRGO,对应下图所示,选择主模式的触发源

void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);

选择从模式

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);

分别单独配置通道1,2,3,4的分频器

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);

分别读取四个通道的CCR,这四个函数和上面的SetCompare1,2,3,4是对应的,读写的都是CCR寄存器,输出比较模式下,CCR是只写的,要用SetCompare写入,输入捕获模式下,CCR是只读的,要用GetCapture读出, 

下面是输入捕获频率的代码:

main.c

#include "stm32f10x.h"                  // Device header              
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"

int main()
{
	
	OLED_Init();
	PWM_Init();
	IC_Init();
	
	OLED_ShowString(1,1,"Freq:00000Hz");
	
    PWM_SetPrescaler(720-1);    //Freq=72M/(PSC+1)/(ARR+1)
	PWM_SetCompare1(50);         //Duty=CCR/(ARR+1)
	while(1)
	{
      OLED_ShowNum(1,6,IC_GetFreq(),5);
	}
}

PWM.c

#include "stm32f10x.h"                  // Device header

void PWM_Init(void)
{
	//时基单元的代码写过,我们找之前定时中断的代码复制一下
	 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //打开时钟、
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	//重映射
	
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);
//	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable ,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;     //GPIO_Pin_15
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	
    TIM_InternalClockConfig(TIM2);//选择内部时钟
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//初始化时基单元
	TIM_TimeBaseInitStructure.TIM_ClockDivision= TIM_CKD_DIV1 ;
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up ;
	TIM_TimeBaseInitStructure.TIM_Period=100-1;//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler=720-1;//PSC
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	//初始化输出比较单元
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1 ;
	TIM_OCInitStructure.TIM_OCPolarity= TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse=0;//CCR   等下再算
	TIM_OC1Init(TIM2,&TIM_OCInitStructure);
	//通道已经初始化完成,在TIM2的OC1通道上就可以输出PWM波形了,这个波形借用GPIO口输出
	 
	 //初始化GPIO
	
	TIM_Cmd(TIM2,ENABLE);//启动定时器
}

void PWM_SetCompare1(uint16_t Compare)
{
	 TIM_SetCompare1(TIM2,Compare);
}

void PWM_SetPrescaler(uint16_t Prescaler)
{
	TIM_PrescalerConfig(TIM2,Prescaler, TIM_PSCReloadMode_Immediate);
}

PWM.h

#ifndef __OLED_H
#define __OLED_H

void PWM_Init(void);
void PWM_SetCompare1(uint16_t Compare);
void PWM_SetPrescaler(uint16_t Prescaler);
#endif

IC.c

#include "stm32f10x.h"                  // Device header

void 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_Pin_15
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	
    TIM_InternalClockConfig(TIM3);//选择内部时钟
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//初始化时基单元
	TIM_TimeBaseInitStructure.TIM_ClockDivision= TIM_CKD_DIV1 ;
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up ;
	TIM_TimeBaseInitStructure.TIM_Period=65536-1;//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler=72-1;//PSC
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
	
	//初始化输入捕获单元
	TIM_ICInitTypeDef TIM_ICInitStructure;
	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);
	TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
	
	TIM_Cmd(TIM3,ENABLE);
}

uint32_t IC_GetFreq(void)
{
	return 1000000/ (TIM_GetCapture1(TIM3)+1);
}

IC.h

#ifndef __IC_H
#define __IC_H

void IC_Init(void);
uint32_t IC_GetFreq(void);
#endif

下面,我们讲解一下代码的操作步骤和逻辑。

开启时钟,配置GPIO,配置时基单元,TIM2输出PWM,TIM3输入捕获。GPIO的时钟。看一下引脚定义表,比如我选择TIM3的通道1,就是PA6,

配置好了之后,初始化输入捕获单元。在tim.h找相应的函数,

接下来找函数把主从模式配置好。

配置TRGI的触发源为TI1FP1.

开启时钟,

之后再写一个函数读取CCR进行计算。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1505724.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Memcached的重要性,如果防范Memcached DDOS攻击

一、Memcached简要 Memcached是一个开源的、高性能的、分布式内存对象缓存系统。它的主要目的是通过降低对数据库的访问来加速动态Web应用程序。 Memcached的用途非常广泛,它主要用于动态Web应用以减轻数据库负载。通过在内存中缓存数据和对象,Memcach…

pytorch_神经网络构建6

文章目录 强化学习概念实现qLearning基于这个思路,那么解决这个问题的代码如下 强化学习概念 强化学习有一个非常直观的表现,就是从出发点到目标之间存在着一个连续的状态转换,比如说从状态一到状态456,而每一个状态都有多种的行为&#xff…

2024/3/10 P1601高精加法

起因是本人在一个为数不多空闲的下午刷题ing&#xff0c;看到了AB problem。“就这&#xff1f;”从而忽略了高精这俩字&#xff0c;然后喜提40分。 于是开始研究何为高精。 #include<iostream> #include<string.h> #include<cstring>using namespace std; c…

数据结构与算法:链式二叉树

上一篇文章我们结束了二叉树的顺序存储&#xff0c;本届内容我们来到二叉树的链式存储&#xff01; 链式二叉树 1.链式二叉树的遍历1.1二叉树的前序&#xff0c;中序&#xff0c;后序遍历1.2 三种遍历方法代码实现 2. 获取相关个数2.1获取节点个数2.2获取叶节点个数2.3 获取树的…

代码随想录算法训练营第day14|二叉树理论基础、二叉树递归遍历、二叉树迭代遍历

目录 a.二叉树理论基础 b.二叉树递归遍历 c.二叉树迭代遍历 迭代法前序遍历 迭代法中序遍历 # 迭代法后序遍历 a.二叉树理论基础 在我们解题过程中二叉树有两种主要的形式&#xff1a;满二叉树和完全二叉树 满二叉树&#xff1a;如果一棵二叉树只有度为0的结点和度为2的…

Mysql 死锁案例1-记录锁读写冲突

死锁复现 CREATE TABLE t (id int(11) NOT NULL,c int(11) DEFAULT NULL,d int(11) DEFAULT NULL,PRIMARY KEY (id),KEY c (c) ) ENGINEInnoDB DEFAULT CHARSETutf8;/*Data for the table t */insert into t(id,c,d) values (0,0,0),(5,5,5),(10,10,10) 事务1事务2T1 START…

Java学习笔记------拼图游戏

图形化界面GUI GUI&#xff1a;Graphical User Interface&#xff08;图像用户接口&#xff09;&#xff0c;指采用图形化的方式显示操作界面 两套体系&#xff1a;AWT包中和Swing包中 组件 JFrame&#xff1a;最外层的窗体 JMenuBar&#xff1a;最上层菜单 JLaber&#…

【软考】图的遍历

目录 1. 概念2. 深度优先搜索2.1 说明2.2 步骤 3. 深度优先搜索例子3.1 无向图3.2 代码示例3.3 结果示例3.4 过程 4. 广度优先搜索4.1 说明4.2 步骤 5. 广度优先搜索例子5.1 无向图5.2 代码示例5.3 结果示例5.4 过程5.5 例题5.5.1 题目1 1. 概念 1.图的遍历是指从某个顶点出发…

递增三元组 刷题笔记

题意为 若存在 a中的数小于b中的数&#xff0c;b中的数小于c中的数 则该数算一种方案 思路 暴力模拟优化 两层循环遍历即可 从b到c的过程我们发现 第三层并不需要循环 直接加上 大于b的数量即可 那么第一层和第三层是对称的 我们有没有可能再去掉一层循环 只做一次遍历 …

Spring boot2.7整合jetcache 本地linkedhashmap缓存方案

好 上文 Spring boot2.7整合jetcache 远程redis缓存方案 我们讲完了 远程实现方案 本文 我们来说说 本地 jetcache解决方案 首先是 application.yml 在jetcache下加上 local:default:type: linkedhashmapkeyConvertor: fastjson我们技术用的 本地缓存 linkedhashmap 这里 我们…

netty草图笔记

学一遍根本记不住&#xff0c;那就再学一遍 public static void test_nettyFuture() {NioEventLoopGroup group new NioEventLoopGroup();log.info("开始提交任务");Future<String> future group.next().submit(() -> {log.info("执行异步任…

DualSPHysics使用FlowTool工具进行后处理,定义的粒子全在domains外,解决办法

可以知道DualSPHysics官方给了后处理工具使用的示例&#xff0c;如下就是官方给的案例&#xff0c;使用FlowTool工具可以计算出在两个实体domain内的粒子数。 然而我自己也定义了2个domains&#xff0c;但是计算出来Tank1和Tank2里边的粒子数一直是空的&#xff0c;粒子全部在…

微服务系列(一)springcloudAlibaba之Nacos注册和配置中心及openFeign远程调用

一&#xff0c;认识微服务 我们先看看开发大型项目采用单体架构存在哪些问题&#xff0c;而微服务架构又是如何解决这些问题的。 1.1 单体架构 单体架构&#xff08;monolithic structure&#xff09;&#xff1a;整个项目中所有功能模块都在一个工程中开发&#xff1b;项目部署…

数学建模【时间序列】

一、时间序列简介 时间序列也称动态序列&#xff0c;是指将某种现象的指标数值按照时间顺序排列而成的数值序列。时间序列分析大致可分成三大部分&#xff0c;分别是描述过去、分析规律和预测未来&#xff0c;本篇将主要介绍时间序列分析中常用的三种模型&#xff1a;季节分解…

第3集《天台教观纲宗》

乙二、约观行释 诸位法师慈悲&#xff01;陈会长慈悲&#xff01;诸位菩萨&#xff01;阿弥陀佛&#xff01; 请大家打开讲义第六页。我们看到乙二、约观行释。这一科是讲到天台教观的修学宗旨。 我们前面讲到&#xff0c;天台教观整个建立的过程&#xff0c;它是先有观法&a…

AHU 汇编 实验一

一、实验名称&#xff1a;实验1 实验1 用Debug命令查看寄存器和内存中的内容 实验目的:求掌握使用Debug命令查看寄存器和内存的方法。 通过第2章两个简单实例认识汇编语言程序&#xff0c;初步了解程序格式&#xff1b;段定义&#xff1b;标号&#xff1b;DOS系统功能&#xf…

017-$route、$router

$route、$router 1、$route2、$router 1、$route $route 对象表示当前的路由信息&#xff0c;包含了当前 URL 解析得到的信息。包含当前的路径&#xff0c;参数&#xff0c;query对象等。 使用场景&#xff1a; 获取路由传参&#xff1a;this.$route.query、this.$route.par…

Linux-socket套接字

前言 在当今数字化时代&#xff0c;网络通信作为连接世界的桥梁&#xff0c;成为计算机科学领域中至关重要的一部分。理解网络编程是每一位程序员必备的技能之一&#xff0c;而掌握套接字编程则是深入了解网络通信的关键。本博客将深入讨论套接字编程中的基本概念、常见API以及…

C++指针(五)完结篇

个人主页&#xff1a;PingdiGuo_guo 收录专栏&#xff1a;C干货专栏 前言 相关文章&#xff1a;C指针&#xff08;一&#xff09;、C指针&#xff08;二&#xff09;、C指针&#xff08;三&#xff09;、C指针&#xff08;四&#xff09;万字图文详解&#xff01; 本篇博客是介…

Independent Variable Dependent Variable

自变量&#xff08;Independent Variable&#xff09; -----------> 因变量&#xff08;Dependent Variable&#xff09; 数据 ----------------------------------------------结果&#xff0c;报告等等