环境配置

  1. 下载官方源码 https://www.freertos.org/

找到这个,他就是visual studio示例demo,我们主要在这个的基础上修改

  1. 下载visio studio

https://visualstudio.microsoft.com/zh-hans/

安装时不需要额外任何插件,打开项目会提示你安装c/c++,这样安的快

  1. 打开第一步圈的那个WIN32.sln

目录结构能看出,可以写多个demo,最后在main.c里调用即可,下面给出本人翻译过的官方示例Blinky示例

  1. 例程入门级详解

这个demo主要讲的是分别通过任务和定时器向队列收发信息,添加了个键盘按键重置定时器、保存log的功能

main.c
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <conio.h>
  4. #include <intrin.h>
  5. /* FreeRTOS kernel includes. */
  6. #include "FreeRTOS.h"
  7. #include "task.h"
  8. /* FreeRTOS+Trace includes. */
  9. #include "trcRecorder.h"
  10. #define mainREGION_1_SIZE 8201
  11. #define mainREGION_2_SIZE 23905
  12. #define mainREGION_3_SIZE 16807
  13. #define mainNO_KEY_PRESS_VALUE -1
  14. #define mainOUTPUT_TRACE_KEY 't'
  15. #define mainINTERRUPT_NUMBER_KEYBOARD 3
  16. //保存dump的文件名
  17. #define mainTRACE_FILE_NAME "Trace.dump"
  18. extern void main_blinky(void);
  19. extern void main_full(void);
  20. extern void main_Task(void);
  21. extern void vFullDemoTickHookFunction(void);
  22. extern void vFullDemoIdleFunction(void);
  23. //用于初始化 FreeRTOS 的堆内存管理器,通常不需要写,自动就调用了
  24. static void prvInitialiseHeap(void);
  25. //内存分配失败时调用,打印错误信息或重启系统等
  26. void vApplicationMallocFailedHook(void);
  27. //空闲任务运行时调用
  28. void vApplicationIdleHook(void);
  29. //堆栈溢出时调用,打印错误信息等
  30. void vApplicationStackOverflowHook(TaskHandle_t pxTask,
  31. char* pcTaskName);
  32. //Tick中断时调用,比如统计任务运行时间等
  33. void vApplicationTickHook(void);
  34. //创建空闲任务前调用,用于自定义分配内存
  35. void vApplicationGetIdleTaskMemory(StaticTask_t** ppxIdleTaskTCBBuffer,
  36. StackType_t** ppxIdleTaskStackBuffer,
  37. uint32_t* pulIdleTaskStackSize);
  38. //定时器任务前调用,自定义分配内存
  39. void vApplicationGetTimerTaskMemory(StaticTask_t** ppxTimerTaskTCBBuffer,
  40. StackType_t** ppxTimerTaskStackBuffer,
  41. uint32_t* pulTimerTaskStackSize);
  42. //停止后保存trace文件
  43. static void prvSaveTraceFile(void);
  44. //创建一个 Windows 线程来处理键盘输入
  45. static DWORD WINAPI prvWindowsKeyboardInputThread(void* pvParam);
  46. //接收键盘输入时的中断处理程序。
  47. static uint32_t prvKeyboardInterruptHandler(void);
  48. //blinky的中断程序
  49. extern void vBlinkyKeyboardInterruptHandler(int xKeyPressed);
  50. /*-----------------------------------------------------------*/
  51. //configSUPPORT_STATIC_ALLOCATION = 1 可以通过回调函数来手动分配内存给空闲任务和定时器任务,简单来说就是用于测试demo
  52. StackType_t uxTimerTaskStack[configTIMER_TASK_STACK_DEPTH];
  53. //获取键盘输入的线程 的句柄
  54. static HANDLE xWindowsKeyboardInputThreadHandle = NULL;
  55. //存储最后一个未被处理的按键,空闲时处理
  56. static int xKeyPressed = mainNO_KEY_PRESS_VALUE;
  57. /*-----------------------------------------------------------*/
  58. int main(void)
  59. {
  60. //初始化堆内存管理器
  61. prvInitialiseHeap();
  62. //初始化Tracer,可选择不用Tracer
  63. configASSERT(xTraceInitialize() == TRC_SUCCESS);
  64. //开启Tracer,configASSERT()调用了,就会保存Tracer
  65. printf(
  66. "The trace will be dumped to the file \"%s\" whenever a call to configASSERT()\r\n"
  67. "fails or the \'%c\' key is pressed.\r\n",
  68. mainTRACE_FILE_NAME, mainOUTPUT_TRACE_KEY);
  69. configASSERT(xTraceEnable(TRC_START) == TRC_SUCCESS);
  70. //设置键盘输入的中断处理程序。
  71. vPortSetInterruptHandler(mainINTERRUPT_NUMBER_KEYBOARD, prvKeyboardInterruptHandler);
  72. // 开处理键盘中断的线程
  73. xWindowsKeyboardInputThreadHandle = CreateThread(
  74. NULL, //指向线程安全属性
  75. 0, //初始化线程堆栈大小,字节为单位
  76. prvWindowsKeyboardInputThread, //线程函数指针
  77. NULL, // 新线程参数
  78. 0, // 标志
  79. NULL);
  80. //将未被 FreeRTOS 任务使用的核心分配给 Windows 线程
  81. SetThreadAffinityMask(xWindowsKeyboardInputThreadHandle, ~0x01u);
  82. main_Task();
  83. return 0;
  84. }
  85. /*-----------------------------------------------------------*/
  86. void vApplicationMallocFailedHook(void)
  87. {
  88. // configUSE_MALLOC_FAILED_HOOK = 1 开启钩子函数 作用是内存分配pvPortMalloc失败进行错误处理
  89. vAssertCalled(__LINE__, __FILE__);
  90. }
  91. /*-----------------------------------------------------------*/
  92. void vApplicationIdleHook(void)
  93. {
  94. }
  95. /*-----------------------------------------------------------*/
  96. void vApplicationStackOverflowHook(TaskHandle_t pxTask,
  97. char* pcTaskName)
  98. {
  99. (void)pcTaskName;
  100. (void)pxTask;
  101. //将configCHECK_FOR_STACK_OVERFLOW定义为1或2,则会执行运行时堆栈溢出检查。如果检测到堆栈溢出,将调用此钩子函数
  102. vAssertCalled(__LINE__, __FILE__);
  103. }
  104. /*-----------------------------------------------------------*/
  105. void vApplicationTickHook(void)
  106. {
  107. //将configUSE_TICK_HOOK设置为1,则每次tick中断都会调用此函数。可以在此处自定义代码,注意不要阻塞
  108. }
  109. /*-----------------------------------------------------------*/
  110. void vApplicationDaemonTaskStartupHook(void)
  111. {
  112. //仅在守护任务开始执行时调用一次的钩子函数(有时称为定时器任务)
  113. }
  114. /*-----------------------------------------------------------*/
  115. void vAssertCalled(unsigned long ulLine,
  116. const char* const pcFileName)
  117. {
  118. static BaseType_t xPrinted = pdFALSE;
  119. volatile uint32_t ulSetToNonZeroInDebuggerToContinue = 0;
  120. // configASSERT() 断言失败调用
  121. (void)ulLine;
  122. (void)pcFileName;
  123. taskENTER_CRITICAL();
  124. {
  125. printf("ASSERT! Line %ld, file %s, GetLastError() %ld\r\n", ulLine, pcFileName, GetLastError());
  126. //停止跟踪记录并保存跟踪
  127. (void)xTraceDisable();
  128. prvSaveTraceFile();
  129. //如果正在调试,则会导致调试器断点
  130. __debugbreak();
  131. //将ulSetToNonZeroInDebuggerToContinue设置为一个非零值,
  132. //可以使程序在断言失败时暂停执行,以便使用调试器来查看当前的程序状态和变量值,定位和解决问题。
  133. while (ulSetToNonZeroInDebuggerToContinue == 0)
  134. {
  135. __asm {
  136. NOP
  137. };
  138. __asm {
  139. NOP
  140. };
  141. }
  142. // 重启Tracer记录
  143. (void)xTraceEnable(TRC_START);
  144. }
  145. taskEXIT_CRITICAL();
  146. }
  147. /*-----------------------------------------------------------*/
  148. static void prvSaveTraceFile(void)
  149. {
  150. FILE* pxOutputFile;
  151. fopen_s(&pxOutputFile, mainTRACE_FILE_NAME, "wb");
  152. if (pxOutputFile != NULL)
  153. {
  154. fwrite(RecorderDataPtr, sizeof(RecorderDataType), 1, pxOutputFile);
  155. fclose(pxOutputFile);
  156. printf("\r\nTrace output saved to %s\r\n\r\n", mainTRACE_FILE_NAME);
  157. }
  158. else
  159. {
  160. printf("\r\nFailed to create trace dump file\r\n\r\n");
  161. }
  162. }
  163. /*-----------------------------------------------------------*/
  164. static void prvInitialiseHeap(void)
  165. {
  166. //heap_5是一个具有灵活性和可配置性的堆实现,
  167. //为了简化示例,我们创建了一个大的数组,并在数组中使用偏移量来确定每个堆区域的位置。
  168. //这些堆区域之间有间隔和杂乱的对齐,这样做是为了模拟实际场景中可能出现的情况。通过使用这些堆区域,我们可以测试和验证堆的分配和释放操作。
  169. static uint8_t ucHeap[configTOTAL_HEAP_SIZE];
  170. volatile uint32_t ulAdditionalOffset = 19; /* Just to prevent 'condition is always true' warnings in configASSERT(). */
  171. const HeapRegion_t xHeapRegions[] =
  172. {
  173. //具有伪偏移量的起始地址
  174. { ucHeap + 1, mainREGION_1_SIZE },
  175. { ucHeap + 15 + mainREGION_1_SIZE, mainREGION_2_SIZE },
  176. { ucHeap + 19 + mainREGION_1_SIZE + mainREGION_2_SIZE, mainREGION_3_SIZE },
  177. { NULL, 0 }
  178. };
  179. // 检查定义的尺寸和偏移是否实际适合
  180. configASSERT((ulAdditionalOffset + mainREGION_1_SIZE + mainREGION_2_SIZE + mainREGION_3_SIZE) < configTOTAL_HEAP_SIZE);
  181. // 未定义configASSERT()时阻止编译器警告
  182. (void)ulAdditionalOffset;
  183. vPortDefineHeapRegions(xHeapRegions);
  184. }
  185. /*-----------------------------------------------------------*/
  186. // configUSE_STATIC_ALLOCATION = 1, 必须提供vApplicationGetIdleTaskMemory()的实现
  187. void vApplicationGetIdleTaskMemory(StaticTask_t** ppxIdleTaskTCBBuffer,
  188. StackType_t** ppxIdleTaskStackBuffer,
  189. uint32_t* pulIdleTaskStackSize)
  190. {
  191. //如果在空闲任务函数中声明的缓冲区变量没有被声明为静态变量,而是被分配在栈上,
  192. //那么在该函数退出后,栈上的变量会被释放,因此这些缓冲区变量将不再存在,可能会导致错误。
  193. static StaticTask_t xIdleTaskTCB;
  194. static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE];
  195. //该函数会返回一个指向静态任务结构体(StaticTask_t)的指针,该结构体将用于存储空闲任务(Idle task)的状态。
  196. *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
  197. //该函数会返回一个数组,这个数组将作为空闲任务(Idle task)的栈使用。
  198. *ppxIdleTaskStackBuffer = uxIdleTaskStack;
  199. //空闲任务栈的大小是通过指针*ppxIdleTaskStackBuffer所指向的数组来确定的。这个数组的类型是StackType_t类型。
  200. //这个数组的大小是以StackType_t类型的单词为单位来指定的,而不是以字节为单位。
  201. //configMINIMAL_STACK_SIZE宏定义,它是指栈中最小的可接受空间大小,以确保任务能够正常运行。
  202. *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
  203. }
  204. /*-----------------------------------------------------------*/
  205. // configUSE_STATIC_ALLOCATION = 1 静态分配任务内存
  206. // configUSE_TIMERS are both set to 1, 开启定时器
  207. //必须要实现 vApplicationGetTimerTaskMemory() 这个函数功能是为定时器任务分配内存
  208. void vApplicationGetTimerTaskMemory(StaticTask_t** ppxTimerTaskTCBBuffer,
  209. StackType_t** ppxTimerTaskStackBuffer,
  210. uint32_t* pulTimerTaskStackSize)
  211. {
  212. // 如果在vApplicationGetTimerTaskMemory()函数内声明提供给Timer任务的缓冲区,则必须将它们声明为静态变量
  213. static StaticTask_t xTimerTaskTCB;
  214. //传递一个指向StaticTask_t结构的指针,其中Timer任务的状态将被存储
  215. *ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
  216. // 传递将用作Timer任务堆栈的数组
  217. *ppxTimerTaskStackBuffer = uxTimerTaskStack;
  218. //传递指向*ppxTimerTaskStackBuffer的数组大小。由于数组必须是StackType_t类型,因此configMINIMAL_STACK_SIZE 单位是字而不是字节
  219. *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
  220. }
  221. /*-----------------------------------------------------------*/
  222. //接收键盘输入时的中断处理程序。
  223. static uint32_t prvKeyboardInterruptHandler(void)
  224. {
  225. /* 处理键盘输入 */
  226. switch (xKeyPressed)
  227. {
  228. case mainNO_KEY_PRESS_VALUE:
  229. break;
  230. case mainOUTPUT_TRACE_KEY:
  231. //通过进入临界区,可以防止在FreeRTOS模拟器内部调用Windows系统调用时发生死锁或错误。这样可以确保保存跟踪文件的操作能够顺利进行
  232. portENTER_CRITICAL();
  233. {
  234. (void)xTraceDisable();
  235. prvSaveTraceFile();
  236. (void)xTraceEnable(TRC_START);
  237. }
  238. portEXIT_CRITICAL();
  239. break;
  240. default:
  241. /* 调用中断处理程序. */
  242. vBlinkyKeyboardInterruptHandler(xKeyPressed);
  243. break;
  244. }
  245. //此中断不需要上下文切换,因此返回pdFALSE
  246. return pdFALSE;
  247. }
  248. /*-----------------------------------------------------------*/
  249. //从Windows线程函数捕获键盘输入并使用整数将其传递到FreeRTOS模拟器
  250. static DWORD WINAPI prvWindowsKeyboardInputThread(void* pvParam)
  251. {
  252. (void)pvParam;
  253. for (; ; )
  254. {
  255. // 阻塞并等待键盘输入.
  256. xKeyPressed = _getch();
  257. //通知FreeRTOS模拟器存在键盘中断。这将触发prvKeyboardInterruptHandler
  258. vPortGenerateSimulatedInterrupt(mainINTERRUPT_NUMBER_KEYBOARD);
  259. }
  260. //不应该到达这里,所以返回负退出状态
  261. return -1;
  262. }
  263. /*-----------------------------------------------------------*/
  264. // 跟踪记录器使用以下代码进行计时
  265. static uint32_t ulEntryTime = 0;
  266. void vTraceTimerReset(void)
  267. {
  268. ulEntryTime = xTaskGetTickCount();
  269. }
  270. uint32_t uiTraceTimerGetFrequency(void)
  271. {
  272. return configTICK_RATE_HZ;
  273. }
  274. uint32_t uiTraceTimerGetValue(void)
  275. {
  276. return(xTaskGetTickCount() - ulEntryTime);
  277. }
