分享一个us计数器,可测试代码运行时长

2019-12-11 18:29发布

本帖最后由 yanyanyan168 于 2019-4-29 20:08 编辑

        从 KEIL MDK 的 Event Recorder 摘出SysTick配置,改成微秒计数器与微秒延时,可以用在M0/M0+/M3/M4等内核MCU上。
应用场景,测试某段代码的运行时长,精确微秒延时。 代码如下,献丑了

  1. typedef struct
  2. {
  3. uint32_t (*init)(void);
  4.   void     (*set)(uint8_t id);        // 设置当前值
  5.   uint32_t (*get)(uint8_t id);        // 获取与上次的差值       
  6.   void            (*Delay)(uint32_t nus);
  7. }
  8. US_DIFF_TypeDef;


  9. /* SysTick period in cycles */
  10. #ifndef SYSTICK_PERIOD
  11. #define SYSTICK_PERIOD  0x01000000U
  12. #endif

  13. /* SysTick variables */
  14. static volatile uint32_t SysTickCount;
  15. static volatile uint8_t  SysTickUpdated;

  16. /* SysTick IRQ handler */
  17. void SysTick_Handler (void) {
  18.   SysTickCount  += SYSTICK_PERIOD;
  19.   SysTickUpdated = 1U;
  20. }

  21. /* Setup SysTick */
  22. uint32_t SysTickSetup (void) {
  23.   SysTickCount  = 0U;
  24.   SysTick->LOAD = SYSTICK_PERIOD - 1U;
  25.   SysTick->VAL  = 0U;
  26.   SysTick->CTRL = SysTick_CTRL_ENABLE_Msk     |
  27.                   SysTick_CTRL_TICKINT_Msk    |
  28.                   SysTick_CTRL_CLKSOURCE_Msk;
  29.   return 1U;
  30. }


  31. /* Get SysTick count */
  32. __STATIC_INLINE uint32_t SysTickGetCount (void) {
  33.   uint32_t val;

  34.   do {
  35.     SysTickUpdated = 0U;
  36.     val  = SysTickCount;
  37.     val += (SYSTICK_PERIOD - 1U) - SysTick->VAL;
  38.   } while (SysTickUpdated != 0U);

  39.   return (val);
  40. }

  41. #define TIMER_NUM_MAX  10             // 计数器最多可支持9个, 最后一个做延时用
  42. static uint32_t us_count[TIMER_NUM_MAX];  

  43. /// 设置计数值初值
  44. void set_current_count(uint8_t id)
  45. {
  46. //        my_assert_param(id < TIMER_NUM_MAX);
  47.     us_count[id]        = SysTickGetCount();
  48. }


  49. // 获取与上一次的差值 返回的是时钟周期数,,转换成微秒需要除以(SystemCoreClock/1000000)
  50. uint32_t get_us_difference(uint8_t id)
  51. {
  52.         volatile uint32_t now_tim ;
  53. //        my_assert_param(id < TIMER_NUM_MAX);
  54.         now_tim = SysTickGetCount();
  55.         now_tim -= us_count[id];

  56.         return now_tim;
  57. }

  58. // 微秒延时
  59. static void usDelay(uint32_t nus)
  60. {
  61.         nus *= (SystemCoreClock/1000000);
  62.         set_current_count(TIMER_NUM_MAX-1);
  63.         volatile uint32_t now_tim ;
  64.         do
  65.         {
  66.                 now_tim = get_us_difference(TIMER_NUM_MAX-1);
  67.         }while(now_tim < nus);
  68. }

  69. US_DIFF_TypeDef usDiff =
  70. {
  71.         SysTickSetup,
  72.         set_current_count,
  73.         get_us_difference,
  74.         usDelay
  75. };

复制代码


应该方法:

  1. uint32_t us_code_tim; // 代码运行时钟周期数,转换成微秒需要除以(SystemCoreClock/1000000)

  2. int32_t main(void)
  3. {
  4.         /* 其它外设初始化   */
  5.         usDiff.init();
  6.         for(;;)
  7.         {
  8.                 usDiff.set(0);
  9.                
  10.                 /* 要测试的代码 */
  11.                
  12.                 us_code_tim = usDiff.get(0);
  13.                
  14.                 usDiff.Delay(200); // 延时200us
  15.         }
  16. }

  17. uint32_t us_tim3; // TIM3中断间隔时钟周期数,,转换成微秒需要除以(SystemCoreClock/1000000)

  18. void TIM3_IRQHandler(void)
  19. {
  20.     /* 其它代码 */
  21.         us_tim3 = usDiff.get(1); // 第一次不准
  22.         usDiff.set(1);
  23. }
复制代码
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
10条回答
njhying
1楼-- · 2019-12-11 22:00
还是使用io引脚测量时间,简单可靠。我的信念:尽量避免一切导致复杂的东西,除了jscope  rtt。
1a2b3c
2楼-- · 2019-12-12 03:31
 精彩回答 2  元偷偷看……
Excellence
3楼-- · 2019-12-12 07:17
谢谢分享。。。。。。。
honami520
4楼-- · 2019-12-12 11:51
这是弄了一个1us的定时器吗?还要进中断,这也太频繁了吧。不如搞个定时器1us计数。然后用查询模式,在一个需要测量的函数或者代码段,的前后都读一下。基本就知道时间了。测量10us级别的也够了。
落叶知秋
5楼-- · 2019-12-12 16:42
来来来,同款功能的另一种实现
https://www.amobbs.com/thread-5665490-1-1.html
wzd5230
6楼-- · 2019-12-12 19:31
直接开一个timer,32位最好。运行之前读一下,运行之后读一下。差值就是时间。

一周热门 更多>