收藏官网首页
查看: 19048|回复: 0

【一起来玩RTOS系列】之RT-Thread 空闲任务idle钩子函数

321

主题

1054

帖子

4513

积分

论坛元老

Rank: 8Rank: 8

积分
4513
QQ
跳转到指定楼层
楼主
发表于 2017-11-25 14:57:44 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
注册成为机智云开发者,手机加虚拟设备快速开发
本帖最后由 bigfanofloT 于 2017-11-25 15:09 编辑

有的场景需要查看CPU 的使用率,RT-Thread可以利用空闲线程的钩子函数去统计 CPU 的使用率,官方就提供了这样的例程。通过RT-Thread提供的rt_thread_idle_sethook()函数来设置空闲任务钩子函数,在进入空闲idle线程的时候会自动执行用户设置的钩子函数。

设置空闲线程钩子

可以调用如下的函数,设置空闲线程运行时执行的钩子函数。

  1. void rt_thread_idle_sethook(void (*hook)(void));
复制代码

当空闲线程运行时会自动执行设置的钩子函数,由于空闲线程具有系统的最低优先级,所以只有在空闲的时候才会执行此钩子函数。空闲线程是一个线程状态永远为就绪态的线程,因此设置的钩子函数必须保证空闲线程在任何时刻都不会处于挂起状态,例如rt_thread_delay() , rt_sem_take() 等可能会导致线程挂起的函数都不能使用。

线程安全:不安全

中断例程:不可调用

下面在机智云gokit开发板上验证如何使用idle钩子函数计算cpu使用率,程序中线程2耗时较长,相比其它线程占用了大量cpu时间;