Blink.c
  1. /* Standard includes. */
  2. #include <stdio.h>
  3. #include <conio.h>
  4. /* Kernel includes. */
  5. #include "FreeRTOS.h"
  6. #include "task.h"
  7. #include "timers.h"
  8. #include "semphr.h"
  9. // 任务优先级
  10. #define mainQUEUE_RECEIVE_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )
  11. #define mainQUEUE_SEND_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )
  12. // 发送频率/ms
  13. #define mainTASK_SEND_FREQUENCY_MS pdMS_TO_TICKS( 200UL )
  14. #define mainTIMER_SEND_FREQUENCY_MS pdMS_TO_TICKS( 2000UL )
  15. // 队列最大长度
  16. #define mainQUEUE_LENGTH ( 2 )
  17. // 任务/定时器发送给队列的数据
  18. #define mainVALUE_SENT_FROM_TASK ( 100UL )
  19. #define mainVALUE_SENT_FROM_TIMER ( 200UL )
  20. // 键盘输入
  21. #define mainNO_KEY_PRESS_VALUE ( -1 )
  22. #define mainRESET_TIMER_KEY ( 'r' )
  23. /*-----------------------------------------------------------*/
  24. // 任务句柄,分别是向队列收发的任务
  25. static void prvQueueReceiveTask( void *pvParameters );
  26. static void prvQueueSendTask( void *pvParameters );
  27. // 定时器的回调函数
  28. static void prvQueueSendTimerCallback( TimerHandle_t xTimerHandle );
  29. /*-----------------------------------------------------------*/
  30. // 队列句柄
  31. static QueueHandle_t xQueue = NULL;
  32. // 定时器句柄
  33. static TimerHandle_t xTimer = NULL;
  34. /*-----------------------------------------------------------*/
  35. void main_blinky( void )
  36. {
  37. const TickType_t xTimerPeriod = mainTIMER_SEND_FREQUENCY_MS;
  38. printf( "\r\nStarting the blinky demo. Press \'%c\' to reset the software timer used in this demo.\r\n\r\n", mainRESET_TIMER_KEY );
  39. // 创建队列
  40. xQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( uint32_t ) );
  41. if( xQueue != NULL )
  42. {
  43. // 创建任务
  44. xTaskCreate( prvQueueReceiveTask, /* The function that implements the task. */
  45. "Rx", /* The text name assigned to the task - for debug only as it is not used by the kernel. */
  46. configMINIMAL_STACK_SIZE, /* The size of the stack to allocate to the task. */
  47. NULL, /* The parameter passed to the task - not used in this simple case. */
  48. mainQUEUE_RECEIVE_TASK_PRIORITY,/* The priority assigned to the task. */
  49. NULL ); /* The task handle is not required, so NULL is passed. */
  50. xTaskCreate( prvQueueSendTask, "TX", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_SEND_TASK_PRIORITY, NULL );
  51. // 创建定时器
  52. xTimer = xTimerCreate( "Timer", /* The text name assigned to the software timer - for debug only as it is not used by the kernel. */
  53. xTimerPeriod, /* The period of the software timer in ticks. */
  54. pdTRUE, /* xAutoReload is set to pdTRUE, so this timer goes off periodically with a period of xTimerPeriod ticks. */
  55. NULL, /* The timer's ID is not used. */
  56. prvQueueSendTimerCallback );/* The function executed when the timer expires. */
  57. //启动定时器
  58. xTimerStart( xTimer, 0 );
  59. // 开启调度器
  60. vTaskStartScheduler();
  61. }
  62. for( ;; );
  63. }
  64. /*-----------------------------------------------------------*/
  65. static void prvQueueSendTask( void *pvParameters )
  66. {
  67. TickType_t xNextWakeTime;
  68. const TickType_t xBlockTime = mainTASK_SEND_FREQUENCY_MS;
  69. const uint32_t ulValueToSend = mainVALUE_SENT_FROM_TASK;
  70. // 防警告“入参没用到”的,实际上没用
  71. ( void ) pvParameters;
  72. // 初始化为当前的tick数
  73. xNextWakeTime = xTaskGetTickCount();
  74. for( ;; )
  75. {
  76. // 延时Block次,然后next会更新为 next + block
  77. vTaskDelayUntil( &xNextWakeTime, xBlockTime );
  78. // 向队列发送数据,数据为100UL
  79. xQueueSend( xQueue, &ulValueToSend, 0U );
  80. }
  81. }
  82. /*-----------------------------------------------------------*/
  83. static void prvQueueSendTimerCallback( TimerHandle_t xTimerHandle )
  84. {
  85. const uint32_t ulValueToSend = mainVALUE_SENT_FROM_TIMER;
  86. ( void ) xTimerHandle;
  87. // 只有定时器到期(设置为2s)才会执行的回调函数,也会向队列发送数据,数据为200UL
  88. xQueueSend( xQueue, &ulValueToSend, 0U );
  89. }
  90. /*-----------------------------------------------------------*/
  91. static void prvQueueReceiveTask( void *pvParameters )
  92. {
  93. uint32_t ulReceivedValue;
  94. ( void ) pvParameters;
  95. for( ;; )
  96. {
  97. // 从队列收数据,队列长度为2
  98. xQueueReceive( xQueue, &ulReceivedValue, portMAX_DELAY );
  99. //进入临界区,确保printf可以执行完毕,因为printf消耗很多堆栈资源
  100. taskENTER_CRITICAL();
  101. {
  102. if (ulReceivedValue == mainVALUE_SENT_FROM_TASK)
  103. {
  104. printf("Message received from task - idle time %llu%%\r\n", ulTaskGetIdleRunTimePercent());
  105. }
  106. else if (ulReceivedValue == mainVALUE_SENT_FROM_TIMER)
  107. {
  108. printf("Message received from software timer\r\n");
  109. }
  110. else
  111. {
  112. printf("Unexpected message\r\n");
  113. }
  114. }
  115. taskEXIT_CRITICAL();
  116. }
  117. }
  118. /*-----------------------------------------------------------*/
  119. /* 被它调用:prvKeyboardInterruptSimulatorTask(),定义在 main.c. */
  120. void vBlinkyKeyboardInterruptHandler( int xKeyPressed )
  121. {
  122. // 处理输入
  123. switch ( xKeyPressed )
  124. {
  125. case mainRESET_TIMER_KEY:
  126. if ( xTimer != NULL )
  127. {
  128. //进入临界区,只允许printf这一个线程,防止死锁
  129. taskENTER_CRITICAL();
  130. {
  131. printf("\r\nResetting software timer.\r\n\r\n");
  132. }
  133. taskEXIT_CRITICAL();
  134. // 重置定时器
  135. xTimerReset( xTimer, portMAX_DELAY );
  136. }
  137. break;
  138. default:
  139. break;
  140. }
  141. }

