delay.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #include "delay.h"
  2. #include "sys.h"
  3. //////////////////////////////////////////////////////////////////////////////////
  4. //如果需要使用OS,则包括下面的头文件即可.
  5. #if SYSTEM_SUPPORT_OS
  6. #include "includes.h" //ucos 使用
  7. #endif
  8. //////////////////////////////////////////////////////////////////////////////////
  9. //本程序只供内部使用,未经作者许可,不得用于其它任何用途
  10. //STM32开发板
  11. //使用SysTick的普通计数模式对延迟进行管理(适合STM32F10x系列)
  12. //包括delay_us,delay_ms
  13. //Copyright(C) 济南鲁泰电气有限公司 2009-2019
  14. //All rights reserved
  15. //********************************************************************************
  16. //V1.2修改说明
  17. //修正了中断中调用出现死循环的错误
  18. //防止延时不准确,采用do while结构!
  19. //V1.3修改说明
  20. //增加了对UCOSII延时的支持.
  21. //如果使用ucosII,delay_init会自动设置SYSTICK的值,使之与ucos的TICKS_PER_SEC对应.
  22. //delay_ms和delay_us也进行了针对ucos的改造.
  23. //delay_us可以在ucos下使用,而且准确度很高,更重要的是没有占用额外的定时器.
  24. //delay_ms在ucos下,可以当成OSTimeDly来用,在未启动ucos时,它采用delay_us实现,从而准确延时
  25. //可以用来初始化外设,在启动了ucos之后delay_ms根据延时的长短,选择OSTimeDly实现或者delay_us实现.
  26. //V1.4修改说明 20110929
  27. //修改了使用ucos,但是ucos未启动的时候,delay_ms中中断无法响应的bug.
  28. //V1.5修改说明 20120902
  29. //在delay_us加入ucos上锁,防止由于ucos打断delay_us的执行,可能导致的延时不准。
  30. //V1.6修改说明 20150109
  31. //在delay_ms加入OSLockNesting判断。
  32. //V1.7修改说明 20150319
  33. //修改OS支持方式,以支持任意OS(不限于UCOSII和UCOSIII,理论上任意OS都可以支持)
  34. //添加:delay_osrunning/delay_ostickspersec/delay_osintnesting三个宏定义
  35. //添加:delay_osschedlock/delay_osschedunlock/delay_ostimedly三个函数
  36. //V1.8修改说明 20150519
  37. //修正UCOSIII支持时的2个bug:
  38. //delay_tickspersec改为:delay_ostickspersec
  39. //delay_intnesting改为:delay_osintnesting
  40. //////////////////////////////////////////////////////////////////////////////////
  41. static u32 fac_us=0; //us延时倍乘数
  42. #if SYSTEM_SUPPORT_OS
  43. static u16 fac_ms=0; //ms延时倍乘数,在os下,代表每个节拍的ms数
  44. #endif
  45. #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS定义了,说明要支持OS了(不限于UCOS).
  46. //当delay_us/delay_ms需要支持OS的时候需要三个与OS相关的宏定义和函数来支持
  47. //首先是3个宏定义:
  48. // delay_osrunning:用于表示OS当前是否正在运行,以决定是否可以使用相关函数
  49. //delay_ostickspersec:用于表示OS设定的时钟节拍,delay_init将根据这个参数来初始哈systick
  50. // delay_osintnesting:用于表示OS中断嵌套级别,因为中断里面不可以调度,delay_ms使用该参数来决定如何运行
  51. //然后是3个函数:
  52. // delay_osschedlock:用于锁定OS任务调度,禁止调度
  53. //delay_osschedunlock:用于解锁OS任务调度,重新开启调度
  54. // delay_ostimedly:用于OS延时,可以引起任务调度.
  55. //本例程仅作UCOSII和UCOSIII的支持,其他OS,请自行参考着移植
  56. //支持UCOSII
  57. #ifdef OS_CRITICAL_METHOD //OS_CRITICAL_METHOD定义了,说明要支持UCOSII
  58. #define delay_osrunning OSRunning //OS是否运行标记,0,不运行;1,在运行
  59. #define delay_ostickspersec OS_TICKS_PER_SEC //OS时钟节拍,即每秒调度次数
  60. #define delay_osintnesting OSIntNesting //中断嵌套级别,即中断嵌套次数
  61. #endif
  62. //支持UCOSIII
  63. #ifdef CPU_CFG_CRITICAL_METHOD //CPU_CFG_CRITICAL_METHOD定义了,说明要支持UCOSIII
  64. #define delay_osrunning OSRunning //OS是否运行标记,0,不运行;1,在运行
  65. #define delay_ostickspersec OSCfg_TickRate_Hz //OS时钟节拍,即每秒调度次数
  66. #define delay_osintnesting OSIntNestingCtr //中断嵌套级别,即中断嵌套次数
  67. #endif
  68. //us级延时时,关闭任务调度(防止打断us级延迟)
  69. void delay_osschedlock(void)
  70. {
  71. #ifdef CPU_CFG_CRITICAL_METHOD //使用UCOSIII
  72. OS_ERR err;
  73. OSSchedLock(&err); //UCOSIII的方式,禁止调度,防止打断us延时
  74. #else //否则UCOSII
  75. OSSchedLock(); //UCOSII的方式,禁止调度,防止打断us延时
  76. #endif
  77. }
  78. //us级延时时,恢复任务调度
  79. void delay_osschedunlock(void)
  80. {
  81. #ifdef CPU_CFG_CRITICAL_METHOD //使用UCOSIII
  82. OS_ERR err;
  83. OSSchedUnlock(&err); //UCOSIII的方式,恢复调度
  84. #else //否则UCOSII
  85. OSSchedUnlock(); //UCOSII的方式,恢复调度
  86. #endif
  87. }
  88. //调用OS自带的延时函数延时
  89. //ticks:延时的节拍数
  90. void delay_ostimedly(u32 ticks)
  91. {
  92. #ifdef CPU_CFG_CRITICAL_METHOD
  93. OS_ERR err;
  94. OSTimeDly(ticks,OS_OPT_TIME_PERIODIC,&err); //UCOSIII延时采用周期模式
  95. #else
  96. OSTimeDly(ticks); //UCOSII延时
  97. #endif
  98. }
  99. //systick中断服务函数,使用ucos时用到
  100. void SysTick_Handler(void)
  101. {
  102. if(delay_osrunning==1) //OS开始跑了,才执行正常的调度处理
  103. {
  104. OSIntEnter(); //进入中断
  105. OSTimeTick(); //调用ucos的时钟服务程序
  106. OSIntExit(); //触发任务切换软中断
  107. }
  108. }
  109. #endif
  110. //初始化延迟函数
  111. //当使用ucos的时候,此函数会初始化ucos的时钟节拍
  112. //SYSTICK的时钟固定为AHB时钟
  113. //SYSCLK:系统时钟频率
  114. void delay_init(u8 SYSCLK)
  115. {
  116. #if SYSTEM_SUPPORT_OS //如果需要支持OS.
  117. u32 reload;
  118. #endif
  119. HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);//SysTick频率为HCLK
  120. fac_us=SYSCLK; //不论是否使用OS,fac_us都需要使用
  121. #if SYSTEM_SUPPORT_OS //如果需要支持OS.
  122. reload=SYSCLK; //每秒钟的计数次数 单位为K
  123. reload*=1000000/delay_ostickspersec; //根据delay_ostickspersec设定溢出时间
  124. //reload为24位寄存器,最大值:16777216,在72M下,约合0.233s左右
  125. fac_ms=1000/delay_ostickspersec; //代表OS可以延时的最少单位
  126. SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;//开启SYSTICK中断
  127. SysTick->LOAD=reload; //每1/OS_TICKS_PER_SEC秒中断一次
  128. SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
  129. #else
  130. #endif
  131. }
  132. #if SYSTEM_SUPPORT_OS //如果需要支持OS.
  133. //延时nus
  134. //nus:要延时的us数.
  135. //nus:0~190887435(最大值即2^32/fac_us@fac_us=22.5)
  136. void delay_us(u32 nus)
  137. {
  138. u32 ticks;
  139. u32 told,tnow,tcnt=0;
  140. u32 reload=SysTick->LOAD; //LOAD的值
  141. ticks=nus*fac_us; //需要的节拍数
  142. delay_osschedlock(); //阻止OS调度,防止打断us延时
  143. told=SysTick->VAL; //刚进入时的计数器值
  144. while(1)
  145. {
  146. tnow=SysTick->VAL;
  147. if(tnow!=told)
  148. {
  149. if(tnow<told)tcnt+=told-tnow; //这里注意一下SYSTICK是一个递减的计数器就可以了.
  150. else tcnt+=reload-tnow+told;
  151. told=tnow;
  152. if(tcnt>=ticks)break; //时间超过/等于要延迟的时间,则退出.
  153. }
  154. };
  155. delay_osschedunlock(); //恢复OS调度
  156. }
  157. //延时nms
  158. //nms:要延时的ms数
  159. //nms:0~65535
  160. void delay_ms(u16 nms)
  161. {
  162. if(delay_osrunning&&delay_osintnesting==0)//如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度)
  163. {
  164. if(nms>=fac_ms) //延时的时间大于OS的最少时间周期
  165. {
  166. delay_ostimedly(nms/fac_ms); //OS延时
  167. }
  168. nms%=fac_ms; //OS已经无法提供这么小的延时了,采用普通方式延时
  169. }
  170. delay_us((u32)(nms*1000)); //普通方式延时
  171. }
  172. #else //不用ucos时
  173. //延时nus
  174. //nus为要延时的us数.
  175. //nus:0~190887435(最大值即2^32/fac_us@fac_us=22.5)
  176. void delay_us(u32 nus)
  177. {
  178. u32 ticks;
  179. u32 told,tnow,tcnt=0;
  180. u32 reload=SysTick->LOAD; //LOAD的值
  181. ticks=nus*fac_us; //需要的节拍数
  182. told=SysTick->VAL; //刚进入时的计数器值
  183. while(1)
  184. {
  185. tnow=SysTick->VAL;
  186. if(tnow!=told)
  187. {
  188. if(tnow<told)tcnt+=told-tnow; //这里注意一下SYSTICK是一个递减的计数器就可以了.
  189. else tcnt+=reload-tnow+told;
  190. told=tnow;
  191. if(tcnt>=ticks)break; //时间超过/等于要延迟的时间,则退出.
  192. }
  193. };
  194. }
  195. //延时nms
  196. //nms:要延时的ms数
  197. void delay_ms(u16 nms)
  198. {
  199. u32 i;
  200. for(i=0;i<nms;i++) delay_us(1000);
  201. }
  202. #endif