文章目录
- 1.SysTick简介
- 2.工作原理
- 3.SysTick寄存器
- 4.代码延时逻辑
- 5.附上整体代码
- 6.一些重要解释
1.SysTick简介
Cortex-M处理器内集成了一个小型的名为SysTick(系统节拍)的定时器,它属于NVIC的一部分,且可以产生 SysTick异常(异常类型#15)。SysTick为简单的向下计数的24位计数器,可以使用处理器时钟或外部参考时钟(通常是片上时钟源)。
2.工作原理
SysTick定时器的工作原理非常简单。它有一个内置的计数器,计数器从一个初始值开始递减,当计数器的值达到零时,它会触发一个中断并重新加载初始值。SysTick定时器一般会与系统时钟频率(通常是CPU时钟)同步工作,可以用来创建精确的时间延迟。
主要特性
定时器计数:SysTick定时器的计数器在每个时钟周期递减,直到它的值为零时会触发一个中断。
中断功能:当计数器到达零时,SysTick会触发一个中断,通常用于处理系统的定时任务(如操作系统的时钟中断)。
自动重载:SysTick有一个自动重载功能,计数器会从预定的值重新加载并继续计数。
可配置的时钟源:SysTick可以选择不同的时钟源,通常选择处理器的系统时钟,或者是外部的低速时钟源
3.SysTick寄存器
4.代码延时逻辑
- 选择时钟源
根据CTRL寄存器的第2位和第0位,来选择时钟源和是否使能定时器
其中位0的意思是:位0=0 失能 关闭定时器
位0=1 使能 开启定时器
SysTuck->CTRL&=(1<<2);//第二位为1.选择高速内部时钟
- 关闭计数器
SysTuck->CTRL&=~(1<<0);//第0 位为0,关闭定时器
- delay_us(num)
定时器计数为0时候,重装载值为倍乘数系统时钟,我这里用的F4,系统分频的是21Mhz,那么应该是211/21Mhz,
周期=1/频率=1/168000000约等于0.00592us;这是系统时钟的周期,
最大延时取决于分频的频率
分频的频率为21Mhz,1个周期的时间为1/21000000s,大概为1/21us,所以倍乘数应该是21.
写入任何值将清零当前数值
SysTick->LOAD=num*value_us;//设置重装在制,其中num是系统时钟的频率,value_us是倍乘数,若num=42Mhz,则value_us=421,21Mhz,value_us=21,8M则value_us=8,原因看标签5的解释
SysTick->VAL=0;//计数器当前值清零
SysTuck->CTRL|=(1<<0);//第0 位为0,关闭定时器
- 等待计数完毕
判断CTRL寄存器的第16位是否为1–》计数到0
CTRL=1 &(1<<16)=1 while (!1)
CTRL=0 &(1<<16)=0 while(!0)
while(!(SysTick->CTRL(&1<<16)))
- 清空当前值
SysTick->VAL=0;
- 关闭计数器
SysTuck->CTRL&=~(1<<0);//第0 位为0,关闭定时器
5.附上整体代码
//仿原子延时,不进入systic中断
void delay_us(u32 nus)
{u32 temp;SysTick->LOAD = 21*nus;SysTick->VAL=0;//计数器当前值清零SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源do{temp=SysTick->CTRL;//读取当前倒计数值}while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达while(!(SysTick->CTRL(&1<<16)))SysTuck->CTRL&=~(1<<0);//第0 位为0,关闭定时器SysTick->VAL=0;//计数器当前值清零
}
void delay_ms(u16 nms)
{u32 temp;SysTick->LOAD = 21000*nms;SysTick->VAL=0;//计数器当前值清零SysTuck->CTRL&=~(1<<0);//第0 位为0,关闭定时器do{temp=SysTick->CTRL;//读取当前倒计数值}while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达SysTuck->CTRL&=~(1<<0);//第0 位为0,关闭定时器SysTick->VAL=0;//计数器当前值清零
}
借鉴链接https://blog.csdn.net/weibo1230123/article/details/81136564?spm=1001.2014.3001.5506
以及还有一个之前的找不到了。。。
6.一些重要解释
-
为什么频率是21M时候,value_us=21,才是1us
因为当时钟源选择21M的时候,1s时间计数为21M次
T=1/f(时间是频率的倒数)
当21M时,计数1次所产生的时间为1/21000000s,是1/21000ms,1/21us,所以*21是1us -
最大延时
当最大延时为21M时,24位计数器最大值为16777215
16777215/21=798915us=798.915ms。
由上两点可以计算出若外部时钟源选择是8M时,则value_us=8,valua_ms=8000,最大延时为167.77215/8=2097152us=2097.152ms
- HAL_Init()会提前配置好HAL_delay的参数
①FLASH读取指令缓存、数据缓存
②设置中断组优先级
③设置SysTick作为基准时间源、配置1ms tick,复位后默认时钟源为HSI(内部高速时钟源)
④初始化底层硬件
附上原始HAL_Init()函数源码,可看可不看
HAL_StatusTypeDef HAL_Init(void)
{/* Configure Flash prefetch, Instruction cache, Data cache */
#if (INSTRUCTION_CACHE_ENABLE != 0)__HAL_FLASH_INSTRUCTION_CACHE_ENABLE();
#endif /* INSTRUCTION_CACHE_ENABLE */#if (DATA_CACHE_ENABLE != 0)__HAL_FLASH_DATA_CACHE_ENABLE();
#endif /* DATA_CACHE_ENABLE */#if (PREFETCH_ENABLE != 0)__HAL_FLASH_PREFETCH_BUFFER_ENABLE();
#endif /* PREFETCH_ENABLE *//* Set Interrupt Group Priority */HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);//中断优先级分组4/* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */HAL_InitTick(TICK_INT_PRIORITY);/* Init the low level hardware */HAL_MspInit();/* Return function status */return HAL_OK;
}
以上资料部分来自于《清华开发者书库 ARM Cortex-M3与Cortex-M4权威指南 (Joseph Yiu、吴常玉、曹孟娟、王丽红。) (Z-Library)》
书籍已上传到博客