FreeRTOS快速上手

FreeRTOS使用

一. 源碼下載和移植文件提取

1.1 源碼下載

在網站https://sourceforge.net/projects/freertos/可以找到freertos最新的源碼。

1.2 移植文件提取

根據第一步,我們會得到一個freertos源碼文件夾(FreeRTOSvxx.x.x),其下有很多對移植用處不大的文件夾,可以不管,直接打開FreeRTOSvxx.x.x\FreeRTOS\Source即可,我們需要的源碼全在這裏。

首先是Source下的這幾個文件,是整個freertos的核心

在這裏插入圖片描述

然後是include文件夾下的頭文件

在這裏插入圖片描述

最後是portable文件夾下的RVDS和MemMang文件夾裏的文件

在這裏插入圖片描述
在RDVS文件夾中選擇使用的芯片類別,比如我在F103上移植的,那麼我就選擇ARM_CM3文件夾下的文件。

在這裏插入圖片描述

打開也就是這些文件

在這裏插入圖片描述
MemMang中是與內存相關的文件,根據自己需要選擇,比如參考別人的移植工程,我就選擇heap_4.c
在這裏插入圖片描述

以上就是需要從源碼中提取出來的全部文件,我們可以全部複製出來放到一個方便操作的文件夾,當然就這樣也沒有任何問題。

二、移植到工程中

2.1 添加源碼到工程

這一步跟建立工程時新建分組一樣,新建一個freertos的分組再把剛剛的.c文件添加進去,然後把.h文件路徑包含到工程就行了

在這裏插入圖片描述

當然,就這樣是肯定不行的,我們還要添加一些移植必要的文件和修改原來的工程文件。

2.2 移植配置文件

對於一塊從未接觸過的芯片,移植操作系統時往往會找網上的例程,但是請注意,freertos可以用STM32CubeMX直接生成啊,那些必要的配置文件直接複製就行了。

我們使用STM32CubeMX選擇自己使用的芯片新建一個激活freertos的工程,然後打開工程文件價下的freertos Source文件夾。

在這裏插入圖片描述

發現這和我們剛剛下載的源碼幾乎一樣,是的,確實幾乎一樣,但是它多了一個CMSIS_RTOS文件夾,這裏面的cmsis_os.c和cmsis_os.h是使用大量條件語句編程實現的操作系統API調用文件,調用這兩個文件裏的函數可以在很大程度上脫離繁瑣的freertosAPI調用,具體實現查看源碼或者百度CMSIS_RTOS就能懂了,不做過多解釋,我們只管快速使用。

在這裏插入圖片描述

然後我們在打開工程文件下的inc文件夾,這有一個至關重要的文件

在這裏插入圖片描述

全部的移植文件都在這裏了,我們只要添加進工程就行了,接下來的事情就是把移植後的錯誤改正。

2.3 移植錯誤排除

我直接使用的CubeMX生成的配置文件及源碼,現在移植到自己建立的標準庫工程,會有很多的錯誤,需要一一修改。

刪除FreeRTOSConfig.h中的main.h
在這裏插入圖片描述

刪除cmsis_os.c中的cmsis_armcc.h
在這裏插入圖片描述

在cmsis_os.c中添加如下函數

在這裏插入圖片描述
修改cmsis_os.c中的osMailAlloc函數如下
在這裏插入圖片描述

修改cmsis_os.c中的osMailCreate

在這裏插入圖片描述
註釋掉stm32f10x_it.c中的兩個中斷函數

在這裏插入圖片描述
滴答時鐘初始化

在這裏插入圖片描述

滴答時鐘中斷

在這裏插入圖片描述

至此,所有移植任務就完成了,再次編譯

在這裏插入圖片描述

三、操作系統的使用

3.1 任務創建

任務句柄

osThreadId led0TaskHandle;
osThreadId led1TaskHandle;

任務函數

void Led0Task(void const * argument);
void Led1Task(void const * argument);

創建任務

