[MM32硬件] 【MM32 eMiniBoard测评报告】SysTick实现软定时器进行线程调度

[复制链接]
 楼主| hbzjt2011 发表于 2020-5-3 21:45 | 显示全部楼层 |阅读模式
       在平时我们针对裸机进行开发不使用RTOS的时候,有时候需要使用到简单的线程调度,如果使用硬件定时器实现的话,可能会受到硬件本身定时器资源的限制,这时候我们可以使用SysTick实现软件定时器。
        软件定时器是用程序模拟出来的定时器,可以由一个硬件定时器模拟出成千上万个软件定时器,这样程序在需要使用较多定时器的时候就不会受限于硬件资源的不足,这是软件定时器的一个优点,即数量不受限制。
        SysTick俗称嘀嗒定时器,是Cortex内核自带的组件,它是一个24位的递减计数器,用户仅需掌握ARM的CMSIS软件提供的一个函数SysTick_Config即可,原代码如下:
  1. /* ##################################    SysTick function  ############################################ */
  2. /** \ingroup  CMSIS_Core_FunctionInterface
  3.     \defgroup CMSIS_Core_SysTickFunctions SysTick Functions
  4.     \brief      Functions that configure the System.
  5.   @{
  6. */

  7. #if (__Vendor_SysTickConfig == 0)

  8. /** \brief  System Tick Configuration

  9.     The function initializes the System Timer and its interrupt, and starts the System Tick Timer.
  10.     Counter is in free running mode to generate periodic interrupts.

  11.     \param [in]  ticks  Number of ticks between two interrupts.

  12.     \return          0  Function succeeded.
  13.     \return          1  Function failed.

  14.     \note     When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the
  15.     function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>
  16.     must contain a vendor-specific implementation of this function.

  17. */
  18. __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
  19. {
  20.   if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk)  return (1);      /* Reload value impossible */

  21.   SysTick->LOAD  = ticks - 1;                                  /* set reload register */
  22.   NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Systick Interrupt */
  23.   SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */
  24.   SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
  25.                    SysTick_CTRL_TICKINT_Msk   |
  26.                    SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */
  27.   return (0);                                                  /* Function successful */
  28. }
