当前位置: 首页 > article >正文

基于OSAL的嵌入式裸机事件驱动框架——软件定时器osal_timer


参考B站up主【架构分析】嵌入式祼机事件驱动框架
感谢大佬分享


软件定时器
定时器使用链表将所有定时器连接起来
需要将定时器更新函数osal_timer_update放在Systick中断中
在这里插入图片描述

osal_timer.h

#ifndef OSAL_TIMER_H  
#define OSAL_TIMER_H  
  
#include "osal.h"  
#include "osal_event.h"  
  
typedef struct  
{  
    void *next;                   /* next timer in the list */  
    osal_uint16_t timeout;        /* timeout value in ticks */  
    osal_uint16_t reload;         /* reload value in ticks */  
    event_id_t event_id;          /* event id */  
    task_id_t task_id;            /* task id */  
}osal_timer_t;  
  
/*接口*/  
osal_uint32_t osal_get_systick(void);  
osal_uint8_t osal_timer_startex(task_id_t task_id, event_id_t event_id, osal_uint16_t timeout);  
osal_uint8_t osal_timer_startre(task_id_t task_id, event_id_t event_id, osal_uint16_t timeout);  
osal_uint8_t osal_timer_stopex(task_id_t task_id, event_id_t event_id);  
  
osal_uint8_t osal_timer_num(void);  
osal_uint16_t osal_timer_gettimeoutex(task_id_t task_id, event_id_t event_id);  
  
void osal_timer_update(void);  
  
  
#endif

osal_timer.c

#include "osal.h"  
#include "osal_event.h"  
#include "osal_memory.h"  
#include <string.h>  
  
/*********************************************************************  
 * @fn      osal_init_system * * @brief * *   This function initializes the "task" system by creating the *   tasks defined in the task table (OSAL_Tasks.h). * * @param   void * * @return  ZSUCCESS */osal_uint8_t osal_init_system( void )  
{  
  // Initialize the Memory Allocation System  
#if OSALMEM_METRICS  
  osal_mem_init();  
#endif  
  
  return ( OSAL_SUCCESS );  
}  
  
/*********************************************************************  
 * @fn      osal_start_system * * @brief * *   This function is the main loop function of the task system.  It *   will look through all task events and call the task_event_processor() *   function for the task with the event.  If there are no events (for *   all tasks), this function puts the processor into Sleep. *   This Function doesn't return. * * @param   void * * @return  none *//*可以考虑不加临界区,直接用原子操作,减少开销*/  
void osal_system_start(void)  
{  
    event_asb_t events,ret_events;  
    osal_task_t *task_active;  
  
    while(1)  
    {  
        task_active = osal_task_active();  
        if ( task_active != NULL )  
        {  
            OSAL_ENTER_CRITICAL();  
            events = task_active->events;  
            task_active->events = SYS_EVE_NONE;  
  
  
            if(events != SYS_EVE_NONE)  
            {  
                if(task_active->ops->handler != NULL)  
                {  
  
                    ret_events = task_active->ops->handler(task_active->task_id,events);  
                    OSAL_ENTER_CRITICAL();  
                    task_active->events |= ret_events;  
                    OSAL_EXIT_CRITICAL();  
                }  
            }  
        }  
    }  
}  
  
  
  
  
/*********************************************************************  
 * @fn      osal_strlen * * @brief * *   Calculates the length of a string.  The string must be null *   terminated. * * @param   char *pString - pointer to text string * * @return  int - number of characters */int osal_strlen( char *pString )  
{  
  return (int)( strlen( pString ) );  
}  
  
