你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32的FreeRTOS学习之列表和列表项实验(十)

[复制链接]
STMCU小助手 发布时间:2022-11-16 21:08
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文件里:

  1. #include "sys.h"
  2. #include "delay.h"
  3. #include "usart.h"
  4. #include "led.h"
  5. #include "timer.h"
  6. #include "timer.h"
  7. #include "key.h"
  8. #include "exti.h"
  9. #include "FreeRTOS.h"
  10. #include "task.h"
  11. // 开始任务
  12. #define START_TASK_PRIO  1           // 任务优先级
  13. #define START_STK_SIZE   128         // 任务堆栈大小
  14. TaskHandle_t StartTask_Handler;      // 任务句柄
  15. void start_task(void *pvParameters); // 任务函数
  16. // 应用任务1
  17. #define TASK1_TASK_PRIO  2           // 任务优先级
  18. #define TASK1_STK_SIZE   128         // 任务堆栈大小
  19. TaskHandle_t Task1Task_Handler;      // 任务句柄
  20. void task1_task(void *pvParameters); // 任务函数
  21. // 列表任务
  22. #define LIST_TASK_PRIO  3            // 任务优先级
  23. #define LIST_STK_SIZE   128          // 任务堆栈大小
  24. TaskHandle_t ListTask_Handler;       // 任务句柄
  25. void list_task(void *pvParameters);  // 任务函数
  26. // 定义一个测试用的列表和3个列表项
  27. List_t TestList;      // 测试用列表
  28. ListItem_t ListItem1; // 测试用列表项1
  29. ListItem_t ListItem2; // 测试用列表项2
  30. ListItem_t ListItem3; // 测试用列表项3
  31. // 主函数
  32. int main(void)
  33. {
  34. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);  // 设置系统中断优先级分组4  
  35. delay_init();                                    // 延时函数初始化  
  36. uart_init(115200);                               // 初始化串口
  37. LED_Init();                                      // 初始化LED
  38. KEY_Init();                                      // 初始化按键
  39. // 创建开始任务
  40. xTaskCreate(   (TaskFunction_t )start_task,            // 任务函数
  41.                 (const char*    )"start_task",          // 任务名称
  42.                 (uint16_t       )START_STK_SIZE,        // 任务堆栈大小
  43.                 (void*          )NULL,                  // 传递给任务函数的参数
  44.                 (UBaseType_t    )START_TASK_PRIO,       // 任务优先级
  45.                 (TaskHandle_t*  )&StartTask_Handler);   // 任务句柄              
  46. vTaskStartScheduler();                                 // 开启任务调度
  47. }
  48. // 开始任务任务函数
  49. void start_task(void *pvParameters)
  50. {
  51.   taskENTER_CRITICAL();           // 进入临界区
  52.   // 创建TASK1任务
  53.   xTaskCreate(  (TaskFunction_t )task1_task,            
  54.                 (const char*    )"task1_task",           
  55.                 (uint16_t       )TASK1_STK_SIZE,        
  56.                 (void*          )NULL,                  
  57.                 (UBaseType_t    )TASK1_TASK_PRIO,        
  58.                 (TaskHandle_t*  )&Task1Task_Handler);   
  59.   // 创建LIST任务
  60.   xTaskCreate(  (TaskFunction_t )list_task,     
  61.                 (const char*    )"list_task",   
  62.                 (uint16_t       )LIST_STK_SIZE,
  63.                 (void*          )NULL,
  64.                 (UBaseType_t    )LIST_TASK_PRIO,
  65.                 (TaskHandle_t*  )&ListTask_Handler);
  66.   vTaskDelete(StartTask_Handler); // 删除开始任务
  67.   taskEXIT_CRITICAL();            // 退出临界区
  68. }
  69. // task1任务函数
  70. void task1_task(void *pvParameters)
  71. {
  72. while(1)
  73. {
  74.   LED0=!LED0;
  75.   vTaskDelay(500);  // 延时500ms,也就是500个时钟节拍
  76. }
  77. }
  78. // list任务函数
  79. void list_task(void *pvParameters)
  80. {
  81. // 第一步:初始化列表和列表项
  82. vListInitialise(&TestList);
  83. vListInitialiseItem(&ListItem1);
  84. vListInitialiseItem(&ListItem2);
  85. vListInitialiseItem(&ListItem3);
  86. ListItem1.xItemValue=40;   //ListItem1列表项值为40
  87. ListItem2.xItemValue=60;   //ListItem2列表项值为60
  88. ListItem3.xItemValue=50;   //ListItem3列表项值为50
  89. // 第二步:打印列表和其他列表项的地址
  90. printf("/*******************列表和列表项地址*******************/\r\n");
  91. printf("项目                              地址     \r\n");
  92. printf("TestList                          %#x     \r\n",(int)&TestList);
  93. printf("TestList->pxIndex                 %#x     \r\n",(int)TestList.pxIndex);
  94. printf("TestList->xListEnd                %#x     \r\n",(int)(&TestList.xListEnd));
  95. printf("ListItem1                         %#x     \r\n",(int)&ListItem1);
  96. printf("ListItem2                         %#x     \r\n",(int)&ListItem2);
  97. printf("ListItem3                         %#x     \r\n",(int)&ListItem3);
  98. printf("/************************结束**************************/\r\n");
  99. printf("按下KEY_UP键继续!\r\n\r\n\r\n");
  100. while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10);  // 等待KEY_UP键按下
  101. // 第三步:向列表TestList添加列表项ListItem1,并通过串口打印所有列表项中成员变量pxNext和pxPrevious的值,
  102. // 通过这两个值观察列表项在列表中的连接情况。
  103. vListInsert(&TestList,&ListItem1);          // 插入列表项ListItem1
  104. printf("/******************添加列表项ListItem1*****************/\r\n");
  105. printf("项目                              地址     \r\n");
  106. printf("TestList->xListEnd->pxNext        %#x     \r\n",(int)(TestList.xListEnd.pxNext));
  107. printf("ListItem1->pxNext                 %#x     \r\n",(int)(ListItem1.pxNext));
  108. printf("/*******************前后向连接分割线********************/\r\n");
  109. printf("TestList->xListEnd->pxPrevious    %#x     \r\n",(int)(TestList.xListEnd.pxPrevious));
  110. printf("ListItem1->pxPrevious             %#x     \r\n",(int)(ListItem1.pxPrevious));
  111. printf("/************************结束**************************/\r\n");
  112. printf("按下KEY_UP键继续!\r\n\r\n\r\n");
  113. while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10);     // 等待KEY_UP键按下
  114. // 第四步:向列表TestList添加列表项ListItem2,并通过串口打印所有列表项中成员变量pxNext和pxPrevious的值,
  115. // 通过这两个值观察列表项在列表中的连接情况。
  116. vListInsert(&TestList,&ListItem2); // 插入列表项ListItem2
  117. printf("/******************添加列表项ListItem2*****************/\r\n");
  118. printf("项目                              地址     \r\n");
  119. printf("TestList->xListEnd->pxNext        %#x     \r\n",(int)(TestList.xListEnd.pxNext));
  120. printf("ListItem1->pxNext                 %#x     \r\n",(int)(ListItem1.pxNext));
  121. printf("ListItem2->pxNext                 %#x     \r\n",(int)(ListItem2.pxNext));
  122. printf("/*******************前后向连接分割线********************/\r\n");
  123. printf("TestList->xListEnd->pxPrevious    %#x     \r\n",(int)(TestList.xListEnd.pxPrevious));
  124. printf("ListItem1->pxPrevious             %#x     \r\n",(int)(ListItem1.pxPrevious));
  125. printf("ListItem2->pxPrevious             %#x     \r\n",(int)(ListItem2.pxPrevious));
  126. printf("/************************结束**************************/\r\n");
  127. printf("按下KEY_UP键继续!\r\n\r\n\r\n");
  128. while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10);     // 等待KEY_UP键按下
  129. // 第五步:向列表TestList添加列表项ListItem3,并通过串口打印所有列表项中成员变量pxNext和pxPrevious的值,
  130. // 通过这两个值观察列表项在列表中的连接情况。
  131. vListInsert(&TestList,&ListItem3);                 // 插入列表项ListItem3
  132. printf("/******************添加列表项ListItem3*****************/\r\n");
  133. printf("项目                              地址     \r\n");
  134. printf("TestList->xListEnd->pxNext        %#x     \r\n",(int)(TestList.xListEnd.pxNext));
  135. printf("ListItem1->pxNext                 %#x     \r\n",(int)(ListItem1.pxNext));
  136. printf("ListItem3->pxNext                 %#x     \r\n",(int)(ListItem3.pxNext));
  137. printf("ListItem2->pxNext                 %#x     \r\n",(int)(ListItem2.pxNext));
  138. printf("/*******************前后向连接分割线********************/\r\n");
  139. printf("TestList->xListEnd->pxPrevious    %#x     \r\n",(int)(TestList.xListEnd.pxPrevious));
  140. printf("ListItem1->pxPrevious             %#x     \r\n",(int)(ListItem1.pxPrevious));
  141. printf("ListItem3->pxPrevious             %#x     \r\n",(int)(ListItem3.pxPrevious));
  142. printf("ListItem2->pxPrevious             %#x     \r\n",(int)(ListItem2.pxPrevious));
  143. printf("/************************结束**************************/\r\n");
  144. printf("按下KEY_UP键继续!\r\n\r\n\r\n");
  145. while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10);     // 等待KEY_UP键按下
  146. // 第六步:删除ListItem2,并通过串口打印所有列表项中成员变量pxNext和pxPrevious的值,
  147. // 通过这两个值观察列表项在列表中的连接情况。
  148. uxListRemove(&ListItem2);      //删除ListItem2
  149. printf("/******************删除列表项ListItem2*****************/\r\n");
  150. printf("项目                              地址     \r\n");
  151. printf("TestList->xListEnd->pxNext        %#x     \r\n",(int)(TestList.xListEnd.pxNext));
  152. printf("ListItem1->pxNext                 %#x     \r\n",(int)(ListItem1.pxNext));
  153. printf("ListItem3->pxNext                 %#x     \r\n",(int)(ListItem3.pxNext));
  154. printf("/*******************前后向连接分割线********************/\r\n");
  155. printf("TestList->xListEnd->pxPrevious    %#x     \r\n",(int)(TestList.xListEnd.pxPrevious));
  156. printf("ListItem1->pxPrevious             %#x     \r\n",(int)(ListItem1.pxPrevious));
  157. printf("ListItem3->pxPrevious             %#x     \r\n",(int)(ListItem3.pxPrevious));
  158. printf("/************************结束**************************/\r\n");
  159. printf("按下KEY_UP键继续!\r\n\r\n\r\n");
  160. while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10);     // 等待KEY_UP键按下
  161. // 第七步:删除ListItem2,并通过串口打印所有列表项中成员变量pxNext和pxPrevious的值,
  162. // 通过这两个值观察列表项在列表中的连接情况。
  163. TestList.pxIndex=TestList.pxIndex->pxNext;       // pxIndex向后移一项,这样pxIndex就会指向ListItem1。
  164. vListInsertEnd(&TestList,&ListItem2);            // 列表末尾添加列表项ListItem2
  165. printf("/***************在末尾添加列表项ListItem2***************/\r\n");
  166. printf("项目                              地址      \r\n");
  167. printf("TestList->pxIndex                 %#x     \r\n",(int)TestList.pxIndex);
  168. printf("TestList->xListEnd->pxNext        %#x     \r\n",(int)(TestList.xListEnd.pxNext));
  169. printf("ListItem2->pxNext                 %#x     \r\n",(int)(ListItem2.pxNext));
  170. printf("ListItem1->pxNext                 %#x     \r\n",(int)(ListItem1.pxNext));
  171. printf("ListItem3->pxNext                 %#x     \r\n",(int)(ListItem3.pxNext));
  172. printf("/*******************前后向连接分割线********************/\r\n");
  173. printf("TestList->xListEnd->pxPrevious    %#x     \r\n",(int)(TestList.xListEnd.pxPrevious));
  174. printf("ListItem2->pxPrevious             %#x     \r\n",(int)(ListItem2.pxPrevious));
  175. printf("ListItem1->pxPrevious             %#x     \r\n",(int)(ListItem1.pxPrevious));
  176. printf("ListItem3->pxPrevious             %#x     \r\n",(int)(ListItem3.pxPrevious));
  177. printf("/************************结束**************************/\r\n\r\n\r\n");
  178. while(1)
  179. {
  180.   LED1=!LED1;
  181.   vTaskDelay(1000);       // 延时1s,也就是1000个时钟节拍
  182. }
  183. }
