delay.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. /**
  2. *****************************************************************************
  3. * 系统延时相关的函数
  4. * 详细说明请参考《Cortex-M3权威指南(中文)》第133 ~ 134页 第8章 SysTick定时器介绍
  5. *
  6. * (C) Copyright 2000-2020, ***
  7. * All Rights Reserved
  8. *****************************************************************************
  9. *
  10. * @File : delay.c
  11. * @By : 陈桂东
  12. * @Version : V1.0
  13. * @Date : 2012 / 10 / 20
  14. *
  15. *****************************************************************************
  16. * Update
  17. * @Version : V1.0.1
  18. * @By : 陈桂东
  19. * @Date : 2014 / 02 / 26
  20. * @Brief : 增加另外一种延时计算方法
  21. *
  22. * @Version : V1.1
  23. * @By : 陈桂东
  24. * @Date : 2014 / 05 / 24
  25. * @Brief : A、增加对C++环境支持
  26. * B、修改在跑ucos时初始化嘀嗒定时器、延时us和ms函数
  27. *
  28. * @Version : V1.2
  29. * @By : 陈桂东
  30. * @Date : 2015 / 10 / 03
  31. * @Brief : 优化延时函数
  32. *
  33. *****************************************************************************
  34. **/
  35. #include "delay.h"
  36. /******************************************************************************
  37. * @ SysTick定时器 相关控制寄存器说明
  38. @ 1、SysTick控制及状态寄存器(地址:0xE000_E010)复位值为0
  39. bit16 COUNTFLAG(R) -> 如果在上次读取本寄存器后,SysTick已经数到了0,则该位为1。如果读取该位,该位将自动清零
  40. bit2 CLKSOURCE(R/W) -> 0=外部时钟源(STCLK)。1=内核时钟(FCLK)
  41. bit1 TICKINT(R/W) -> 1=SysTick倒数到0时产生SysTick异常请求,0=数到0时无动作
  42. bit0 ENABLE(R/W) -> SysTick定时器的使能位
  43. @ 2、SysTick重装载数值寄存器(地址:0xE000_E014)复位值为0
  44. [23:0] RELOAD(R/W) -> 当倒数至零时,将被重装载的值
  45. @ 3、SysTick当前数值寄存器(地址:0xE000_E018) 复位值为0
  46. [23:0] CURRENT(R/Wc) -> 读取时返回当前倒计数的值,写它则使之清零,同时还会清除在SysTick 控制及状态寄存器中的COUNTFLAG标志
  47. @ 4、SysTick校准数值寄存器(地址:0xE000_E01C)复位值: bit31未知。bit30未知。[23:0]为0
  48. bit32 NOREF(R) -> 1=没有外部参考时钟(STCLK不可用)。0=外部参考时钟可用
  49. bit30 SKEW(R) -> 1=校准值不是准确的10ms。0=校准值是准确的10ms
  50. [23:0] TENMS(R/W) -> 10ms的时间内倒计数的格数。芯片设计者应该通过Cortex‐M3的输入信号提供该数值。若该值读回零,则表示无法使用校准功能
  51. ******************************************************************************/
  52. #if _SYSTEM_SUPPORT_ROTS == 1
  53. #if _RTOS_Type_Support == 1 //RAW-OS
  54. #include "raw_api.h"
  55. #else //uCOS
  56. #include "includes.h"
  57. #endif
  58. /**
  59. *****************************************************************************
  60. * @Name : SysTick定时器中断服务函数
  61. *
  62. * @Brief : 在此编写了,则stm32f10x_it.c中就不需要编写,否则stm32f10x_it.c中就要编写
  63. *
  64. * @Input : none
  65. *
  66. * @Output : none
  67. *
  68. * @Return : none
  69. *****************************************************************************
  70. **/
  71. void SysTick_Handler ( void )
  72. {
  73. /* 编写与SysTick定时器中断操作相关的API函数调用 */
  74. #if _RTOS_Type_Support == 1 //RAW-OS
  75. raw_enter_interrupt();
  76. #if (CONFIG_RAW_TASK_0 > 0) // 开启了TASK_0特性
  77. task_0_tick_post();
  78. #else
  79. raw_time_tick();
  80. #endif
  81. raw_finish_int();
  82. #else //uCOS
  83. OSIntEnter(); //ucos进入中断
  84. OSTimeTick(); //调用ucos的时钟服务函数
  85. OSIntExit(); //ucos退出中断
  86. #endif
  87. }
  88. #endif /* end _SYSTEM_SUPPORT_ROTS */
  89. #if _USER_OtherDelay == 0 //使用嘀嗒定时器做延时时基
  90. /******************************************************************************
  91. 定义计算变量
  92. ******************************************************************************/
  93. static uint8_t fac_us = 0; //us延时倍乘数
  94. static uint16_t fac_ms = 0; //ms延时倍乘数
  95. #endif
  96. /**
  97. *****************************************************************************
  98. * @Name : 初始化延时函数
  99. *
  100. * @Brief : 主要Cortex-M3内核对系统时钟计数单元
  101. * 详细见《Cortex-M3权威指南(中文)》第216页 a) 时钟周期(CYCCNT) 的内容
  102. * 周立功《CM3计数参考手册》第28、29页、第110、125页
  103. *
  104. * @Input : none
  105. *
  106. * @Output : none
  107. *
  108. * @Return : none
  109. *****************************************************************************
  110. **/
  111. void delay_init ( void )
  112. {
  113. #if _USER_OtherDelay == 1 //使用其他资源做延时时基
  114. DEM_CTRL |= 1 << 24; //该位必须为1,使能跟踪和调试模块的使用。详细见:周立功《CM3计数参考手册》第115页介绍
  115. //在没有使用跟踪时,该位使能对功率使用的控制。它能够由应用程序或调试器使能,供ITM使用
  116. //在DWT能够使用之前,调试异常和监控控制寄存器的TRCENA(bit24)位必须置位
  117. DWT_CTRL |= 1 << 0; //使能DWT_CYCCNT计数器。
  118. //如果不使能,则计数器不执行计数操作,因此不会产生PC采样或CYCCNTENA事件。
  119. //在正常使用时,CYCCNT计数器应由调试器初始化为0。
  120. #else //使用嘀嗒定时器做延时时基
  121. #if _SYSTEM_SUPPORT_ROTS == 1 //运行了OS
  122. uint32_t RELOAD = 0; //挡计数器倒数到0时的重装值,有效位:0 ~ 23
  123. #endif
  124. /* 根据SysTick定时器的时钟分频来确定重装值 */
  125. /* 8分频时除以8000‘000,1分频时除以1000’000 */
  126. SysTick_CLKSourceConfig ( SysTick_CLKSource_HCLK_Div8 ); //选择外部时钟 HCLK / 8
  127. fac_us = SystemCoreClock / 8000000; //系统时钟的 1/8
  128. #if _SYSTEM_SUPPORT_ROTS == 1 //运行了OS
  129. RELOAD = SystemCoreClock / 8000000; //每秒钟的计数次数,单位Hz
  130. #if _RTOS_Type_Support == 1 // RAW-OS
  131. RELOAD *= 1000000 / RAW_TICKS_PER_SECOND; //根据操作系统的心跳时长来计算溢出时间,单位:KHz
  132. //RELOAD为24位计数器,最大值为:16777216
  133. fac_ms = 1000 / RAW_TICKS_PER_SECOND;
  134. #else // uCOS
  135. RELOAD *= 1000000 / OS_TICKS_PER_SEC; //根据操作系统的心跳时长来计算溢出时间,单位:KHz
  136. //RELOAD为24位计数器,最大值为:16777216
  137. fac_ms = 1000 / OS_TICKS_PER_SEC;
  138. #endif
  139. SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; //开启SysTick定时器中断请求
  140. SysTick->LOAD = RELOAD; //溢出计数值,每1/TICKINT_CNT秒中断一次
  141. SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开始倒数
  142. #else //没有运行OS
  143. fac_ms = ( uint16_t ) fac_us * 1000; //ms需要的SysTick时钟数
  144. #endif
  145. #endif //end _USER_OtherDelay
  146. }
  147. /**
  148. *****************************************************************************
  149. * @Name : 延时n个us
  150. *
  151. * @Brief : none
  152. *
  153. * @Input : nus:要延时的us数
  154. *
  155. * @Output : none
  156. *
  157. * @Return : none
  158. *****************************************************************************
  159. **/
  160. void delay_us ( uint32_t nus )
  161. {
  162. #if _USER_OtherDelay == 1 //使用其他资源做延时时基
  163. uint32_t savecount, endcnt, CPU_cnt;
  164. savecount = DWT_CYCCNT; //保存计数器当前数值
  165. CPU_cnt = nus * ( SystemCoreClock / ( 1000 * 1000 ) ); //计算达到所需延时值的CPU时钟数。即多少个系统时钟计数
  166. //得到更精确延时时间,减去前面代码运行的时间即可
  167. endcnt = savecount + CPU_cnt; //计算所需延时时间DWT_CYCCNT的计数值,在溢出时返回到0
  168. if ( endcnt > savecount ) //所需延时值大于当前计数值
  169. {
  170. while ( DWT_CYCCNT < endcnt ); //循环等待所需要的延时时间的CPU时钟计数值
  171. }
  172. else //小于当前计数值
  173. {
  174. while ( DWT_CYCCNT > endcnt ); //等待计数器溢出翻转
  175. while ( DWT_CYCCNT < endcnt ); //等待所需延时时间到达
  176. }
  177. #else //使用嘀嗒定时器做延时时基
  178. uint32_t temp = 0;
  179. #if _SYSTEM_SUPPORT_ROTS == 1 //运行了OS
  180. uint32_t VAL_Prev = 0; //开始计时之前的值
  181. uint32_t VAL_Now = 0; //当前计时值
  182. uint32_t VAL_cnt = 0; //计数
  183. uint32_t Reload = SysTick->LOAD; //获取到LOAD的值
  184. temp = nus * fac_us; //得到延时的节拍数
  185. #if _RTOS_Type_Support == 1 // RAW-OS
  186. raw_disable_sche(); //阻止RAW-OS调度,防止打断us延时
  187. #else // uCOS
  188. OSSchedLock(); //阻止ucos调度,防止打断us延时
  189. #endif
  190. VAL_Prev = SysTick->VAL; //保存当前的计数值
  191. while ( 1 )
  192. {
  193. VAL_Now = SysTick->VAL; //读取数值
  194. if ( VAL_Now != VAL_Prev )
  195. {
  196. if ( VAL_Now < VAL_Prev ) VAL_cnt += VAL_Prev - VAL_Now; //因为SysTick是一个递减的定时器
  197. else VAL_cnt += Reload - VAL_Now + VAL_Prev;
  198. VAL_Prev = VAL_Now; //刷新
  199. if ( VAL_cnt >= temp ) break; //超过/等于需要的延时值了,则退出循环
  200. }
  201. };
  202. #if _RTOS_Type_Support == 1 // RAW-OS
  203. raw_enable_sche(); //开启RAW-OS调度
  204. #else // uCOS
  205. OSSchedUnlock(); //开启ucos调度
  206. #endif
  207. #else //没有运行os
  208. SysTick->LOAD = nus * fac_us; //时间加载
  209. SysTick->VAL = 0x00; //清空计数器
  210. SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开始倒数
  211. do
  212. {
  213. temp = SysTick->CTRL;
  214. }
  215. while ( temp & 0x01 && ! ( temp & ( 1 << 16 ) ) ); //等待时间到达
  216. SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数器
  217. SysTick->VAL = 0x00; //清空计数器
  218. #endif //end _SYSTEM_SUPPORT_ROTS
  219. #endif //end _USER_OtherDelay
  220. }
  221. /**
  222. *****************************************************************************
  223. * @Name : 延时n个ms
  224. *
  225. * @Brief : 1、延时ms级定义,延时范围:1 ~ 65535ms。延时最大值可变,不爆机uint32_t/1000范围即可
  226. * 2、SysTick->LOAD为24位寄存器,所以,最大延时为:
  227. * nms <= 0xffffff*8*1000/SYSCLK
  228. * SYSCLK单位为Hz,nms单位为ms
  229. * 注意nms的范围 0 ~ 1864(72M情况下)
  230. *
  231. * @Input : nms:要延时的ms数
  232. *
  233. * @Output : none
  234. *
  235. * @Return : none
  236. *****************************************************************************
  237. **/
  238. void delay_ms ( uint16_t nms )
  239. {
  240. #if _USER_OtherDelay == 1 //使用其他资源做延时时基
  241. delay_us ( ( uint32_t ) ( nms * 1000 ) ); //采用普通的延时
  242. #else //使用嘀嗒定时器做延时时基
  243. #if _SYSTEM_SUPPORT_ROTS == 1 //运行了OS
  244. #if _RTOS_Type_Support == 1 // RAW-OS
  245. if ( raw_os_active == RAW_OS_RUNNING && raw_int_nesting == 0 )
  246. #else //uCOS
  247. if ( OSRunning == OS_TRUE && OSLockNesting == 0 ) //ucos已经在跑了
  248. #endif
  249. {
  250. if ( nms > fac_ms ) //延时大于ucos基数
  251. {
  252. #if _RTOS_Type_Support == 1 // RAW-OS
  253. raw_sleep ( nms / fac_ms );
  254. #else // uCOS
  255. OSTimeDly ( nms / fac_ms ); //采用ucos延时
  256. #endif
  257. }
  258. nms %= fac_ms; //ucos无法提供小于节拍的延时了
  259. }
  260. if ( nms == 0 ) return; //没意义了,直接退出,不加这句,在运行RAW-OS时会死机
  261. delay_us ( ( uint32_t ) ( nms * 1000 ) ); //采用普通的延时
  262. #else //没有运行os
  263. uint32_t temp;
  264. SysTick->LOAD = ( uint32_t ) nms * fac_ms; //时间加载(SysTick->LOAD为24bit)
  265. SysTick->VAL = 0x00; //清空计数器
  266. SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开始倒数
  267. do
  268. {
  269. temp = SysTick->CTRL;
  270. }
  271. while ( temp & 0x01 && ! ( temp & ( 1 << 16 ) ) ); //等待时间到达
  272. SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数器
  273. SysTick->VAL = 0x00; //清空计数器
  274. #endif //end _SYSTEM_SUPPORT_ROTS
  275. #endif //end _USER_OtherDelay
  276. }