/*********************************************************************  
 * @fn      osal_memcpy * * @brief * *   Generic memory copy. * *   Note: This function differs from the standard memcpy(), since *         it returns the pointer to the next destination uint8. The *         standard memcpy() returns the original destination address. * * @param   dst - destination address * @param   src - source address * @param   len - number of bytes to copy * * @return  pointer to end of destination buffer */void *osal_memcpy( void *dst, const void *src, unsigned int len )  
{  
  osal_uint8_t *pDst;  
  const osal_uint8_t *pSrc;  
  
  pSrc = src;  
  pDst = dst;  
  
  while ( len-- )  
    *pDst++ = *pSrc++;  
  
  return ( pDst );  
}  
  
/*********************************************************************  
 * @fn      osal_revmemcpy * * @brief   Generic reverse memory copy.  Starts at the end of the *   source buffer, by taking the source address pointer and moving *   pointer ahead "len" bytes, then decrementing the pointer. * *   Note: This function differs from the standard memcpy(), since *         it returns the pointer to the next destination uint8. The *         standard memcpy() returns the original destination address. * * @param   dst - destination address * @param   src - source address * @param   len - number of bytes to copy * * @return  pointer to end of destination buffer */void *osal_revmemcpy( void *dst, const void *src, unsigned int len )  
{  
  osal_uint8_t *pDst;  
  const osal_uint8_t *pSrc;  
  
  pSrc = src;  
  pSrc += (len-1);  
  pDst = dst;  
  
  while ( len-- )  
    *pDst++ = *pSrc--;  
  
  return ( pDst );  
}  
  
/*********************************************************************  
 * @fn      osal_memdup * * @brief   Allocates a buffer [with osal_mem_alloc()] and copies *          the src buffer into the newly allocated space. * * @param   src - source address * @param   len - number of bytes to copy * * @return  pointer to the new allocated buffer, or NULL if *          allocation problem. */void *osal_memdup( const void *src, unsigned int len )  
{  
    osal_uint8_t *pDst;  
  
  pDst = osal_mem_alloc( len );  
  if ( pDst )  
  {  
    osal_memcpy( pDst, src, len );  
  }  
  
  return ( (void *)pDst );  
}  
  
/*********************************************************************  
 * @fn      osal_memcmp * * @brief * *   Generic memory compare. * * @param   src1 - source 1 addrexx * @param   src2 - source 2 address * @param   len - number of bytes to compare * * @return  TRUE - same, FALSE - different */osal_uint8_t osal_memcmp( const void *src1, const void *src2, unsigned int len )  
{  
  const osal_uint8_t *pSrc1;  
  const osal_uint8_t *pSrc2;  
  
  pSrc1 = src1;  
  pSrc2 = src2;  
  
  while ( len-- )  
  {  
    if( *pSrc1++ != *pSrc2++ )  
      return OSAL_ERROR;  
  }  
  return OSAL_SUCCESS;  
}  
  
/*********************************************************************  
 * @fn      osal_memset * * @brief * *   Set memory buffer to value. * * @param   dest - pointer to buffer * @param   value - what to set each uint8 of the message * @param   size - how big * * @return  pointer to destination buffer */void *osal_memset( void *dest, osal_uint8_t value, int len )  
{  
  return memset( dest, value, len );  
}

osal_timer_create

定时器创建
1如果定时器已存在,则更新定时器的timeout
2如果不存在,则创建一个心得定时器并将其插入定时器链表尾部

