0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Free RTOS的軟件定時(shí)器

汽車(chē)電子技術(shù) ? 來(lái)源:玩轉(zhuǎn)單片機(jī) ? 作者: Julian ? 2023-02-10 15:53 ? 次閱讀

軟件定時(shí)器FreeRTOS中的一個(gè)重要模塊,使用軟件定時(shí)器可以方便的實(shí)現(xiàn)一些與超時(shí)或周期性相關(guān)的功能。


硬件定時(shí)器


芯片本身提供的定時(shí)功能。一般是由外部晶振提供給芯片輸入時(shí)鐘,芯片向軟件模塊提供一組配置寄存器,接受控制輸入,到達(dá)設(shè)定時(shí)間值后芯片中斷控制器產(chǎn)生時(shí)鐘中斷。硬件定時(shí)器的精度一般很高,可以達(dá)到納秒級(jí)別,并且是中斷觸發(fā)方式。


軟件定時(shí)器


軟件定時(shí)器是由操作系統(tǒng)提供的一類系統(tǒng)接口,它構(gòu)建在硬件定時(shí)器基礎(chǔ)之上,使系統(tǒng)能夠提供不受硬件定時(shí)器資源限制的定時(shí)器服務(wù),它實(shí)現(xiàn)的功能與硬件定時(shí)器也是類似的。


FreeRTOS 軟件定時(shí)器功能

裁剪:能通過(guò)宏關(guān)閉軟件定時(shí)器功能。

軟件定時(shí)器創(chuàng)建。

軟件定時(shí)器啟動(dòng)。

軟件定時(shí)器停止。

軟件定時(shí)器復(fù)位。

軟件定時(shí)器刪除。


軟件定時(shí)器模式


單次模式:當(dāng)用戶創(chuàng)建了定時(shí)器并啟動(dòng)了定時(shí)器后,定時(shí)時(shí)間到了,只執(zhí)行一次回調(diào)函數(shù)之后就將該定時(shí)器刪除,不再重新執(zhí)行。

周期模式:這個(gè)定時(shí)器會(huì)按照設(shè)置的定時(shí)時(shí)間循環(huán)執(zhí)行回調(diào)函數(shù),直到用戶將定時(shí)器刪除

poYBAGPl9zqAEXkAAAE78KsCOCE553.png


FreeRTOS 通過(guò)一個(gè) prvTimerTask 任務(wù)(也叫守護(hù)任務(wù) Daemon)管理軟定時(shí)器,它是在啟動(dòng)調(diào)度器時(shí)自動(dòng)創(chuàng)建的,為了滿足用戶定時(shí)需求。prvTimerTask 任務(wù)會(huì)在其執(zhí)行期間檢查用戶啟動(dòng)的時(shí)間周期溢出的定時(shí)器,并調(diào)用其回調(diào)函數(shù)。只有設(shè)置 FreeRTOSConfig.h中的宏定義 configUSE_TIMERS 設(shè)置為 1 ,將相關(guān)代碼編譯進(jìn)來(lái),才能正常使用軟件定時(shí)器相關(guān)功能。

配置定時(shí)器

//啟用軟件定時(shí)器
#define configUSE_TIMERS                    1                              
//軟件定時(shí)器優(yōu)先級(jí)
#define configTIMER_TASK_PRIORITY            (configMAX_PRIORITIES-1)        
//軟件定時(shí)器隊(duì)列長(zhǎng)度
#define configTIMER_QUEUE_LENGTH            10                               
//軟件定時(shí)器任務(wù)堆棧大小
#define configTIMER_TASK_STACK_DEPTH        (configMINIMAL_STACK_SIZE*2) 


創(chuàng)建定時(shí)器

TimerHandle_t xTimerCreate( const char *pcTimerName, 
                            const TickType_t xTimerPeriod, 
                            const UBaseType_t uxAutoReload, 
                            void * const pvTimerID, 
                           TimerCallbackFunction_t pxCallbackFunction );

參數(shù)

pcTimerName:定時(shí)器名稱

xTimerPeriod :定時(shí)周期

uxAutoReload : 如果將uxAutoReload設(shè)置為pdTRUE,則計(jì)時(shí)器將以xTimerPeriod參數(shù)設(shè)置的頻率重復(fù)終止。如果將uxAutoReload設(shè)置為pdFALSE,則計(jì)時(shí)器將是一次觸發(fā),并在其到期后進(jìn)入休眠狀態(tài)。

