hbzjt2011 发表于 2021-1-5 22:25

【东软载波ES32F369x】SysTick实现软定时器进行简单任务调度

本帖最后由 hbzjt2011 于 2021-1-5 22:28 编辑

#申请原创#          SysTick俗称嘀嗒定时器,是Cortex内核自带的组件,它是一个24位的递减计数器,利用SysTick实现软定时器结合回调任务函数可以实现简单任务调度。本次演示例子中利用两个软定时器实现了LED灯循环亮灭和按键扫描两个任务。首先将软定时器程序源文件soft_timer.c和soft_timer.h加入工程目中的driver文件夹。soft_timer.c

#include "soft_timer.h"

static struct soft_timer* soft_timer_list;

/**
* @briefreset the soft_timer_list.
* @retval None.
*/

void soft_timer_list_reset(void)
{
      soft_timer_list = TIMER_NULL;
}


/**
* @briefadd a timer to the software timer list.
* @paramtimer---------pointer to the timer you want to add.
* @paramcall_back-----the call back function when the timer is over.
* @paramtime_count-----the timer count.
* @retval None.
*/


void add_timer(struct soft_timer* timer,void(*call_back)(void),unsigned int time_count)
{
      struct soft_timer* p;

      p = soft_timer_list;

      if(p==TIMER_NULL)                              //if the soft_timer_list have no timer
      {
                p = timer;
                p->flag = TIMER_FLAG_SUSPEND;
                p->tick_count = time_count;
                p->time_over_proc = call_back;
                p->next = TIMER_NULL;
                soft_timer_list = p;

      }
      else
      {
                p = soft_timer_list;
                while(p->next!=TIMER_NULL)
                {
                        p = p->next;
                }
                p->next = timer;
                p->next->flag = TIMER_FLAG_SUSPEND;
                p->next->tick_count = time_count;
                p->next->time_over_proc = call_back;
                p->next->next = TIMER_NULL;
      }
      



}


/**
* @briefremove a timer from the software timer list.
* @retval None.
*/
void remove_timer(struct soft_timer* timer)
{
      struct soft_timer* t;
      for(t = soft_timer_list; t != TIMER_NULL; t = t->next)
      {
                if(t->next==timer)
                {
                        t->next = timer->next;
                        break;
                }
      }
}



/**
* @briefstart or continue a timer   
* @retval None.
*/

void start_timer(struct soft_timer* timer)
{
      timer->flag = TIMER_FLAG_RUN ;
}







/**
* @briefstop a timer without calling back
* @retval None.
*/
void stop_timer(struct soft_timer* timer)
{
      timer->flag = TIMER_FLAG_STOP;
      timer->tick_count = 0;
}



/**
* @briefstop a timer with calling back
* @retval None.
*/

void stop_timer_with_call(struct soft_timer* timer)
{
      if(timer->flag == TIMER_FLAG_RUN)
                timer->tick_count = 0;
      else if(timer->flag == TIMER_FLAG_SUSPEND)
      {
                timer->flag = TIMER_FLAG_RUN;
                timer->tick_count = 0;
      }
}



/**
* @briefsuspend a timer
* @retval None.
*/
void suspend_timer(struct soft_timer* timer)
{
      if(timer->flag == TIMER_FLAG_RUN)
                timer->flag = TIMER_FLAG_SUSPEND;
}


/**
* @briefreload the tick_count for a timer
* @retval None.
*/
void reload_timer(struct soft_timer* timer,unsigned int time_count)
{
      timer->flag = TIMER_FLAG_SUSPEND;
      timer->tick_count = time_count;
}



/**
* @briefshoulde be called periodicly by the hardware timer ISR
* @retval None.
*/
void timer_periodic_refresh(void)
{

      struct soft_timer* t;

      for(t = soft_timer_list; t != TIMER_NULL; t = t->next)
      {
                if(t->flag==TIMER_FLAG_RUN)
                {
                        if(t->tick_count > 0)
                              -- t->tick_count;
                        else
                        {
                              stop_timer(t);
                              t->time_over_proc();
                        }
                }
      }
      
}
soft_timer.h

#ifndef __SOFT_TIMER_H__
#define __SOFT_TIMER_H__


struct soft_timer{
      int flag;                                                      //run flag, which can be SUSPEND,RUN,STOP
      unsigned int tick_count;                        //left ticks to be run
      void (*time_over_proc)(void);                //timer over callback function
      struct soft_timer* next;
};

#define TIMER_FLAG_SUSPEND                0
#define TIMER_FLAG_RUN                        1
#define TIMER_FLAG_STOP                        2

#define TIMER_NULL                ((struct soft_timer*)0)


void soft_timer_list_reset(void);
void add_timer(struct soft_timer* timer,void(*call_back)(void),unsigned int time_count);
void remove_timer(struct soft_timer* timer);
void start_timer(struct soft_timer* timer);
void stop_timer(struct soft_timer* timer);
void stop_timer_with_call(struct soft_timer* timer);
void suspend_timer(struct soft_timer* timer);
void reload_timer(struct soft_timer* timer,unsigned int time_count);
void timer_periodic_refresh(void);



