【STM32开发】-FreeRTOS开发入手学习

一、什么是FreeRTOS?

FreeRTOS 是 RTOS 系统的一种,FreeRTOS 十分的小巧,可以在资源有限的微控制器中运行;

1、 FreeRTOS是免费的。

2、许多其他半导体厂商产品的 SDK 包就使用 FreeRTOS 作为其操作系统,尤其是 WIFI、

蓝牙这些带协议栈的芯片或模块。

3、FreeRTOS 被移植到了很多不同的微处理器上。

4、FreeRTOS 的内核支持抢占式,合作式和时间片调度。

5、FreeRTOS 系统简单、小巧、易用,通常情况下内核占用 4k-9k 字节的空间。

二、FreeRTOS移植

1、创建基础文件,添加FreeRTOS源码

portable 文件夹,需要留下 keil、MemMang 和 RVDS这三个文件夹:

最后创建基础工程,新建分组 FreeRTOS_CORE 和 FreeRTOS_PORTABLE:

2、修改SYSTEM文件

①修改sys.h文件

在 sys.h 文件里面用宏 SYSTEM_SUPPORT_OS 来定义是否使用 OS,我们使用了 FreeRTOS

cpp 复制代码
#define SYSTEM_SUPPORT_OS    1    //定义系统文件夹是否支持 OS

②修改usart.c文件

添加 FreeRTOS.h 头文件:

cpp 复制代码
#include "FreeRTOS.h"    //os 使用

使用 FreeRTOS 不需要OSIntEnter()和 OSIntExit()中断函数,将对应的代码删除:

cpp 复制代码
void USART1_IRQHandler(void)                	
{
	u8 Res;

	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) 
		{
		Res =USART_ReceiveData(USART1);	
		
		if((USART_RX_STA&0x8000)==0)
			{
			if(USART_RX_STA&0x4000)
				{
				if(Res!=0x0a)USART_RX_STA=0;
				else USART_RX_STA|=0x8000;	 
				}
			else 
				{	
				if(Res==0x0d)USART_RX_STA|=0x4000;
				else
					{
					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
					USART_RX_STA++;
					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;	  
					}		 
				}
			}   		 
     } 
} 

3、修改delay.c文件

cpp 复制代码
//systick 中断服务函数,使用 OS 时用到
void SysTick_Handler(void)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
{
xPortSysTickHandler();
}
cpp 复制代码
//初始化延迟函数
//SYSTICK 的时钟固定为 AHB 时钟,基础例程里面 SYSTICK 时钟频率为 AHB/8
//SYSCLK:系统时钟频率
{ void delay_init()
u32 reload;
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);//选择外部时钟 HCLK
fac_us=SystemCoreClock/1000000;
//不论是否使用 OS,fac_us 都需要使用
reload=SystemCoreClock/1000000;
//每秒钟的计数次数 单位为 M
reload*=1000000/configTICK_RATE_HZ;
//根据 configTICK_RATE_HZ 设定溢出
//时间 reload 为 24 位寄存器,最大值:
//16777216,在 72M 下,约合 0.233s 左右
fac_ms=1000/configTICK_RATE_HZ;
//代表 OS 可以延时的最少单位
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //开启 SYSTICK 中断
SysTick->LOAD=reload;
//每 1/configTICK_RATE_HZ 秒中断
//一次
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启 SYSTICK
}

修改延时函数:

cpp 复制代码
//延时 nus
//nus:要延时的 us 数.
//nus:0~204522252(最大值即 2^32/fac_us@fac_us=168)
void delay_us(u32 nus)
{
    u32 ticks;
    u32 told,tnow,tcnt=0;
    u32 reload=SysTick->LOAD;    //LOAD 的值
    ticks=nus*fac_us;//需要的节拍数
    told=SysTick->VAL;//刚进入时的计数器值
    while(1)
    {
        tnow=SysTick->VAL;
        if(tnow!=told)
        {
            //这里注意一下 SYSTICK 是一个递减的计数器就可以了.
            if(tnow<told)tcnt+=told-tnow;
            else tcnt+=reload-tnow+told;
            told=tnow;
            if(tcnt>=ticks)break;//时间超过/等于要延迟的时间,则退出.
        }
    };
}
/延时 nms,会引起任务调度
//nms:要延时的 ms 数
//nms:0~65535
void delay_ms(u32 nms)
{
    if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
    {
        if(nms>=fac_ms)//延时的时间大于 OS 的最少时间周期
        {
            vTaskDelay(nms/fac_ms);//FreeRTOS 延时
        }
        nms%=fac_ms;//OS 已经无法提供这么小的延时了,
                        //采用普通方式延时
    }
    delay_us((u32)(nms*1000));//普通方式延时
}
//延时 nms,不会引起任务调度
//nms:要延时的 ms 数
void delay_xms(u32 nms)
{
    u32 i;
    for(i=0;i<nms;i++) delay_us(1000);
}

修改完编译。

三、关于FreeRTOS 任务

RTOS 系统的核心就是任务管理。

1、创建任务

使用函数 xTaskCreate()或 xTaskCreateStatic()来创建任务,

任务模版:

cpp 复制代码
void vATaskFunction(void *pvParameters)
{
for( ; ; )
{
    --任务应用程序--
    vTaskDelay();
}
/* 不 能 从 任 务 函 数 中 返 回 或 者 退 出 , 从 任 务 函 数 中 返 回 或 退 出 的 话 就 会 调 用
configASSERT(),前提是你定义了 configASSERT()。如果一定要从任务函数中退出的话那一定
要调用函数 vTaskDelete(NULL)来删除此任务。*/
    vTaskDelete(NULL);
}

常用函数:

1、xTaxkCreate()函数

