1. 实验目的
列表和列表项实验演练。
2. 实验设计
本实验设计3个任务:
start_task:用来创建其他2个任务;
task1_task:应用任务1,控制LED灯闪烁,提示系统正常运行;
list_task:列表和列表项操作任务,调用列表和列表项相关API函数,通过串口输出相应信息观察这些API函数的运行过程。
本实验需要用到按键,用于控制任务的运行。
3. 硬件
1) 正点原子战舰v3开发板(其他板子应该也可以,主要涉及USART,LED,KEY);
2) JLINK仿真器。
4. 代码解读
如果不考虑usart、led、key的函数(不是本章的重点),那么主要的函数都在main.c文件里:
- #include "sys.h"
- #include "delay.h"
- #include "usart.h"
- #include "led.h"
- #include "timer.h"
- #include "timer.h"
- #include "key.h"
- #include "exti.h"
- #include "FreeRTOS.h"
- #include "task.h"
- // 开始任务
- #define START_TASK_PRIO 1 // 任务优先级
- #define START_STK_SIZE 128 // 任务堆栈大小
- TaskHandle_t StartTask_Handler; // 任务句柄
- void start_task(void *pvParameters); // 任务函数
- // 应用任务1
- #define TASK1_TASK_PRIO 2 // 任务优先级
- #define TASK1_STK_SIZE 128 // 任务堆栈大小
- TaskHandle_t Task1Task_Handler; // 任务句柄
- void task1_task(void *pvParameters); // 任务函数
- // 列表任务
- #define LIST_TASK_PRIO 3 // 任务优先级
- #define LIST_STK_SIZE 128 // 任务堆栈大小
- TaskHandle_t ListTask_Handler; // 任务句柄
- void list_task(void *pvParameters); // 任务函数
- // 定义一个测试用的列表和3个列表项
- List_t TestList; // 测试用列表
- ListItem_t ListItem1; // 测试用列表项1
- ListItem_t ListItem2; // 测试用列表项2
- ListItem_t ListItem3; // 测试用列表项3
- // 主函数
- int main(void)
- {
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); // 设置系统中断优先级分组4
- delay_init(); // 延时函数初始化
- uart_init(115200); // 初始化串口
- LED_Init(); // 初始化LED
- KEY_Init(); // 初始化按键
- // 创建开始任务
- 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); // 任务句柄
- vTaskStartScheduler(); // 开启任务调度
- }
- // 开始任务任务函数
- void start_task(void *pvParameters)
- {
- taskENTER_CRITICAL(); // 进入临界区
- // 创建TASK1任务
- xTaskCreate( (TaskFunction_t )task1_task,
- (const char* )"task1_task",
- (uint16_t )TASK1_STK_SIZE,
- (void* )NULL,
- (UBaseType_t )TASK1_TASK_PRIO,
- (TaskHandle_t* )&Task1Task_Handler);
- // 创建LIST任务
- xTaskCreate( (TaskFunction_t )list_task,
- (const char* )"list_task",
- (uint16_t )LIST_STK_SIZE,
- (void* )NULL,
- (UBaseType_t )LIST_TASK_PRIO,
- (TaskHandle_t* )&ListTask_Handler);
- vTaskDelete(StartTask_Handler); // 删除开始任务
- taskEXIT_CRITICAL(); // 退出临界区
- }
- // task1任务函数
- void task1_task(void *pvParameters)
- {
- while(1)
- {
- LED0=!LED0;
- vTaskDelay(500); // 延时500ms,也就是500个时钟节拍
- }
- }
- // list任务函数
- void list_task(void *pvParameters)
- {
- // 第一步:初始化列表和列表项
- vListInitialise(&TestList);
- vListInitialiseItem(&ListItem1);
- vListInitialiseItem(&ListItem2);
- vListInitialiseItem(&ListItem3);
- ListItem1.xItemValue=40; //ListItem1列表项值为40
- ListItem2.xItemValue=60; //ListItem2列表项值为60
- ListItem3.xItemValue=50; //ListItem3列表项值为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); // 等待KEY_UP键按下
- // 第三步:向列表TestList添加列表项ListItem1,并通过串口打印所有列表项中成员变量pxNext和pxPrevious的值,
- // 通过这两个值观察列表项在列表中的连接情况。
- vListInsert(&TestList,&ListItem1); // 插入列表项ListItem1
- printf("/******************添加列表项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); // 等待KEY_UP键按下
- // 第四步:向列表TestList添加列表项ListItem2,并通过串口打印所有列表项中成员变量pxNext和pxPrevious的值,
- // 通过这两个值观察列表项在列表中的连接情况。
- vListInsert(&TestList,&ListItem2); // 插入列表项ListItem2
- printf("/******************添加列表项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); // 等待KEY_UP键按下
- // 第五步:向列表TestList添加列表项ListItem3,并通过串口打印所有列表项中成员变量pxNext和pxPrevious的值,
- // 通过这两个值观察列表项在列表中的连接情况。
- vListInsert(&TestList,&ListItem3); // 插入列表项ListItem3
- printf("/******************添加列表项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); // 等待KEY_UP键按下
- // 第六步:删除ListItem2,并通过串口打印所有列表项中成员变量pxNext和pxPrevious的值,
- // 通过这两个值观察列表项在列表中的连接情况。
- uxListRemove(&ListItem2); //删除ListItem2
- printf("/******************删除列表项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); // 等待KEY_UP键按下
- // 第七步:删除ListItem2,并通过串口打印所有列表项中成员变量pxNext和pxPrevious的值,
- // 通过这两个值观察列表项在列表中的连接情况。
- TestList.pxIndex=TestList.pxIndex->pxNext; // pxIndex向后移一项,这样pxIndex就会指向ListItem1。
- vListInsertEnd(&TestList,&ListItem2); // 列表末尾添加列表项ListItem2
- printf("/***************在末尾添加列表项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个时钟节拍
- }
- }
复制代码
5. 实验结果
系统运行后,观察串口调试助手,初始化后如下图所示:
初始化后:
pxIndex指向xListEnd,为ox200000c0;
xListEnd的地址为ox200000c0;
ListItem1的地址为ox200000cc;
ListItem2的地址为ox200000e0;
ListItem3的地址为ox200000f4;
单击按键,添加列表项ListItem1,完成后如下图所示:
xListEnd的下一个项的地址为ox200000cc,xListEnd的上一个项的地址为ox200000cc;
ListItem1下一个项的地址为0x200000c0,ListItem1上一个项的地址为0x200000c0。
因为:
xListEnd ————>ListItem1————>xListEnd
继续单击按键,添加列表项ListItem2,完成后如下图所示:
xListEnd的下一个项的地址为ox200000cc,xListEnd的上一个项的地址为ox200000e0;
ListItem1下一个项的地址为0x200000e0,ListItem1上一个项的地址为0x200000c0;
ListItem2下一个项的地址为0x200000c0,ListItem2上一个项的地址为0x200000cc;
因为:
xListEnd ————>ListItem1————>ListItem2————>xListEnd
继续单击按键,添加列表项ListItem3,完成后如下图所示:
xListEnd的下一个项的地址为ox200000cc,xListEnd的上一个项的地址为ox200000f4;
ListItem1下一个项的地址为0x200000f4,ListItem1上一个项的地址为0x200000c0;
ListItem3下一个项的地址为0x200000c0,ListItem3上一个项的地址为0x200000cc;
因为:
xListEnd ————>ListItem1————>ListItem3————>xListEnd
继续单击按键是,删除列表项ListItem2,完成后如下图所示:
xListEnd的下一个项的地址为ox200000cc,xListEnd的上一个项的地址为ox200000e0;
ListItem1下一个项的地址为0x200000f4,ListItem1上一个项的地址为0x200000c0;
ListItem3下一个项的地址为0x200000c0,ListItem3上一个项的地址为0x200000cc;
ListItem2下一个项的地址为0x200000c0,ListItem2上一个项的地址为0x200000f4;
因为:
xListEnd ————>ListItem1————>ListItem3————>ListItem2————>xListEnd
继续单击按键,末尾添加列表项ListItem2,完成后如下图所示:
xListEnd的下一个项的地址为ox200000e0,xListEnd的上一个项的地址为ox200000f4;
ListItem2下一个项的地址为0x200000cc,ListItem2上一个项的地址为0x200000c0;
ListItem1下一个项的地址为0x200000f4,ListItem1上一个项的地址为0x200000e0;
ListItem3下一个项的地址为0x200000c0,ListItem3上一个项的地址为0x200000cc;
因为:
xListEnd ————>ListItem2————>ListItem1————>ListItem3————>xListEnd
还要注意一个:
此时,pxIndex指向ListItem1,及其地址为0x200000cc!
你可以理解为,末尾添加列表项后,pxIndex指向添加该列表项的后一项地址。
————————————————
版权声明:天亮继续睡
|