/*********************************************************************  
 * @fn      osal_timer_create * * @brief   Add a timer to the timer list. *          Ints must be disabled. * * @param   task_id * @param   event_flag * @param   timeout * * @return  osal_timer_t * - pointer to newly created timer */static osal_timer_t *osal_timer_create(task_id_t task_id, event_id_t event_id, osal_uint16_t timeout)  
{  
    osal_timer_t  *timer_new;  
    osal_timer_t  *timer_sech;  
  
    //check if timer already exists, if yes, update timeout  
    timer_new = osal_timer_find(task_id, event_id);  
    if (timer_new!= NULL)  
    {  
        timer_new->timeout = timeout;  
        return timer_new;  
    }else{  
        timer_new = (osal_timer_t *)osal_mem_alloc(sizeof(osal_timer_t));  
        if (timer_new != NULL)  
        {  
            timer_new->task_id = task_id;  
            timer_new->event_id = event_id;  
            timer_new->timeout = timeout;  
            timer_new->next = (void *)NULL;  
            timer_new->reload = 0;  
  
            /* add timer to list  
             * if list is empty, set head to new timer             * else, traverse list to find end of list and add new timer */            if(timer_head == NULL){  
                timer_head = timer_new;  
            }else{  
                timer_sech = timer_head;  
                while(timer_sech->next != NULL)  
                {  
                    timer_sech = timer_sech->next;  
                }  
                timer_sech->next = timer_new;  
            }  
            return timer_new;  
        }  
        else{  
            return NULL;  
        }  
    }  
}

osal_timer_startex

一次性定时器
其reload值为0

/*********************************************************************  
 * @fn      osal_start_timerEx * * @brief * *   This function is called to start a timer to expire in n mSecs. *   When the timer expires, the calling task will get the specified event. * * @param   uint8 taskID - task id to set timer for * @param   uint16 event_id - event to be notified with * @param   UNINT16 timeout_value - in milliseconds. * * @return  OSAL_SUCCESS, or INVALID_TIMER. */osal_uint8_t osal_timer_startex(task_id_t task_id, event_id_t event_id, osal_uint16_t timeout)  
{  
    osal_timer_t  *timer_new;  
  
    OSAL_ENTER_CRITICAL();  
    timer_new = osal_timer_create(task_id, event_id, timeout);  
    OSAL_EXIT_CRITICAL();  
  
    return ((timer_new != NULL) ? OSAL_SUCCESS : INVALID_TIMER);  
}  

osal_timer_startre

可自动重装载定时器
现创建一个一次性定时器,然后将其自动重装载值设为 timeout

/*********************************************************************  
 * @fn      osal_start_reload_timer * * @brief * *   This function is called to start a timer to expire in n mSecs. *   When the timer expires, the calling task will get the specified event *   and the timer will be reloaded with the timeout value. * * @param   uint8 taskID - task id to set timer for * @param   uint16 event_id - event to be notified with * @param   UNINT16 timeout_value - in milliseconds. * * @return  OSAL_SUCCESS, or NO_TIMER_AVAIL. */osal_uint8_t osal_timer_startre(task_id_t task_id, event_id_t event_id, osal_uint16_t timeout)  
{  
    osal_timer_t  *timer_new;  
  
    OSAL_ENTER_CRITICAL();  
    timer_new = osal_timer_create(task_id, event_id, timeout);  
    if(timer_new != NULL){  
        timer_new->reload = timeout;  
    }  
    OSAL_EXIT_CRITICAL();  
  
    return ((timer_new != NULL) ? OSAL_SUCCESS : INVALID_TIMER);  
}

osal_timer_del

删除定时器,将定时器对应的event_id设为无事件SYS_EVE_NONE
此定时器会在定时器更新函数中被清理

/*********************************************************************  
 * @fn      osal_timer_del * * @brief   Delete a timer from a timer list. * * @param   table * @param   rmTimer * * @return  none */static void osal_timer_del(osal_timer_t *timer)  
{  
    if(timer!= NULL){  
        timer->event_id = SYS_EVE_NONE;  
    }  
}

osal_timer_update

将次函数放在systick中断里,每个tick调用一次

1更新OSAL时钟osal_systick
2遍历定时器链表,将每个定时器的timeout–,有时间到的,将其对应的任务事件置位(这里仅置位,函数执行在osal_system_start中执行)
3清理已删除的定时器

