当前位置:网站首页>基于GD32F1x0手动编程实现简易freertos之任务阻塞延时
基于GD32F1x0手动编程实现简易freertos之任务阻塞延时
2022-04-22 20:46:00 【木子芯双】
上篇博客讲述了简易FreeRtos的任务创建、堆栈分配、任务启动、任务切换及任务抢占的实现过程,本篇将讲述freertos中任务阻塞延时的实现过程。在FreeRtos中优先级划分制度非常严格,跟封建社会的等级划分差不多,不同的任务根据优先级的不同被划分为三六九等,当高优先级的任务在执行时,低优先级的任务永远不可能获得CPU的控制权。那这很明显是霸权主义么,如果没有好的解决方法安抚优先级低的任务,那优先级低的任务肯定会聚众闹事,增加整个Rtos系统的不稳定性。所以呢?那肯定是有相关安抚民心的政策了,高优先级的任务大口吃肉,总得允许低优先级的喝点肉汤吧(开个小玩笑)。所以低优先级的任务需要运行获得CPU的控制权,那就是让高优先级的任务进入阻塞延时,什么意思呢?就是将高优先级的任务暂时从就绪列表移除,将其放入一个延时列表,等一段时间后再将其从延时列表中移除,再次加入就绪列表。这样在就绪列表移除高优先级任务的那段时间,低优先级的任务(也就是说高优先级任务吃完肉了,低优先级可以进去喝汤啦!)不就可以执行啦!
1、任务计数器函数实现
这个函数主要是在systick中断实现,判断是否有任务阻塞时间到,需要加入就绪列表,没有任务要解除阻塞时,则执行同优先级的下一个任务,根据返回值是否为1来确定是否触发PendSv任务切换中断,代码实现如下:
/*! \brief SysTick Handler \param[in] none \arg none \param[out] none \retval none */
void SysTick_Handler(void)
{
if(xSchedulerRunning!=0){
if(TaskIncrementTick()){
/* Pend a context switch. */
*( portNVIC_INT_CTRL ) = portNVIC_PENDSVSET;/* 触发一个PendSv中断 */
}
}
}
/*! \brief task increment count \param[in] none \arg none \param[out] none \retval task switch flag */
uint32_t TaskIncrementTick(void)
{
Task* pxTCB=NULL;
uint32_t xItemValue=0,xSwitchRequired =0;
/*如果任务调度器没有被挂起*/
if(uxSchedulerSuspended ==0){
xTickCount+=1;//计数器值加1,这是一个全局变量
if(xTickCount>=xNextTaskUnblockTime){
//如果计数器的值大于等于下一个任务的阻塞时间时,说明有任务需要解除阻塞延时
if(xDelayedTaskList.list_number==0){
//此时阻塞延时列表的元素为空,说明没有任务需要解除阻塞
xNextTaskUnblockTime=0xffffffff;//那么就将下一个任务的阻塞时间设置为最大值。
}else{
/*如果阻塞延时列表的元素不为空,则将阻塞时间到的任务解除阻塞*/
pxTCB=xDelayedTaskList.xListEnd.pxNext->pvOwner;//获取下一个要解除阻塞延时的任务
xItemValue=pxTCB->xStateListItem.ItemValue;//获取它要阻塞的时间
if(xTickCount < xItemValue){
/*如果计数器的时间小于该任务的阻塞时间,说明该任务还未到解除阻塞*/
xNextTaskUnblockTime=xItemValue;//将下一次要解除阻塞的时间值更新为该任务的阻塞时间值
}else{
uxListRemove(&pxTCB->xStateListItem);//将该任务从延时列表移除
AddNewTaskToReadyList(pxTCB);//将该任务重新加入就绪列表
}
if((&pxTCB->xEventListItem)!=NULL){
/*如果事件列表不为空,说明该任务在等待信号量 */
uxListRemove(&pxTCB->xEventListItem);//也将该任务事件列表从阻塞列表中移除,说明等待信号量超时
}
if(pxTCB->uxPriority >= pxCurrentTCB->uxPriority){
xSwitchRequired=1;//如果解除阻塞的任务优先级大于当前任务,那就需要执行一次任务切换了
}
}
}
if(pxReadyTasksLists[pxCurrentTCB->uxPriority].list_number >= 1){
xSwitchRequired=1;//同优先级的其他任务按时间片轮流执行,也需要进行一次任务切换
}
}else{
++xPendedTicks;//当调度器挂起时,任务计数器增加
}
return xSwitchRequired;//返回任务切换标志位
}
2、任务阻塞延时函数实现
加入延时列表的任务按阻塞延时的时间从小到大排列,则阻塞时间到,依次解除阻塞。阻塞延时函数代码如下:
/*! \brief task blocking delay \param[in] xTicksToDelay \arg delay value \param[out] none \retval none */
void vTaskDelay(const uint32_t xTicksToDelay)
{
uint32_t xAlreadyYielded =0;
if(xTicksToDelay > 0){
vTaskSuspendAll();//将任务调度器挂起
prvAddCurrentTaskToDelayedList( xTicksToDelay,0);//将任务加入阻塞延时列表,这另外一个参数是是否允许加入挂起列表
xAlreadyYielded=xTaskResumeAll();//恢复任务调度器
}
if(xAlreadyYielded==0){
//恢复任务调度器后,需要执行一次上下文切换
*( portNVIC_INT_CTRL ) = portNVIC_PENDSVSET;/*trigger a PendSv interrupt */
}
}
/*! \brief task increment count \param[in] none \arg none \param[out] none \retval task switch flag */
void prvAddCurrentTaskToDelayedList( uint32_t xTicksToWait, const uint32_t xCanBlockIndefinitely)
{
uint32_t xTimeToWake;
const uint32_t xConstTickCount = xTickCount;//获取任务计数器
uxListRemove( &( pxCurrentTCB->xStateListItem ) );//将当前任务从就绪列表移除
if( ( xTicksToWait == 0xffffffff ) && ( xCanBlockIndefinitely !=0 ) ){
//如果任务阻塞的时间为最大值,且允许将任务加入挂起列表
vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );//则将任务加入挂起列表
}else{
xTimeToWake = xConstTickCount + xTicksToWait;//计算任务阻塞延时,当前的计数值加上任务需要阻塞的时间,也就是相对延时
pxCurrentTCB->xStateListItem.ItemValue= xTimeToWake;//该任务状态列表的Value值为需要阻塞的时间。
if(xTimeToWake < xConstTickCount){
/*任务计数器值溢出 */
vListInsert(&pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );//则将阻塞任务加入溢出延时列表
}else{
vListInsert( &xDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );//阻塞任务加入延时列表。
if(xTimeToWake < xNextTaskUnblockTime){
xNextTaskUnblockTime = xTimeToWake;//如果该阻塞任务的阻塞时间小于下一个要解除阻塞的任务时间,则更新下一个解除阻塞时间
}
}
}
}
3、实验验证
该实验是创建了TaskA、TaskB及TaskC,任务A和B的优先级为2,任务C的优先级为3,systick中断时间为10ms,当任务C运行500次后,将任务C进入阻塞时间3秒,这个时候任务A和任务B轮流执行。实验现象为C执行一段时间后,A和B轮流执行,之后C又执行,A和B又轮流执行…,这样高优先级的任务和低优先级的任务不就都可以执行了么。代码如下:
/*! \file main.c \brief led spark with systick */
#include "gd32f1x0.h"
#include <stdio.h>
#include "main.h"
#include "gd32f1x0_eval.h"
#include "task.h"
__align(4) static char Task_Stack_A[512]={
0};
__align(4) static char Task_Stack_B[512]={
0};
__align(4) static char Task_Stack_C[512]={
0};
void Task_A(void);
void Task_B(void);
void Task_C(void);
__align(4) Task TCB_A,TCB_B,TCB_C;
/*! \brief main function \param[in] none \param[out] none \retval none */
int main(void)
{
gd_eval_com_init(EVAL_COM1);
Creat_Task(Task_A,128,2,&TCB_A,Task_Stack_A);
Creat_Task(Task_B,128,2,&TCB_B,Task_Stack_B);
Creat_Task(Task_C,128,2,&TCB_C,Task_Stack_C);
Task_Start();
//while (1);
}
void Task_A(void)
{
while(1){
printf("taskA is running!!!\n");
}
}
void Task_B(void)
{
while(1){
printf("taskB is running!!!\n");
}
}
void Task_C(void)
{
uint16_t num=0;
while(1){
printf("taskC is running!!!\n");
#if 1
num++;
if(num==500){
num=0;
vTaskDelay(300);
}
#endif
}
}
/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
usart_data_transmit(EVAL_COM1, (uint8_t)ch);
while(RESET == usart_flag_get(EVAL_COM1, USART_FLAG_TBE));
return ch;
}
代码我已上传到https://download.csdn.net/download/qq_31446727/85163156地址,大家可下载测试,如有不解或者不对的地方,欢迎大家在博文下留言,大家互相交流,共同学习进步!!!
版权声明
本文为[木子芯双]所创,转载请带上原文链接,感谢
https://blog.csdn.net/qq_31446727/article/details/124232001
边栏推荐
- - 4. 比较字符串 (10 分)C语言标准函数库中包括 strcmp 函数,用于字符串的比较。作为练习,我们自己编写一个功能与之相同的函数。
- leetcode222、完全二叉树的节点个数
- Use of swift protocol
- L1-046 divide singles
- What is a SAML assertion?
- Error running ‘JeecgSystemApplication‘: Command line is too long. Shorten command line for JeecgSyst
- Add / remove / filter / sort array elements
- MySQL 进阶 存储过程 存储函数 -- 存储过程介绍、存储过程基本语法、变量(系统变量、用户定义变量、局部变量)、if、参数、case、while、repeat、loop、游标、条件处理程序
- Matlab learning notes - calculate eigenvectors and manually execute PCA
- 京东新品情报局剧透OPPO K10系列 或联动国漫IP带来惊喜?
猜你喜欢