复制代码

5. 实验结果
系统运行后,观察串口调试助手,初始化后如下图所示:
20210322135514411.png

初始化后:
pxIndex指向xListEnd,为ox200000c0;
xListEnd的地址为ox200000c0;
ListItem1的地址为ox200000cc;
ListItem2的地址为ox200000e0;
ListItem3的地址为ox200000f4;
单击按键,添加列表项ListItem1,完成后如下图所示:

20210322135652375.png

xListEnd的下一个项的地址为ox200000cc,xListEnd的上一个项的地址为ox200000cc;
ListItem1下一个项的地址为0x200000c0,ListItem1上一个项的地址为0x200000c0。
因为:

xListEnd ————>ListItem1————>xListEnd
继续单击按键,添加列表项ListItem2,完成后如下图所示:

20210322140717138.png

xListEnd的下一个项的地址为ox200000cc,xListEnd的上一个项的地址为ox200000e0;
ListItem1下一个项的地址为0x200000e0,ListItem1上一个项的地址为0x200000c0;
ListItem2下一个项的地址为0x200000c0,ListItem2上一个项的地址为0x200000cc;
因为:

xListEnd ————>ListItem1————>ListItem2————>xListEnd
继续单击按键,添加列表项ListItem3,完成后如下图所示:

20210322141643875.png

xListEnd的下一个项的地址为ox200000cc,xListEnd的上一个项的地址为ox200000f4;
ListItem1下一个项的地址为0x200000f4,ListItem1上一个项的地址为0x200000c0;
ListItem3下一个项的地址为0x200000c0,ListItem3上一个项的地址为0x200000cc;
因为:

xListEnd ————>ListItem1————>ListItem3————>xListEnd
继续单击按键是,删除列表项ListItem2,完成后如下图所示:

20210322141902176.png

xListEnd的下一个项的地址为ox200000cc,xListEnd的上一个项的地址为ox200000e0;
ListItem1下一个项的地址为0x200000f4,ListItem1上一个项的地址为0x200000c0;
ListItem3下一个项的地址为0x200000c0,ListItem3上一个项的地址为0x200000cc;
ListItem2下一个项的地址为0x200000c0,ListItem2上一个项的地址为0x200000f4;
因为:
xListEnd ————>ListItem1————>ListItem3————>ListItem2————>xListEnd

继续单击按键,末尾添加列表项ListItem2,完成后如下图所示:

20210322142130342.png

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指向添加该列表项的后一项地址。
————————————————
版权声明:天亮继续睡


收藏 评论0 发布时间:2022-11-16 21:08

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版