pvTimerID分配給正在創(chuàng)建的計(jì)時(shí)器的標(biāo)識(shí)符。

pxCallbackFunction計(jì)時(shí)器到期時(shí)要調(diào)用的函數(shù)。

返回值

如果成功創(chuàng)建了計(jì)時(shí)器,則返回新創(chuàng)建的計(jì)時(shí)器的句柄。如果由于剩余的FreeRTOS堆不足而無(wú)法分配計(jì)時(shí)器結(jié)構(gòu)而無(wú)法創(chuàng)建計(jì)時(shí)器,則返回NULL

啟動(dòng)定時(shí)器

BaseType_t xTimerStart( TimerHandle_t xTimer, 
                        TickType_t xTicksToWait );

參數(shù)

xTimer:計(jì)時(shí)器的句柄

xTicksToWait:指定在計(jì)時(shí)器命令隊(duì)列已經(jīng)滿的情況下,任務(wù)應(yīng)保持阻塞狀態(tài)以等待空間可用的最大時(shí)間。

返回值

如果即使經(jīng)過(guò)xBlockTime刻度后仍無(wú)法將啟動(dòng)命令發(fā)送到計(jì)時(shí)器命令隊(duì)列,則將返回pdFAIL。如果命令已成功發(fā)送到計(jì)時(shí)器命令隊(duì)列,則將返回pdPASS。

停止定時(shí)器

BaseType_t xTimerStop( TimerHandle_t xTimer, 
                       TickType_t xTicksToWait );

參數(shù):同上

返回值:同上


復(fù)位定時(shí)器

BaseType_t xTimerReset( TimerHandle_t xTimer, 
                        TickType_t xTicksToWait );

參數(shù):同上

返回值:同上


刪除定時(shí)器

BaseType_t xTimerDelete( TimerHandle_t xTimer, 
                         TickType_t xTicksToWait );

參數(shù):同上類似

返回值:同上類似


改變定時(shí)器周期

BaseType_t xTimerChangePeriod( TimerHandle_t xTimer, 
                               TickType_txNewPeriod,
                               TickType_t xTicksToWait );

參數(shù)

xTimer:定時(shí)器的句柄

xNewPeriod:新的周期參數(shù)

xTicksToWait:指定在計(jì)時(shí)器命令隊(duì)列已經(jīng)滿的情況下,任務(wù)應(yīng)保持阻塞狀態(tài)以等待空間可用的最大時(shí)間。

返回值

如果即使經(jīng)過(guò)xBlockTime滴答聲后仍無(wú)法將更改周期命令發(fā)送到計(jì)時(shí)器命令隊(duì)列,則將返回pdFAIL。如果命令已成功發(fā)送到計(jì)時(shí)器命令隊(duì)列,則將返回pdPASS。


還有中斷啟動(dòng)定時(shí)器、停止、復(fù)位、改變周期的API函數(shù),請(qǐng)查閱官方文檔!


附上小例程

#include "stm32f10x.h"
#include 
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "timers.h"

//毫秒級(jí)的延時(shí)
void Delay_Ms(u16 time)
{    
   u16 i=0;  
   while(time--)
   {
      i=12000;  //自己定義
      while(i--) ;    
   }
}

void LED_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;        //定義結(jié)構(gòu)體變量
  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);  //開(kāi)啟時(shí)鐘
  
  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;            //選擇你要設(shè)置的IO口
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;      //設(shè)置推挽輸出模式
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;     //設(shè)置傳輸速率
  GPIO_Init(GPIOC,&GPIO_InitStructure);                //初始化GPIO
  
  GPIO_SetBits(GPIOC,GPIO_Pin_0);             //將LED端口拉高,熄滅LED
}

void KEY_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure; //定義結(jié)構(gòu)體變量  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);
  
  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;     //選擇你要設(shè)置的IO口
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;//下拉輸入  
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;     //設(shè)置傳輸速率
  GPIO_Init(GPIOA,&GPIO_InitStructure);      /* 初始化GPIO */
  
  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_2|GPIO_Pin_4;
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;  //上拉輸入
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  GPIO_Init(GPIOE,&GPIO_InitStructure);
}


