FreeRTOS的列表和列表项

列表和列表项

列表

列表是FreeRTOS中的一个数据结构,概念上和链表有点类型,是一个循环双向链表,列表被用来跟踪FreeRTOS中的任务。列表的类型是List_T,具体定义如下:

typedef struct xLIST
{listFIRST_LIST_INTEGRITY_CHECK_VALUE				/*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */configLIST_VOLATILE UBaseType_t uxNumberOfItems;ListItem_t * configLIST_VOLATILE pxIndex;			/*< Used to walk through the list.  Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */MiniListItem_t xListEnd;							/*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */listSECOND_LIST_INTEGRITY_CHECK_VALUE				/*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
} List_t;
  • listFIRST_LIST_INTEGRITY_CHECK_VALUE和listSECOND_LIST_INTEGRITY_CHECK_VALUE都是用来检查列表完整性的,需要将宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 设置为1,默认不开启。
  • uxNumberOfItems:记录列表项的数量
  • pxIndex:指向当前的列表项,可用来遍历列表,类型是ListItem_t *
  • xListEnd:作为一个标记,表示列表最后一个列表项,类型是MiniListItem_t 。
列表项

FreeRTOS提供了两种列表项:列表项(ListItem_t 类型)和迷你列表项(MiniListItem_t 类型)。对于列表项,具体定义为:

struct xLIST_ITEM
{listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE			/*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */configLIST_VOLATILE TickType_t xItemValue;			/*< The value being listed.  In most cases this is used to sort the list in descending order. */struct xLIST_ITEM * configLIST_VOLATILE pxNext;		/*< Pointer to the next ListItem_t in the list. */struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;	/*< Pointer to the previous ListItem_t in the list. */void * pvOwner;										/*< Pointer to the object (normally a TCB) that contains the list item.  There is therefore a two way link between the object containing the list item and the list item itself. */void * configLIST_VOLATILE pvContainer;				/*< Pointer to the list in which this list item is placed (if any). */listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE			/*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
};
typedef struct xLIST_ITEM ListItem_t;					/* For some reason lint wants this as two separate definitions. */
  • listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE检查列表项完整性
  • xItemValue:列表项的值
  • pxNext:指向下一个列表项
  • pxPrevious:指向前一个列表项
  • pvOwner:记录此列表项归谁拥有,通常是任务控制块
  • pvContainer:记录该列表项归哪个列表

迷你列表项:

struct xMINI_LIST_ITEM
{listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE			/*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */configLIST_VOLATILE TickType_t xItemValue;struct xLIST_ITEM * configLIST_VOLATILE pxNext;struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;

可以看出迷你列表项只是比列表项少了几个成员变量,迷你列表项所有的成员变量列表项都有。
对于列表结构体List_t中的xListEnd是MiniListItem_t类型,表示最后一个列表项,pxIndex是ListItem_t指针类型,指向真正有数据的列表项。

列表和列表项初始化

列表初始化

新创建的或者定义的列表需要对其做初始化处理,列表初始化其实就是初始化列表结构体List_t中的各个成员变量,列表的初始化通过函数vListInitialise()来完成。

void vListInitialise( List_t * const pxList )
{/* The list structure contains a list item which is used to mark theend of the list.  To initialise the list the list end is insertedas the only list entry. */pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );			/*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. *//* The list end value is the highest possible value in the list toensure it remains at the end of the list. */pxList->xListEnd.xItemValue = portMAX_DELAY;/* The list end next and previous pointers point to itself so we knowwhen the list is empty. */pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );	/*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */pxList->uxNumberOfItems = ( UBaseType_t ) 0U;/* Write known values into the list ifconfigUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}

函数的参数是一个列表

  • pxIndex 指向强制类型转换的xListEnd
  • xItemValue 列表项的值为portMAX_DELAY
    在这里插入图片描述
  • pxNext :指向自己
  • pxPrevious :指向自己
  • uxNumberOfItems :列表中的列表项数目为0

下图为初始化后的列表
在这里插入图片描述

列表项初始化
void vListInitialiseItem( ListItem_t * const pxItem )
{/* Make sure the list item is not recorded as being on a list. */pxItem->pvContainer = NULL;/* Write known values into the list item ifconfigUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
}

函数的参数是一个列表项指针,只是将列表项的pvContainer初始化为NULL
下图为列表项初始后的列表项
在这里插入图片描述

列表项插入

列表项插入相当于和在循环双向链表中按照数值的递增插入数据原理是一样的。
列表项的插入式通过函数vListInsert来完成的

void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )

参数:

  • pxList:要插入的列表
  • pxNewListItem :要插入的列表项
    vListInsert是根据pxNewListItem 中的成员变量xItemValue的值来决定插入位置。根据xItemValue的升序方式排序。

具体插入过程如下:

void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t *pxIterator;
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;/* Only effective when configASSERT() is also defined, these tests may catchthe list data structures being overwritten in memory.  They will not catchdata errors caused by incorrect configuration or use of FreeRTOS. */listTEST_LIST_INTEGRITY( pxList );listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );/* Insert the new list item into the list, sorted in xItemValue order.If the list already contains a list item with the same item value then thenew list item should be placed after it.  This ensures that TCB's which arestored in ready lists (all of which have the same xItemValue value) get ashare of the CPU.  However, if the xItemValue is the same as the back markerthe iteration loop below will not end.  Therefore the value is checkedfirst, and the algorithm slightly modified if necessary. */if( xValueOfInsertion == portMAX_DELAY ){pxIterator = pxList->xListEnd.pxPrevious;}else{/* *** NOTE ***********************************************************If you find your application is crashing here then likely causes arelisted below.  In addition see http://www.freertos.org/FAQHelp.html formore tips, and ensure configASSERT() is defined!http://www.freertos.org/a00110.html#configASSERT1) Stack overflow -see http://www.freertos.org/Stacks-and-stack-overflow-checking.html2) Incorrect interrupt priority assignment, especially on Cortex-Mparts where numerically high priority values denote low actualinterrupt priorities, which can seem counter intuitive.  Seehttp://www.freertos.org/RTOS-Cortex-M3-M4.html and the definitionof configMAX_SYSCALL_INTERRUPT_PRIORITY onhttp://www.freertos.org/a00110.html3) Calling an API function from within a critical section or whenthe scheduler is suspended, or calling an API function that doesnot end in "FromISR" from an interrupt.4) Using a queue or semaphore before it has been initialised orbefore the scheduler has been started (are interrupts firingbefore vTaskStartScheduler() has been called?).**********************************************************************/for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */{/* There is nothing to do here, just iterating to the wantedinsertion position. */}}pxNewListItem->pxNext = pxIterator->pxNext;pxNewListItem->pxNext->pxPrevious = pxNewListItem;pxNewListItem->pxPrevious = pxIterator;pxIterator->pxNext = pxNewListItem;/* Remember which list the item is in.  This allows fast removal of theitem later. */pxNewListItem->pvContainer = ( void * ) pxList;( pxList->uxNumberOfItems )++;
}
  1. 获取pxNewListItem的xItemValue值
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
  1. 检查列表和列表项的完整性
	listTEST_LIST_INTEGRITY( pxList );listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
  1. 判断插入的位置,如果等于portMAX_DELAY ,列表项的最大值,插入的位置是列表最末尾
	if( xValueOfInsertion == portMAX_DELAY ){pxIterator = pxList->xListEnd.pxPrevious;}
  1. 不等于portMAX_DELAY ,则for循环找到插入位置,这个查找过程是按照升序的方式查找列表项插入点的,列表的xListEnd 可以想成链表的头,不放数据,方便查询用的,xListEnd 指向的列表项的xItemValue 值最小
