【STM32】定时器

systick定时器:

【STM32】Systick定时器-CSDN博客

0.通用定时器框图

1.时钟源

2.控制器

3.输入捕获

计数器实际上是与比较寄存器的影子寄存器进行比较的。

4.输出比较

1.STM32的定时器学习要点

参考手册

STM32F1xx中文参考手册.pdf · 林何/STM32F103C8 - 码云 - 开源中国 (gitee.com)

1.通用定时器和其他的区别

1)其实最多可以有17个定时器

2)功能差别

2.STM32定时器的学习要点

1)先学会定时器基本概念的使用

2)高级功能用到到时再去细看

3)设计本身的复杂性导致学习难度大,要有耐心

4)很多书面概念要搞清楚,需要不断前后对照

5)学习三宝:数据手册+外设库源码+例程

2.通用定时器的数据手册

进行比较计数器和寄存器的值进行电平的反转。

1.TIMx主要功能

定时器是基于计数器进行的,分频,然后走一格就计数一次。

1.向上/向下

向上:加法计数器【从x不断++到65535】

向下:减法计数器【从x不断--到0】

2.TIM的所属APB

3.发生的中断/DMA

2.通用定时器框图

3.预分频器

1.时基单元

1)可以在运行的时候对预分频器的值进行修改

我们这里可以在运行时对其进行修改的是count计数器(可以在当前事件执行时进行更新,也可以等到下一次更新事件发生后在进行改变)

预分频器(预分频器的值只能在下一次更新事件到来时被采用。)

2)影子寄存器【预装载寄存器】:在硬件上实际上是存在的,但是没有给他分配地址(不需要程序进行干预)

1.1 TIMx_CR1_ARPE:修改位

1.2 TIMx_CR1_UDIS:中断允许位

1.3 TIMx_CR1_CEN:时钟和计数器的使能

注意点:

真正的计时器使能信号CNR_EN是在CEN的一个时钟周期后被设置(表示计数器是在一个周期后才开始计时)

2.预分频器描述

预分频器可以在工作时被改 变。但是新的预分频器参数只能在下一次更新事件到来时被采用。【因为预分频器中带有缓冲器】

2.1 计数器的时序图:1分频--2分频

2.2 计数器的时序图:1分频--4分频

4.计数器

1.向上计数器模式

1.与51单片机不同

2.基本概念

3.是否产生更新事件

4.计数器时序图

5.ARPE=0时的更新事件【立即模式-不缓存】

6.ARPE=1时的更新事件【下一周期改变--缓存】

2.向下计数模式

注意点:

向下计数模式没有【立即模式】,因为如果原来ff,然后现在走到05,然后修改为36,不可能重新回36在继续减,这是不合理的。

3.中央对齐模式(向上/向下计数)

在中央对齐模式,计数器从0开始计数到自动加载的值(TIMx_ARR寄存器)−1,产生一个计数器 溢出事件,然后向下计数到1并且产生一个计数器下溢事件;然后再从0开始重新计数。

1.注意点

1)在这个模式,不能写入TIMx_CR1中的DIR方向位。它由硬件更新并指示当前的计数方向。

2)注意加减的边界值问题:

        加法计数器是寄存器值-1

        减法计数器是减到1

2.计数器时序图

3.ARPE=1时的更新事件【下一周期更新--缓存】

5.时钟选择

1.内部时钟(CK_INT)--常规模式

1.使能

通过设置TIMx_SMCR寄存器的SMS=000,表示使用内部时钟【常规模式】。

2.外部时钟模式1:外部输入脚(TIx)

3.外部时钟模式2:外部触发输入(ETR)

4.内部触发输入(ITRx):一个定时器的输出作为另外一个定时器的输入

6.库函数

1.TIM_TimeBaseInit

