05:(寄存器开发)定时器一

devtools/2024/10/8 17:28:41/

定时器

  • 1、系统定时器SysTick
    • 1.1、SysTick中断的使用
    • 1.2、使用SysTick制作延迟函数
  • 2、基本定时器
    • 2.1、基本定时器中断的使用
    • 2.2、使用基本定时器制作延时函数

1、系统定时器SysTick

1.1、SysTick中断的使用

①SysTcik系统滴答定时器和片上外设定时器不同,它在CPU内核中,如同NVIC和RCC一样,在使用它的时候,不需要在开启时钟,他们都内嵌在AHB系统时钟总线里面,因为一上电都已经开启了。
SysTick是一个24位的向下计数器,而计数器的频率为AHB或者AHB/8。当重装载数值寄存器的值递减到0的时候(COUNTFLAG标志位由0变为1),系统定时器就产生一次中断(开启中断的情况下),以此循环往复。
由于SysTick定时器在CPU内核里面,所以产生的中断源来源于CPU内部,我们在配置NVIC的时候不在需要配置中断源使能函数

由于SysTick在CPU内部,所以使用手册里面没有介绍有关于它的寄存器,有关于它的介绍的手册在如下链接: link

如下图为:SysTick的控制和状态寄存器
在这里插入图片描述如下图为:SysTick的重装载值寄存器
在这里插入图片描述在这里插入图片描述

如下为使用SysTick定时器中断实现LED每隔1s亮灭一次
①SysTick_Timer.c文件代码如下:

#include "stm32f10x.h"        
#include "LED.h"/** @Function:SysTick定时器的初始化*/
void SysTick_Timer_Init(void)
{/* 1、配置时钟源:1 = AHB(72MHz),0 = AHB/8(9MHz) */SysTick->CTRL |= SysTick_CTRL_CLKSOURCE;//选用的72MHz/* 2、使能中断请求 */SysTick->CTRL |= SysTick_CTRL_TICKINT;/* 3、设置重装值,需要定时1s则重装值为72000000 > 2^24-1所以先定时1ms,则定时器1ms重装值为72000*/SysTick->LOAD = 72000 - 1;/* 4、配置优先级 */NVIC_SetPriorityGrouping(4);NVIC_SetPriority(SysTick_IRQn,0);/* 5、使能计数器*/SysTick->CTRL |= SysTick_CTRL_ENABLE;
}/** @Function:中断服务函数:LED间隔1s闪烁*/
void SysTick_Handler(void)
{SysTick->CTRL &= ~SysTick_CTRL_COUNTFLAG;//清除标志位static uint16_t count = 0;count++;if(count == 1000){count = 0;LED_Turn(LED0);}
}

②LED.c文件的代码如下:

#include "stm32f10x.h"                  // Device header
#include "LED.h"/** PA0~PA7引脚的初始化*/
void LED_Init(uint32_t PA_x)
{/* 1. 打开GPIOA的时钟 */RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;/* 2. 将PA0~PA7配置为通用输出开漏模式  */if(PA_x != PA_ALL){GPIOA->CRL |= PA_x; GPIOA->CRL &= ~(PA_x << 2);}else{GPIOA->CRL |= PA_ALL;GPIOA->CRL &= PA_ALL;}}/** 点亮LEDx*/
void LED_ON(uint16_t LEDx)
{GPIOA->ODR |= LEDx;
}/** 熄灭LEDx*/
void LED_OFF(uint16_t LEDx)
{GPIOA->ODR &= ~LEDx;
}/** 翻转LEDx*/
void LED_Turn(uint16_t LEDx)
{/* 如果是关闭那么就打开,如果是打开那么就关闭 */if((GPIOA->ODR & LEDx) == 0)//关闭{LED_ON(LEDx);}else{LED_OFF(LEDx);}
}

主函数文件的代码如下:

#include "stm32f10x.h"                
#include "OLED.h"
#include "SysTick_Timer.h"
#include "LED.h"int main(void)
{OLED_Init();LED_Init(PA_0);SysTick_Timer_Init();LED_OFF(LED0);OLED_ShowString(1,1,"nihao");while(1){}
}

实物演示效果如下:

SysTick_Interrupt

1.2、使用SysTick制作延迟函数

在这里插入图片描述

通过获取计时器里面的值来制作延迟函数,函数的形式参数为我们手动写入的计数器的重装值,当计时器里面的数值还没有减到0时,让其一直等待循环,当计时器里面的数值减到0时,让其跳出循环,任何关闭定时器。

①Delay.c文件的代码如下:

#include "Delay.h" /** @Function:延迟函数us*/
void Delay_us(uint16_t us)
{/* 1、设置时钟源 */SysTick->CTRL |= SysTick_CTRL_CLKSOURCE;//选用AHB(72MHz)/* 2、不需要中断 */SysTick->CTRL &= ~SysTick_CTRL_TICKINT;/* 3、给寄存器VAL写入数据,让标志位COUNTFLAG清零 */SysTick->VAL = 0;/* 4、设置重装值 */SysTick->LOAD = 72 * us;//1us来一个脉冲计数/* 5、使能定时器 */SysTick->CTRL |= SysTick_CTRL_ENABLE;/* 6、等待计数器到0,标准位变为1,跳出循环 */while(!((SysTick->CTRL) & SysTick_CTRL_COUNTFLAG));/* 6、关闭定时器 */SysTick->CTRL &= ~SysTick_CTRL_ENABLE;
}/** @Function:延迟函数ms*/
void Delay_ms(uint16_t ms)
{while (ms--){Delay_us(1000);}
}/** @Function:延迟函数s*/
void Delay_s(uint16_t s)
{while (s--){Delay_ms(1000);}
}

②主函数文件代码如下:

/** LED灯每隔1s闪烁一下,并且OLED上面的数值加1,加到10后重头开始加*/
#include "stm32f10x.h"                
#include "OLED.h"
#include "LED.h"
#include "Delay.h"int main(void)
{uint16_t Data = 0;LED_Init(PA_0);OLED_Init();OLED_ShowString(1,1,"Data:");LED_OFF(LED0);while(1){LED_Turn(LED0);OLED_ShowNum(1,6,Data,2);Data++;if(Data == 11){Data = 0;}Delay_ms(1000); }
}

实物演示效果如下:

延迟函数

2、基本定时器

片上外设定时器:TIM6和TIM7是基本定时器。TM2~TIM5是通用定时器。TM1和TM8是高级定时器。而stm32f10c8t6只有定时器TIM1,TIM2,TIM3,TIM4。即1个高级定时器,3个通用定时器
基本定时器TIM6和TIM7各包含一个16位自动装载计数器,由各自的可编程预分频器驱动。
这2个定时器是互相独立的,不共享任何资源。这个2个基本定时器只能向上计数,由于没有外部IO,所以只能计时,不能对外部脉冲进行计数。
功能:定时中断,主模式,触发DAC。

在这里插入图片描述由上图所示:定时器TIM2~TIM7挂载中心ABP1上面,其中APB1的Fmax = 36MHz,所以APB1的分配系数 = 2。而由图中蓝色框中所得:给定时器TIM2 ~ TIM7提供时钟脉冲的频率F = 72MHz。下图为基本定时器中的结构图

在这里插入图片描述
由上图所示:传来的时钟脉冲通过PSC预分频器后在传递到计数器,PSC = 0,为1分频;PSC = 1,为2分频。其中PSC为16位的寄存器,所以最大分频系数 = 2^16 = 65536分频。
重装载值 = 99,则需要100个脉冲才能使99重装为),则相当于计数100次。自动重装载寄存器也是16位寄存器,所以最大的计数次数 = 2^16 = 65536次

在这里插入图片描述

