1、delay文件夹。
delay.c和delay.h两个文件,其中有七个函数:
void delay_osschedlock(void);
void delay_osschedunlock(void);
void delay_ostimedly(u32 ticks);
void SysTick_Handler(void);
void delay_init(void);
void delay_ms(u16 nms);
void delay_ns(u32 nus);
前四个函数仅在操作系统的时候需要用到,后三个无论是否支持操作系统都需要用到。
CM3内核有SysTick(滴答)定时器,是一个24位倒计数定时器。
①当需要delay_ms和delay_ns支持操作系统时,需要用到3个宏定义和4个函数。
#define delay_osrunning OSRUNNING //OS是否运行,1运行,0不运行
#define delay_ostickspersec OS_TICKS_PER_SEC //OS时钟节拍,每秒调度次数
#define delay_osintnesting OSIntNesting //中断嵌套级别,即中断嵌套次数
void delay_osschedlock(void) //关闭OS任务调度,防止打断延迟
void delay_osschedunlock(void) //恢复OS任务调度,可以打断延迟
void delay_ostimedly(u32 ticks) //OS自带延迟函数,ticks延迟节拍数
void SysTick_Handler(void) //systick中断服务函数
②delay_init函数。
两个重要的参数:fac_us和fac_ms,SysTick选择时钟源,如果需要支持操作系统,只需要在sys.h中设置SYSTEM_SUPPORT_OS宏的值为1即可,默认SYSTEM_SUPPORT_OS宏的值为0,函数如下:
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,SystemCoreClock值为72000000
reload*=1000000/delay_ostickspersec; //根据delay_ostickspersec 设定溢出时间
//reload 为24 位寄存器,最大值:16777216,在72M 下,约合1.86s 左右
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
}
delay_int函数使用了条件编译,不支持操作系统时设置fac_us和fac_ms,支持操作系统时设置了fac_us(和不支持操作系统的相同)、fac_ms、SysTick->CTRL、SysTick->LOAD,编译是根据sys.h中的宏SYSTEM_SUPPORT_OS确定。
SysTick是MDK定义的一个结构体(core_m3.h里面),里面包含CTRL、LOAD、VAL、CALIB四个成员变量。
有操作系统时,fac_ms代表操作系统自带延迟函数所能实现的最小延迟时间,如delay_ostickspessec=200,那么fac_ms就是5ms。
③无操作系统的延迟函数。
delay_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; //清空计数器
}
不带操作系统的delay_us,把延迟换算为Systick时钟数,然后写入LOAD,滴答定时器关闭或者计时完成停止循环,即完成定时。有滴答定时器的开启判断是放置滴答定时器关闭后导致死循环。LOAD是24位有效位,72MHz主频时,SysTics频率9MHz,每个滴答周期1/9us,最大延迟时间 t = 2^24/9 = 1864135us = 1.86s。
delay_ms函数同delay_us,函数如下:
void delay_ms(u16 nms)
{
u32 temp;
SysTick->LOAD=(u32)nm