STM32LL库编程系列第一讲——Delay精准延时函数(详细,适合新手)

第一讲——Delay精准延时函数(详细,适合新手)



前言

在网上有关STM32编程的资料和文章琳琅满目,但大多使用的是标准库和HAL库,使用LL库的文章少之又少,趁着自己正在使用LL库,来记录分享学习下
使用的开发板是正点原子的STM32F4探索者V2,芯片是STM32F407ZGT6。资料去正点原子官网下载即可。


一、什么是标准库、LL库、HAL库?

STM32标准库、LL库和HAL库是针对STMicroelectronics的STM32微控制器系列的不同软件库。它们之间的区别如下:

  1. STM32标准库:STM32标准库是STMicroelectronics提供的最基本的软件库,提供了对STM32微控制器的基本功能的访问。它提供了对寄存器的直接访问,需要用户自行编写底层驱动代码。STM32标准库较为底层,灵活性较高,但编程复杂度也较高。

  2. LL库(Low-Level库):LL库是STMicroelectronics推出的低级别抽象层库,位于标准库和HAL库之间。LL库提供了对STM32微控制器底层功能的更高级别的抽象,减少了用户编写底层驱动代码的工作量。LL库相比标准库提供了更多的抽象,但相对于HAL库来说仍然较为接近底层。

  3. HAL库(Hardware Abstraction Layer库):HAL库是STMicroelectronics提供的高级别抽象库,为用户提供了更加简化和易用的API,使得用户可以更快速地开发应用程序而不必关心底层硬件细节。HAL库提供了对各种外设(如UART、SPI、I2C等)的封装,使得用户可以通过简单的函数调用实现对外设的控制。

总的来说,STM32标准库提供了最基本的功能,LL库提供了更高级别的抽象,而HAL库则提供了更简化和易用的API,使得用户能够更轻松地开发应用程序。选择使用哪种库取决于用户的需求和对开发的控制程度。
对于刚开始学习我认为从标准库开始是比较合理的,对一个外设的初始化都需要自行配置,虽然有些麻烦,但对理解各外设的工作都有这很大的帮助,这也是经验的积累。用标准库把大多外设驱动成功后,就可以接触LL库和HAL库了,这里会用到STM32CubeMX 软件,使用该软件能直观快速生成LL库和标准库工程。LL库封装少,更接近底层,从标准库能很快上手;但HAL库封装程度深、资源占用大、灵活性低,很难找到底层逻辑。但网上LL库资源少,大家都不得不转到HAL了。好了,废话结束,正式开始!

二、使用CubeMX新建工程

先在电脑建立一个空白文件夹,注意路径只允许英文、数字和下划线。我的工程路径如下:

E:\keil_Projects\STM32F407_LL\delay

在这里插入图片描述
接着打开STM32CubeMX,如要下载安装,网上有很多教程,去学就好。
在这里插入图片描述
点击框选1图标新建工程,等待一下,进入下面页面
在这里插入图片描述
现在左边框图2找到芯片大致型号,再在框图3找到具体芯片,双击进入配置页面
在这里插入图片描述
左边点击RCC进入时钟配置,选择HSE(外部高速时钟),选择陶瓷晶振。
在这里插入图片描述
接着左边点击SYS,Debug选择Serial Wire也就是SW模式下载,还有JTAG下载方式,区别不大,SW占用IO口更少,所以选择SW下载,时钟源默认了Systick,可以更改成其他定时器,但是没必要,这里默认就好。
STM32的systick是一个系统定时器,通常用于实现操作系统的时钟节拍或者延时功能。它可以通过配置来产生固定时间间隔的中断,常用于处理周期性的任务或者时间相关的操作。在STM32微控制器中,systick定时器通常与系统时钟关联,可以提供较为精确的定时功能。
本文仅仅写延时函数,所以就不开其他外设了,IO配置就到这里了。
在这里插入图片描述
接着点击NVIC,进入中断管理,不知道是不是版本原因,每次systick抢占优先级默认15,也就是最低,也有这个情况手动改回0即可。
点击上方Clock Configuration进入时钟树配置
在这里插入图片描述
这是刚进入的页面,接下来注意标号说明。
找到input frequency,这是时钟输入频率,改成8M(写8就行,单位默认M)具体数值看开发板手册,也可以直接对光看晶振,接入多少晶振,就填多少,一般都是8M。
将PLL source Mux 选择HSE,/M选择8,晶振分频为1M;*N处选择336,倍频为336M;/P处选择2,分频为168M;system clock Mux 选择PLLCLK。以上操作保证了最大168M频率的输出。
将APB1 prescaler 选择4;APB2 prescaler选择2。其他默认即可,保证所有总线最大时钟输出。如图
在这里插入图片描述
网上很多教程一般到这就结束了,但是请同学们注意框选出时钟,这里是systick的两个具体时钟源,从图中可以看出都是168M,其实上面一个可以选择/8,变成21M,如图
在这里插入图片描述
这样才是正确的,但是为了给同学们减少困惑,我们就保持不变,不分频,最后时钟配置如图
在这里插入图片描述

