嵌入式:FreeRTOS的使用(未完)

摘要:
为了便于与UCOS进行比较,它按照UCOS的顺序进行编译。

为了方便与UCOS对比,顺序按照UCOS那篇编写。

0、一些移植、系统相关 

1、框架写法(个人习惯相关)

1-1、main 函数里创建一个开始任务

int main(void)
{
	初始化外设
	
    xTaskCreate();   		//创建开始任务   
				
    vTaskStartScheduler(); 	//开启任务调度
}

1-2、开始任务里,创建我们要运行的多个任务

void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区

    xTaskCreate(); 	//创建任务  1 
    xTaskCreate(); 	//创建任务  2 
    xTaskCreate(); 	//创建任务  3 
	
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}

2、任务创建、挂起、删除

2-0、相关配置

#define configSUPPORT_DYNAMIC_ALLOCATION        1                       //支持动态内存申请
//#define configSUPPORT_STATIC_ALLOCATION        	1                       //支持静态内存申请
#define configTOTAL_HEAP_SIZE					((size_t)(20*1024))     //系统所有总的堆大小,heap_x.h需要,动态申请

2-1、任务创建(动态)

//==================任务创建宏定义,便于修改==================

#define START_TASK_PRIO			1		//任务优先级
#define START_STK_SIZE 			256  	//任务堆栈大小

TaskHandle_t StartTask_Handler;			//任务句柄
void start_task(void *pvParameters);	//任务函数

//==================任务创建函数==================

xTaskCreate((TaskFunction_t )start_task,            //任务函数
			(const char*    )"start_task",          //任务名称
			(uint16_t       )START_STK_SIZE,        //任务堆栈大小
			(void*          )NULL,                  //传递给任务函数的参数
			(UBaseType_t    )START_TASK_PRIO,       //任务优先级
			(TaskHandle_t*  )&StartTask_Handler);   //任务句柄     

2-2、任务挂起

vTaskSuspend(Task1Task_Handler);	//挂起任务1

2-3、任务解挂

2-3-1、任务内任务解挂

vTaskResume(Task1Task_Handler);	//恢复任务1

2-3-2、中断内任务解挂

BaseType_t YieldRequired;

YieldRequired=xTaskResumeFromISR(Task1Task_Handler);    //恢复任务1

portYIELD_FROM_ISR(YieldRequired);    //判断是否需要调度到恢复的任务

2-4、任务删除

vTaskDelete(Task1Task_Handler);    //删除任务1

2-5、任务创建(静态)

2-5-1、静态任务创建

//==================任务创建宏定义,便于修改==================

#define START_TASK_PRIO		1				//任务优先级
#define START_STK_SIZE 		128  			//任务堆栈大小	

StackType_t StartTaskStack[START_STK_SIZE];	//任务堆栈
StaticTask_t StartTaskTCB;					//任务控制块

TaskHandle_t StartTask_Handler;				//任务句柄
void start_task(void *pvParameters);		//任务函数

//==================任务创建函数==================

StartTask_Handler=xTaskCreateStatic((TaskFunction_t	)start_task,		//任务函数
									(const char* 	)"start_task",		//任务名称
									(uint32_t 		)START_STK_SIZE,	//任务堆栈大小
									(void* 		  	)NULL,				//传递给任务函数的参数
									(UBaseType_t 	)START_TASK_PRIO, 	//任务优先级
									(StackType_t*   )StartTaskStack,	//任务堆栈
									(StaticTask_t*  )&StartTaskTCB);	//任务控制块     

2-5-2、静态创建任务还需实现 空闲任务、定时任务

//==================任务创建宏定义,便于修改==================

static StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE];			//空闲任务任务堆栈
static StaticTask_t IdleTaskTCB;									//空闲任务控制块

static StackType_t TimerTaskStack[configTIMER_TASK_STACK_DEPTH];	//定时器服务任务堆栈
static StaticTask_t TimerTaskTCB;									//定时器服务任务控制块

