完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
delay延时函数讲解(Systick应用)
频率定义:单位时间内完成周期性变化次数。 (借鉴正点原子网课) (一)Systick定时器,是一个简单的定时器(最主要的),对于CM3,CM4内核芯片,都有Systick定时器。 Systick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。比如UCOS中,分时复用,需要一个最小的时间戳,一般在STM32+UCOS系统中,都采用Systick做UCOS心跳时钟。 (二) Systick定时器就是系统滴答定时器,一个24 位的倒计数定时器,计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作(这也是为什么要特意开发出Systick定时器的缘由,如果此时用普通定时器在睡眠模式下会大大增加功耗 )。 SysTick定时器被捆绑在NVIC(中断优先级管理)中,用于产生SYSTICK异常。 Systick中断的优先级也可以设置。 (三)4个Systick寄存器 ①CTRL SysTick 控制和状态寄存器 LOAD 备注: TICKINT 中断位(1),M3外部时钟源72/8=9MHZ,M4外部时钟源是168/21=21MHZ ②SysTick 自动重装载除值寄存器 ③SysTick 当前值寄存器 CALIB (四)Systick库函数 void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource) { /* Check the parameters */ assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource)); //!!该段代码的作用是选择以下某段时钟源 if (SysTick_CLKSource == SysTick_CLKSource_HCLK) { SysTick->CTRL |= SysTick_CLKSource_HCLK; } else { SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8; } } static __INLINE uint32_t SysTick_Config(uint32_t ticks) { //两个中断中间有多少个ticks周期。 if (ticks-1 > SysTick_LOAD_RELOAD_Msk) return (1); //对tick值进行有效性分析,最后要写到24位的LOAD寄存器,不能大于24位寄存器2的24次方 /* Reload value impossible */ /* set reload register */ SysTick->LOAD = ticks - 1; //设置重装载寄存器值 /* set Priority for Cortex-M0 System Interrupts */ NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); //设置优先级 SysTick->VAL = 0; //设置Value值为0,会重新去加载。 /* Load the SysTick Counter Value */ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; //设置时钟源,中断,使能 /* Enable SysTick IRQ and SysTick Timer */ return (0); /* Function successful */ } static __IO uint32_t TimingDelay; void Delay(__IO uint32_t nTime) { TimingDelay = nTime; while(TimingDelay != 0); } void SysTdler(void) { if (TimingDelay != 0x00) { TimingDelay--; } } int main(void) { … if (SysTick_Config(SystemCoreClock / 1000)) //systick时钟为HCLK,中断时间间隔1ms { while (1); } while(1) { Delay(200);//2ms … } } (四)用中断方式实现delay延时(举例) static __IO uint32_t TimingDelay; void Delay(__IO uint32_t nTime) { TimingDelay = nTime; while(TimingDelay != 0); } void SysTdler(void) //每等待一毫秒产生一个中断 { if (TimingDelay != 0x00) { TimingDelay--; } } int main(void) { … if (SysTick_Config(SystemCoreClock / 1000)) //systick时钟为HCLK,中断时间间隔1ms { while (1); } while(1) { Delay(200);//200ms … } } //在Main中先设置好入口参数ticks的值,配置好初始化systick,进入Delay(200)循环,在这个循环体 //中每一次中断,Systick中断服务函数Systick_Handler自动减一,知道最后减到0,while结束循环,此延时函数也就结束了。 (五)delay_init函数介绍 //初始化延迟函数 //当使用 OS 的时候,此函数会初始化 OS 的时钟节拍 //SYSTICK 的时钟固定为 HCLK 时钟的 1/8 void delay_init() {#if SYSTEM_SUPPORT_OS //如果需要支持 OS. u32 reload; #endif SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCLK/8 fac_us=SystemCoreClock/8000000; //为系统时钟的 1/8 #if SYSTEM_SUPPORT_OS //如果需要支持 OS. reload=SystemCoreClock/8000000; //每秒钟的计数次数 单位为 M reload*=1000000/delay_ostickspersec; //根据 delay_ostickspersec 设定溢出时间 //reload 为 24 位寄存器,最大值:16777216,在 168M 下,约合 0.7989s 左右 fac_ms=1000/delay_ostickspersec; //代表 OS 可以延时的最少单位 SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //开启 SYSTICK 中断 SysTick->LOAD=reload; //每 1/delay_ostickspersec 秒中断一次 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启 SYSTICK #else fac_ms=(u16)fac_us*1000; //非 OS 下,代表每个 ms 需要的 systick 时钟数 #endif 该函数用来初始化 2 个重要参数:fac_us 以及 fac_ms;同时把 SysTick 的时钟源选择为外部时 钟,如果需要支持操作系统(OS),只需要在 sys.h 里面,设置 SYSTEM_SUPPORT_OS 宏的值 为 1 即可,然后,该函数会根据 delay_ostickspersec 宏的设置,来配置 SysTick 的中断时间,并 开启 SysTick 中断。 可以看到,delay_init 函数使用了条件编译,来选择不同的初始化过程,如果不使用 OS 的 时候,只是设置一下 SysTick 的时钟源以及确定 fac_us 和 fac_ms 的值。 (六)Delay_us,Delay_xms,Delay_ms 的延时函数介绍 void delay_us(u32 nus) { u32 temp; SysTick->LOAD=nus*fac_us; //时间加载,我们要延时n倍的us, 1us是一个fac_ua周期,所以总共要延时的周期值为二者相乘最后送到Load中。 SysTick->VAL=0x00; //清空计数器 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开启使能位 开始倒数 do { temp=SysTick->CTRL; }while((temp&0x01)&&!(temp&(1<<16))); //用来判断 systick 定时器是否还处于开启状态,然后在等待时间到达,也就是数到0的时候,此时第十六位设置为1 SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器使能位 SysTick->VAL =0X00; //清空计数器 } void delay_xms(u16 nms) { //跟上列同理 u32 temp; SysTick->LOAD=(u32)nms*fac_ms; // SysTick->VAL =0x00; // SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; do { temp=SysTick->CTRL; }while((temp&0x01)&&!(temp&(1<<16))); // SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; // SysTick->VAL =0X00; // } // void delay_ms(u16 nms) { u8 repeat=nms/540; //nms除以540后的整数值赋值给repeat,也就是倍数 u16 remain=nms%540; //nms除以540后余数值赋值给remain while(repeat) //开始倍数循环 循环条件依次减一直到最后为零 { delay_xms(540); //延时一次540ms repeat--; } if(remain)delay_xms(remain); //延时n倍的540后,剩余的值在这里延时 } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1781 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1621 浏览 1 评论
1085 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
728 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1680 浏览 2 评论
1938浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
732浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
570浏览 3评论
596浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
559浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-24 15:49 , Processed in 0.723247 second(s), Total 76, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号