[DAY 19] _ARM-M0-内核外设SysTick-写个精准的Delay

SysTick是内核系统的定时器,先来看看SysTick来源在哪,下图stm32f030cc的时钟树
https://ithelp.ithome.com.tw/upload/images/20211002/20141979GbyNv30Dnq.png

SysTick的时钟为HCLK的8分频,systick = HCLK/8
先提一下标准库的大概运作方式,标准库有写好自动判断要用外部石因还是内部,外部不正常或没接上的话会自动使用内部HSI,有挂外部的话石中的进行路线如下图,
https://ithelp.ithome.com.tw/upload/images/20211002/20141979qBhoL8qNl0.png
可以看到红色路径是有挂8M时会跑的路径,重点来了!! PREDIV和PLLMUL是除多少和乘上多少,要来看看system_stm32f0xx.c,这个是标准库刚方写好的,建议不要去动了,官方写的算完整了。以下是系统时钟配置的函示
static void SetSysClock(void)这函是底下的一部份:

/*PLL configuration */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLMULL6);

应该有看到除1和乘6吧,这个看法也可以套运在其他MCU上,标准库都差不多的。
再来要看看STM32F0xxx Cortex-M0 programming manual M0编程手册,要看这是因为我们是用操作内核的暂存器
手册网址:https://www.st.com/resource/en/programming_manual/pm0215-stm32f0xxx-cortexm0-programming-manual-stmicroelectronics.pdf
先来看看程序吧:

"bsp_SysTick.h"

#ifndef __SYSTICK_H
#define __SYSTICK_H

#include "stm32f0xx.h"

#define STK_CSR (*(volatile unsigned long*)0xE00E010)
#define STK_RVR (*(volatile unsigned long*)0xE00E014)
#define STK_CVR (*(volatile unsigned long*)0xE00E018)
	
void delay_ms(uint16_t nms);//16
void delay_us(uint16_t nus);//16
void SysTick_Init(uint8_t SYSCLK);//8
#endif /* __SYSTICK_H */

上面可以看到我有定义三个暂存器指标,这三个位置在第四章节
https://ithelp.ithome.com.tw/upload/images/20211002/20141979OchVSdxKSk.png
再来看看

"bsp_SysTick.c"

#include "bsp_SysTick.h"
static uint8_t	fac_us=0;
static uint16_t	fac_ms=0;
void SysTick_Init(uint8_t SYSCLK)
{
	SysTick->CTRL = 0xfffffffb;
	fac_us=SYSCLK/8;
	fac_ms=(uint16_t)fac_us*1000;

}
void delay_ms(uint16_t nms)
{
	uint32_t temp;
	SysTick->LOAD = (uint32_t)nms*fac_ms;
	SysTick->VAL =0x00; 	
	SysTick->CTRL =0x01;
	do
	{
	 temp = SysTick->CTRL;
	}
	while((temp&0x01)&&(!(temp&(1<<16))));
	SysTick->CTRL = 0x00;
	SysTick->VAL =0x00;
}
void delay_us(uint16_t nus)
{
	uint32_t temp;
	SysTick->LOAD = (uint32_t)nus*fac_us;
	SysTick->VAL =0x00; 	
	SysTick->CTRL =0x01;
	do
	{
	 temp = SysTick->CTRL;
	}
	while((temp&0x01)&&(!(temp&(1<<16))));
	SysTick->CTRL = 0x00;
	SysTick->VAL =0x00;
}

这些操作方法M0编程手册里的说明很清楚了,有兴趣的就自己看看吧,绝对不会看不懂很好理解。
再来是看主程序要如何使用?

main.c

#include "bsp_SysTick.h"

int main(void)
{
 SysTick_Init(48);//初始化
 delay_ms(20);
}

初始化後就可以使用了,我打48是因为我有挂外部石因震荡8M除1在乘6倍频就会变48M,才会输入48,还是不知道为甚麽在往前看看,假如不外挂石因用内部的话这边要改成8
这绝对会比用回圈计数还准。


<<:  Day 0x16 - 代码建立 (Part 2: 交易状态、退款状态)

>>:  EP20 - 整合 Jenkins 自动部署到 EKS

第廿七天:旅游快结束的周一

虽然还有一天...有点怀念ESO...收拾一下东西,等会要往车站移动了。 收拾完行李check ou...

数据分析的好夥伴 - Python基础:资料形式(上)

在学习完SQL之後,接下来让我们进入下一个阶段:Python的学习! 先说为什麽你需要学Python...

Day18 Elastic APM (二)

接下来我们要开始运用APM Agent的函式库来去做应用程序方面的监控。 APM 安装 kibana...

Day 29- 鬼斧神工 :Serverless 电商 - 实战 - 测试计画。

前言 在我们完成一项产品的时候都需要做到各种测试,并完成相关测试计画,才是一个完整的产品。 单元测试...

[NestJS 带你飞!] DAY28 - CORS

大部分的开发人员在面对前端後端是不同网域的时候,会碰上一个名叫 跨来源资源共享 (Cross-Ori...