?个人名片:
🦁作者简介:一名喜欢分享和记录学习的在校大学生
🐯个人主页:妄北y🐧个人QQ:2061314755
🐻个人邮箱:2061314755@qq.com
🦉个人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:系统定时器,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;i<us;i++)
{
// 当计数器的值减小到0的时候,CRTL寄存器的位16会置1
while( !((SysTick->CTRL)&(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;i<ms;i++)
{
// 当计数器的值减小到0的时候,CRTL寄存器的位16会置1
// 当置1时,读取该位会清0
while( !((SysTick->CTRL)&(1<<16)) );
}
// 关闭SysTick定时器
SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk;
}
大佬觉得有用的话点个赞 👍🏻 呗。
??????本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍
🔥🔥🔥任务在无形中完成,价值在无形中升华,让我们一起加油吧!🌙🌙🌙
?
?