for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) 
  1. 将列表项插入到列表中
	pxNewListItem->pxNext = pxIterator->pxNext;pxNewListItem->pxNext->pxPrevious = pxNewListItem;pxNewListItem->pxPrevious = pxIterator;pxIterator->pxNext = pxNewListItem;/* Remember which list the item is in.  This allows fast removal of theitem later. */pxNewListItem->pvContainer = ( void * ) pxList;
  1. 列表的列表项数目加1
	( pxList->uxNumberOfItems )++;
列表项插入过程

一个初始化的空列表如下:
在这里插入图片描述
插入值为40的列表项后
在这里插入图片描述

插入值60的列表项
在这里插入图片描述
插入50后的列表项为
在这里插入图片描述

列表末尾插入

末尾插入就不根据xItemValue了,直接插入末端。原理和在循环双向链表的末尾插入数据是一样的

void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )

列表项的删除

UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove );
  • pxItemToRemove :要删除的列表项

列表的遍历

列表结构体中的pxIndex是用来遍历链表的,在说列表项插入的时候,也用到了列表的遍历,具体代码如下:

for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) 

FreeRTOS提供了一个函数来完成列表的遍历,这个函数是listGET_OWNER_OF_NEXT_ENTRY。每调用一次该函数pxIndex变量就会指向下一个列表项,并且返回这个列表项的pxOwner变量值