/*********************************************************************  
 * @fn      osal_timer_update * * @brief   Update the timer structures for timer ticks. * * @param   none * * @return  none */void osal_timer_update(void)  
{  
    osal_timer_t  *timer_sech;//遍历定时器  
    osal_timer_t  *timer_prev;//保存上一个定时器  
  
    OSAL_ENTER_CRITICAL();  
    osal_systick++;  
    OSAL_EXIT_CRITICAL();  
  
    //链表非空,遍历定时器链表  
    if(timer_head!= NULL)  
    {  
        timer_sech = timer_head;  
        timer_prev = (void *)NULL;  
        while(timer_sech != NULL)  
        {  
            osal_timer_t *timer_free = NULL;//保存要删除的定时器,单词定时器运行一次后就要删除,事件为SYS_EVE_NONE的定时器也要删除  
            OSAL_ENTER_CRITICAL();  
            timer_sech->timeout--;  
  
            //可重载定时器超时,事件有效,重新加载定时器  
            if((timer_sech->timeout == 0) && (timer_sech->event_id != SYS_EVE_NONE) && (timer_sech->reload != 0))  
            {  
                osal_task_seteve(timer_sech->task_id, timer_sech->event_id);  
                timer_sech->timeout = timer_sech->reload;  
            }  
  
            //单次定时器超时,或存在事件为SYS_EVE_NONE的定时器,都将其幅值为timer_free,等待删除  
            if((timer_sech->timeout == 0) || (timer_sech->event_id == SYS_EVE_NONE))  
            {  
                //如果是第一次进来就删除,timer_sech要删除,将timer_head指向别处NULL  
                if(timer_prev == NULL){  
                    timer_head = timer_sech->next;  
                }else{  
                    //timer_sech删除,将timer_prev->next指向timer_sech->next,中间扣掉了timer_sech  
                    timer_prev->next = timer_sech->next;  
                }  
                //将要删除的定时器保存到timer_free,等待删除,timer_sech继续遍历  
                timer_free = timer_sech;  
                timer_sech = timer_sech->next;  
            }else{  
                //无删除定时器,遍历下一个定时器  
                timer_prev = timer_sech;  
                timer_sech = timer_sech->next;  
            }  
            OSAL_EXIT_CRITICAL();  
  
            //存在要删除的定时器,释放内存  
            if(timer_free != NULL)  
            {  
                //如果是单次定时器超时,则发送事件后再删除  
                if(timer_free->timeout == 0){  
                    osal_task_seteve(timer_free->task_id, timer_free->event_id);  
                }  
                osal_mem_free(timer_free);  
            }  
        }  
    }  
}

http://www.kler.cn/a/520299.html

相关文章:

  • SQL GROUP BY 详解
  • dmfldr实战
  • SOME/IP--协议英文原文讲解1
  • 前端力扣刷题 | 4:hot100之 子串
  • LongLoRA:高效扩展大语言模型上下文长度的微调方法
  • 数据结构与算法再探(六)动态规划
  • 自由学习记录(32)
  • [VSCode] vscode下载安装及安装中文插件详解(附下载链接)
  • HBase-2.5.10 伪分布式环境搭建【Mac】
  • linux ——waitpid介绍及示例
  • Office2021下载与安装保姆级教程【Office Tool Plus】
  • 蓝桥杯c/c++需要掌握的基础语法总结
  • AWS Wavelength
  • LeetCode:2412. 完成所有交易的初始最少钱数(贪心 java)
  • Spring MVC 中的 DispatcherServlet:工作流程与应用场景解析
  • FreeRTOS实时操作系统学习小结
  • kubernetes 核心技术-Service
  • 【SQL注入】DVWA靶场SQL注入实践
  • 在线可编辑Excel
  • 【超详细】C#事件
  • MyBatis最佳实践:提升数据库交互效率的秘密武器
  • 聊一聊 CSS 样式的导入方式
  • 使用Ollama部署deepseek大模型
  • unity制作动画的技巧相关注意点
  • 证券投资和量化交易的概率和预测的准确性
  • 深入探索 Vue 3 Markdown 编辑器:高级功能与实现