个人名片:
作者简介:一名喜欢分享和记录学习的在校大学生
个人主页:妄北y个人QQ:2061314755
个人邮箱:[email protected]
个人WeChat:Vir2021GKBS
本文由妄北y原创,首发CSDN
座右铭:大多数人想要改造这个世界,但却罕有人想改造自己。
专栏导航:
妄北y系列专栏导航:
C/C++的基础算法:C/C++是一种常用的编程语言,可以用于实现各种算法,这里我们对一些基础算法进行了详细的介绍与分享。
C/C++刷题库:分享一些关于编程的练习基础题,也会后续加入一系列的算法题,分享自己的解题思路和方法。
计算机网络:对计算机网络的基础知识框架有一个简单的学习与认识,对计算机网络中常见的题型进行一个总结与归纳。
QT基础入门学习:对QT的基础图形化页面设计进行了一个简单的学习与认识,利用QT的基础知识进行了翻金币小游戏的制作
Linux基础编程:初步认识什么是Linux,为什么学Linux,安装环境,进行基础命令的学习,入门级的shell编程。
Linux的系统编程+网络编程:IO编程、进程、线程、进程间通讯(包括管道、信号、信号量、共享内存等)网络编程主要就是socket,poll,epoll,以及对TCP/IP的理解,同时要学会高并发式服务器的编写。
Linux应用开发基础开发:分享Linux的基本概念、命令行操作、文件系统、用户和权限管理等,网络编程相关知识,TCP/IP 协议、套接字(Socket)编程等,可以实现网络通信功能。
Linux项目开发:Linux基础知识的实践,做项目是最锻炼能力的一个学习方法,这里我们会学习到一些简单基础的项目开发与应用,而且都是毕业设计级别的哦。
非常期待和您一起在这个小小的互联网世界里共同探索、学习和成长。 ✨✨ 欢迎订阅本专栏 ✨✨
文章介绍:
本篇文章对STM32学习的相关知识进行分享!
因为 SysTick 是属于 CM3 内核的外设, 有关寄存器的定义和部分库函数都在 core_CM3.h 这个头文件中实现。所以学习 SysTick 的时候可以参考这两个资料,一个是文档,一个是源码。
如果您觉得文章不错,期待你的一键三连哦,你的鼓励是我创作动力的源泉,让我们一起加油,一起奔跑,让我们顶峰相见!!!
感谢大家点赞收藏⭐评论✍️
目录:
目录
一、SysTick 简介
二、SysTick功能框图
SysTick定时时间计算
三、SysTick 定时实验
1.硬件设计
2.软件设计
3.编程要点
(1)SysTick 配置库函数
(2)配置 SysTick 中断优先级
(3)SysTick 初始化函数
(4)SysTick 定时函数
(5)SysTick 中断服务函数
(6)主函数
4.systick 微秒级延时
5.systick 毫秒级延时
SysTick:系统定时器,24位,只能递减,存在于内核,嵌套在NVIC中,所有的Cortex-M内核的单片机都具有这个定时器。
SysTick—系统定时器有 4 个寄存器,简要介绍如下。在使用 SysTick 产生定时的时候,只需要配置前三个寄存器,最后一个校准寄存器不需要使用。
counter在时钟的驱动下,从reload初值开始往下递减计数到0,产生中断和置位COUNTFLAG标志。然后又从reload值开始重新递减计数,如此循环。
t : 一个计数循环的时间,跟reload和CLK有关
CLK : 72M或者9M,由CTRL寄存器配置
RELOAD :24位,用户自己配置
t = reload * ( 1/clk )
Clk = 72M时,t = (72)*(1/72 M)= 1U
SClk = 72M时,t = (72000)*(1/72 M)= 1MS时间单位换算:
1s = 1000ms = 1000 000 us = 1000 000 000ns
利用 SysTick 产生 1s 的时基,LED 以 1s 的频率闪烁
SysTick 属于单片机内部的外设,不需要额外的硬件电路,剩下的只需一个 LED 灯即可。
我们创建了两个文件:bsp_SysTick.c 和 bsp_ SysTick.h 文件用来存放 SysTick 驱动程序及相关宏定义,中断服务函数放在 stm32f10x_it.c 文件中。SysTick 属于内核的外设,有关的寄存器定义和库函数都在内核相关的库文件 core_cm3.h 中。
设置重装载寄存器的值
清除当前数值寄存器的值
配置控制与状态寄存器
// 这个 固件库函数 在 core_cm3.h中
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
// reload 寄存器为24bit,最大值为2^24
if (ticks > SysTick_LOAD_RELOAD_Msk) return (1);
// 配置 reload 寄存器的初始值
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;
// 配置中断优先级为 1<<4-1 = 15,优先级为最低
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
// 配置 counter 计数器的值
SysTick->VAL = 0;
// 配置systick 的时钟为 72M
// 使能中断
// 使能systick
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
return (0);
}
用固件库编程的时候我们只需要调用库函数 SysTick_Config() 即可,SysTick_Config() 库函数主要配置了 SysTick 中的三个寄存器:LOAD、VAL 和 CTRL,有关具体的部分看代码注释即可。
在 SysTick_Config() 库函数还调用了固件库函数 NVIC_SetPriority() 来配置系统定时器的中断优先 级,该库函数也在 core_m3.h 中定义,原型如下:
__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
if ((int32_t)IRQn < 0) {
SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] =
(uint8_t)((priority << (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
}
else {
NVIC->IP[((uint32_t)(int32_t)IRQn)] =
(uint8_t)((priority << (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
}
}
如果要修改内核外设的优先级,只需要修改下面三个寄存器对应的某个字段即可。
/**
* @brief 启动系统滴答定时器 SysTick
* @param 无
* @retval 无
*/
void SysTick_Init(void)
{
/* SystemFrequency / 1000 1ms中断一次
* SystemFrequency / 100000 10us中断一次
* SystemFrequency / 1000000 1us中断一次
*/
// if (SysTick_Config(SystemFrequency / 100000)) // ST3.0.0库版本
if (SysTick_Config(SystemCoreClock / 100000)) // ST3.5.0库版本
{
/* Capture error */
while (1);
}
}
SysTick 初始化函数由用户编写,里面调用了 SysTick_Config() 这个固件库函数,通过设置该固件库函数的形参,就决定了系统定时器经过多少时间就产生一次中断。
SysTick 中断时间的计算
SysTick_Config(SystemCoreClock / 100000)
SysTick_Config()的形我们配置为 SystemCoreClock / 100000=72M/100000=720,从刚刚分析我们 知道这个形参的值最终是写到重装载寄存器 LOAD 中的,从而可知我们现在把 SysTick 定时器中 断一次的时间 TINT=720/72M=10us。
/**
* @brief us延时程序,10us为一个单位
* @param
* @arg nTime: Delay_us( 1 ) 则实现的延时为 1 * 10us = 10us
* @retval 无
*/
void Delay_us(__IO u32 nTime)
{
TimingDelay = nTime;
// 使能滴答定时器
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
while(TimingDelay != 0);
}
函数 Delay_us() 中我们等待 TimingDelay 为 0,当 TimingDelay 为 0 的时候表示延时时间到。变量 TimingDelay 在中断函数中递减,即 SysTick 每进一次中断即 10us 的时间 TimingDelay 递减一次。
void SysTick_Handler(void)
{
TimingDelay_Decrement();
}
中断服务函数调用了另外一个函数 TimingDelay_Decrement(),原型如下:
/**
* @brief 获取节拍程序
* @param 无
* @retval 无
* @attention 在 SysTick 中断函数 SysTick_Handler()调用
*/
void TimingDelay_Decrement(void)
{
if (TimingDelay != 0x00)
{
TimingDelay--;
}
}
/*
* t : 定时时间
* Ticks : 多少个时钟周期产生一次中断
* f : 时钟频率 72000000
* t = Ticks * 1/f = (72000000/100000) * (1/72000000) = 10us
*/
/**
* @brief 主函数
* @param 无
* @retval 无
*/
int main(void)
{
/* LED 端口初始化 */
LED_GPIO_Config();
/* 配置SysTick 为10us中断一次 */
SysTick_Init();
// for(;;)
// {
// LED1( ON );
// Delay_us(100000); // 100000 * 10us = 1000ms
// //Delay_ms(100);
// LED1( OFF );
//
// LED2( ON );
// Delay_us(100000); // 100000 * 10us = 1000ms
// //Delay_ms(100);
// LED2( OFF );
//
// LED3( ON );
// Delay_us(100000); // 100000 * 10us = 1000ms
// //Delay_ms(100);
// LED3( OFF );
// }
for(;;)
{
LED1( ON );
SysTick_Delay_Ms( 1000 );
LED1( OFF );
LED2( ON );
SysTick_Delay_Ms( 1000 );
LED2( OFF );
LED3( ON );
SysTick_Delay_Ms( 1000 );
LED3( OFF );
}
}
主函数中初始化了 LED 和 SysTick,然后在一个 while 循环中以 1s 的频率让 LED 闪烁。
void SysTick_Delay_Us( __IO uint32_t us)
{
uint32_t i;
SysTick_Config(SystemCoreClock/1000000);
for(i=0;iCTRL)&(1<<16)) );
}
// 关闭SysTick定时器
SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;
}
void SysTick_Delay_Ms( __IO uint32_t ms)
{
uint32_t i;
SysTick_Config(SystemCoreClock/1000);
for(i=0;iCTRL)&(1<<16)) );
}
// 关闭SysTick定时器
SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk;
}
大佬觉得有用的话点个赞 呗。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!
任务在无形中完成,价值在无形中升华,让我们一起加油吧!