//==================任务创建函数==================

//获取空闲任务地任务堆栈和任务控制块内存
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, 
								   StackType_t **ppxIdleTaskStackBuffer, 
								   uint32_t *pulIdleTaskStackSize)
{
	*ppxIdleTaskTCBBuffer=&IdleTaskTCB;
	*ppxIdleTaskStackBuffer=IdleTaskStack;
	*pulIdleTaskStackSize=configMINIMAL_STACK_SIZE;
}

//获取定时器服务任务的任务堆栈和任务控制块内存
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, 
									StackType_t **ppxTimerTaskStackBuffer, 
									uint32_t *pulTimerTaskStackSize)
{
	*ppxTimerTaskTCBBuffer=&TimerTaskTCB;
	*ppxTimerTaskStackBuffer=TimerTaskStack;
	*pulTimerTaskStackSize=configTIMER_TASK_STACK_DEPTH;
}

  

3、时间片轮转

3-0、相关配置(时间片片长 即 1/Tick中断频率)

#define configUSE_PREEMPTION					1                       //1使用抢占式内核,0使用协程
#define configUSE_TIME_SLICING					1						//1使能时间片调度(默认式使能的)
#define configTICK_RATE_HZ						(20)                  	//时钟节拍频率,20HZ = 50ms

3-1、两个任务优先级相等

#define TASK1_TASK_PRIO		2
#define TASK1_STK_SIZE 		128  
TaskHandle_t Task1Task_Handler;
void task1_task(void *pvParameters);

#define TASK2_TASK_PRIO		2
#define TASK2_STK_SIZE 		128  
TaskHandle_t Task2Task_Handler;
void task2_task(void *pvParameters);

4、钩子函数。

4-0、相关配置

#define configUSE_IDLE_HOOK						1                       //1,使用空闲钩子;0,不使用
#define configUSE_TICK_HOOK						1                       //1,使用时间片钩子;0,不使用

4-1、自己实现钩子函数

void vApplicationIdleHook( void );        //空闲钩子函数
void vApplicationTickHook( void );        //时钟节拍钩子函数


5、软件定时器

5-1、软件定时器创建

//==============定时器结构体、函数声明==============

TimerHandle_t 	MyTimer_Handle;    //定时器句柄
void ReloadCallback(TimerHandle_t xTimer); 		//定时器回调函数

//==============定时器创建==============

MyTimer_Handle=xTimerCreate((const char*		)"ReloadTimer",			//定时器名称
							(TickType_t			)1000,					//周期1s(1000个时钟节拍)
							(UBaseType_t		)pdTRUE,				//周期模式
							(void*				)1,						//定时器ID
							(TimerCallbackFunction_t)ReloadCallback);	//定时器回调函数

5-2、定时器“中断服务函数”,回调函数

void ReloadCallback(TimerHandle_t xTimer)
{
    //do something
}

5-3、定时器开启(也有复位效果)

xTimerStart(MyTimer_Handle,0);	//开启定时器

5-4、定时器停止

xTimerStop(MyTimer_Handle,0); 	//关闭定时器

5-5、定时器复位

xTimerReset(MyTimer_Handle, 0)

6、消息队列

6-1、消息队列创建

//================消息队列宏定义================
 
#define MESSAGE_Q_NUM   4   		//发送数据的消息队列的数量 
#define MESSAGE_Q_ITEM_NUM	200		//每个消息的空间大小
QueueHandle_t Message_Queue;		//信息队列句柄
 
//================消息队列创建================

Message_Queue=xQueueCreate(MESSAGE_Q_NUM,MESSAGE_Q_ITEM_NUM);

6-2、消息发送

6-2-1、任务内消息发送

u8 sendData[MESSAGE_Q_ITEM_NUM];
BaseType_t err;