#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )										\
{																							\
List_t * const pxConstList = ( pxList );													\/* Increment the index to the next item and return the item, ensuring */				\/* we don't return the marker used at the end of the list.  */							\( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;							\if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )	\{																						\( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;						\}																						\( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;											\
}

pxTCB用来保存pxIndex所指向的列表项pvOwner变量值。pxList是要遍历的列表
将pxIndex指向下一个列表项

( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;

如果指向的列表项是xListEnd ,表示已经到了列表末尾,然后跳过末尾,再一次重新指向列表的第一个列表项。

	if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )	\{																						\( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;						\}	

将pxIndex所指向的新列表项的pvOwner赋值给pxTCB

	( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;			

列表项的插入和删除实验

实验设计,三个任务:
start_task:创建其他两个任务
task1_task:应用任务1,控制LED0闪烁,用来提示系统正在运行
task2_task:列表和列表项操作任务,调用列表和列表相关的API,并且通过串口输出相应的信息来观察这些API函数的运行过程。

任务设置
#define START_STACK_SIZE 128
#define START_TASK_PIO 1
TaskHandle_t Start_Handler;
void start_task(void * pvParameters);#define TASK1_STACK_SIZE 128
#define TASK1_TASK_PIO 2
TaskHandle_t Task1_Handler;
void task1_task(void * pvParameters);#define TASK2_STACK_SIZE 128
#define TASK2_TASK_PIO 3
TaskHandle_t Task2_Handler;
void task2_task(void * pvParameters);
列表项和列表的定义
//定义一个测试用的列表和是哪个列表项
List_t TestList;
ListItem_t ListItem1;
ListItem_t ListItem2;
ListItem_t ListItem3;
main函数
int main(void)
{HAL_Init();                     //初始化HAL库   Stm32_Clock_Init(360,25,2,8);   //设置时钟,180Mhzdelay_init(180);                //初始化延时函数uart_init(115200);              //初始化串口LED_Init();                     //初始化LED KEY_Init();						//初始化按键SDRAM_Init();					//初始化SDRAMLCD_Init();						//初始化LCDPOINT_COLOR = RED;LCD_ShowString(30,10,200,16,16,"Apollo STM32F4/F7");	LCD_ShowString(30,30,200,16,16,"FreeRTOS Examp 7-1");LCD_ShowString(30,50,200,16,16,"list and listItem");LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");LCD_ShowString(30,90,200,16,16,"2016/10/9");//创建开始任务xTaskCreate(start_task,"start_task",START_STACK_SIZE,NULL,START_TASK_PIO,&Start_Handler);vTaskStartScheduler();
}
任务函数
//开始任务任务函数
void start_task(void * pvParameters)
{taskENTER_CRITICAL();		//进入临界区//创建任务xTaskCreate(task1_task,"task1_task",TASK1_STACK_SIZE,NULL,TASK1_TASK_PIO,&Task1_Handler);xTaskCreate(task2_task,"task1_task",TASK2_STACK_SIZE,NULL,TASK2_TASK_PIO,&Task2_Handler);vTaskDelete(Start_Handler);//退出临界区taskEXIT_CRITICAL();
}//task1任务函数
void task1_task(void * pvParameters)
{while(1){LED0 = !LED0;vTaskDelay(500);}
}
//list任务函数
void task2_task(void * pvParameters)
{//初始化列表和列表项vListInitialise(&TestList);vListInitialiseItem(&ListItem1);vListInitialiseItem(&ListItem2);vListInitialiseItem(&ListItem3);ListItem1.xItemValue=40;ListItem2.xItemValue = 60;ListItem3.xItemValue=50;//第二步:打印列表和其他列表项的地址printf("/*******************列表和列表项地址*******************/\r\n");printf("项目                              地址				    \r\n");printf("TestList                          %#x					\r\n",(int)&TestList);printf("TestList->pxIndex                 %#x					\r\n",(int)TestList.pxIndex);printf("TestList->xListEnd                %#x					\r\n",(int)(&TestList.xListEnd));printf("ListItem1                         %#x					\r\n",(int)&ListItem1);printf("ListItem2                         %#x					\r\n",(int)&ListItem2);printf("ListItem3                         %#x					\r\n",(int)&ListItem3);printf("/************************结束**************************/\r\n");printf("按下KEY_UP键继续!\r\n\r\n\r\n");while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10);	//第三步:向列表TestList添加列表项ListItem1,并通过串口打印所有//列表项中成员变量pxNext和pxPrevious的值,通过这两个值观察列表//项在列表中的连接情况。vListInsert(&TestList,&ListItem1);		//插入列表项ListItem1printf("/******************添加列表项ListItem1*****************/\r\n");printf("项目                              地址				    \r\n");printf("TestList->xListEnd->pxNext        %#x					\r\n",(int)(TestList.xListEnd.pxNext));printf("ListItem1->pxNext                 %#x					\r\n",(int)(ListItem1.pxNext));printf("/*******************前后向连接分割线********************/\r\n");printf("TestList->xListEnd->pxPrevious    %#x					\r\n",(int)(TestList.xListEnd.pxPrevious));printf("ListItem1->pxPrevious             %#x					\r\n",(int)(ListItem1.pxPrevious));printf("/************************结束**************************/\r\n");printf("按下KEY_UP键继续!\r\n\r\n\r\n");while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10);	//第四步:向列表TestList添加列表项ListItem2,并通过串口打印所有//列表项中成员变量pxNext和pxPrevious的值,通过这两个值观察列表//项在列表中的连接情况。vListInsert(&TestList,&ListItem2);	//插入列表项ListItem2printf("/******************添加列表项ListItem2*****************/\r\n");printf("项目                              地址				    \r\n");printf("TestList->xListEnd->pxNext        %#x					\r\n",(int)(TestList.xListEnd.pxNext));printf("ListItem1->pxNext                 %#x					\r\n",(int)(ListItem1.pxNext));printf("ListItem2->pxNext                 %#x					\r\n",(int)(ListItem2.pxNext));printf("/*******************前后向连接分割线********************/\r\n");printf("TestList->xListEnd->pxPrevious    %#x					\r\n",(int)(TestList.xListEnd.pxPrevious));printf("ListItem1->pxPrevious             %#x					\r\n",(int)(ListItem1.pxPrevious));printf("ListItem2->pxPrevious             %#x					\r\n",(int)(ListItem2.pxPrevious));printf("/************************结束**************************/\r\n");printf("按下KEY_UP键继续!\r\n\r\n\r\n");while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10);		//第五步:向列表TestList添加列表项ListItem3,并通过串口打印所有//列表项中成员变量pxNext和pxPrevious的值,通过这两个值观察列表//项在列表中的连接情况。vListInsert(&TestList,&ListItem3);	//插入列表项ListItem3printf("/******************添加列表项ListItem3*****************/\r\n");printf("项目                              地址				    \r\n");printf("TestList->xListEnd->pxNext        %#x					\r\n",(int)(TestList.xListEnd.pxNext));printf("ListItem1->pxNext                 %#x					\r\n",(int)(ListItem1.pxNext));printf("ListItem3->pxNext                 %#x					\r\n",(int)(ListItem3.pxNext));printf("ListItem2->pxNext                 %#x					\r\n",(int)(ListItem2.pxNext));printf("/*******************前后向连接分割线********************/\r\n");printf("TestList->xListEnd->pxPrevious    %#x					\r\n",(int)(TestList.xListEnd.pxPrevious));printf("ListItem1->pxPrevious             %#x					\r\n",(int)(ListItem1.pxPrevious));printf("ListItem3->pxPrevious             %#x					\r\n",(int)(ListItem3.pxPrevious));printf("ListItem2->pxPrevious             %#x					\r\n",(int)(ListItem2.pxPrevious));printf("/************************结束**************************/\r\n");printf("按下KEY_UP键继续!\r\n\r\n\r\n");while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10);	//第六步:删除ListItem2,并通过串口打印所有列表项中成员变量pxNext和//pxPrevious的值,通过这两个值观察列表项在列表中的连接情况。uxListRemove(&ListItem2);						//删除ListItem2printf("/******************删除列表项ListItem2*****************/\r\n");printf("项目                              地址				    \r\n");printf("TestList->xListEnd->pxNext        %#x					\r\n",(int)(TestList.xListEnd.pxNext));printf("ListItem1->pxNext                 %#x					\r\n",(int)(ListItem1.pxNext));printf("ListItem3->pxNext                 %#x					\r\n",(int)(ListItem3.pxNext));printf("/*******************前后向连接分割线********************/\r\n");printf("TestList->xListEnd->pxPrevious    %#x					\r\n",(int)(TestList.xListEnd.pxPrevious));printf("ListItem1->pxPrevious             %#x					\r\n",(int)(ListItem1.pxPrevious));printf("ListItem3->pxPrevious             %#x					\r\n",(int)(ListItem3.pxPrevious));printf("/************************结束**************************/\r\n");printf("按下KEY_UP键继续!\r\n\r\n\r\n");while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10);	//第七步:删除ListItem2,并通过串口打印所有列表项中成员变量pxNext和//pxPrevious的值,通过这两个值观察列表项在列表中的连接情况。TestList.pxIndex=TestList.pxIndex->pxNext;			//pxIndex向后移一项,这样pxIndex就会指向ListItem1。vListInsertEnd(&TestList,&ListItem2);				//列表末尾添加列表项ListItem2printf("/***************在末尾添加列表项ListItem2***************/\r\n");printf("项目                              地址				    \r\n");printf("TestList->pxIndex                 %#x					\r\n",(int)TestList.pxIndex);printf("TestList->xListEnd->pxNext        %#x					\r\n",(int)(TestList.xListEnd.pxNext));printf("ListItem2->pxNext                 %#x					\r\n",(int)(ListItem2.pxNext));printf("ListItem1->pxNext                 %#x					\r\n",(int)(ListItem1.pxNext));printf("ListItem3->pxNext                 %#x					\r\n",(int)(ListItem3.pxNext));printf("/*******************前后向连接分割线********************/\r\n");printf("TestList->xListEnd->pxPrevious    %#x					\r\n",(int)(TestList.xListEnd.pxPrevious));printf("ListItem2->pxPrevious             %#x					\r\n",(int)(ListItem2.pxPrevious));printf("ListItem1->pxPrevious             %#x					\r\n",(int)(ListItem1.pxPrevious));printf("ListItem3->pxPrevious             %#x					\r\n",(int)(ListItem3.pxPrevious));printf("/************************结束**************************/\r\n\r\n\r\n");while(1){LED1=!LED1;vTaskDelay(1000);                           //延时1s,也就是1000个时钟节拍	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/379746.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FreeRTOS队列

在实际应用中&#xff0c;我们会遇到一个任务或者中断服务需要和另一个任务进行消息传递&#xff0c;FreeRTOS提供了队列的机制来完成任务与任务、任务与中断之间的消息传递。 0x01 队列简介 队列是为了任务与任务、任务与中断之间的通信而准备的&#xff0c;可以在任务与任务…

剧情介绍:“阿甘正传”

阿甘是个智商只有75的低能儿。在学校里为了躲避别的孩子的欺侮&#xff0c;听从一个朋友珍妮的话而开始“跑”。他跑着躲避别人的捉弄。在中学时&#xff0c;他为了躲避别人而跑进了一所学校的橄榄球场&#xff0c;就这样跑进了大学。阿甘被破格录取&#xff0c;并成了橄榄球巨…

FreeRTOS信号量---二值信号量

信号量可以用来进行资源管理和任务同步&#xff0c;FreeRTOS中信号量又分为二值信号量、计算型信号量、互斥信号量和递归互斥信号量。 0x01 二值信号量 二值信号量其实就是一个只有一个队列项的队列&#xff0c;这个特殊的队列要么是满的&#xff0c;要么是空的&#xff0c;任…

FreeRTOS软件定时器

软件定时器允许设置一段时间&#xff0c;当设置的时间达到后就执行指定的功能函数&#xff0c;被软件定时器调用的功能函数叫做定时器的回调函数。软件定时器的回调函数是在定时器服务任务中执行的&#xff0c;所以一定不能在回调函数中调用任何阻塞任务的API函数&#xff0c;比…

WP7之Application Bar控件

Microsoft.Phone.Shell命名空间中定义了ApplicationBar及其相关类&#xff08;ApplicationBarIconButton和ApplicationBarMenuItem&#xff09;&#xff0c;这些类派生自Object,并完全独立于常规Silverlight编程中的DependencyObject,UIElement和FrameworkElement类层次结构。A…

TomCat使用以及端口号被占用的处理方法

一.HTTP协议 什么是HTTP协议 HTTP协议&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;是因特网上应用最为广泛的一种网络传输协议&#xff0c;所有的WWW文件都必须遵守这个标准。 HTTP请求 HTTP响应 2.如何处理端口被占用 方法一&#xff…

FreeRTOS事件标志组

使用信号量来同步的话&#xff0c;任务只能与单个事务或任务进行同步&#xff0c;有时候某个任务可能会需要与多个事件或任务进行同步&#xff0c;此时信号量就无能为力了&#xff0c;FreeRTOS为此提供了一个可选的解决方法&#xff0c;那就是事件标志组。 0x01 事件标志组 事…

FusionCharts等产品简介

以前做柱状图、饼形图等图表都是根据数据绘制出来的静态图&#xff0c;偶然看到别人的一套系统&#xff0c;居然可以让柱状图的柱子动画般的逐个出现&#xff0c;效果还是很不错的。不要跟我抬杠说不就是展现数据嘛&#xff0c;静态图表有什么不好&#xff0c;要知道用户一般可…

Eclipse和Tomcat绑定并且将上传资源到Tomcat上

步骤如下&#xff1a; 创建一个Dynamic Web Project&#xff08;图一&#xff09; Target runtime 选择Apache Tomcat v7.0版本&#xff08;图二&#xff09; 切记要选择 v7.0 和2.5 &#xff08;若没有图二选项见图三&#xff09; 然后&#xff0c;点击window --> Prefer…

FreeRTOS任务通知

从v8.2.0版本开始&#xff0c;FreeRTOS新增了任务通知这个功能&#xff0c;可以使用任务通知来代替信号量、消息队列、事件标志组等这些东西&#xff0c;使用任务通知的话效率会更高。 任务通知在FreeRTOS是一个可选的选项&#xff0c;要使用任务通知的话就需要将宏configUSE_T…

kinect在openni下也能玩抠出人物换背景

之前想了个很拉风的名字《用kinect玩穿越》&#xff0c;但是现在功能还不是很完善&#xff0c;细节处理也不是很好&#xff0c;脸皮没有足够的厚&#xff0c;所以呢还是叫换背景吧。 这里面包含两个技术要点&#xff1a; 一、抠出活动人物 在微软的SDK里深度图像的前3位即0-2位…

Emit学习-基础篇-基本概念介绍

之前的Hello World例子应该已经让我们对Emit有了一个模糊的了解&#xff0c;那么Emit到底是什么样一个东西&#xff0c;他又能实现些什么功能呢&#xff1f;昨天查了点资料&#xff0c;大致总结了下&#xff0c;由于才开始学习肯定有不完善的地方&#xff0c;希望大家能够批评指…

The FreeRTOS Distribution(介绍、移植、类型定义)

1 Understand the FreeRTOS Distribution 1.1 Definition &#xff1a;FreeRTOS Port FreeRTOS目前可以在20种不同的编译器构建&#xff0c;并且可以在30多种不同的处理器架构上运行&#xff0c;每个受支持的编译器和处理器组合被认为是一个单独的FreeRTOS Port。 1.2 Build…

Eclipse项目左上角出现大红色感叹号怎么办?

出现大红色感叹号是因为环境不匹配 解决方法&#xff1a; 右击出现大红色感叹号的项目 点击 Libraries&#xff0c;将有叉号的给Remove掉 然后再点击 Add Library —> JRE System Library —> Next 勾选第二个即可 之后&#xff0c;就不会出现大红色感叹号了。

PCB---STM32最小系统制作过程

PCB 制作过程STM32核心模块连接外部电源晶振OSC_IN(8MHz)OSC32_IN(32.768MHz&#xff09;复位下载口BOOT模式电源模块添加功能UARTWKUPSTM32核心模块 这里我们以STM32F103C8T6为列&#xff0c;先将芯片的原理图放到原理图中 对于STM32&#xff0c;有几个模块是核心&#xff0…

FreeRTOS---堆内存管理(一)

FreeRTOS的堆内存管理简介动态内存分配及其与 FreeRTOS 的相关性动态内存分配选项内存分配方案Heap_1heap_2Heap_3Heap_4设置heap_4的起始地址Heap_5vPortDefineHeapRegions()堆相关的函数xPortGetFreeHeapSizexPortGetMinimumEverFreeHeapSizeMalloc调用失败的Hook函数这篇文章…

FreeRTOS--堆内存管理(二)

堆内存管理代码具体实现heap_1内存申请函数内存释放函数heap_2内存块内存堆初始化函数内存块插入函数内存申请函数判断是不是第一次申请内存开始分配内存内存释放函数heap_3heap_4内存堆初始化函数内存块插入函数heap_5上一篇文章说了FreeRTOS实现堆内存的原理&#xff0c;这一…

css中的node.js_在Node App中使用基本HTML,CSS和JavaScript

css中的node.jsYou may think this is not important, but it is!. As a beginner in node.js, most coding exercises are always server sided. 您可能认为这并不重要&#xff0c;但确实如此&#xff01; 作为node.js的初学者&#xff0c;大多数编码练习始终都是服务器端的。…

Binary String Matching(C++)

题目描述: Given two strings A and B, whose alphabet consist only ‘0’ and ‘1’. Your task is only to tell how many times does A appear as a substring of B? For example, the text string B is ‘1001110110’ while the pattern string A is ‘11’, you should…

VisualStudio2019配置OpenCV

VisualStudio2019配置OpenCV配置0x01 准备0x02 配置系统环境0x03 复制文件0x04 配置VisualStudio2019测试配置 0x01 准备 下载opencv&#xff0c;官网地址&#xff1a;https://opencv.org/releases/# 下载之后&#xff0c;自行安装 0x02 配置系统环境 找到高级系统设置 …