注意:在使用rt_thread_idle_sethook前需要在rtconfig.h中开启宏RT_USING_IDLE_HOOK



  1. /**
  2.   ***********************************
  3.   * File Name          : main.c
  4.   * Description        : Main program body
  5.   ***********************************
  6.   ** This notice applies to any and all portions of this file
  7.   * that are not between comment pairs USER CODE BEGIN and
  8.   * USER CODE END. Other portions of this file, whether
  9.   * inserted by the user or by software development tools
  10.   * are owned by their respective copyright owners.
  11.   *
  12.   * COPYRIGHT(c) 2017 STMicroelectronics
  13.   *
  14.   * Redistribution and use in source and binary forms, with or without modification,
  15.   * are permitted provided that the following conditions are met:
  16.   *   1. Redistributions of source code must retain the above copyright notice,
  17.   *      this list of conditions and the following disclaimer.
  18.   *   2. Redistributions in binary form must reproduce the above copyright notice,
  19.   *      this list of conditions and the following disclaimer in the documentation
  20.   *      and/or other materials provided with the distribution.
  21.   *   3. Neither the name of STMicroelectronics nor the names of its contributors
  22.   *      may be used to endorse or promote products derived from this software
  23.   *      without specific prior written permission.
  24.   *
  25.   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  26.   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  28.   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  29.   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  31.   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  32.   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  33.   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  34.   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  35.   *
  36.   ***********************************
  37.   */
  38. /* Includes ------------------------------------------------------------------*/
  39. #include "main.h"
  40. #include "STM32f1xx_hal.h"
  41. #include "usart.h"
  42. #include "gpio.h"

  43. /* USER CODE BEGIN Includes */
  44. #include "rtthread.h"
  45. #include "string.h"
  46. /* USER CODE END Includes */

  47. /* Private variables ---------------------------------------------------------*/

  48. /* USER CODE BEGIN PV */
  49. /* Private variables ---------------------------------------------------------*/

  50. /* USER CODE END PV */

  51. /* Private function prototypes -----------------------------------------------*/
  52. void SystemClock_Config(void);

  53. /* USER CODE BEGIN PFP */
  54. /* Private function prototypes -----------------------------------------------*/

  55. /* USER CODE END PFP */

  56. /* USER CODE BEGIN 0 */
  57. //重映射串口1到rt_kprintf
  58. void rt_hw_console_output(const char *str)
  59. {
  60.     /* empty console output */
  61.         char aa='\r';
  62.           rt_enter_critical();

  63.                 while(*str!='\0')
  64.                 {
  65.                         if(*str=='\n')
  66.                         {
  67.                                 HAL_UART_Transmit(&huart1, (uint8_t *)&aa, 1, 10);
  68.                         }
  69.                                 HAL_UART_Transmit(&huart1, (uint8_t *)(str++), 1, 10);
  70.                 }
  71.                
  72.                 rt_exit_critical();
  73. }

  74. void rt_hw_us_delay(int us)
  75. {
  76.     rt_uint32_t delta;

  77.     /* 获得延时经过的tick数 */
  78.     us = us * (SysTick->LOAD/(1000000/RT_TICK_PER_SECOND));

  79.     /* 获得当前时间 */
  80.     delta = SysTick->VAL;

  81.     /* 循环获得当前时间,直到达到指定的时间后退出循环 */
  82.     while (delta - SysTick->VAL< us);
  83. }

  84. void rt_hw_ms_delay(int ms)
  85. {
  86.         int i=0,j=0;
  87. for(j=0;j<ms;j++)
  88.         {
  89.         for (i=0;i<2;i++)
  90.         rt_hw_us_delay(500);
  91.         }
  92. }



  93. #define CPU_USAGE_CALC_TICK        10
  94. #define CPU_USAGE_LOOP                  100

  95. static rt_uint8_t  cpu_usage_major = 0, cpu_usage_minor= 0;
  96. static rt_uint32_t total_count = 0;

  97. static void cpu_usage_idle_hook(void)
  98. {
  99.     rt_tick_t tick;
  100.     rt_uint32_t count;
  101.     volatile rt_uint32_t loop;

  102.     if (total_count == 0)
  103.     {
  104.         rt_enter_critical();
  105.                         
  106.                 /* get total count */
  107.         tick = rt_tick_get();
  108.         while(rt_tick_get() - tick < CPU_USAGE_CALC_TICK)
  109.         {
  110.             total_count ++;
  111.             loop = 0;

  112.             while (loop < CPU_USAGE_LOOP) loop ++;
  113.         }
  114.                                 
  115.         rt_exit_critical();
  116.     }

  117.     count = 0;
  118.     /* get CPU usage */
  119.     tick = rt_tick_get();
  120.         
  121.     while (rt_tick_get() - tick < CPU_USAGE_CALC_TICK)
  122.     {
  123.         count ++;
  124.         loop  = 0;
  125.         while (loop < CPU_USAGE_LOOP) loop ++;
  126.     }

  127.     /* calculate major and minor */
  128.     if (count < total_count)
  129.     {
  130.         count = total_count - count;
  131.         cpu_usage_major = (count * 100) / total_count;
  132.         cpu_usage_minor = ((count * 100) % total_count) * 100 / total_count;
  133.                         
  134.     }
  135.     else
  136.     {
  137.         total_count = count;

  138.         /* no CPU usage */
  139.         cpu_usage_major = 0;
  140.         cpu_usage_minor = 0;
  141.     }
  142. }

  143. void cpu_usage_get(rt_uint8_t *major, rt_uint8_t *minor)
  144. {
  145.     RT_ASSERT(major != RT_NULL);
  146.     RT_ASSERT(minor != RT_NULL);

  147.     *major = cpu_usage_major;
  148.     *minor = cpu_usage_minor;
  149. }
  150. /*
  151. * 程序清单:通过rt_thread_yield函数线程让出处理器
  152. * 创建两个相同优先级的线程, 它们会通过rt_thread_yield
  153. * 接口把处理器相互让给对方进行执行。
  154. */
  155. /* 指向线程控制块的指针 */
  156. static rt_thread_t tid1 = RT_NULL;
  157. static rt_thread_t tid2 = RT_NULL;
  158. static rt_thread_t tid3 = RT_NULL;
  159. static rt_thread_t tid4 = RT_NULL;
  160. static rt_thread_t tid5 = RT_NULL;

  161. /* 线程1入口 */
  162. static void thread1_entry(void* parameter)
  163. {   
  164.     while (1)
  165.     {
  166.                         //rt_kprintf("thread1 running!\r\n");        
  167.                         LED1_ON();
  168.                         rt_thread_delay(50);
  169.                         LED1_OFF();
  170.                         rt_thread_delay(950);               
  171.     }
  172. }

  173. /* 线程2入口 */
  174. static void thread2_entry(void* parameter)
  175. {
  176.     while (1)
  177.     {
  178.                         rt_kprintf("thread2 running!\r\n");
  179.                         LED2_Toggle();
  180.                         rt_hw_ms_delay(1000);
  181.                         rt_thread_delay(200);
  182.     }
  183. }

  184. /* 线程3入口 */
  185. static void thread3_entry(void* parameter)
  186. {
  187.     while (1)
  188.     {
  189.                         //rt_kprintf("thread3 running!\r\n");
  190.                         LED3_Toggle();
  191.                         rt_thread_delay(500);
  192.     }
  193. }
  194. /* 线程4入口 */
  195. static void thread4_entry(void* parameter)
  196. {
  197.     while (1)
  198.     {
  199.                         //rt_kprintf("thread4 running!\r\n");
  200.                         LED4_Toggle();
  201.                         rt_thread_delay(1000);
  202.     }
  203. }
  204. /* 线程5入口 */
  205. static void thread5_entry(void* parameter)
  206. {
  207.         rt_uint8_t major, minor;
  208.         while (1)
  209.         {
  210.                 cpu_usage_get(&major, &minor);

  211.                 /*打印CPU占用率*/
  212.                 rt_kprintf("major %d%%\r\n",major);
  213.                
  214.                 /*打印CPU空闲率*/
  215.                 rt_kprintf("minor %d%%\r\n",minor);
  216.                
  217.                 rt_thread_delay(200);
  218.         }
  219. }

  220. /* USER CODE END 0 */

  221. int main(void)
  222. {

  223.   /* USER CODE BEGIN 1 */

  224.   /* USER CODE END 1 */

  225.   /* MCU Configuration----------------------------------------------------------*/

  226. //  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  227. //  HAL_Init();

  228. //  /* USER CODE BEGIN Init */

  229. //  /* USER CODE END Init */

  230. //  /* Configure the system clock */
  231. //  SystemClock_Config();

  232. //  /* USER CODE BEGIN SysInit */

  233. //  /* USER CODE END SysInit */

  234. //  /* Initialize all configured peripherals */
  235. //  MX_GPIO_Init();
  236. //  MX_USART1_UART_Init();

  237.   /* USER CODE BEGIN 2 */
  238.         
  239.          /* set idle thread hook */
  240.    rt_thread_idle_sethook(cpu_usage_idle_hook);
  241.         
  242.     /* 创建线程1 */
  243.     tid1 = rt_thread_create("led1",
  244.                                                         thread1_entry,
  245.                                                         RT_NULL,
  246.                                                         512,
  247.                                                         3,
  248.                                                         20);
  249.         if (tid1 != RT_NULL)
  250.                 rt_thread_startup(tid1);
  251.         
  252.         /* 创建线程2 */
  253.         tid2 = rt_thread_create("led2",
  254.                                                         thread2_entry,
  255.                                                         RT_NULL,
  256.                                                         512,
  257.                                                         3,
  258.                                                         20);

  259.         if (tid2 != RT_NULL)
  260.                 rt_thread_startup(tid2);
  261.         
  262.         /* 创建线程3 */
  263.         tid3 = rt_thread_create("led3",
  264.                                                         thread3_entry,
  265.                                                         RT_NULL,
  266.                                                         512,
  267.                                                         3,
  268.                                                         20);

  269.         if (tid3 != RT_NULL)
  270.                 rt_thread_startup(tid3);
  271.         
  272.         /* 创建线程4 */
  273.         tid4 = rt_thread_create("led4",
  274.                                                         thread4_entry,
  275.                                                         RT_NULL,
  276.                                                         512,
  277.                                                         3,
  278.                                                         20);

  279.         if (tid4 != RT_NULL)
  280.                 rt_thread_startup(tid4);
  281.         
  282.         /* 创建线程5 */
  283.         tid5 = rt_thread_create("t5",
  284.                                                         thread5_entry,
  285.                                                         RT_NULL,
  286.                                                         512,
  287.                                                         3,
  288.                                                         20);

  289.         if (tid5 != RT_NULL)
  290.                 rt_thread_startup(tid5);
  291.         
  292.         
  293.         printf("\r\n机智云  只为智能硬件而生\r\n");
  294.         printf("Gizwits Smart Cloud for Smart Products\r\n");
  295.         printf("链接|增值|开放|中立|安全|自有|自由|生态\r\n");
  296.         printf("www.gizwits.com\r\n");
  297.         printf("\r\nGokit RT-Thread Demo\r\n\r\n");
  298.         
  299.         return 0;
  300.         
  301.         


  302.   /* USER CODE END 2 */

  303.   /* Infinite loop */
  304.   /* USER CODE BEGIN WHILE */
  305. //  while (1)
  306. //  {
  307.   /* USER CODE END WHILE */

  308.   /* USER CODE BEGIN 3 */
  309. //               
  310. //  }
  311.   /* USER CODE END 3 */

  312. }

  313. /** System Clock Configuration
  314. */
  315. void SystemClock_Config(void)
  316. {

  317.   RCC_OscInitTypeDef RCC_OscInitStruct;
  318.   RCC_ClkInitTypeDef RCC_ClkInitStruct;

  319.     /**Initializes the CPU, AHB and APB busses clocks
  320.     */
  321.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  322.   RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  323.   RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  324.   RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  325.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  326.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  327.   RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  328.   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  329.   {
  330.     _Error_Handler(__FILE__, __LINE__);
  331.   }

  332.     /**Initializes the CPU, AHB and APB busses clocks
  333.     */
  334.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  335.                               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  336.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  337.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  338.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  339.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  340.   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  341.   {
  342.     _Error_Handler(__FILE__, __LINE__);
  343.   }

  344.     /**Configure the Systick interrupt time
  345.     */
  346.   HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

  347.     /**Configure the Systick
  348.     */
  349.   HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  350.   /* SysTick_IRQn interrupt configuration */
  351.   HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
  352. }

  353. /* USER CODE BEGIN 4 */

  354. /* USER CODE END 4 */

  355. /**
  356.   * @brief  This function is executed in case of error occurrence.
  357.   * @param  None
  358.   * @retval None
  359.   */
  360. void _Error_Handler(char * file, int line)
  361. {
  362.   /* USER CODE BEGIN Error_Handler_Debug */
  363.   /* User can add his own implementation to report the HAL error return state */
  364.   while(1)
  365.   {
  366.   }
  367.   /* USER CODE END Error_Handler_Debug */
  368. }

  369. #ifdef USE_FULL_ASSERT

  370. /**
  371.    * @brief Reports the name of the source file and the source line number
  372.    * where the assert_param error has occurred.
  373.    * @param file: pointer to the source file name
  374.    * @param line: assert_param error line source number
  375.    * @retval None
  376.    */
  377. void assert_failed(uint8_t* file, uint32_t line)
  378. {
  379.   /* USER CODE BEGIN 6 */
  380.   /* User can add his own implementation to report the file name and line number,
  381.     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  382.   /* USER CODE END 6 */

  383. }

  384. #endif

  385. /**
  386.   * @}
  387.   */

  388. /**
  389.   * @}
  390. */

  391. /*********** (C) COPYRIGHT STMicroelectronics ***END OF FILE**/