要新加demo的时候,需要新建一个c文件,在main.c中extern进去,然后再main函数中调用

再次复习官方文档

Assert断言函数

建议在main函数中添加,用于在开发过程中进行断言检查。通过在代码中使用断言,我们可以在开发和调试过程中快速发现和定位潜在的问题。

演示demo中定义在了FreeRTOSconfig.h中

  1. #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __LINE__, __FILE__ )

断言函数定义位于main.c

  1. void vAssertCalled(unsigned long ulLine,
  2. const char* const pcFileName)
  3. {
  4. static BaseType_t xPrinted = pdFALSE;
  5. volatile uint32_t ulSetToNonZeroInDebuggerToContinue = 0;
  6. // configASSERT() 断言失败调用
  7. (void)ulLine;
  8. (void)pcFileName;
  9. taskENTER_CRITICAL();
  10. {
  11. printf("ASSERT! Line %ld, file %s, GetLastError() %ld\r\n", ulLine, pcFileName, GetLastError());
  12. //停止跟踪记录并保存跟踪
  13. (void)xTraceDisable();
  14. prvSaveTraceFile();
  15. //如果正在调试,则会导致调试器断点
  16. __debugbreak();
  17. //将ulSetToNonZeroInDebuggerToContinue设置为一个非零值,
  18. //可以使程序在断言失败时暂停执行,以便使用调试器来查看当前的程序状态和变量值,定位和解决问题。
  19. while (ulSetToNonZeroInDebuggerToContinue == 0)
  20. {
  21. __asm {
  22. NOP
  23. };
  24. __asm {
  25. NOP
  26. };
  27. }
  28. // 重启Tracer记录
  29. (void)xTraceEnable(TRC_START);
  30. }
  31. taskEXIT_CRITICAL();
  32. }

