当前位置: 首页 > news >正文

STM32_06_Systick定时器

Systick定时器又称滴答定时器。

延时时间

一样的代码在不同的机器它的延时时间也会有轻微的区别,因此我们要通过Systick定时器来获取精确的延时。


Systick定时器

原理就是数数,假设一个周期=10ms,我们设个初始值y,然后从y自减到0,我们计算用了20个时钟周期,那这个时候我们所需的时间是20x10=200ms=0.2s,这样我们就能设置一个确定的时间了,初始值y就是200ms,用这个时间我们就能延时。 进入while()循环等待,y的值减至0,这个循环的时间就是200ms。

  • 如上图,如果我们初始值是 72
  • 000 时钟周期,那我们的延时时间就是1ms。
  • 再举个例子:如果初始值是 72 0000 时钟周期,那它的延时时间是?
    ------ 10ms
  • 思路:初始值 -> 时钟周期 -> 时间
    时间 -> 时钟周期 -> 配置初始值
  • 滴答定时器实际上是9MHz
    1s = 9 000 000 时钟周期           1ms = 9 000 时钟周期        1us = 9 时钟周期
    如果延时时间是30ms,时钟周期是 9000 * 30 = 27 0000,初始值就是270000

思考:

  1. 怎么去设置初始值?
    看第二个寄存器(LOAD),比如你的初始值想设置为 9 0000,那我们就把 9 0000 放到这个LOAD寄存器里就可以了。
  2. 你怎么知道你那个初始值最终是减到0了?
    判断这个寄存器的第16位。【16】= 1(减到0了);【16】 = 1(还没减到0)。

[0]: 一旦开启定时器,初始值就开始自减;一旦关闭定时器,初始值即停止自减。

LOAD寄存器:比如你的初始值想设置为 9 0000,那我们就把 9 0000 放到这个LOAD寄存器里就可以了。

VAL寄存器:假设LOAD寄存器当中放的是 9 0000,一旦打开定时器,我们就把这个 9 0000 加载到VAL寄存器当中,然后每个时钟周期-1.

当减到0的时候,CTRL【16】= 1,即等待 / 延时的时间就到期了。


Systick寄存器结构体

思考:为什么上面三个寄存器叫CTRL,LOAD,VAL呢?


初始化计数次数


微秒延时


毫秒延时


实战演练-掌控需求

代码示例:

systick.h:

// systick.h
#ifndef __SYSTICK_H__
#define __SYSTICK_H__#include "stm32f10x.h"
extern void Systick_Init(void);
extern void delay_us(u32 n);
extern void delay_ms(u32 n);#endif

systick.c:

// systick.c
#include "systick.h"static u32 fac_us = 0;
static u32 fac_ms = 0;
//
// 定时器初始化
//
void Systick_Init(void){// 1.配置定时器时钟为9MHz// CTRL【2】 = 0SysTick->CTRL &= ~(1 << 2);// 2.1us计数周期fac_us = 9;// 3.1us计数周期fac_ms = 9000;
}
//
// 延时n微秒
//
void delay_us(u32 n){u32 temp;// 1.设置初始值SysTick->LOAD = n * fac_us;// 2.将VAL清空SysTick->VAL = 0;// 3.启动定时器SysTick->CTRL |= (1 << 0);// 启动了定时器,初始值会加载到VAL中,每个时钟周期减1// 直到0// 循环等待,直到初始值自减到0// 判断CTRL【16】// [16] = 1,时间到期,结束循环// xxxxxxxxxxxxxxxxxxxxxxxx	CTRL// 100000000000000000000000	& (1 << 16)// x00000000000000000000000do{temp = SysTick->CTRL;}while((temp & 0x01) && (!(temp & (1 << 16))));// 结束循环 - 时间到期// 关闭定时器SysTick->CTRL &= ~(1 << 0);SysTick->VAL = 0;
}//
// 延时n毫秒
//
void delay_ms(u32 n){u32 temp;// 1.设置初始值SysTick->LOAD = n * fac_ms;// 2.将VAL清空SysTick->VAL = 0;// 3.启动定时器SysTick->CTRL |= (1 << 0);// 启动了定时器,初始值会加载到VAL中,每个时钟周期减1// 直到0// 循环等待,直到初始值自减到0// 判断CTRL【16】// [16] = 1,时间到期,结束循环// xxxxxxxxxxxxxxxxxxxxxxxx	CTRL// 100000000000000000000000	& (1 << 16)// x00000000000000000000000do{temp = SysTick->CTRL;}while((temp & 0x01) && (!(temp & (1 << 16))));// 结束循环 - 时间到期// 关闭定时器SysTick->CTRL &= ~(1 << 0);SysTick->VAL = 0;
}
}

main.c:

// main.c
#include "stm32f10x.h" 
#include "led.h"
#include "beep.h"
#include "system.h"
#include "systick.h"// 时钟树配置
// 参数1:div	参数2:pllm
void RCC_HSE_Config(u32 div, u32 pllm){// 1.设置为默认值RCC_DeInit();// 2.打开HSE时钟RCC_HSEConfig(RCC_HSE_ON);// 3.等待HSE起振if(RCC_WaitForHSEStartUp() == SUCCESS){// 4.配置AHB  不分频RCC_HCLKConfig(RCC_SYSCLK_Div1);// 5.配置APB1 2分频RCC_PCLK1Config(RCC_HCLK_Div2);// 6.配置APB2 不分频RCC_PCLK2Config(RCC_HCLK_Div1);// 7.配置PLL时钟源:div 倍频系数:pllm//RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);RCC_PLLConfig(div,pllm);// 8.使能PLLRCC_PLLCmd(ENABLE);// 9.循环判断PLL是否生效while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);// 10.配置SYSCLK的时钟源为PLLRCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);}
}// 位带只是对输入/输出做优化,和初始化无关
int main(void){// 配置时钟树// pll时钟源:HSE 倍频系数:9 PLLCLK=SYSCLK=72MHzRCC_HSE_Config(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);// pll时钟源:HSE/2 倍频系数:9 PLLCLK=SYSCLK=36MHz//RCC_HSE_Config(RCC_PLLSource_HSE_Div2,RCC_PLLMul_9);// pll时钟源:HSE 倍频系数:9 PLLCLK=SYSCLK=128MHz// 长时间超频是不行的,系统不稳定//RCC_HSE_Config(RCC_PLLSource_HSE_Div1,RCC_PLLMul_16);// LED初始化LED_Init();// BEEP初始化BEEP_Init();// Systick初始化Systick_Init();while(1){// 循环开关灯 + 蜂鸣器LED0 = !LED0;// 1 - 0 - 1LED1 = !LED1;BEEP = !BEEP;// 延时1000msdelay_ms(1000);}
}  

实验现象见视频。


文章转载自:

http://1TVhcpPo.tgmnx.cn
http://0RTiHPQq.tgmnx.cn
http://6w8hA0aC.tgmnx.cn
http://mTrGl5Dm.tgmnx.cn
http://Qk7XQzeA.tgmnx.cn
http://j92omnCA.tgmnx.cn
http://8UXFx4gw.tgmnx.cn
http://otC21Cun.tgmnx.cn
http://H3dMO5so.tgmnx.cn
http://QDr1wQF6.tgmnx.cn
http://SOMKJ2Mt.tgmnx.cn
http://AhoRbiP1.tgmnx.cn
http://oJnIev7Y.tgmnx.cn
http://eqzr5JOt.tgmnx.cn
http://8gGDMIVP.tgmnx.cn
http://y29sBr6f.tgmnx.cn
http://npZVNohV.tgmnx.cn
http://W0xWsmIR.tgmnx.cn
http://HR0DboSJ.tgmnx.cn
http://1BxjiwaA.tgmnx.cn
http://v2hb37pr.tgmnx.cn
http://y7b6YPqV.tgmnx.cn
http://QPortVR4.tgmnx.cn
http://aewiwatf.tgmnx.cn
http://A6x8DAid.tgmnx.cn
http://Et3X3FT0.tgmnx.cn
http://PJ3yixua.tgmnx.cn
http://lE9rdc85.tgmnx.cn
http://CkEF2x6Q.tgmnx.cn
http://2G5qNxgx.tgmnx.cn
http://www.dtcms.com/a/383767.html

相关文章:

  • 用 Java 学会 Protocol Buffers从 0 到 1 的完整实战
  • 237.删除链表中的节点
  • 【Vue2手录14】导航守卫
  • Qt如何读写xml文件,几种方式对比,读写xml的Demo工程
  • 子网划分专项训练-1,eNSP实验,vlan/dhcp,IP规划
  • 云原生改造实战:Spring Boot 应用的 Kubernetes 迁移全指南
  • 看门狗的驱动原理
  • [论文阅读] 人工智能 + 软件工程 | 大语言模型驱动的多来源漏洞影响库识别研究解析
  • 【前缀和+哈希表】P3131 [USACO16JAN] Subsequences Summing to Sevens S
  • 05.【Linux系统编程】进程(进程概念、进程状态(注意僵尸和孤儿)、进程优先级、进程切换和调度)
  • 【从零开始java学习|小结】记录学习和编程中的问题
  • 图像拼接案例,抠图案例
  • 分层解耦讲解
  • 安装Hadoop中遇到的一些问题和解决
  • 音视频-色域
  • 返利软件的分布式缓存架构:Redis集群在高并发场景下的优化策略
  • 如何让知识上传与查询更便捷
  • set/multiset容器
  • 区块链:搭建简单Fabric网络并调用智能合约
  • Keepalived的详细实操安装流程及其配置文件选项的详解
  • windows下,podman迁移镜像文件位置
  • 技能补全之正则表达式
  • Altium Designer(AD24)打开工程文件的几种方法
  • 26考研——内存管理(3)
  • 知识库缺乏维护和清理机制会造成哪些后果
  • android studio 华为 安装app 层层验证
  • 机器学习(三):决策树
  • 气缸夹爪机构分析
  • np.sum(e_x, axis=-1, keepdims=True)
  • kafka--基础知识点--5.3--producer事务