err=xQueueSend(Message_Queue,&senddata,10);    //10为发送等待时间,有可能队列已满,err = errQUEUE_FULL 或 err = pdPASS

6-2-2、中断内消息发送

u8 sendData[MESSAGE_Q_ITEM_NUM];
BaseType_t xHigherPriorityTaskWoken;

xQueueSendFromISR(Message_Queue,sendData,&xHigherPriorityTaskWoken);    //向队列中发送数据,返回值,依然是 满了或Pass,第三个参数是判断高优先级接受到队列后,退出中断,是否需要调度

portYIELD_FROM_ISR(xHigherPriorityTaskWoken);//如果需要的话进行一次任务切换

6-3、消息接收

6-3-1、任务内消息接收

u8 *receiveData;

xQueueReceive(Message_Queue,receiveData,portMAX_DELAY)    //返回值为pdPASS 或 errQUEUE_EMPTY,这里等待时间用了portMAX_DELAY阻塞,所以不用再判断了。

6-3-2、中断内消息接收

u8 *receiveData;

err=xQueueReceiveFromISR(Message_Queue,receiveData,&xTaskWokenByReceive); //向队列中接受数据,返回值, FAIL或Pass,第三个参数是判断高优先级接受到队列后,退出中断,是否需要调度

portYIELD_FROM_ISR(xTaskWokenByReceive);//如果需要的话进行一次任务切换

6-4、队列剩余大小

u8 remain_size;		//消息队列剩余大小

remain_size=uxQueueSpacesAvailable(Message_Queue);	//得到队列剩余大小

6-5、队列使用大小

u8 used_size;		//消息队列使用大小

used_size=uxQueueMessagesWaiting(Message_Queue);	//得到队列使用大小

7、二值信号量(还有静态创建函数、中断内接受/发送函数,基本同上,不再重复)

7-1、二值信号量创建

SemaphoreHandle_t BinarySemaphore;	//二值信号量句柄

BinarySemaphore=xSemaphoreCreateBinary();	//创建二值信号量	

7-2、二值信号量等待

BaseType_t err;

err = xSemaphoreTake(BinarySemaphore,portMAX_DELAY);	//获取信号量

7-3、二值信号量发送

BaseType_t err;

err = xSemaphoreGive(BinarySemaphore);	//释放二值信号量

  

8、计数信号量(还有静态创建函数、中断内接受/发送函数,基本同上,不再重复)

8-1、计数信号量创建

SemaphoreHandle_t CountSemaphore;//计数型信号量

CountSemaphore=xSemaphoreCreateCounting(255,0);		//创建计数型信号量,最大计数和初始化计数,参数没改动的话,为long,所以最大值可以设计为不止255

8-2、计数信号量等待

UBaseType_t semavalue;

xSemaphoreTake(CountSemaphore,portMAX_DELAY); 	//等待数值信号量,阻塞

semavalue=uxSemaphoreGetCount(CountSemaphore); 	//获取数值信号量值

8-3、计数信号量发送

BaseType_t err;

err=xSemaphoreGive(CountSemaphore);//释放计数型信号量

 

9、互斥信号量(还有静态创建函数,在中断不能用互斥信号量)

9-1、互斥信号量创建

SemaphoreHandle_t MutexSemaphore;	//互斥信号量

MutexSemaphore=xSemaphoreCreateMutex();		//创建互斥信号量

9-2、互斥信号量等待

xSemaphoreTake(MutexSemaphore,portMAX_DELAY);	//获取互斥信号量,因为是阻塞,也就不需要查看什么返回值

9-3、互斥信号量发送

xSemaphoreGive(MutexSemaphore);					//释放互斥信号量

  

10、递归互斥信号量(还有静态创建函数,在中断不能用递归互斥信号量)

10-1、递归互斥信号量创建

SemaphoreHandle_t RecursiveMutex;

RecursiveMutex = xSemaphoreCreateRecursiveMutex();        //创建递归互斥信号量

