FreeRTOS学习笔记---软件定时器基础操作(基于ESPIDF)

参考文档是韦东山老师的第16章 软件定时器(software timer) | 百问网

软件定时器

是什么

定时器定时器,我们可以初步把他了解为具有硬件定时器部分功能的定时器,也就运行到达某些规定的时刻中,CPU会跳转进入回调函数执行中断任务。但是软件定时器比硬件定时器多了一些介质("定时器命令队列"(timer command queue)和守护任务)。

根据文档我们可以知道,软件定时器的本质有点像队列通知,在我们使用函数创建定时器,并在需要触发的时候在某个任务使用Star开启定时器(这时候写入定时器队列,该队列在FreeRTOS中自带),只要“某个任务”进入阻塞,那么根据优先级运行到“定时器队列”所在的任务函数中(也就是守护任务),在守护任务中,会执行软件定时器的回调函数(自己写的)。这些状态的跳转可以参考下面的图片

API函数

/* 使用动态分配内存的方法创建定时器
 * pcTimerName:定时器名字, 用处不大, 尽在调试时用到
 * xTimerPeriodInTicks: 周期, 以Tick为单位
 * uxAutoReload: 类型, pdTRUE表示自动加载, pdFALSE表示一次性
 * pvTimerID: 回调函数可以使用此参数, 比如分辨是哪个定时器
 * pxCallbackFunction: 回调函数
 * 返回值: 成功则返回TimerHandle_t, 否则返回NULL
 */
TimerHandle_t xTimerCreate( const char * const pcTimerName, 
							const TickType_t xTimerPeriodInTicks,
							const UBaseType_t uxAutoReload,
							void * const pvTimerID,
							TimerCallbackFunction_t pxCallbackFunction );

/* 启动定时器
 * xTimer: 哪个定时器
 * xTicksToWait: 超时时间
 * 返回值: pdFAIL表示"启动命令"在xTicksToWait个Tick内无法写入队列
 *        pdPASS表示成功
 */
BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );

/* 修改定时器的周期
 * xTimer: 哪个定时器
 * xNewPeriod: 新周期
 * xTicksToWait: 超时时间, 命令写入队列的超时时间 
 * 返回值: pdFAIL表示"修改周期命令"在xTicksToWait个Tick内无法写入队列
 *        pdPASS表示成功
 */
BaseType_t xTimerChangePeriod(   TimerHandle_t xTimer,
                                 TickType_t xNewPeriod,
                                 TickType_t xTicksToWait );

实验

创建软件定时器,再创建一个任务通知以及接收任务通知的任务,当任务通知到来时使用xTimerChangePeriod间接启动定时器

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "esp_log.h"

static TaskHandle_t     TaskAh;
static TaskHandle_t     TaskBh;
static TimerHandle_t    TaskTimerh;

uint32_t timer = 0;
uint32_t timer_last = 0;

void TaskA(void *param)
{
    //发送通知]
    uint32_t value = 0;
    while(1)
    {
        xTaskNotify(TaskBh,value ,eSetValueWithOverwrite);
        vTaskDelay(pdMS_TO_TICKS(1000));
        value++;
    }
}

void TaskB(void *param)
{
    //接收并打印
    uint32_t value ;
    while (1)
    {
        //如果发现数值变换
        if(timer != timer_last)
        {
            ESP_LOGI("timer","%lu",timer);
            timer_last = timer;
        }
        xTaskNotifyWait(0x00,ULLONG_MAX,&value,portMAX_DELAY);
        ESP_LOGI("ev","notify value:%lu",value);
        xTimerChangePeriod(TaskTimerh, pdMS_TO_TICKS(1000)  , pdMS_TO_TICKS(10));
    }
}

//回调函数干的事尽量少一点
void TaskTimer_cb()
{
    timer++;
}

void app_main()
{
    //taskDISABLE_INTERRUPTS();本来想进入临界区创建任务后再退出的,但是发现不管用,所以使用了后面的挂起和开始
    xTaskCreatePinnedToCore(TaskA , "TaskA" , 2048 , NULL , 5 , &TaskAh , 1);
    vTaskSuspend(TaskAh);
    xTaskCreatePinnedToCore(TaskB , "TaskB" , 2048 , NULL , 5 , &TaskBh , 1);  
    vTaskSuspend(TaskBh);
    TaskTimerh = xTimerCreate( "Timer" , pdMS_TO_TICKS(1000) , pdFALSE , NULL , TaskTimer_cb);
    //taskENABLE_INTERRUPTS();
    vTaskResume(TaskAh);
    vTaskResume(TaskBh);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值