osThreadDef(led0Task, Led0Task, osPriorityNormal, 0, 128);
osThreadDef(led1Task, Led1Task, osPriorityNormal, 0, 128);
led0TaskHandle    = osThreadCreate(osThread(led0Task), NULL);
led1TaskHandle    = osThreadCreate(osThread(led1Task), NULL);

任務代碼

void Led0Task(void const * argument)
{
    while(1)
    {
        GPIO_SetBits(GPIOB,GPIO_Pin_5);
        osDelay(200);
        GPIO_ResetBits(GPIOB,GPIO_Pin_5);
        osDelay(200);
    }
}
void Led1Task(void const * argument)
{
    while(1)
    {
        GPIO_SetBits(GPIOE,GPIO_Pin_5);
        osDelay(155);
        GPIO_ResetBits(GPIOE,GPIO_Pin_5);
        osDelay(155);
    }
}

3.2 信號量使用

信號量句柄

osSemaphoreId semaHandle;
osSemaphoreDef(se);

信號量任務

void SemRecvTask(void const * argument);

創建信號量

semaHandle = osSemaphoreCreate(osSemaphore(se), 1);

任務代碼

void SemRecvTask(void const * argument)
{
    osStatus sem;
    while(1)
    {
        sem = (osStatus)osSemaphoreWait(semaHandle, osWaitForever);
        if(sem == osOK)
        {
            /*
            **TODO
            */
        }
        osSemaphoreRelease(semaHandle);
        osDelay(500);
    }
}

3.3 信號使用

設置信號

void SingalSendTask(void const * argument)
{
    uint16_t cnt = 0;
    while(1)
    {
        ++cnt;
        if(cnt % 9 == 0)
        {
            printf("task led1 running times: %d\r\n",cnt);
            osSignalSet(led0TaskHandle,0x04);
        }
        GPIO_SetBits(GPIOE,GPIO_Pin_5);
        osDelay(155);
        GPIO_ResetBits(GPIOE,GPIO_Pin_5);
        osDelay(155);
    }
}

等待信號

void SingalRecvTask(void const * argument)
{
    osEvent event;
    while(1)
    {
        event = osSignalWait(0x04,100);
        if(event.status == osEventSignal)
        {
            if(event.value.signals &0x04)
            {
                printf("lend0 recv val:%d\r\n",event.value.signals);
            }
        }
        GPIO_ResetBits(GPIOB,GPIO_Pin_5);
        osDelay(200);
        GPIO_SetBits(GPIOB,GPIO_Pin_5);
        osDelay(200);
    }
}

3.4 互斥信號量使用

互斥信號量句柄

osMutexId mutexHandle;

osMutexDef(MUTEX);

互斥信號量任務

void Mutex1RecvTask(void const * argument);
void Mutex2RecvTask(void const * argument);

創建互斥信號量

mutexHandle = osMutexCreate(osMutex(MUTEX));

任務代碼

void Mutex1RecvTask(void const * argument)
{
    osStatus err;
    while(1)
    {
        err = osMutexWait(mutexHandle,osWaitForever);
        if(osOK == err)
        {
            printf("led0 recv mutexsem!\r\n");
        }
        err = osMutexRelease(mutexHandle);
        GPIO_ResetBits(GPIOB,GPIO_Pin_5);
        osDelay(200);
        GPIO_SetBits(GPIOB,GPIO_Pin_5);
        osDelay(200);
    }
}

void Mutex2RecvTask(void const * argument)
{
    osStatus err;
    while(1)
    {
        err = osMutexWait(mutexHandle,osWaitForever);
        if(osOK == err)
        {
            printf("led1 recv mutexsem!\r\n");
        }
        err = osMutexRelease(mutexHandle);
        GPIO_SetBits(GPIOE,GPIO_Pin_5);
        osDelay(200);
        GPIO_ResetBits(GPIOE,GPIO_Pin_5);
        osDelay(200);
    }
}

3.5 消息隊列使用

消息隊列句柄

osMessageQId msgHandle;
osMessageQDef(MSG, 1, uint8_t*); //發送消息爲指針(結構體指針也行)
//osMessageQDef(MSG, 1, uint16_t);//發送整形數值