复制代码

通过串口打印信息可以看到cpu使用率cpu_usage_major和空闲率cpu_usage_minor:

  1. \ | /
  2. - RT -     Thread Operating System
  3. / | \     2.1.0 build Nov 25 2017
  4. 2006 - 2017 Copyright by rt-thread team

  5. 机智云  只为智能硬件而生
  6. Gizwits Smart Cloud for Smart Products
  7. 链接|增值|开放|中立|安全|自有|自由|生态
  8. www.gizwits.com

  9. Gokit RT-Thread Demo

  10. thread2 running!
  11. major 0%
  12. minor 0%
  13. major 0%
  14. minor 0%
  15. major 0%
  16. minor 0%
  17. major 0%
  18. minor 0%
  19. thread2 running!
  20. major 6%
  21. minor 30%
  22. major 6%
  23. minor 30%
  24. major 6%
  25. minor 30%
  26. major 6%
  27. minor 30%
  28. major 6%
  29. minor 30%
  30. thread2 running!
  31. major 6%
  32. minor 30%
  33. major 6%
  34. minor 30%
  35. major 6%
  36. minor 30%
  37. thread2 running!
  38. major 6%
  39. minor 30%
  40. major 6%
  41. minor 30%
  42. major 6%
  43. minor 30%
  44. major 6%
  45. minor 30%
  46. major 6%
  47. minor 30%
  48. thread2 running!
  49. major 6%
  50. minor 30%
  51. major 6%
  52. minor 30%
  53. major 6%
  54. minor 30%
  55. thread2 running!
  56. major 6%
  57. minor 30%
  58. major 6%
  59. minor 30%
  60. major 6%
  61. minor 30%
  62. major 6%
  63. minor 30%
  64. major 6%
  65. minor 30%
  66. thread2 running!
  67. major 6%
  68. minor 30%
  69. major 6%
  70. minor 30%
  71. major 6%
  72. minor 30%
  73. major 6%
  74. minor 30%
  75. thread2 running!
  76. major 27%
  77. minor 46%
  78. major 27%
  79. minor 46%
  80. major 27%
  81. minor 46%
  82. major 6%
  83. minor 22%
  84. thread2 running!
  85. major 6%
  86. minor 22%
  87. major 6%
  88. minor 22%
  89. major 6%
  90. minor 22%
  91. major 6%
  92. minor 30%
  93. thread2 running!
  94. major 27%
  95. minor 30%
  96. major 27%
  97. minor 30%
  98. major 27%
  99. minor 30%
  100. major 6%
  101. minor 22%
  102. thread2 running!
  103. major 6%
  104. minor 22%
  105. major 6%
  106. minor 22%
  107. major 6%
  108. minor 22%
  109. major 6%
  110. minor 30%
  111. thread2 running!
  112. major 27%
  113. minor 30%
复制代码

源码下载:


Gokit_RT-Thread.zip (8.71 MB, 下载次数: 18, 售价: 1 金钱)



1、机智云QQ群:G1群:104975951 G2群:491509598 G3群:287087942
机智云爱好者-APP开发群: 599735135
QQ群目前非常活跃,欢迎大家参与进来,交流,讨论,答疑,解惑~~
2、机智云微信公众号: 机智云 gizwits、 机智云智能宠物屋go-iot
关注机智云Gizwits官方公众号随时掌握最新资讯和活动信息
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

加入Q群 返回顶部

版权与免责声明 © 2006-2024 Gizwits IoT Technology Co., Ltd. ( 粤ICP备11090211号 )

快速回复 返回顶部 返回列表