void USART_init(uint32_t bound)
{
  GPIO_InitTypeDef GPIO_InitStruct;   //定義GPIO結(jié)構(gòu)體變量
  USART_InitTypeDef USART_InitStruct;   //定義串口結(jié)構(gòu)體變量
  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);   //使能GPIOC的時(shí)鐘
  
  GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;   //配置TX引腳
  GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;   //配置PA9為復(fù)用推挽輸出
  GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;   //配置PA9速率
  GPIO_Init(GPIOA,&GPIO_InitStruct);   //GPIO初始化函數(shù)
  
  GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;   //配置RX引腳
  GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;   //配置PA10為浮空輸入
  GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;   //配置PA10速率
  GPIO_Init(GPIOA,&GPIO_InitStruct);   //GPIO初始化函數(shù)
  
  
  USART_InitStruct.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;   //發(fā)送接收模式
  USART_InitStruct.USART_Parity=USART_Parity_No;   //無(wú)奇偶校驗(yàn)
  USART_InitStruct.USART_BaudRate=bound;   //波特率
  USART_InitStruct.USART_StopBits=USART_StopBits_1;   //停止位1位
  USART_InitStruct.USART_WordLength=USART_WordLength_8b;   //字長(zhǎng)8位
  USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;   //無(wú)硬件數(shù)據(jù)流控制
  USART_Init(USART1,&USART_InitStruct);   //串口初始化函數(shù)
  
  USART_Cmd(USART1,ENABLE);   //使能USART1
}

int fputc(int ch,FILE *f)   //printf重定向函數(shù)
{
  USART_SendData(USART1,(uint8_t)ch);   //發(fā)送一字節(jié)數(shù)據(jù)
  while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);   //等待發(fā)送完成
  return ch;
}


#define START_TASK_PRIO 5      //任務(wù)優(yōu)先級(jí)
#define START_STK_SIZE 128      //任務(wù)堆棧大小
TaskHandle_t StartTask_Handler;   //任務(wù)句柄
void Start_Task(void *pvParameters);//任務(wù)函數(shù)

#define Low_TASK_PRIO 2       //任務(wù)優(yōu)先級(jí)
#define Low_STK_SIZE 50       //任務(wù)堆棧大小
TaskHandle_t LowTask_Handler;     //任務(wù)句柄
void Low_Task(void *p_arg);     //任務(wù)函數(shù)

#define Med_TASK_PRIO 3       //任務(wù)優(yōu)先級(jí)
#define Med_STK_SIZE 50       //任務(wù)堆棧大小
TaskHandle_t MedTask_Handler;     //任務(wù)句柄
void Med_Task(void *p_arg);     //任務(wù)函數(shù)

TimerHandle_t Time0Handler = NULL;  //軟件定時(shí)器句柄
void Time0Callback( TimerHandle_t pxTimer );//回調(diào)函數(shù)

int main( void ) 
{
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設(shè)置系統(tǒng)中斷優(yōu)先級(jí)分組 4
  
  LED_Init(); //初始化 LED
  KEY_Init();
  USART_init(9600);
  
  //創(chuàng)建開(kāi)始任務(wù)
  xTaskCreate(
    (TaskFunction_t )Start_Task,     //任務(wù)函數(shù)
    (const char* )"Start_Task",     //任務(wù)名稱
    (uint16_t )START_STK_SIZE,       //任務(wù)堆棧大小
    (void* )NULL,             //傳遞給任務(wù)函數(shù)的參數(shù)
    (UBaseType_t )START_TASK_PRIO,     //任務(wù)優(yōu)先級(jí)
    (TaskHandle_t* )&StartTask_Handler  //任務(wù)句柄 
  );
  vTaskStartScheduler();  //開(kāi)啟調(diào)度
}

//開(kāi)始任務(wù)函數(shù)
void Start_Task(void *pvParameters)
{
  taskENTER_CRITICAL();   //進(jìn)入臨界區(qū)
  //創(chuàng)建軟件定時(shí)器
  Time0Handler = xTimerCreate( ( char *                ) "Time0",     //定時(shí)器的名稱
                 ( TickType_t              ) 1000,       //定時(shí)周期
                 ( UBaseType_t             ) pdTRUE,       //是否重裝載 (pdTRUE or pdFAIL)
                 ( void *                  ) 0,         //ID號(hào)
                 ( TimerCallbackFunction_t ) Time0Callback ); //回調(diào)函數(shù)
  //開(kāi)啟定時(shí)器
  xTimerStart( Time0Handler, portMAX_DELAY );
  //創(chuàng)建 Low 任務(wù)
  xTaskCreate(
    (TaskFunction_t )Low_Task, 
    (const char* )"Low_Task", 
    (uint16_t )Low_STK_SIZE, 
    (void* )NULL,
    (UBaseType_t )Low_TASK_PRIO,
    (TaskHandle_t* )&LowTask_Handler
  );
  //創(chuàng)建 Med 任務(wù)
  xTaskCreate(
    (TaskFunction_t )Med_Task, 
    (const char* )"Med_Task", 
    (uint16_t )Med_STK_SIZE, 
    (void* )NULL,
    (UBaseType_t )Med_TASK_PRIO,
    (TaskHandle_t* )&MedTask_Handler
  );
  vTaskDelete(StartTask_Handler); //刪除開(kāi)始任務(wù)
  taskEXIT_CRITICAL();   //退出臨界區(qū)
}