函数的形参表示内核时钟多少个周期后触发一次Systick定时中断,比如形参配置为如下数值。
-- SystemCoreClock / 1000  表示定时频率为 1000Hz, 也就是定时周期为  1ms。
-- SystemCoreClock / 500   表示定时频率为 500Hz,  也就是定时周期为  2ms。
-- SystemCoreClock / 2000  表示定时频率为 2000Hz, 也就是定时周期为  500us。

          本次实验中使用软定时器实现了两个线程调度函数,其中第一个线程实现了按键扫描的功能,第二个线程实现了板载LED流水灯的功能,main函数如下:
  1. #include "delay.h"
  2. #include "sys.h"
  3. #include "led.h"
  4. #include "key.h"
  5. #include "uart.h"
  6. #include "soft_timer.h"


  7. //变量定义
  8. uint8_t count = 0;
  9. extern u32 SystemCoreClock;

  10. struct soft_timer test_timer1,test_timer2;        //creat 2 soft timers

  11. void timer1_call_back(void);                //call back functions when timer over
  12. void timer2_call_back(void);

  13. void hw_timer_init(void)
  14. {

  15.         SysTick_Config(SystemCoreClock / 100);                                        //10 ms
  16.         NVIC_SetPriority (SysTick_IRQn, 1);                                //NVIC config  

  17. }

  18. //按键扫描函数
  19. void KeyScan(void)
  20. {       
  21.         uint8_t  t;
  22.         t=KEY_Scan(0);                    //得到键值
  23.         switch(t)
  24.         {                                 
  25.         case KEY1_PRES:         //K1默认不连PC13,默认连接reset复位按键,所以按下K1会复位
  26.                         printf("KEY1 Clicked!\r\n");  
  27.                         break;
  28.         case WKUP_PRES:
  29.                         printf("KEY2 Clicked!\r\n");
  30.                         break;
  31.         case KEY3_PRES:                               
  32.                         printf("KEY3 Clicked!\r\n");
  33.                         break;
  34.         case KEY4_PRES:                               
  35.                         printf("KEY4 Clicked!\r\n");
  36.                         break;
  37.         default:
  38.                         break;       
  39.         }
  40. }

  41. void timer1_call_back(void)
  42. {

  43.         reload_timer(&test_timer1,10);                //
  44.         start_timer(&test_timer1);                        //should be restart because of one shot software timer.

  45.         //按键扫描
  46.         KeyScan();
  47. }

  48. void timer2_call_back(void)
  49. {

  50.         reload_timer(&test_timer2,30);               
  51.         start_timer(&test_timer2);

  52.         count++;
  53.         if(count==1)
  54.         {
  55.                 LED1_ON();
  56.                 LED2_OFF();
  57.                 LED3_OFF();
  58.                 LED4_OFF();       
  59.         }else if(count==2)
  60.         {
  61.                 LED1_OFF();
  62.                 LED2_ON();
  63.                 LED3_OFF();
  64.                 LED4_OFF();       
  65.         }else if(count==3)
  66.         {
  67.                 LED1_OFF();
  68.                 LED2_OFF();
  69.                 LED3_ON();
  70.                 LED4_OFF();               
  71.         }else if(count==4)
  72.         {
  73.                 count = 0;
  74.                 LED1_OFF();
  75.                 LED2_OFF();
  76.                 LED3_OFF();
  77.                 LED4_ON();       
  78.         }
  79. }

  80. /********************************************************************************************************
  81. **函数信息 :main(void)                       
  82. **功能描述 :
  83. **输入参数 :无
  84. **输出参数 :无
  85. ********************************************************************************************************/
  86. int main(void)
  87. {
  88.    
  89.     delay_init();       
  90.     LED_Init();                                       //初始化与LED连接的硬件接口
  91.     KEY_Init();                      //初始化与按键连接的硬件接口
  92.         uart_initwBaudRate(9600);        //串口初始化
  93.        
  94.         hw_timer_init();
  95.        
  96.         soft_timer_list_reset();

  97.         add_timer(&test_timer1,timer1_call_back,60);        //
  98.         start_timer(&test_timer1);

  99.         add_timer(&test_timer2,timer2_call_back,30);        //
  100.         start_timer(&test_timer2);

  101.        
  102.         //打印欢迎信息
  103.         printf("Soft Timer Test Using SysTick\r\n");
  104.         printf("1、KeyScan\r\n");
  105.         printf("2、LED\r\n");
  106.                           
  107.     while(1)
  108.     {
  109.                                        
  110.         }
  111. }

该工程中已经将软件定时器编写成了驱动文件,便于移植和使用,主要文件为soft_timer.c和soft_timer.h文件,在Keil工程中添加源文件后的目录如下:
工程目录.png
使用时需要在SysTick中断处理函数中添加软定时器刷新函数:
SysTick.png
接下来使用时进行硬件定时器初始化和中断优先级配置和:
微信截图_20200503214104.png
最后就是软件定时器的创建和回调函数编写:
微信截图_20200503214158.png
本实验最后实现了LED流水灯和按键扫描两个线程的调度:
微信截图_20200503214344.png
本工程完整源码如下:
[payamount]2.00[/payamount]
[pay] MM32L0xx.rar (2.85 MB, 下载次数: 1) [/pay]
kxsi 发表于 2020-6-1 16:34 | 显示全部楼层
非常感谢楼主分享
nawu 发表于 2020-6-1 16:34 | 显示全部楼层
代码很详细
qcliu 发表于 2020-6-1 16:34 | 显示全部楼层
介绍的很清楚
tfqi 发表于 2020-6-1 16:35 | 显示全部楼层
是需要跑系统的吗
wiba 发表于 2020-6-1 16:35 | 显示全部楼层
楼主辛苦了
hello、C 发表于 2020-6-4 13:42 来自手机 | 显示全部楼层
看看什么情况,楼主辛苦了
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:欢迎参与LabVIEW版块的讨论学习! 点我一键即达

256

主题

2827

帖子

44

粉丝
快速回复 在线客服 返回列表 返回顶部
个人签名:欢迎参与LabVIEW版块的讨论学习! 点我一键即达

256

主题

2827

帖子

44

粉丝
快速回复 在线客服 返回列表 返回顶部