void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
{
  uint16_t tmpcr1 = 0;

  /* Check the parameters */
  assert_param(IS_TIM_ALL_PERIPH(TIMx)); 
  assert_param(IS_TIM_COUNTER_MODE(TIM_TimeBaseInitStruct->TIM_CounterMode));
  assert_param(IS_TIM_CKD_DIV(TIM_TimeBaseInitStruct->TIM_ClockDivision));

  tmpcr1 = TIMx->CR1;  

  if((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM2) || (TIMx == TIM3)||
     (TIMx == TIM4) || (TIMx == TIM5)) 
  {
    /* Select the Counter Mode */
    tmpcr1 &= (uint16_t)(~((uint16_t)(TIM_CR1_DIR | TIM_CR1_CMS)));
    tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_CounterMode;
  }
 
  if((TIMx != TIM6) && (TIMx != TIM7))
  {
    /* Set the clock division */
    tmpcr1 &= (uint16_t)(~((uint16_t)TIM_CR1_CKD));
    tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_ClockDivision;
  }

  TIMx->CR1 = tmpcr1;

  /* Set the Autoreload value */
  //要计数的值
  TIMx->ARR = TIM_TimeBaseInitStruct->TIM_Period ;
 
  /* Set the Prescaler value */
  //预分频参数
  TIMx->PSC = TIM_TimeBaseInitStruct->TIM_Prescaler;
    
  if ((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM15)|| (TIMx == TIM16) || (TIMx == TIM17))  
  {
    /* Set the Repetition Counter value */
    TIMx->RCR = TIM_TimeBaseInitStruct->TIM_RepetitionCounter;
  }

  /* Generate an update event to reload the Prescaler and the Repetition counter
     values immediately */
     //预分频器参数的改变
  TIMx->EGR = TIM_PSCReloadMode_Immediate;           
}

2.TIM_ITConfig

void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)
{  
  /* Check the parameters */
  assert_param(IS_TIM_ALL_PERIPH(TIMx));
  assert_param(IS_TIM_IT(TIM_IT));
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  
  if (NewState != DISABLE)
  {
    /* Enable the Interrupt sources */
    TIMx->DIER |= TIM_IT;
  }
  else
  {
    /* Disable the Interrupt sources */
    TIMx->DIER &= (uint16_t)~TIM_IT;
  }
}

7.定时器例程分析和编程实践

1.RCC_Configuration

TIM2接APB1,GPIOB接APB2

2.GPIO_Configuration

配置的是GPIOB

3.NVIC_Configuartion

void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

#ifdef  VECT_TAB_RAM
  /* Set the Vector Table base location at 0x20000000 */
  NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else  /* VECT_TAB_FLASH  */
  /* Set the Vector Table base location at 0x08000000 */
  NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif

   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  /* Enable the TIM1 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

}

 4.TIM2_IRQHandler

5.时钟编写

8.代码移植

1.先写定时器

如果不知道定时器的名字是什么可以去“startup_stm32f10x_hd.s”查看

再去“stm32f10x_it.c”中填写

2.RCC_Configuration

注意点:

TIM2和GPIOB所对应的APB对应不一样,所以一定要分开声明,要不然会出现错误。

TIM2---》APB2

GPIOB--》APB1

void RCC_Configuration(void)
{
	//打开时钟
	//注意点:
	//TIM2和GPIOB的APB不一样,所以只能分开声明,要不然不起效果
//	RCC_APB2PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB2Periph_GPIOB, ENABLE);	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
}

3.GPIO_Configuration

void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

   /* GPIOA Configuration: */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure); 
  
  GPIO_WriteBit(GPIOB, GPIO_Pin_8, Bit_RESET); 
}

4.NVIC_Configuration

void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

#ifdef  VECT_TAB_RAM
  /* Set the Vector Table base location at 0x20000000 */
  NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else  /* VECT_TAB_FLASH  */
  /* Set the Vector Table base location at 0x08000000 */
  NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif

   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  /* Enable the TIM1 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

}

5.APB的分频问题

TIM2接APB1,GPIOB接APB2

我们APB1不能超过36MHZ,所以要对72MHZ进行分频

		//72MHZ定时器的定义
		// 主频是72MHz,HCLK是72M,PCLK2是72M,PCLK1是36M
		// TIM2接在PCLK1下(APB1)所以源是36M,CK_CNT是36M/7200=5KHz
		TIM_TimeBaseStructure.TIM_Prescaler = 7199;
	//例如:时钟频率=72/(时钟预分频+1)
		TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
		// 计数个数是10000,所以计数时间是10000*1/5000=2s
		TIM_TimeBaseStructure.TIM_Period = 9999;//自动重装载寄存器周期的值(定时时间)累计
		//0xffff 个频后产生个更新或者中断(也就是说定时时间到)

6.完整代码

main

#include "stm32f10x.h"                  // Device header
/**

	根据定时器2来实现数码管每隔1秒闪烁一次
*/


void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);