#endif /*__SOFT_TIMER_H__*/然后在main.c程序中配置Systick的周期和中断优先级:
void hw_timer_init(void)
{
      ald_systick_interval_select(SYSTICK_INTERVAL_10MS);                //10 ms
      NVIC_SetPriority (SysTick_IRQn, 1);                              //NVIC config
}同时再irq.c文件中的系统嘀嗒定时器中断处理函数中添加软定时器刷新函数:
void SysTick_Handler(void)
{
      ald_inc_tick();
      timer_periodic_refresh();
      return;
}
然后再程序运行开始后初始化定时器,同时复位定时器列表,添加软定时器1和软定时器2,同时在定时器1回调函数中添加按键扫描处理函数,在定时器2回调函数中添加LED灯处理函数,编译下载即可实现两个定时器任务循环调度运行。时间片可以通过定时器创建时设定。工程文件目录如下:

key.c
#include "main.h"
//////////////////////////////////////////////////////////////////////////////////         
//开发板
//按键输入 驱动代码                  
//////////////////////////////////////////////////////////////////////////////////         

//按键初始化函数
void KEY_Init(void)
{
   
      gpio_init_t x;

      x.mode = GPIO_MODE_INPUT;
      x.odos = GPIO_PUSH_PULL;
      x.pupd = GPIO_FLOATING;
      x.podrv = GPIO_OUT_DRIVE_6;
      x.nodrv = GPIO_OUT_DRIVE_6;
      x.flt= GPIO_FILTER_DISABLE;
      x.type = GPIO_TYPE_CMOS;
      x.func = GPIO_FUNC_1;

      ald_gpio_init(BSP_KEY1_PORT, BSP_KEY1_PIN, &x);
      ald_gpio_init(BSP_KEY2_PORT, BSP_KEY2_PIN, &x);
      ald_gpio_init(BSP_KEY3_PORT, BSP_KEY3_PIN, &x);
      ald_gpio_init(BSP_KEY4_PORT, BSP_KEY4_PIN, &x);
      ald_gpio_init(BSP_KEY5_PORT, BSP_KEY5_PIN, &x);
   
}
//按键处理函数
//返回按键值
//mode:0,不支持连续按;1,支持连续按;
//返回值:
//0,没有任何按键按下
//KEY1_PRES,KEY1按下
//WKUP_PRES,WK_UP按下
//KEY3_PRES,KEY3按下
//KEY4_PRES,KEY4按下
uint8_t KEY_Scan(uint8_t mode)
{         
    static uint8_t key_up=1;//按键按松开标志
    if(mode)key_up=1;//支持连按                  
    if(key_up&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0||KEY5==0))
    {
      //delay_ms(10);//去抖动
      key_up=0;
      if(KEY1==0)return KEY1_PRES;
      else if(KEY2==0)return KEY2_PRES;
      else if(KEY3==0)return KEY3_PRES;
      else if(KEY4==0)return KEY4_PRES;
                        else if(KEY5==0)return KEY5_PRES;
    }else if(KEY1==1&&KEY3==1&&KEY4==1&&KEY2==1&&KEY5==1)key_up=1;            
    return 0;// 无按键按下
}
key.h

#ifndef __KEY_H
#define __KEY_H         

//////////////////////////////////////////////////////////////////////////////////         
//开发板
//按键驱动代码         
//////////////////////////////////////////////////////////////////////////////////            

/* KEY1 ---> UP
* KEY2 ---> DOWN
* KEY3 ---> MID
* KEY4 ---> LEFT
* KEY5 ---> RIGHT
*/
#define BSP_KEY_MAX      5
#define BSP_KEY1_PORT      GPIOB
#define BSP_KEY1_PIN      GPIO_PIN_2
#define BSP_KEY2_PORT      GPIOB
#define BSP_KEY2_PIN      GPIO_PIN_12
#define BSP_KEY3_PORT      GPIOC
#define BSP_KEY3_PIN      GPIO_PIN_10
#define BSP_KEY4_PORT      GPIOC
#define BSP_KEY4_PIN      GPIO_PIN_11
#define BSP_KEY5_PORT      GPIOC
#define BSP_KEY5_PIN      GPIO_PIN_12

#define KEY1ald_gpio_read_pin(BSP_KEY1_PORT, BSP_KEY1_PIN)//读取按键1
#define KEY2ald_gpio_read_pin(BSP_KEY2_PORT, BSP_KEY2_PIN)//读取按键2
#define KEY3ald_gpio_read_pin(BSP_KEY3_PORT, BSP_KEY3_PIN)//读取按键3
#define KEY4ald_gpio_read_pin(BSP_KEY4_PORT, BSP_KEY4_PIN)//读取按键4
#define KEY5ald_gpio_read_pin(BSP_KEY5_PORT, BSP_KEY5_PIN)//读取按键5