消息隊列任務

void MsgQSendTask(void const * argument);
void MsgQRecvTask(void const * argument);

創建消息隊列

msgHandle = osMessageCreate(osMessageQ(MSG),NULL);

任務代碼

void MsgQSendTask(void const * argument)
{
    uint16_t cnt = 0;
    osStatus err;
    while(1)
    {
        ++cnt;
        if(cnt % 9 == 0)
        {
            err = osMessagePut(msgHandle, (uint32_t)"say", osWaitForever);
            if(osOK != err)
            {
                printf("send error\r\n");
            }
            else
            {
                printf("send ok\r\n");
            }
            //發送整型
            //osMessagePut(msgHandle, 5, osWaitForever);
        }
        GPIO_ResetBits(GPIOB,GPIO_Pin_5);
        osDelay(200);
        GPIO_SetBits(GPIOB,GPIO_Pin_5);
        osDelay(200);
    }
}


void MsgQRecvTask(void const * argument)
{
    osEvent event;
    while(1)
    {
        event = osMessageGet(msgHandle, osWaitForever);
        if(event.status == osEventMessage)
        {
            if(event.def.message_id == msgHandle)
            {
                printf("lend1 recv val:%s\r\n",(uint8_t *)event.value.p);
            }
        }
        //只有收到消息後才執行
        GPIO_SetBits(GPIOE,GPIO_Pin_5);
        osDelay(155);
        GPIO_ResetBits(GPIOE,GPIO_Pin_5);
        osDelay(155);
    }
}

3.6 消息郵箱使用

消息郵箱句柄

osMailQId mailHandle;
osMailQDef(MAIL, 1, uint16_t);

消息郵箱任務

void MailSendTask(void const * argument);
void MailRecvTask(void const * argument);

創建消息郵箱

mailHandle = osMailCreate(osMailQ(MAIL),NULL);

任務代碼

void MailSendTask(void const * argument)
{
    uint16_t cnt = 0;
    osStatus err;
    while(1)
    {
        ++cnt;
        if(cnt % 9 == 0)
        {
            err = osMailPut(mailHandle, (uint8_t *)"say hi");
            if(osOK != err)
            {
                printf("send error\r\n");
            }
            else
            {
                printf("send ok\r\n");
            }
        }
        GPIO_ResetBits(GPIOB,GPIO_Pin_5);
        osDelay(200);
        GPIO_SetBits(GPIOB,GPIO_Pin_5);
        osDelay(200);
    }
}
void MailRecvTask(void const * argument)
{
    osEvent event;
    while(1)
    {
        event = osMailGet(mailHandle, osWaitForever);
        if(event.status == osEventMail)
        {
            if(event.def.mail_id == mailHandle)
            {
                printf("lend1 recv val:%s\r\n",(uint8_t *)event.value.p);
            }
        }
        //接收到郵箱後才執行
        GPIO_SetBits(GPIOE,GPIO_Pin_5);
        osDelay(155);
        GPIO_ResetBits(GPIOE,GPIO_Pin_5);
        osDelay(155);
    }
}

3.7 軟件定時器使用

軟件定時器句柄

osTimerId timHandle;
osTimerDef(TIM, timcCallbackFunction);

回調函數

static void timcCallbackFunction()
{
//     printf("i am timer\r\n");
         LED1 = !LED1;
}

創建軟件定時器

timHandle = osTimerCreate(osTimer(TIM), osTimerPeriodic, NULL);

任務代碼

void TimTask(void const * argument)
{
    uint16_t cnt = 0;
         osTimerStart(timHandle, 100);
         while(1)
         {
                 ++cnt;
                 if(cnt == 10)
                 {
                          osTimerStop(timHandle);
                 }
                 if(cnt == 20)
                 {
                          osTimerStart(timHandle, 300);
                 }
                 GPIO_ResetBits(GPIOB,GPIO_Pin_5);
                 osDelay(200);
                 GPIO_SetBits(GPIOB,GPIO_Pin_5);
                 osDelay(200);
         }
}