MySQL 进阶 触发器 -- 触发器介绍、触发器语法、触发器案例

Asynchronous replication of MySQL master-slave replication

Postman tests the correct posture of array, list and map input APIs

如何让机器人更像“人”,让slam更灵活?

未授权访问漏洞总结

中美程序员对比:你认同吗

@Requestmapping get request parameters

H. Maximal AND

Design and analysis of MySQL high availability architecture

Active mode and passive mode of FTP
随机推荐
leetcode-92-反转链表
Domain name resolution process
Dynamic database tool -- database inspector
How to make robots more like "people" and make slams more flexible?
MySQL主从复制之GTID复制
【办公】PPT制作流程
The interviewer would rather have my younger brother who has just graduated and worked for one year than me who has worked for five years, with an annual salary of 25W
Improving Few-Shot Part Segmentation using Coarse Supervision学习笔记
MATLAB学习笔记 - 计算特征向量手动执行PCA
October's Android interview failed miserably in byte three, and fortunately won Xiaomi offer
智慧农业成为发展道路,充分发挥智能化,解放人力
MySQL learning notes
Use of list
Better implementation ideas based on MySQL in some scenarios (continuous update)
Time and date formatting
做了5年Android,靠着这份190页的面试资料,成功入职腾讯
Soochow securities x kangaroo cloud: the data is easily available and has millisecond response ability. What did Soochow securities do right?
Displays the difference between an implementation interface and an implicit implementation interface
Perfect forwarding implementation mechanism
MySQL主从复制之异步复制