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);

    }

}



发布了42 篇原创文章 · 获赞 12 · 访问量 1万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览