四、參考代碼

4.1 main.c

#include "sys.h"

#include "usart.h"

#include "led.h"

#include "delay.h"

#include "cmsis_os.h"

#include "FreeRTOS.h"



int main(void)

{

         clock_init();

         uart_init(115200);

         LED_Init();

         MX_FREERTOS_Init();

         osKernelStart();

}

4.2 freertos.c

#include "FreeRTOS.h"

#include "task.h"

#include "cmsis_os.h"

#include "stm32f10x.h"

#include "usart.h"

#include "stdio.h"

#include "led.h"



//優先級

osPriority prio;





//程序運行狀態

osThreadState taskstate;





//任務句柄

osThreadId defaultTaskHandle;

osThreadId led0TaskHandle;

osThreadId led1TaskHandle;

osThreadId printTaskHandle;



//任務函數

void StartDefaultTask(void const * argument);

void Led0Task(void const * argument);

void Led1Task(void const * argument);

void PrintTask(void const * argument);





//信號量

osSemaphoreId semaHandle;

osSemaphoreDef(se);



//信號量任務

void SemSendTask(void const * argument);

void SemRecvTask(void const * argument);





//信號任務

void SingalSendTask(void const * argument);

void SingalRecvTask(void const * argument);





//消息隊列

osMessageQId msgHandle;

osMessageQDef(MSG, 1, uint8_t*); //發送消息爲指針(結構體指針也行)

//osMessageQDef(MSG, 1, uint16_t);//發送整形數值



//消息隊列函數

void MsgQSendTask(void const * argument);

void MsgQRecvTask(void const * argument);





//消息郵箱

osMailQId mailHandle;

osMailQDef(MAIL, 1, uint16_t);



//消息郵箱函數

void MailSendTask(void const * argument);

void MailRecvTask(void const * argument);





//互斥信號量

osMutexId mutexHandle;

osMutexDef(MUTEX);



//互斥信號量函數

void Mutex1RecvTask(void const * argument);

void Mutex2RecvTask(void const * argument);





//軟件定時器

static void timcCallbackFunction();

osTimerId timHandle;

osTimerDef(TIM, timcCallbackFunction);



void TimTask(void const * argument);





void MX_FREERTOS_Init(void) {



    //任務初始化

    osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);

    osThreadDef(led0Task, Led0Task, osPriorityNormal, 0, 128);

    osThreadDef(led1Task, Led1Task, osPriorityNormal, 0, 128);

    osThreadDef(printTask, PrintTask, osPriorityNormal, 0, 128);



    //創建任務

    defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

    led0TaskHandle    = osThreadCreate(osThread(led0Task), NULL);

    led1TaskHandle    = osThreadCreate(osThread(led1Task), NULL);

    printTaskHandle   = osThreadCreate(osThread(printTask), NULL);



    //創建信號量

    semaHandle = osSemaphoreCreate(osSemaphore(se), 1);

    if(NULL != semaHandle)

    {

        //printf("Sem create success!\r\n");

    }



    //創建消息隊列

    msgHandle = osMessageCreate(osMessageQ(MSG),NULL);



    //創建消息郵箱

    mailHandle = osMailCreate(osMailQ(MAIL),NULL);



    //創建互斥信號量

    mutexHandle = osMutexCreate(osMutex(MUTEX));



    timHandle = osTimerCreate(osTimer(TIM), osTimerPeriodic, NULL);

}





void StartDefaultTask(void const * argument)

{

    for(;;)

    {

        osDelay(11);

    }

}





void Led0Task(void const * argument)

{

    while(1)

    {

        GPIO_SetBits(GPIOB,GPIO_Pin_5);

        osDelay(200);

        GPIO_ResetBits(GPIOB,GPIO_Pin_5);

        osDelay(200);

    }

}





void Led1Task(void const * argument)