#define KEY1_PRES      1                //KEY1
#define KEY2_PRES      2                //KEY2
#define KEY3_PRES      3                //KEY3
#define KEY4_PRES      4                //KEY4
#define KEY5_PRES      5                //KEY5

void KEY_Init(void);//IO初始化
uint8_t KEY_Scan(uint8_t mode);          //按键扫描函数      

#endif
main.c
#include "main.h"


/** @addtogroup Projects_Templates_ALD
* @{
*/

/** @addtogroup Templates
* @{
*/
extern uart_handle_t h_uart;
uint8_t tx_buf;

uint8_t count = 0;

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

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

void hw_timer_init(void)
{
      ald_systick_interval_select(SYSTICK_INTERVAL_10MS);                //10 ms
      NVIC_SetPriority (SysTick_IRQn, 1);                              //NVIC config
}

//按键扫描函数
void KeyScan(void)
{      
      uint8_tt;
      t=KEY_Scan(0);                  //得到键值
      switch(t)
      {                                 
                case KEY1_PRES:
                        sprintf((char *)tx_buf, "KEY1 Clicked!\n");
                        ald_uart_send(&h_uart, tx_buf, sizeof("KEY1 Clicked!\n"), 1000);                        
                        break;
                case KEY2_PRES:
                        sprintf((char *)tx_buf, "KEY2 Clicked!\n");
                        ald_uart_send(&h_uart, tx_buf, sizeof("KEY2 Clicked!\n"), 1000);                        
                        break;
                case KEY3_PRES:                              
                        sprintf((char *)tx_buf, "KEY3 Clicked!\n");
                        ald_uart_send(&h_uart, tx_buf, sizeof("KEY3 Clicked!\n"), 1000);                        
                        break;
                case KEY4_PRES:                              
                        sprintf((char *)tx_buf, "KEY4 Clicked!\n");
                        ald_uart_send(&h_uart, tx_buf, sizeof("KEY4 Clicked!\n"), 1000);                        
                        break;
                case KEY5_PRES:                              
                        sprintf((char *)tx_buf, "KEY5 Clicked!\n");
                        ald_uart_send(&h_uart, tx_buf, sizeof("KEY5 Clicked!\n"), 1000);                        
                        break;
                default:
                        break;      
      }
}

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

      //按键扫描
      KeyScan();
}

void timer2_call_back(void)
{
      reload_timer(&test_timer2,30);               
      start_timer(&test_timer2);
      
      count++;
      if(count==1)
      {
                ald_gpio_write_pin(LED1_PORT, LED1_PIN, 0);
                ald_gpio_write_pin(LED2_PORT, LED2_PIN, 1);   
      }else if(count==2)
      {
                count = 0;
                ald_gpio_write_pin(LED1_PORT, LED1_PIN, 1);
                ald_gpio_write_pin(LED2_PORT, LED2_PIN, 0);      
      }
}

/**
* @briefThis is main function.
*         Detect running time.
* @retval Status
*/
int main()
{
      /* Initialize ALD */
      ald_cmu_init();
      /* Configure system clock */
      ald_cmu_pll1_config(CMU_PLL1_INPUT_HOSC_3, CMU_PLL1_OUTPUT_72M);
      ald_cmu_clock_config(CMU_CLOCK_PLL1, 72000000);
      /* Enable peripheral */
      ald_cmu_perh_clock_config(CMU_PERH_GPIO, ENABLE);
      ald_cmu_perh_clock_config(CMU_PERH_UART0, ENABLE);
      
      /* Initialize tx_buf */
      memset(tx_buf, 0x55, sizeof(tx_buf));

      ///* Initialize uart_usb */
      uart_usb_init();
      
      /* Initialize led */
      led_pin_init();
      
      KEY_Init();                      //初始化与按键连接的硬件接口
      
      hw_timer_init();      
      soft_timer_list_reset();

      add_timer(&test_timer1,timer1_call_back,60);      //
      start_timer(&test_timer1);

      add_timer(&test_timer2,timer2_call_back,30);      //
      start_timer(&test_timer2);

//打印信息
      printf_e("Soft Timer Test Using SysTick\r\n");
      printf_e("1、KeyScan\r\n");
      printf_e("2、LED\r\n");

      while (1) {
#if 0
                /* Send a message */
                sprintf((char *)tx_buf, "es32 uart test!\n");
                ald_uart_send(&h_uart, tx_buf, sizeof("es32 uart test!\n"), 1000);
               
                ald_gpio_write_pin(LED1_PORT, LED1_PIN, 0);
                ald_gpio_write_pin(LED2_PORT, LED2_PIN, 0);
                ald_delay_ms(500);
                ald_gpio_write_pin(LED1_PORT, LED1_PIN, 1);
                ald_gpio_write_pin(LED2_PORT, LED2_PIN, 1);
                ald_delay_ms(500);
#endif
                ald_delay_ms(500);
      }
}程序编译无误下载后,即可看到LED灯循环亮灭,按下开发板上的五向按键串口进行相应的打印输出。


@21小跑堂
页: [1]
查看完整版本: 【东软载波ES32F369x】SysTick实现软定时器进行简单任务调度