如果 x 表达式的结果为假(即为0),则会调用函数 vAssertCalled,并传递当前代码所在的行号和文件名作为参数。这样可以方便地在断言失败时跟踪和记录相关信息,以便进行调试和排查问题。

从未完全禁用中断,即使是临界区

在 FreeRTOS 中,任务调度器是通过中断来触发的。当发生一个中断时,任务调度器会暂停当前任务,并根据优先级切换到下一个任务。在某些情况下,为了确保关键代码的原子性或实时性(原子性指的是,要不就运行完 要不就干脆不运行),可能需要完全禁用中断。但是在移植 FreeRTOS 时,出于特定的需求或硬件限制,选择不完全禁用中断。

任务函数示例

推荐事件驱动型,记得删除

  1. void vATaskFunction( void *pvParameters )
  2. {
  3. for( ;; )
  4. {
  5. if( WaitForEvent( EventObject, TimeOut ) == pdPASS )
  6. {
  7. -- Handle event here. --
  8. }
  9. else
  10. {
  11. -- Clear errors, or take actions here. --
  12. }
  13. }
  14. /* As per the first code listing above. */
  15. vTaskDelete( NULL );
  16. }

创建任务的宏控

void vTask( void *pvParameters );

可以写成

portTASK_FUNCTION_PROTO( vTask, pvParameters );