int main(){
	  //设置TIM2定时器
	  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	
	  RCC_Configuration();  //系统时钟配置
  	NVIC_Configuration();	 //NVIC配置
  	GPIO_Configuration();	 //通用IO端口配置
	
		//72MHZ定时器的定义
		// 主频是72MHz,HCLK是72M,PCLK2是72M,PCLK1是36M
		// TIM2接在PCLK1下(APB1)所以源是36M,CK_CNT是36M/7200=5KHz
		TIM_TimeBaseStructure.TIM_Prescaler = 7199;
	//例如:时钟频率=72/(时钟预分频+1)
		TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
		// 计数个数是10000,所以计数时间是10000*1/5000=2s
        //注意点:我们计算出来的值是5,但是我们实际上是从0开始,所以我们这里要-1
		TIM_TimeBaseStructure.TIM_Period = 4;//自动重装载寄存器周期的值(定时时间)累计
		//0xffff 个频后产生个更新或者中断(也就是说定时时间到)
		TIM_TimeBaseStructure.TIM_ClockDivision = 0;
		//初始化定时器2
		TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
		
		//打开中断,溢出中断
		TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); 
	  //定时器打开
		TIM_Cmd(TIM2, ENABLE); 
		while (1);
		//进入中断

	return 0;
}


void RCC_Configuration(void)
{
	//打开时钟
	//注意点:
	//TIM2和GPIOB的APB不一样,所以只能分开声明,要不然不起效果
//	RCC_APB2PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB2Periph_GPIOB, ENABLE);	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
}


void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

   /* GPIOA Configuration: */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure); 
  
	//使亮数码管
  GPIO_WriteBit(GPIOB, GPIO_Pin_8, Bit_SET); 
}

void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