在这里插入图片描述
接下来进入projeck manager
proieck name 选择工程名,用C语言变量命名规则命名
projeck location 选择工程路径,选择前面建的文件夹
toolchain/IDE 改成MDK-ARM 版本选择最高就行,你用其他的编译器也行,大部分都是keil5
从左边进入页面code generattor,配置直接看图吧在这里插入图片描述
最后进入advanced settings ,将外设都选择为LL库即可
在这里插入图片描述
到这里工程就配置完了,点击GENERATE CODE 生成工程文件,如果路径有问题会报错,成功如下
在这里插入图片描述
打开刚才新建的文件夹可以看到工程文件加载进来
在这里插入图片描述
找到delay.uvprojx双击进入keil(keil的下载安装及破解网上有大量教程)如图
在这里插入图片描述
接下来,对步骤操作就不大量描述了,主要讲原理


二、系统延时LL_mDelay()原理讲解

找到下面代码,LL_Init1msTick(168000000);写入了168M,如果cubemx配置to cortex system timer 选择8分频,这里填入的就是21000000。但这样系统延时函数就错了,为什么错,接着看。

  LL_Init1msTick(168000000);
  LL_SetSystemCoreClock(168000000);

可以先编译一下,没有错误,选中函数,邮件,按F12,进入函数LL_Init1msTick,再进入LL_InitTick代码如下

__STATIC_INLINE void LL_InitTick(uint32_t HCLKFrequency, uint32_t Ticks)
{
  /* Configure the SysTick to have interrupt in 1ms time base */
  SysTick->LOAD  = (uint32_t)((HCLKFrequency / Ticks) - 1UL);  /* set reload register */
  SysTick->VAL   = 0UL;                                       /* Load the SysTick Counter Value */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_ENABLE_Msk;                   /* Enable the Systick Timer */
}

__STATIC_INLINE是一个宏定义,用于定义静态内联函数,这里不过多讲述。
接下来附上三个systick的寄存器(引用正点原子的图)
在这里插入图片描述

SysTick->LOAD  = (uint32_t)((HCLKFrequency / Ticks) - 1UL);  /* set reload register */

将LOAD写入了168000-1 这是系统重装载的值,装载时系统会自动加1,所以装载值为168000。

 SysTick->VAL   = 0UL;                                    

将VAL写0,VAL的值会按照时钟频率依次递减。

SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_ENABLE_Msk;                  

进入宏定义可以看到,将CTRL低三位赋值101,时钟源选择HCLK,也就是168M,但是LOAD写入的计时数是基于HCLK/8的,因为一旦cubemx配置to cortex system timer 选择8分频,这里LOAD写入的值就是21000-1,那么系统延时就是错的,会快8倍,但cubemx的to cortex system timer 不分频,直接让两个时钟频率一致,那就没有问题,但理论上还是错误的,正确的应该是将CTRL低三位赋值001,也就是

SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk;              

这样逻辑才是正确的,但是可以不去更改回来,理论错了知道就好,以后cubemx的to cortex system timer 就不分频,那样也就没有错误了。
当CTRL最低位为1,定时器使能,LOAD的值会加1装载到VAL,VAL会按照168M频率递减,也就是1s内减少168000000个数,装载的168000减到0正好耗时1ms,实现延时。

同学们可以进入void LL_mDelay(uint32_t Delay)函数,可以看到该函数就是以1ms为基准进行延时的。


二、delay自定义延时函数编程

delay.c代码如下

#include "delay.h"

/// @brief nus延时
/// @param nus 延时的nus数
void delay_us(uint32_t nus)
{
	uint32_t temp;
	SysTick->LOAD=nus*168-1; // 计数值加载
	SysTick->VAL=0x00; // 清空计数器
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; // 开始计数
	do
	{
		temp=SysTick->CTRL; // 读取控制寄存器状态
	}while((temp&0x01)&&!(temp&(1<<16))); // temp&0x01:定时器使能,!(temp&(1<<16)):定时器计数值不为0
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; // 关闭计数
	SysTick->VAL=0x00;// 清空计数器
}

/// @brief nms延时
/// @param nus 延时的ms数
void delay_ms(uint32_t nms)
{
	uint32_t repeat=nms/50;
	uint32_t remain=nms%50;
	while(repeat)
	{
		delay_us(50*1000); // 延时 50 ms
		repeat--;
	}
	if(remain)
	{
		delay_us(remain*1000); // 延时remain ms
	}
}

按照寄存器的写法,先将LOAD赋值装载值,然后清零VAL,最后使能CTRL开始计时
LOAD值有限制的,这是一个24位寄存器,最大值为2^24-1,及最大一次可以延时(2^24)/168 us
多说一句,如果cubemx配置to cortex system timer 选择8分频,那么改成如下即可

SysTick->LOAD=nus*168/8-1; // 计数值加载

一旦使能,VAL = LOAD+1,并且开始递减。接着再循环中读取CTRL的值,当VAL计数到0,CTRL最高位为1。代表延时结束,这里加入了CTRL使能位判断是很关键的,避免没使能进入循环,从而循环里出不来。
循环结束后关闭使能,清空VAL,us延时函数结束
ms延时基于1000us延时,重复运行delay_us(1000);的倍数解决的,这里50ms做一个分度,就是因为LOAD写入的值有限制。
到这里延时函数就写完了,附上头文件delay.h代码

#ifndef __DELAY_H
#define __DELAY_H 

#include "stdint.h"
#include "stm32f407xx.h"

void delay_us(uint32_t nus);
void delay_ms(uint32_t nms);

#endif	   

直接头文件加入到mian.c中就可以使用了,注意工程中不可同时使用LL_mDelay()和自定义延时函数,否则陷入死循环。可以舍弃LL_mDelay()函数,不再用了。
这里写入4个延时来验证精准度

  while (1)
  {
    /* USER CODE END WHILE */
		delay_us(10);
		delay_us(100);
		delay_us(1000);
		delay_ms(10);
		delay_ms(1000);
    /* USER CODE BEGIN 3 */
  }

我这里使用的是STLink仿真器,
在这里插入图片描述
在这里插入图片描述
这里core clock一定要选择对应时钟频率,这里是168M,不然不准(默认的画是10M)
在这里插入图片描述
勾选Reset and run 即可
编译后将程序下载到开发板中,点击在这里插入图片描述进入调试模式,如图
在这里插入图片描述
接下来看视频演示

delay演示验证

到这里就结束了。工程会上传百度网盘打包免费发布出来
链接:https://pan.baidu.com/s/1_nCZ4yaZwYbB0JLz1rumWg?pwd=1234
提取码:1234


尾言

这是本人CSDN第一讲,后面会继续更新STM32LL库编程操作,时间匆忙,如有错误之处还请指出(应该会有些错别字,不影响阅读就行)

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值