{

    while(1)

    {

        GPIO_SetBits(GPIOE,GPIO_Pin_5);

        osDelay(155);

        GPIO_ResetBits(GPIOE,GPIO_Pin_5);

        osDelay(155);

    }

}







void PrintTask(void const * argument)

{

    while(1)

    {

        osDelay(100);

    }

}





/*軟件定時器使用

**實現軟件精確延時

*/



static void timcCallbackFunction()

{

//     printf("i am timer\r\n");

         LED1 = !LED1;

}



void TimTask(void const * argument)

{

    uint16_t cnt = 0;

         osTimerStart(timHandle, 100);

         while(1)

         {

                 ++cnt;

                 if(cnt == 10)

                 {

                          osTimerStop(timHandle);

                 }

                 if(cnt == 20)

                 {

                          osTimerStart(timHandle, 300);

                 }

                 GPIO_ResetBits(GPIOB,GPIO_Pin_5);

                 osDelay(200);

                 GPIO_SetBits(GPIOB,GPIO_Pin_5);

                 osDelay(200);

         }

}





/*互斥信號量

**保證一個資源在一個時刻只能由一個任務訪問

**和信號量使用方式一樣

*/

void Mutex1RecvTask(void const * argument)

{

    osStatus err;

    while(1)

    {

        err = osMutexWait(mutexHandle,osWaitForever);

        //err = osSemaphoreWait(semaHandle, osWaitForever);

        if(osOK == err)

        {

            printf("led0 recv mutexsem!\r\n");

        }

        err = osMutexRelease(mutexHandle);

        //err = osSemaphoreRelease(semaHandle);

        GPIO_ResetBits(GPIOB,GPIO_Pin_5);

        osDelay(200);

        GPIO_SetBits(GPIOB,GPIO_Pin_5);

        osDelay(200);

    }

}



void Mutex2RecvTask(void const * argument)

{

    osStatus err;

    while(1)

    {

        err = osMutexWait(mutexHandle,osWaitForever);

        //err = osSemaphoreWait(semaHandle, osWaitForever);

        if(osOK == err)

        {

            printf("led1 recv mutexsem!\r\n");

        }

        err = osMutexRelease(mutexHandle);

        //err = osSemaphoreRelease(semaHandle);

        GPIO_SetBits(GPIOE,GPIO_Pin_5);

        osDelay(200);

        GPIO_ResetBits(GPIOE,GPIO_Pin_5);

        osDelay(200);

    }

}



/*消息郵箱

**和消息隊列使用十分類似

***/

void MailSendTask(void const * argument)

{

    uint16_t cnt = 0;

    osStatus err;

    while(1)

    {

        ++cnt;

        if(cnt % 9 == 0)

        {

            err = osMailPut(mailHandle, (uint8_t *)"say hi");

            if(osOK != err)

            {

                printf("send error\r\n");

            }

            else

            {

                printf("send ok\r\n");

            }

        }

        GPIO_ResetBits(GPIOB,GPIO_Pin_5);

        osDelay(200);

        GPIO_SetBits(GPIOB,GPIO_Pin_5);

        osDelay(200);

    }

}



void MailRecvTask(void const * argument)

{

    osEvent event;

    while(1)

    {

        event = osMailGet(mailHandle, osWaitForever);

        if(event.status == osEventMail)

        {

            if(event.def.mail_id == mailHandle)

            {

                printf("lend1 recv val:%s\r\n",(uint8_t *)event.value.p);

            }

        }

        //接收到郵箱後才執行

        GPIO_SetBits(GPIOE,GPIO_Pin_5);

        osDelay(155);

        GPIO_ResetBits(GPIOE,GPIO_Pin_5);

        osDelay(155);

    }

}





/*消息隊列

**主要就是掌握這put和get兩個函數

**以及看下這個結構體,如何取出消息來

typedef struct  {

  osStatus                 status;     ///< status code: event or error information

  union  {

    uint32_t                    v;     ///< message as 32-bit value

    void                       *p;     ///< message or mail as void pointer

    int32_t               signals;     ///< signal flags

  } value;                             ///< event value

  union  {

    osMailQId             mail_id;     ///< mail id obtained by \ref osMailCreate

    osMessageQId       message_id;     ///< message id obtained by \ref osMessageCreate

  } def;                               ///< event definition

} osEvent;

***/