10-2、递归互斥信号量等待

xSemaphoreTakeRecursive(RecursiveMutex,10);        //10为等待节拍

10-3、递归互斥信号量发送

xSemaphoreGiveRecursive(RecursiveMutex);        //发送递归互斥信号量

11、事件标记组(还有静态创建函数、中断内接受/发送函数,基本同上,不再重复)

11-1、事件标记组创建

//例子:3个事件
#define EVENTBIT_0	(1<<0)				
#define EVENTBIT_1	(1<<1)
#define EVENTBIT_2	(1<<2)
#define EVENTBIT_ALL	(EVENTBIT_0|EVENTBIT_1|EVENTBIT_2)


EventGroupHandle_t EventGroupHandler;	        //事件标志组句柄

EventGroupHandler=xEventGroupCreate();	 //创建事件标志组

11-2、事件标记组置位

xEventGroupSetBits(EventGroupHandler,EVENTBIT_1);        //事件1置位

11-3、事件标记组清除置位

xEventGroupClearBits(EventGroupHandler,EVENTBIT_1);        //事件1清除

11-4、事件标记组值获取

EventBits_t NewValue;

NewValue = xEventGroupGetBits(EventGroupHandler);	//获取事件组的

11-5、事件标记位组等待

EventValue=xEventGroupWaitBits((EventGroupHandle_t	)EventGroupHandler,		//句柄	
							   (EventBits_t			)EVENTBIT_ALL,			//标志位
							   (BaseType_t			)pdTRUE,				//获取成功后 清除	
							   (BaseType_t			)pdTRUE,				//等待所有标志位 置位
							   (TickType_t			)portMAX_DELAY);		//阻塞

12、内存管理

12-1、内存申请

u8 *buffer;

buffer=pvPortMalloc(30);			//申请内存,30个字节

12-2、内存释放

vPortFree(buffer);	//释放内存

12-3、获取内存剩余空间

u32 freeSize;

freeSize = xPortGetFreeHeapSize();		//获取剩余内存大小

 13、通知

13-1、通知事件发送(++)

xTaskNotifyGive(task_Handler);    //给task_Handler发送个通知

13-2、通知事件获取(--,并根据参数是否清0)

u32 NotifyValue;

NotifyValue=ulTaskNotifyTake(pdTRUE,portMAX_DELAY);	    //获取任务通知,参数1,读完清0,参数2阻塞

13-3、通知值发送

13-3-1、通知值发送(设置通知值,可发送一个数据)

u8 data;
BaseType_t err;

err=xTaskNotify((TaskHandle_t	)Task_Handler,		//接收任务通知的任务句柄
				(uint32_t		)data,						//任务通知值
				(eNotifyAction	)eSetValueWithOverwrite);	//覆写的方式发送任务通知

13-3-2、通知值发送(设置通知值,可做标记位组)

#define EVENTBIT_1	(1<<1)

xTaskNotify((TaskHandle_t	)Task_Handler,		//接收任务通知的任务句柄
			(uint32_t		)EVENTBIT_1,		//要更新的bit
			(eNotifyAction	)eSetBits);			//更新指定的bit

13-4、通知值获取(获取通知值,并判断是否需要清0)

BaseType_t err;
uint32_t NotifyValue;

err=xTaskNotifyWait((uint32_t	)0x00,				//进入函数,没有接受到通知,不清除任何bit
					(uint32_t	)ULONG_MAX,			//退出函数,接受到通知,清除所有(0xffffffffUL)位的bit,
					(uint32_t*	)&NotifyValue,		//保存任务通知值
					(TickType_t	)portMAX_DELAY);	//阻塞时间

  

  

================================================ 为了好与UCOS的文章对比,这些内容也放下面================================================

1、中断

1-0、相关配置

#ifdef __NVIC_PRIO_BITS
	#define configPRIO_BITS       		__NVIC_PRIO_BITS	//STM32库自带