预加载寄存器和影子寄存器:
  如上图PSC预分频寄存器和重装寄存器后面有阴影,则阴影部分就是影子寄存器。而时基单元的数据都是看影子寄存器里面的数据,
  那什么是预加载寄存器喃?预加载寄存器是为了在时基单元工作的时候,更新影子寄存器里面的数据,而更新的时机是这个周期计数完成,下个周期计数器值从0开始的时候。例如重装值为20,而在时基单元工作的时候,我们想将重装值更新为15,那么我们将15的数据写入重装载寄存器的预加载寄存器里面,然后预加载寄存器会在下一个计数周期的计数值为0的时候将15更新到影子寄存器里面。当然我们也可以选用不启用预加载寄存器,那么写入的数据会立马更新到影子寄存器里面。
【注意】写入数据都是写入到预加载寄存器里面,影子寄存器是不允许写入数据的
在这里插入图片描述

2.1、基本定时器中断的使用

由于stm32f10c8t6没有基本定时器,所以下面的代码不是使用stm32f103c8t6的支持包,而是使用stm32f103zet6的支持包编辑的。
在这里插入图片描述
下面是有关寄存器的介绍
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

①Basic_Timer文件的代码如下:

#include "stm32f10x.h"   
#include "LED.h"/** @Function:基本定时器TIM6的初始化*/
void Basic_Timer_Init(void)
{/* 1、开启时钟 */RCC->APB1ENR |= RCC_APB1ENR_TIM6EN;/* 2、选择时钟来源 *///基本定时器只有一个时钟源,所以无需我们代码编写/* 3、设置分频系数 */TIM6->PSC = 7200 - 1;//分频系数为7200,则72MHZ/7200 = 10000Hz,1s/10000 = 0.1ms//即每隔0.1ms,来一个脉冲,计数器+1/* 4、设定重装载值 */TIM6->ARR = 10000 - 1;//定时器1s/* 5、使能定时器中断请求 */TIM6->DIER |= 0x01;/* 6、开始预加载模式 */TIM6->CR1 |= TIM_CR1_ARPE;/* 7、配置NVIC */NVIC_SetPriorityGrouping(4);;NVIC_SetPriority(TIM6_IRQn,0);NVIC_EnableIRQ(TIM6_IRQn);/* 7、使能计数器 */TIM6->CR1 |= TIM_CR1_CEN;
}/** @Function:基本定时器TIM6中断的服务函数*/
void TIM6_IRQHandler(void)
{if((TIM6->SR) & TIM_SR_UIF)//判断标志位{TIM6->SR &= ~TIM_SR_UIF;//清除标志位LED_Turn(LED0);//LED0的翻转}
}

②主函数文件代码如下:

#include "stm32f10x.h"                
#include "OLED.h"
#include "LED.h"
#include "Basic_Timer.h"int main(void)
{LED_Init(PA_0);LED_OFF(LED0);Basic_Timer_Init();while(1){}
}

综上:总结SysTick定时器和基本定时器的区别如下
①时钟来源不同:滴答定时器的时钟来源于系统总线AHB,基本定时器的时钟来源于APB1
②计数不同:滴答定时器是向下计数(24位),而基本定时器是向上计数(16位)
③所处位置不同:滴答定时器位于芯片内核,使用时不用开启时钟,中断时也不用开启NVIC_EnableIRQ()。基本定时器属于片上外设,使用时要开启时钟,使用中断时也要开启NVIC_EnableIRQ()
④内部结构不同:滴答定时器没有影子寄存器和预加载寄存器,也没有预分频寄存器。

2.2、使用基本定时器制作延时函数

①Delay.c文件的代码如下:

void Delay_us(uint16_t us)
{/* 1、开启时钟 */RCC->APB1ENR |= RCC_APB1ENR_TIM6EN;/* 2、选择时钟来源 *///基本定时器只有一个时钟源,所以无需我们代码编写/* 3、设置分频系数 */TIM6->PSC = 72 - 1;//分频系数为7200,则72MHZ/72 = 1MHz,1s/1MHz = 1us//即每隔1us,来一个脉冲,计数器+1/* 4、设定重装载值 */TIM6->ARR = us - 1;/* 5、初始化一下计数器和预分频器 */TIM6->EGR |= TIM_EGR_UG;/* 6、初始化一下计数器和预分频器会使UIF置位,清除标志位 */TIM6->SR &= ~TIM_SR_UIF;/* 7、开启计数器 */TIM6->CR1 |= TIM_CR1_CEN;/* 8、等待循环完成 */while(!((TIM6->SR) & TIM_SR_UIF));/* 9、关闭计数器 */TIM6->CR1 &= ~TIM_CR1_CEN;
}void Delay_ms(uint16_t ms)
{while (ms--){Delay_us(1000);}
}void Delay_s(uint16_t s)
{while (s--){Delay_ms(1000);}
}

http://www.ppmy.cn/devtools/122374.html

相关文章

Python 读取与处理出入库 Excel 数据实战案例(HTML 网页展示)

有如下数据&#xff0c;需要对数据合并处理&#xff0c;输出到数据库。 数据样例&#xff1a;&#x1f447; excel内容&#xff1a; 出入库统计表河北库.xlsx: 出入库统计表天津库.xlsx: 01实现过程 1、创建test.py文件&#xff0c;然后将下面代码复制到里面&#xff0c;最后…

大厂面试真题-介绍以下Docker的Overlay网络

Overlay网络&#xff0c;又称为叠加网络或覆盖网络&#xff0c;是一种在现有物理网络&#xff08;Underlay网络&#xff09;之上构建的虚拟网络架构。它通过虚拟化技术&#xff0c;在不对基础网络进行大规模修改的条件下&#xff0c;实现应用在网络上的承载&#xff0c;并能与其…

论文阅读笔记-Pre-trained Models for Natural Language Processing: A Survey

前言 预训练模型给下游任务带来的效果不言而喻,有了预训练模型,我们可以使用它来加速解决问题的过程。正如论文中所说的那样,预训练模型(PTMs)的出现将自然语言处理(NLP)带入了一个新时代。本篇论文基于分类从四个角度对现有PTMs进行系统分类,描述如何使PTMs的知识适应…

万界星空科技MES数据集成平台

制造执行系统MES作为连接企业上层ERP系统和现场控制系统的桥梁&#xff0c;承担了实时数据采集、处理、分析和传递的重要任务。MES数据集成平台是一个集成各类数据源&#xff0c;将数据进行整合和统一管理的系统&#xff0c;通过提供标准化接口和协议&#xff0c;实现数据的无缝…

Ubuntu 安装RUST

官方给的是这样如下脚本 curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh 太慢了 curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh -x 执行这个脚本后会给出对应的下载链接 如下图 我直接给出来 大多数应该都是这个 https://static.rust-…

Fastjson反序列化

Fastjson反序列化一共有三条利用链 TempLatesImpl&#xff1a;实战中不适用JdbcRowSetImpl&#xff1a;实际运用中较为广泛BasicDataSource&#xff08;BCEL&#xff09; 反序列化核心 反序列化是通过字符串或字节流&#xff0c;利用Java的反射机制重构一个对象。主要有两种…

Android Framework AMS(02)AMS启动及相关初始化5-8

该系列文章总纲链接&#xff1a;专题总纲目录 Android Framework 总纲 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节主要涉及systemserver启动AMS及初始化AMS相关操作。同时由于该部分内容过多&#xff0c;因此拆成2个章节&#xff0c;本章节是第二章节&…

【FPGA开发】Xilinx FPGA差分输入时钟的使用方法

正文 以前在使用ZYNQ的领航者ZYNQ7020进行FPGA学习时&#xff0c;它们使用的单端50M的输入时钟&#xff0c;在verlog代码编写上比较简单&#xff0c;而现在使用Alinx的AXU3EG开发板时&#xff0c;发现它使用的是200M的差分输入时钟&#xff0c;哪这个时候&#xff0c;输入时钟要…