void MsgQSendTask(void const * argument)

{

    uint16_t cnt = 0;

    osStatus err;

    while(1)

    {

        ++cnt;

        if(cnt % 9 == 0)

        {

            err = osMessagePut(msgHandle, (uint32_t)"say", osWaitForever);

            if(osOK != err)

            {

                printf("send error\r\n");

            }

            else

            {

                printf("send ok\r\n");

            }

            //發送整型

            //osMessagePut(msgHandle, 5, osWaitForever);

        }

        GPIO_ResetBits(GPIOB,GPIO_Pin_5);

        osDelay(200);

        GPIO_SetBits(GPIOB,GPIO_Pin_5);

        osDelay(200);

    }

}



void MsgQRecvTask(void const * argument)

{

    osEvent event;

    while(1)

    {

        event = osMessageGet(msgHandle, osWaitForever);

        if(event.status == osEventMessage)

        {

            if(event.def.message_id == msgHandle)

            {

                printf("lend1 recv val:%s\r\n",(uint8_t *)event.value.p);

            }

        }



        //只有收到消息後才執行

        GPIO_SetBits(GPIOE,GPIO_Pin_5);

        osDelay(155);

        GPIO_ResetBits(GPIOE,GPIO_Pin_5);

        osDelay(155);

    }

}





/*信號發送和接收



**int32_t osSignalSet (osThreadId thread_id, int32_t signal);

**thread_id:發送到哪個任務

**signal   :信號值,用二進制表示



**osEvent osSignalWait (int32_t signals, uint32_t millisec);

**signals:信號值,跟平時寫的那種flag一樣,不過這個可以接收多個任務發送來的信號按位判斷

**millisec:等待延時

*/

void SingalSendTask(void const * argument)

{

    osEvent event;

    while(1)

    {

        event = osSignalWait(0x04,100);

        if(event.status == osEventSignal)

        {

            if(event.value.signals &0x04)

            {

                printf("lend0 recv val:%d\r\n",event.value.signals);

            }

        }



        osSignalSet(led1TaskHandle,0x08);

        GPIO_ResetBits(GPIOB,GPIO_Pin_5);

        osDelay(200);

        GPIO_SetBits(GPIOB,GPIO_Pin_5);

        osDelay(200);

    }

}





void SingalRecvTask(void const * argument)

{

    uint16_t cnt = 0;

    osEvent event;



    while(1)

    {

        ++cnt;

        if(cnt % 9 == 0)

        {

            printf("task led1 running times: %d\r\n",cnt);

            osSignalSet(led0TaskHandle,0x04);

        }



        event = osSignalWait(0x08,100);

        if(event.status == osEventSignal)

        {

            if(event.value.signals &0x08)

            {

                printf("led1 recv val:%d\r\n",event.value.signals);

            }

        }

        GPIO_SetBits(GPIOE,GPIO_Pin_5);

        osDelay(155);

        GPIO_ResetBits(GPIOE,GPIO_Pin_5);

        osDelay(155);

    }

}









/*信號量的接收和釋放



**osSemaphoreId semaHandle;//創建句柄

**osSemaphoreDef(se);  //定義

**semaHandle = osSemaphoreCreate(osSemaphore(se), 1);創建信號量

**osSemaphoreRelease(semaHandle);釋放到另一個任務

**osSemaphoreWait(semaHandle, osWaitForever);接收

*/





void SemRecvTask(void const * argument)

{

    osStatus sem;

    while(1)

    {

        sem = (osStatus)osSemaphoreWait(semaHandle, osWaitForever);

        if(sem == osOK)

        {

            /*

            **TODO

            */

            //printf("get it %d\r\n", (uint16_t)semaHandle);

        }

        osSemaphoreRelease(semaHandle);

        osDelay(500);

    }

}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章