打印
[国产单片机]

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

[复制链接]
668|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 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;

/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  reset the soft_timer_list.
  * @retval None.
  */

void soft_timer_list_reset(void)
{
        soft_timer_list = TIMER_NULL;
}


/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  add a timer to the software timer list.
  * @param  timer---------pointer to the timer you want to add.
  * @param  call_back-----the call back function when the timer is over.
  * @param  time_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;
        }
        



}


/**
  * @brief  remove 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;
                }
        }
}



/**
  * @brief  start or continue a timer   
  * @retval None.
  */

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







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



/**
  * @brief  stop 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;
        }
}



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


/**
  * @brief  reload 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;
}



/**
  * @brief  shoulde 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 KEY1  ald_gpio_read_pin(BSP_KEY1_PORT, BSP_KEY1_PIN)//读取按键1
#define KEY2  ald_gpio_read_pin(BSP_KEY2_PORT, BSP_KEY2_PIN)//读取按键2
#define KEY3  ald_gpio_read_pin(BSP_KEY3_PORT, BSP_KEY3_PIN)//读取按键3
#define KEY4  ald_gpio_read_pin(BSP_KEY4_PORT, BSP_KEY4_PIN)//读取按键4
#define KEY5  ald_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[32];

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_t  t;
        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);      
        }
}

/**
  * @brief  This 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小跑堂

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

157

主题

2338

帖子

41

粉丝