cpp 复制代码
BaseType_t xTaskCreate(
    TaskFunction_t        pxTaskCode,
    const char * const    pcName,
    const uint16_t        usStackDepth,
    void * const          pvParameters,
    UBaseType_t           uxPriority,
    TaskHandle_t * const  pxCreatedTask )

参数:

pxTaskCode:任务函数。

pcName:任务名字,一般用于追踪和调试,任务名字长度不能超过。

configMAX_TASK_NAME_LEN。

usStackDepth:任务堆栈大小,注意实际申请到的堆栈是 usStackDepth 的 4 倍。其中空闲任

务的任务堆栈大小为 configMINIMAL_STACK_SIZE。

pvParameters:传递给任务函数的参数。

uxPriotiry:任务优先级,范围 0~ configMAX_PRIORITIES-1。

pxCreatedTask: 任务句柄,任务创建成功以后会返回此任务的任务句柄,这个句柄其实就是

任务的任务堆栈。此参数就用来保存这个任务句柄。其他 API 函数可能会使用 到这个句柄。

返回值:

pdPASS: 任务创建成功。

errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY: 任务创建失败,因为堆内存不足!

2、xTaskCreateStatic()函数

cpp 复制代码
TaskHandle_t xTaskCreateStatic( TaskFunction_t        pxTaskCode,
                                const char * const    pcName,
                                const uint32_t        ulStackDepth,
                                void * const          pvParameters,
                                UBaseType_t           uxPriority,
                                StackType_t * const   puxStackBuffer,
                                StaticTask_t * const  pxTaskBuffer )

参数:

pxTaskCode:任务函数。

pcName:任务名字,一般用于追踪和调试,任务名字长度不能超过。

configMAX_TASK_NAME_LEN。

usStackDepth:任务堆栈大小,由于本函数是静态方法创建任务,所以任务堆栈由用户给出,

一般是个数组,此参数就是这个数组的大小。

pvParameters:传递给任务函数的参数。

uxPriotiry:任务优先级,范围 0~ configMAX_PRIORITIES-1。

puxStackBuffer: 任务堆栈,一般为数组,数组类型要为 StackType_t 类型。

pxTaskBuffer:任务控制块。

返回值:

NULL:

任务创建失败,puxStackBuffer 或 pxTaskBuffer 为 NULL 的时候会导致这个错误的发生。

其他值:

任务创建成功,返回任务的任务句柄。

3、 xTaskCreateRestricted()函数

cpp 复制代码
BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition,
                                    TaskHandle_t *               pxCreatedTask )

参数:

pxTaskDefinition:指向一个结构体 TaskParameters_t,这个结构体描述了任务的任务函数、

堆栈大小、优先级等。此结构体在文件 task.h 中有定义。

pxCreatedTask:任务句柄。

返回值:

pdPASS:任务创建成功。

其他值:任务未创建成功,很有可能是因为 FreeRTOS 的堆太小了

4、 vTaskDelete()函数

vTaskDelete( TaskHandle_t xTaskToDelete )

参数:

xTaskToDelete:要删除的任务的任务句柄。

返回值:

四、FreeRTOS列表和列表项

1、什么是列表?

列表概念上和链表很相似,列表用来跟踪FreeRTOS中的任务。与列表相关的全部东西都在文件list.c 和 list.h 中。结构体如下:

cpp 复制代码
typedef struct xLIST
{
    listFIRST_LIST_INTEGRITY_CHECK_VALUE
    configLIST_VOLATILE UBaseType_t    uxNumberOfItems;
    ListItem_t * configLIST_VOLATILE   pxIndex;
    MiniListItem_t                     xListEnd;
    listSECOND_LIST_INTEGRITY_CHECK_VALUE
} List_t;

2、列表项

列表项就是存放在列表中的项目,FreeRTOS 提供了两种列表项:列表项和迷你列表项。

cpp 复制代码
struct xLIST_ITEM
{
    listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
    configLIST_VOLATILE TickType_t            xItemValue;
    struct xLIST_ITEM * configLIST_VOLATILE   pxNext;
    struct xLIST_ITEM * configLIST_VOLATILE   pxPrevious;
    void *                                    pvOwner;
    void * configLIST_VOLATILE                pvContainer;
    listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
};
typedef struct xLIST_ITEM ListItem_t;

3、迷你列表项

cpp 复制代码
struct xMINI_LIST_ITEM
{
    listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE

    configLIST_VOLATILE TickType_t        xItemValue;
    struct xLIST_ITEM * configLIST_VOLATILE pxNext;
    struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;

其他初始化看管方文档。

相关推荐
无敌最俊朗@1 小时前
stm32学习之路——八种GPIO口工作模式
c语言·stm32·单片机·学习
EterNity_TiMe_2 小时前
【论文复现】STM32设计的物联网智能鱼缸
stm32·单片机·嵌入式硬件·物联网·学习·性能优化
L_cl2 小时前
Python学习从0到1 day28 Python 高阶技巧 ⑤ 多线程
学习
前端SkyRain2 小时前
后端Node学习项目-用户管理-增删改查
后端·学习·node.js
提笔惊蚂蚁2 小时前
结构化(经典)软件开发方法: 需求分析阶段+设计阶段
后端·学习·需求分析
DDDiccc2 小时前
JAVA学习日记(十五) 数据结构
数据结构·学习
腾科张老师4 小时前
为什么要使用Ansible实现Linux管理自动化?
linux·网络·学习·自动化·ansible
7yewh5 小时前
嵌入式硬件杂谈(一)-推挽 开漏 高阻态 上拉电阻
驱动开发·stm32·嵌入式硬件·mcu·物联网·硬件架构·pcb工艺
tao_sc6 小时前
luckfox-pico-max学习记录
学习
zx_zx_1236 小时前
多态的学习
c++·学习