队列的几个特点

  1. 消息通过队列以副本的方式发送, 这意味着数据本身被复制到队列中, 而不是队列始终只存储对数据的引用

  2. 使用按副本传递数据的队列不会阻止队列用于按引用传递数据,如果消息太大,也可以开一个队列存指针

任务通知

  1. 任务创建自带任务通知数组:用于存储一个状态(挂起或非挂起)和一个32位的通知值。在数组中,每个索引对应一条任务通知

  2. configTASK_NOTIFICATION_ARRAY_ENTRIES默认为1,表示通知数组长度,也就是最多有几条通知

  3. 向任务发送直达任务通知时,可以通过覆盖原值、仅在接收任务已读取值时才覆盖原值、设置位操作或进行增量操作来更新通知值

限制

  1. 在发送任务通知之前,必须确保只有一个任务会接收这个事件

FreeRTOS例程开发的更多相关文章

  1. FreeRTOS - 程序开发阶段建议

    1.创建任务.定时器等都需要耗用分配给FreeRTOS的heap,由于RAM有限,分配作为FreeRTOS的heap量有限,一不小心就不够用了,所以应该有检测任务.定时器等是否创建成功,如下图: 2. ...

  2. cube+FreeRTOS联合开发采坑笔记

    加了看门狗之后不断重启的可能 原因: 任务容量分配不足,在"FreeRTOSConfig.h"的配置中,有个configTOTAL_HEAP_SIZE中将堆大小调到最大.

  3. CrazyBingo mini VIP 2.0 视频开发板 NIOS移植例程(原创)

    创建一个NIOS环境 注意事项 前言:(先了解下硬件) 本板卡目前主要适合以下几类人: (1)对FPGA 逻辑开发有强烈的兴趣,并且有一定的HDL基础 (2)计划采用FPGA图像架构,学习并研究图像算 ...

  4. VOFM 例程

    SAP ERP 实施中,经常会用到例程开发(TCODE:VOFM).这个开发目前我用到的是影响SD和MM的定价过程.创建例程需要ACCESS KEY,这个可以通过申请得到,创建后例程会被包含在一个RE ...

  5. wumei-smart智能家居开原项目

    一.项目简介 物美智能(wumei-smart)]是一套开源的软硬件系统,可用于二次开发和学习,快速搭建自己的智能家居系统. 硬件工程师可以把自己的设备集成到系统:软件工程师可以使用项目中的设备熟悉软 ...

  6. 【RTOS】基于V7开发板的RTX5和FreeRTOS带CMSIS-RTOS V2封装层的模板例程下载,AC6和AC5两个版本

    说明: 1.使用MDK的RTE环境开发RTX5和FreeRTOS,简单易移植,统一采用CMSIS-RTOS V2封装层. 2.DTCM是H7里面性能最高的RAM,主频400MHz,跟内核速度一样,所以 ...

  7. 【RTOS】基于V7开发板的uCOS-III,uCOS-II,RTX4,RTX5,FreeRTOS原版和带CMSIS-RTOS V2封装层版全部集齐

    RTOS模板制作好后,后面堆各种中间件就方便了. 1.基于V7开发板的最新版uCOS-II V2.92.16程序模板,含MDK和IAR,支持uC/Probe https://www.cnblogs.c ...

  8. 【iCore双核心组合是开发板例程】【12个 verilog 中级实验例程发布】

    _____________________________________ 深入交流QQ群: A: 204255896(1000人超级群,可加入) B: 165201798(500人超级群,满员) C ...

  9. Android应用---基于NDK的samples例程hello-jni学习NDK开发

    Android应用---基于NDK的samples例程hello-jni学习NDK开发 NDK下载地址:http://developer.android.com/tools/sdk/ndk/index ...

  10. 迅为iTOP-4418/6818开发板-驱动-IO初始化配置介绍和例程

    对于所有的处理器,pad 一般可以分为两大类:IO(输入输出).Power(VDD 和GDD).类似摄像头 IO.以太网 IO.PWM 的 IO 等等,都可以统称为 IO.一个 IO,有可能能够被配置 ...