void Low_Task(void *pvParameters)
{
  while(1)
  {
    
    vTaskDelay(1000);
  }
}

void Med_Task(void *pvParameters)
{
  //BaseType_t xReturn = NULL;
  while(1)
  {
    printf("正在運(yùn)行n");
    vTaskDelay(1000);
  }
}

void Time0Callback( TimerHandle_t pxTimer )
{
  static int count = 0;
  printf("%dn",++count);
}


實(shí)驗(yàn)現(xiàn)象

pYYBAGPl99KAejgvAABWsxgh4dQ062.png


--END--

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 軟件定時(shí)器
    +關(guān)注

    關(guān)注

    0

    文章

    18

    瀏覽量

    6723
  • FreeRTOS
    +關(guān)注

    關(guān)注

    12

    文章

    483

    瀏覽量

    61849
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    使用cola_os軟件定時(shí)器實(shí)現(xiàn)時(shí)間片輪詢框架

    如果使用RTOS顯得太浪費(fèi),這時(shí)候可以嘗試使用使用cola_os這類基于軟件定時(shí)器實(shí)現(xiàn)的時(shí)間片輪詢框架。
    的頭像 發(fā)表于 09-22 09:03 ?1321次閱讀
    使用cola_os<b class='flag-5'>軟件</b><b class='flag-5'>定時(shí)器</b>實(shí)現(xiàn)時(shí)間片輪詢框架

    基于STM32的軟件定時(shí)器設(shè)計(jì)

    軟件定時(shí)器是用程序模擬出來(lái)的定時(shí)器,可以由一個(gè)硬件定時(shí)器模擬出成千上萬(wàn)個(gè)軟件定時(shí)器,這樣程序在需
    發(fā)表于 07-03 17:06 ?953次閱讀
    基于STM32的<b class='flag-5'>軟件</b><b class='flag-5'>定時(shí)器</b>設(shè)計(jì)

    Linux和RTOS的時(shí)鐘和定時(shí)器怎么使用

    Linux發(fā)燒友1.RTOS篇1.1RT-Thread簡(jiǎn)介1.2時(shí)鐘管理1.2.1時(shí)鐘節(jié)拍1.3獲取系統(tǒng)節(jié)拍1.4定時(shí)器分類1.5定時(shí)器源碼分析1.6定時(shí)器相關(guān)函數(shù)1.61動(dòng)態(tài)創(chuàng)建一個(gè)
    發(fā)表于 01-17 08:13

    定時(shí)器初值計(jì)算軟件工具

    定時(shí)器初值計(jì)算軟件工具
    發(fā)表于 03-20 10:23 ?239次下載

    555定時(shí)器電路設(shè)計(jì)軟件

    555定時(shí)器電路設(shè)計(jì)軟件
    發(fā)表于 03-02 11:29 ?287次下載

    555定時(shí)器應(yīng)用設(shè)計(jì)軟件免費(fèi)下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是555定時(shí)器應(yīng)用設(shè)計(jì)軟件免費(fèi)下載,本軟件是一款555定時(shí)器設(shè)計(jì)軟件,使用非常方便。
    發(fā)表于 12-17 08:00 ?51次下載
    555<b class='flag-5'>定時(shí)器</b>應(yīng)用設(shè)計(jì)<b class='flag-5'>軟件</b>免費(fèi)下載

    ESP8266的管腳的控制和軟件定時(shí)器的使用

    先說(shuō)定時(shí)器,ESP8266內(nèi)部的定時(shí)器分為軟件定時(shí)器和硬件定時(shí)器。手冊(cè)中指出硬件定時(shí)器其實(shí)就跟單
    的頭像 發(fā)表于 07-29 14:57 ?9377次閱讀
    ESP8266的管腳的控制和<b class='flag-5'>軟件</b><b class='flag-5'>定時(shí)器</b>的使用

    設(shè)計(jì)軟件定時(shí)器

    軟件定時(shí)器搬來(lái)使用2、自己設(shè)計(jì)軟件定時(shí)器這里我只介紹第二種方法,我們知道,硬件定時(shí)器是通過(guò)對(duì)系統(tǒng)時(shí)鐘周期進(jìn)行計(jì)數(shù)實(shí)現(xiàn)的,那么
    發(fā)表于 11-05 18:35 ?2次下載
    設(shè)計(jì)<b class='flag-5'>軟件</b><b class='flag-5'>定時(shí)器</b>

    基于硬件定時(shí)器軟件定時(shí)器

    概括硬件定時(shí)器很精確,軟件定時(shí)器無(wú)論如何都有延遲,主要用在不需要精確定時(shí)的地方,而且軟件定時(shí)比較
    發(fā)表于 11-25 09:51 ?8次下載
    基于硬件<b class='flag-5'>定時(shí)器</b>的<b class='flag-5'>軟件</b><b class='flag-5'>定時(shí)器</b>

    詳細(xì)剖析Linux和RTOS(RT-Thread)的時(shí)鐘和定時(shí)器的使用

    Linux發(fā)燒友1.RTOS篇1.1RT-Thread簡(jiǎn)介1.2時(shí)鐘管理1.2.1時(shí)鐘節(jié)拍1.3獲取系統(tǒng)節(jié)拍1.4定時(shí)器分類1.5定時(shí)器源碼分析1.6定時(shí)器相關(guān)函數(shù)1.61動(dòng)態(tài)創(chuàng)建一個(gè)
    發(fā)表于 01-17 09:31 ?4次下載
    詳細(xì)剖析Linux和<b class='flag-5'>RTOS</b>(RT-Thread)的時(shí)鐘和<b class='flag-5'>定時(shí)器</b>的使用

    軟件定時(shí)器簡(jiǎn)介及程序配置

      軟件定時(shí)器就是允許函數(shù)設(shè)置一定的等待時(shí)間,然后執(zhí)行。定時(shí)器執(zhí)行的函數(shù)被稱為定時(shí)器的回調(diào)函數(shù)。定時(shí)器從啟動(dòng)到執(zhí)行回調(diào)函數(shù)之間的時(shí)間稱為
    的頭像 發(fā)表于 12-06 16:10 ?3768次閱讀
    <b class='flag-5'>軟件</b><b class='flag-5'>定時(shí)器</b>簡(jiǎn)介及程序配置

    freeRTOS軟件定時(shí)器的使用

    freeRTOS中加入了軟件定時(shí)器這個(gè)功能組件,是一個(gè)可選的、不屬于freeRTOS內(nèi)核的功能,由定時(shí)器服務(wù)(其實(shí)就是一個(gè)定時(shí)器任務(wù))來(lái)提供。
    的頭像 發(fā)表于 02-10 13:55 ?1950次閱讀

    什么是軟件定時(shí)器?軟件定時(shí)器的實(shí)現(xiàn)原理

    軟件定時(shí)器是用程序模擬出來(lái)的定時(shí)器,可以由一個(gè)硬件定時(shí)器模擬出成千上萬(wàn)個(gè)軟件定時(shí)器,這樣程序在需
    的頭像 發(fā)表于 05-23 17:05 ?2588次閱讀

    關(guān)于軟件定時(shí)器的一些討論

    這就是簡(jiǎn)單的軟件定時(shí)器,是的,這就是特別簡(jiǎn)潔版本的軟件定時(shí)器。當(dāng)然它是有缺點(diǎn)的,比如systick_ms每1ms加1,所以軟件
    的頭像 發(fā)表于 10-13 16:14 ?492次閱讀
    關(guān)于<b class='flag-5'>軟件</b><b class='flag-5'>定時(shí)器</b>的一些討論

    如何實(shí)現(xiàn)一個(gè)軟件定時(shí)器?

    在Linux,uC/OS,F(xiàn)reeRTOS等操作系統(tǒng)中,都帶有軟件定時(shí)器,原理大同小異。典型的實(shí)現(xiàn)方法是:通過(guò)一個(gè)硬件定時(shí)器產(chǎn)生固定的時(shí)鐘節(jié)拍,每次硬件定時(shí)器中斷到,就對(duì)一個(gè)全局的時(shí)間
    的頭像 發(fā)表于 04-29 11:00 ?525次閱讀