#ifdef  VECT_TAB_RAM
  /* Set the Vector Table base location at 0x20000000 */
  NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else  /* VECT_TAB_FLASH  */
  /* Set the Vector Table base location at 0x08000000 */
  NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif

   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  /* Enable the TIM1 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

}

stm32f10x_it.c

void TIM2_IRQHandler(void){
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)  //检测制定的中断是否发生
  {
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);  //清除中断处理位。
		//LED的取反
	 	GPIO_WriteBit(GPIOB, GPIO_Pin_8, !GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_8));
  }  
}

9.问题解决:APB频率计算问题

cnt的计数公式 

cnt=1s*频率值(HZ)

例如:

此时TIM2一定是分完频,结果为36MHZ

初始化:TIM_TimeBaseStructure.TIM_Prescaler = 7199;--》【最后要+1】

CK_CNT=36M/72 00=5KHZ

实际测试得到的是1KHZ的结果,说明前面分析有误

初始化:计数个数为1 0000个

所以:计数时间为:1 0000*1/5000=2s

结论:APB1时钟确实是36MHZ,但是APB1到定时器时钟那边中间被乘以2,所以又变成72MHZ了。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode-394 字符串解码(不会,复习)

此题不会!!!!!!!!!!!! 题解思路:元组思想:数字[字符串],每次遇到中括号意味着要重复数字次字符串…

Web APIs——综合案例

1、学生就业统计表 2、渲染业务 根据持久化数据渲染页面 步骤: ①:读取localstorage本地数据 如果有数据则转换为对象放到变量里面一会使用它渲染页面如果没有则用默认空数组[]为了测试效果,可以先把initData存入本地存储看效果 ②&…

Oracle11g for centos7

准备工作 x86 centos7 oracle11G 环境搭建 配置好虚拟机,网络通畅,建议最少3G内存。 安装依赖 yum install binutils compat-libstdc-33 glibc* ksh gcc gcc-c libgcc libstdc* libaio libaio-devel libXext libX11 libXau libxcb libXi make sy…

2023第六届泰迪杯数据分析,第五届泰迪杯数据分析技能赛B题源码图片分享

需要B题源码以及第六届带队”指导“请私信本人,团队包含技能赛双一等,数学建模省一,泰迪杯挖掘国一,研究生队友。 去年一等作品可视化图如下,私信获取源码

static关键字的三种用法

在C语言中,关键字"static"可以用于不同的上下文,具有不同的作用。以下是"static"在C语言中的主要作用: 1. 静态变量(Static Variables): 在C语言中,使用static关键字来声明…

Java算法(五):手写数组逆置API方法,实现数组逆置。 while实现 for循环实现

Java算法(五) while 循环实现 需求: 已知一个数组,arr {11, 22, 33, 44, 55};使用程序实现把数组中的元素交换位置。 交换后的数组为 arr {55, 44, 33, 22, 11}; 并在控制台输出交换后的数组元素。 代码示例 package com.…

JS 处理文档选择和范围创建【createRange | getSelection】

介绍 1、const selection window.getSelection(); 说明: 1、用于获取用户当前文档选择的对象; 2、它返回一个 Selection 对象,该对象代表了用户选择的文本范围(可以包含一个或多个范围,因为用户可以同时选择多个不相…

YOLO目标检测——红绿灯检测数据集【含对应voc、coco和yolo三种格式标签】

实际项目应用:红绿灯检测数据集在自动驾驶、交通安全监控、智能交通系统、交通流量监测和驾驶员辅助系统等领域都有广泛应用的潜力数据集说明:红绿灯检测数据集,真实场景的高质量图片数据,数据场景丰富,含有国内红绿灯…

Android:OkHttp同步请求和异步请求

一、前言 网络请求之前工作中用到的是post请求,然后了解之后发现请求的种类还有很多种。下面着重讲到是get和post的同步请求和异步请求。 二、具体内容 1.Okhttp的特点: 支持Http/2并允许对同一主机的所有请求共享一套接字;如果非HTTP/2&…

运维相关(一) - Vue项目配置WebSocket连接{ws、wss 连接方式}

Vue项目配置WebSocket连接 ws、wss 两种方式 1. 写作背景2. 晒出代码2.1 前端 vue.config.js 的代码2.2 Vue项目路由配置代码3.3 服务器Nginx配置 3. 使用方式3.1 前端代码3.2 后端代码 4. 测试使用 1. 写作背景 项目使用的是ruoyi的前后端分离框架项目需要使用到 websocket , …

数据结构与算法—双链表

前言 前面有很详细的讲过线性表(顺序表和链表),当时讲的链表以单链表为主,但在实际应用中双链表有很多应用场景,例如大家熟知的LinkedList。 双链表与单链表区别 单链表和双链表都是线性表的链式实现,它们的主要区别在于节点结构…

lua 时间差功能概略

简介 在进行程序设计过程中,经常需要对某些函数、某些程序片断从开始运行到运行结束所耗费的时间进行一些量化。这种量化实际上就是计算时间差。 获取函数耗时情景如下: function time_used() --开始计时-- do something at here. --结束计时--时间差&…

交易所开发搭建

在当今的数字货币市场中,交易所开发搭建已经成为了一个重要的领域。交易所是数字货币交易的主要场所,为投资者提供了安全、可靠、高效的交易服本务文。将详细介绍交易所开发搭建的整个流程,包括需求分析、设计、技术选型、开发、测试和上线等…

【2】Spring Boot 3 项目搭建

目录 【2】Spring Boot 3 初始项目搭建项目生成1. 使用IDEA商业版创建2. 使用官方start脚手架创建 配置与启动Git版本控制 个人主页: 【⭐️个人主页】 需要您的【💖 点赞关注】支持 💯 【2】Spring Boot 3 初始项目搭建 项目生成 1. 使用IDEA商业版创…

【Element】隐藏 el-table 展开行的箭头

需求 点击行展开行,隐藏箭头 方法 首先需求是点击行显示展开行 row-click"rowClick"const rowClick (row: any, column: any, event: any) > {console.log(row, column, event)if (multipleTable.value) {multipleTable.value.toggleRowExpansio…

PostgreSQL 技术内幕(十一)位图扫描

扫描算子在上层计算和底层存储之间,向下扫描底层存储的数据,向上作为计算的输入源,在SQL的执行层中,起着关键的作用。顺序、索引、位图等不同类型的扫描算子适配不同的数据分布场景。然而,扫描算子背后的实现原理是怎样…

投资自己,成就未来——人大女王金融硕士助力您成为金融领域的佼佼者

在这个日新月异的时代,金融行业的发展日益繁荣,对于金融人才的需求也越来越大。为了应对这一挑战,越来越多的人选择投身金融领域,提升自己的专业素养。而中国人民大学女王金融硕士项目,正是为了满足这一需求而设立的&a…

JVM在线分析-解决问题的工具一(jinfo,jmap,jstack)

1. jinfo (base) PS C:\Users\zishi\Desktop> jinfo Usage:jinfo <option> <pid>(to connect to a running process)where <option> is one of:-flag <name> to print the value of the named VM flag #输出对应名称的参数-flag [|-]<n…

Pandas数据预处理Pandas合并数据集在线闯关_头歌实践教学平台

Pandas数据预处理合并数据集 第1关 Concat与Append操作第2关 合并与连接第3关 案例&#xff1a;美国各州的统计数据 第1关 Concat与Append操作 任务描述 本关任务&#xff1a;使用read_csv()读取两个csv文件中的数据&#xff0c;将两个数据集合并&#xff0c;将索引设为Ladder…