随机推荐

  1. Thinkphp5.x全漏洞复现分析

    基础知识 命名空间和子命名空间 我们可以把namespace理解为一个单独的空间,事实上它也就是一个空间而已,子命名空间那就是空间里再划分几个小空间,举个例子: <?php namespace ...

  2. sql多表分页查询【oracle】

    sql多表查询[oracle] 做个记录,好歹是写出来了,使用左连接的方法,进行四表查询,且使用rownum进行分页 把涉及内容的全部替换了,不过应该都看得懂,就不说了 select * from ( ...

  3. 力扣412(java)-Fizz Buzz(简单)

    题目: 给你一个整数 n ,找出从 1 到 n 各个整数的 Fizz Buzz 表示,并用字符串数组 answer(下标从 1 开始)返回结果,其中: answer[i] == "FizzB ...

  4. HarmonyOS NEXT应用开发案例——行程地址交换动画

    介绍 本示例介绍使用显式动画 animateTo 实现左右地址交换动画.该场景多用于机票.火车票购买等出行类订票软件中. 效果预览图 使用说明 加载完成后显示地址交换动画页面,点击中间的图标,左右两边 ...

  5. Apsara Stack 同行者专刊 | 政企混合云技术架构的演进和发展

    简介: 现在,政企客户已进入到用云计算全面替换传统IT基础架构的攻坚阶段,混合云与传统架构的技术产品能力也正在经历全面的比较与评估.阿里云混合云平台首席架构师张晓丹分享IT架构技术深刻洞察,并对政企混 ...

  6. Go Mysql Driver 集成 Seata-Golang 解决分布式事务问题

    简介: 2020 年 4 月,我们开始尝试实现 go 语言的分布式事务框架 Seata-Golang.众所周知,Seata AT 模式以无业务代码侵入的特点,被广大开发者推崇.Java 版 Seata ...

  7. ClickHouse Keeper 源码解析

    简介:ClickHouse 社区在21.8版本中引入了 ClickHouse Keeper.ClickHouse Keeper 是完全兼容 Zookeeper 协议的分布式协调服务.本文对开源版本 C ...

  8. 6.prometheus监控--监控redis/rabbitmq/mongodb

    1.监控redis 1.1 redis_exporter安装方式 1.1.1 二进制源码安装方式 参考nginx二进制安装方法 redis_exporter下载地址:https://github.co ...

  9. Linux中典型的文件权限问题

    总结起来说,可以打个比方,目录就像一间上了锁有窗户的屋子.如果你只想看屋子里面有啥,那么只要拥有r权限,不必进入到屋子,透过屋子的窗户就能看到里面的东西:但是如果你想改变屋子里面的物件,或者从屋子里面 ...

  10. C语言:快速排序(详解)

    快速排序采用的是两头对比交换 http://t.csdn.cn/TXcAK 上面这个连接大家可以点进去看看博客李小白大大的图文解释,我觉得这个是对我启发比较大的,对刚接触快速排序的人来说非常友好,很快 ...