#else
	#define configPRIO_BITS       		4  					//STM32提供4Bit的中断优先级	
#endif

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY			15                      //中断最低优先级
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY	5                       //系统可管理的最高中断优先级
#define configKERNEL_INTERRUPT_PRIORITY 			( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )	//内核中断优先级,用来配置上下文切换、时钟节拍优先级,因为STM32优先级寄存器用高4位,所以要左移
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )	//用来屏蔽中断的阈值,左移原因同上



#define xPortPendSVHandler 	PendSV_Handler
#define vPortSVCHandler 	SVC_Handler

1-1、中断处理

无需特殊处理

2、临界段处理

2-1、任务内临界段处理

taskEXIT_CRITICAL();

//任务处理

taskEXIT_CRITICAL();

2-2、中断内临界段处理

taskENTER_CRITICAL_FROM_ISR();

//中断内处理

taskEXIT_CRITICAL_FROM_ISR();

3、引起调度函数

3-1、延时

 vTaskDelay(1000);                           //延时1000个时钟节拍,也就是1s

免责声明:文章转载自《嵌入式:FreeRTOS的使用(未完)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇【电路】DC风扇控制kafka客户端和服务端开发(三)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

痞子衡嵌入式:ARM Cortex-M内核那些事(5)- 一表搜罗指令集

  大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是ARM Cortex-M指令集。 指令集 指令长度(bits) 包含指令 CortexM0 CortexM0+ CortexM1 CortexM3 CortexM4 CortexM7 CortexM23 CortexM33 Thumb-1 16 ADC, ADD, ADR, AN...

[JIT_APP]Java基础知识总结

一、Java语言的基础知识 1. 开发Java语言的公司 美国Sun(Sum Microsystems)公司开发。 2.Java的3个版本 J2SE(Java2 Standard Edition) 标准版,是为开发普通桌面和商务应用程序提供的解决方案。该技术体系是其他两者的基础,可以完成一些桌面应用程序的开发。比如Java版的扫雷。平时所说的JDK...

笔记之Cyclone IV第一卷第四章Cyclone IV器件中的嵌入式乘法器

嵌入式乘法器可以配置成一个 18 × 18 乘法器,或者配置成两个 9 × 9 乘法器。对于那些大于18 × 18 的乘法运算 ,QuartusII 软件会将多个嵌入式乘法器模块级联在一起。虽然没有乘法器数据位宽的限制,但数据位宽越大,乘法运算就会越慢。 除了 Cyclone IV 器件中的嵌入式乘法器,通过将 M9K 存储器模块用作查找表 (LUT) 可...

蜂鸟E203系列——嵌入式软件环境

目录 安装串口显示 安装konsole 安装screen 运行hbird demo程序 打开控制台 编译 demo 程序 下载程序 结果显示 运行 coremark 跑分程序 运行 dhrystone 跑分程序 参考文档 目录 安装串口显示 安装konsole 安装screen 运行hbird demo程序 打开控制台 编...

MiniMapX简介

MiniMapX简介    MiniMapX充分考虑到了嵌入式设备资源有限的特点,从数据结构到基本算法都精益求精,对资源的消耗很低,而其性能却很优异,功能强大、系统稳定,用户能灵活定制系统,为面向嵌入式应用的GIS开发提供了方便的工具。    MiniMapX小巧精悍、开发方式灵活、资源消耗低,运行效率高,可广泛应用于测绘、国土、交通、旅游、通讯、军...

ARM Linux BenchMark【转】

转自:https://blog.csdn.net/sy373466062/article/details/49070025 背景说明 许多公司有很多不同的ARM SoC的研发产品,ARM核心可能有Cortex-A8/A9/A15,核心数可能有单核双核和四核.现在,几乎每出一款手机,网络上马上就有人对其评测.对比和评测不同ARM SoC 芯片以及嵌入式系统是...