完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
CM4 内核的处理和 CM3 一样,内部都包含了一个 SysTick 定时器,SysTick 是一个 24 位的倒计数定时器,当计到 0 时,将从 RELOAD 寄存器中自动重装载定时初值。只要不把它在 SysTick 控制及状态寄存器中的使能位清除,就永不停息。
delay 文件夹内包含了 delay.c 和 delay.h 两个文件,这两个文件用来实现系统的延时功能,其中包含 7 个函数: -下面4 个函数,仅在支持操作系统(OS)的时候,需要用到 void delay_osschedlock(void); void delay_osschedunlock(void); void delay_ostimedly(u32 ticks); void SysTick_Handler(void); -下面 3 个函数,则不论是否支持 OS 都需要用到。 void delay_init(u8 SYSCLK); void delay_ms(u16 nms); void delay_us(u32 nus); 以 UCOSII 为例,介绍如何实现操作系统和我们的 delay 函数共用 SysTick 定时器。 首先,我们简单介绍下 UCOSII 的时钟:ucos 运行需要一个系统时钟节拍(“心跳”),而这个节拍是固定的(由 OS_TICKS_PER_SEC 宏定义设置),比如要求 5ms 一次(即可设置:OS_TICKS_PER_SEC=200),在 STM32 上面,一般是由 SysTick 来为 ucos 提供时钟节拍,也就是 systick要设置为 5ms 中断一次,而且这个时钟一般是不能被打断的(否则就不准了)。 在 ucos 下 systick 不能再被随意更改,如果我们还想利用 systick 来做 delay_us 或者delay_ms 的延时,就必须利用时钟摘取法。以 delay_us 为例,比如delay_us(50),在刚进入 delay_us 的时候先计算好这段延时需要等待的 systick 计数次数,这里为 50 * 21次(假设系统时钟为 168Mhz,因为 systick 的频率为系统时钟频率的 1/8,那么 systick每增加 1,就是 1/21us),然后我们就一直统计 systick 的计数变化,直到这个值变化了 50*21,一旦检测到变化达到或者超过这个值,就说明延时 50us 时间到了。这样,我们只是抓取 SysTick计数器的变化,并不需要修改 SysTick 的任何状态,完全不影响 systick 作为 UCOS 时钟节拍的功能,这就是实现 delay 和操作系统共用 SysTick 定时器的原理。 操作系统支持的3宏定义及4相关函数 当需要 delay_ms 和 delay_us 支持操作系统(OS)的时候,我们需要用到 3 个宏定义和 4个函数 //本例程仅作 UCOSII 和 UCOSIII 的支持,其他 OS,请自行参考着移植 //支持 UCOSII // #ifdef OS_CRITICAL_METHOD //OS_CRITICAL_METHOD 定义了,说明要支持 UCOSII #define delay_osrunning OSRunning //OS 是否运行标记,0,不运行;1,在运行 #define delay_ostickspersec OS_TICKS_PER_SEC //OS 时钟节拍,即每秒调度次数 #define delay_osintnesting OSIntNesting //中断嵌套级别,即中断嵌套次数 #endif //支持 UCOSIII// #ifdef CPU_CFG_CRITICAL_METHOD //CPU_CFG_CRITICAL_METHOD 定义了,说明要支持 UCOSIII #define delay_osrunning OSRunning //OS 是否运行标记,0,不运行;1,在运行 #define delay_ostickspersec OSCfg_TickRate_Hz //OS 时钟节拍,即每秒调度次数 #define delay_osintnesting OSIntNestingCtr //中断嵌套级别,即中断嵌套次数 #endif //us 级延时时,关闭任务调度(防止打断us级延迟) void delay_osschedlock(void) { #ifdef CPU_CFG_CRITICAL_METHOD //使用 UCOSIII OS_ERR err; OSSchedLock(&err); //UCOSIII 的方式,禁止调度,防止打断 us 延时 #else //否则 UCOSII OSSchedLock(); //UCOSII 的方式,禁止调度,防止打断 us 延时 #endif } //us 级延时时,恢复任务调度 void delay_osschedunlock(void) { #ifdef CPU_CFG_CRITICAL_METHOD //使用 UCOSIII OS_ERR err; OSSchedUnlock(&err); //UCOSIII 的方式,恢复调度 #else //否则 UCOSII OSSchedUnlock(); //UCOSII 的方式,恢复调度 #endif } //调用 OS 自带的延时函数延时// void delay_ostimedly(u32 ticks) //ticks:延时的节拍数 { #ifdef CPU_CFG_CRITICAL_METHOD //使用 UCOSIII 时 OS_ERR err; OSTimeDly(ticks,OS_OPT_TIME_PERIODIC,&err);//UCOSIII 延时采用周期模式 #else OSTimeDly(ticks); //UCOSII 延时 #endif } //systick 中断服务函数,使用 ucos 时用到 void SysTick_Handler(void) { if(delay_osrunning==1) //OS 开始跑了,才执行正常的调度处理 { OSIntEnter(); //进入中断 OSTimeTick(); //调用 ucos 的时钟服务程序 OSIntExit(); //触发任务切换软中断 } } delay_init 函数 delay_init() 函数用来初始化 2 个重要参数:fac_us 以及 fac_ms;同时把 SysTick 的时钟源选择为外部时钟,如果需要支持操作系统(OS),只需要在 sys.h 里面,设置 SYSTEM_SUPPORT_OS 宏的值为 1 即可,然后,该函数会根据 delay_ostickspersec 宏的设置,来配置 SysTick 的中断时间,并开启 SysTick 中断。 //初始化延迟函数 //当使用 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 为系统时钟的 1/8 fac_us=SystemCoreClock/8000000; //1us所需要的时钟周期 ,单位可理解为 “个/us” //SysTick时钟是sysclk 8分频,即SysTick时钟频率=sysclk/8, systick 计1次数所需时间为8/sysclk(s)=8*10^6/sysclk(us),因此,SysTick 1微秒计数个数为fac_us=sysclk/8*10^6. //sysick时钟频率=sysclk/8 =》 1s计数 sysclk/8 个 #if SYSTEM_SUPPORT_OS //如果需要支持 OS. reload=SystemCoreClock/8000000; //每秒钟的计数次数 单位为 M reload*=1000000/delay_ostickspersec; //根据delay_ostickspersec设定溢出时间,溢出时间=(个/us) * (每次任务调度所需时间) //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 } SysTick结构体: SysTick 是 MDK 定义了的一个结构体(在 core_m4.h 里面),里面包含 CTRL、LOAD、VAL、CALIB 等 4 个寄存器 delay_us()函数 不使用 OS 的时候,delay_us()函数如下 // /延时 us ,nus 为要延时的 us 数。 void delay_us(u32 nus) { u32 temp; SysTick-》LOAD=nus*fac_us; //时间数加载 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; //清空计数器 } //注意 nus 的值,不能太大,必须保证 nus《=(2^24)/fac_us,否则将导致延时时间不准确 使用 OS 的时候,delay_us 的实现函数如下: 延时 us ; nus 为要延时的 us 数。 void delay_us(u32 nus) { u32 ticks; u32 told,tnow,tcnt=0; u32 reload=SysTick-》LOAD; //LOAD 的值 ticks=nus*fac_us; //需要的节拍数 delay_osschedlock(); //阻止 OS 调度,防止打断 us 延时 told=SysTick-》VAL; //刚进入时的计数器值 while(1) { tnow=SysTick-》VAL; if(tnow!=told) { if(tnow《told)tcnt+=told-tnow; //注意 SYSTICK 是一个递减的计数器。 else tcnt+=reload-tnow+told; told=tnow; if(tcnt》=ticks)break; //时间超过/等于要延迟的时间,则退出。 } }; delay_osschedunlock(); //恢复 OS 调度 } |
|
|
|
CM4 内核的处理和 CM3 一样,内部都包含了一个 SysTick 定时器,SysTick 是一个 24 位的倒计数定时器,当计到 0 时,将从 RELOAD 寄存器中自动重装载定时初值。只要不把它在 SysTick 控制及状态寄存器中的使能位清除,就永不停息。
delay 文件夹内包含了 delay.c 和 delay.h 两个文件,这两个文件用来实现系统的延时功能,其中包含 7 个函数: -下面4 个函数,仅在支持操作系统(OS)的时候,需要用到 void delay_osschedlock(void); void delay_osschedunlock(void); void delay_ostimedly(u32 ticks); void SysTick_Handler(void); -下面 3 个函数,则不论是否支持 OS 都需要用到。 void delay_init(u8 SYSCLK); void delay_ms(u16 nms); void delay_us(u32 nus); 以 UCOSII 为例,介绍如何实现操作系统和我们的 delay 函数共用 SysTick 定时器。 首先,我们简单介绍下 UCOSII 的时钟:ucos 运行需要一个系统时钟节拍(“心跳”),而这个节拍是固定的(由 OS_TICKS_PER_SEC 宏定义设置),比如要求 5ms 一次(即可设置:OS_TICKS_PER_SEC=200),在 STM32 上面,一般是由 SysTick 来为 ucos 提供时钟节拍,也就是 systick要设置为 5ms 中断一次,而且这个时钟一般是不能被打断的(否则就不准了)。 在 ucos 下 systick 不能再被随意更改,如果我们还想利用 systick 来做 delay_us 或者delay_ms 的延时,就必须利用时钟摘取法。以 delay_us 为例,比如delay_us(50),在刚进入 delay_us 的时候先计算好这段延时需要等待的 systick 计数次数,这里为 50 * 21次(假设系统时钟为 168Mhz,因为 systick 的频率为系统时钟频率的 1/8,那么 systick每增加 1,就是 1/21us),然后我们就一直统计 systick 的计数变化,直到这个值变化了 50*21,一旦检测到变化达到或者超过这个值,就说明延时 50us 时间到了。这样,我们只是抓取 SysTick计数器的变化,并不需要修改 SysTick 的任何状态,完全不影响 systick 作为 UCOS 时钟节拍的功能,这就是实现 delay 和操作系统共用 SysTick 定时器的原理。 操作系统支持的3宏定义及4相关函数 当需要 delay_ms 和 delay_us 支持操作系统(OS)的时候,我们需要用到 3 个宏定义和 4个函数 //本例程仅作 UCOSII 和 UCOSIII 的支持,其他 OS,请自行参考着移植 //支持 UCOSII // #ifdef OS_CRITICAL_METHOD //OS_CRITICAL_METHOD 定义了,说明要支持 UCOSII #define delay_osrunning OSRunning //OS 是否运行标记,0,不运行;1,在运行 #define delay_ostickspersec OS_TICKS_PER_SEC //OS 时钟节拍,即每秒调度次数 #define delay_osintnesting OSIntNesting //中断嵌套级别,即中断嵌套次数 #endif //支持 UCOSIII// #ifdef CPU_CFG_CRITICAL_METHOD //CPU_CFG_CRITICAL_METHOD 定义了,说明要支持 UCOSIII #define delay_osrunning OSRunning //OS 是否运行标记,0,不运行;1,在运行 #define delay_ostickspersec OSCfg_TickRate_Hz //OS 时钟节拍,即每秒调度次数 #define delay_osintnesting OSIntNestingCtr //中断嵌套级别,即中断嵌套次数 #endif //us 级延时时,关闭任务调度(防止打断us级延迟) void delay_osschedlock(void) { #ifdef CPU_CFG_CRITICAL_METHOD //使用 UCOSIII OS_ERR err; OSSchedLock(&err); //UCOSIII 的方式,禁止调度,防止打断 us 延时 #else //否则 UCOSII OSSchedLock(); //UCOSII 的方式,禁止调度,防止打断 us 延时 #endif } //us 级延时时,恢复任务调度 void delay_osschedunlock(void) { #ifdef CPU_CFG_CRITICAL_METHOD //使用 UCOSIII OS_ERR err; OSSchedUnlock(&err); //UCOSIII 的方式,恢复调度 #else //否则 UCOSII OSSchedUnlock(); //UCOSII 的方式,恢复调度 #endif } //调用 OS 自带的延时函数延时// void delay_ostimedly(u32 ticks) //ticks:延时的节拍数 { #ifdef CPU_CFG_CRITICAL_METHOD //使用 UCOSIII 时 OS_ERR err; OSTimeDly(ticks,OS_OPT_TIME_PERIODIC,&err);//UCOSIII 延时采用周期模式 #else OSTimeDly(ticks); //UCOSII 延时 #endif } //systick 中断服务函数,使用 ucos 时用到 void SysTick_Handler(void) { if(delay_osrunning==1) //OS 开始跑了,才执行正常的调度处理 { OSIntEnter(); //进入中断 OSTimeTick(); //调用 ucos 的时钟服务程序 OSIntExit(); //触发任务切换软中断 } } delay_init 函数 delay_init() 函数用来初始化 2 个重要参数:fac_us 以及 fac_ms;同时把 SysTick 的时钟源选择为外部时钟,如果需要支持操作系统(OS),只需要在 sys.h 里面,设置 SYSTEM_SUPPORT_OS 宏的值为 1 即可,然后,该函数会根据 delay_ostickspersec 宏的设置,来配置 SysTick 的中断时间,并开启 SysTick 中断。 //初始化延迟函数 //当使用 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 为系统时钟的 1/8 fac_us=SystemCoreClock/8000000; //1us所需要的时钟周期 ,单位可理解为 “个/us” //SysTick时钟是sysclk 8分频,即SysTick时钟频率=sysclk/8, systick 计1次数所需时间为8/sysclk(s)=8*10^6/sysclk(us),因此,SysTick 1微秒计数个数为fac_us=sysclk/8*10^6. //sysick时钟频率=sysclk/8 =》 1s计数 sysclk/8 个 #if SYSTEM_SUPPORT_OS //如果需要支持 OS. reload=SystemCoreClock/8000000; //每秒钟的计数次数 单位为 M reload*=1000000/delay_ostickspersec; //根据delay_ostickspersec设定溢出时间,溢出时间=(个/us) * (每次任务调度所需时间) //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 } SysTick结构体: SysTick 是 MDK 定义了的一个结构体(在 core_m4.h 里面),里面包含 CTRL、LOAD、VAL、CALIB 等 4 个寄存器 delay_us()函数 不使用 OS 的时候,delay_us()函数如下 // /延时 us ,nus 为要延时的 us 数。 void delay_us(u32 nus) { u32 temp; SysTick-》LOAD=nus*fac_us; //时间数加载 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; //清空计数器 } //注意 nus 的值,不能太大,必须保证 nus《=(2^24)/fac_us,否则将导致延时时间不准确 使用 OS 的时候,delay_us 的实现函数如下: 延时 us ; nus 为要延时的 us 数。 void delay_us(u32 nus) { u32 ticks; u32 told,tnow,tcnt=0; u32 reload=SysTick-》LOAD; //LOAD 的值 ticks=nus*fac_us; //需要的节拍数 delay_osschedlock(); //阻止 OS 调度,防止打断 us 延时 told=SysTick-》VAL; //刚进入时的计数器值 while(1) { tnow=SysTick-》VAL; if(tnow!=told) { if(tnow《told)tcnt+=told-tnow; //注意 SYSTICK 是一个递减的计数器。 else tcnt+=reload-tnow+told; told=tnow; if(tcnt》=ticks)break; //时间超过/等于要延迟的时间,则退出。 } }; delay_osschedunlock(); //恢复 OS 调度 } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1916 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1680 浏览 1 评论
1172 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
771 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1732 浏览 2 评论
1974浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
809浏览 4评论
stm32f4下spi+dma读取数据不对是什么原因导致的?
257浏览 3评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
625浏览 3评论
634浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-1-25 09:18 , Processed in 0.715008 second(s), Total 44, Slave 39 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号