STM32F1与STM32CubeIDE编程实例-ThreadX中的事件标志组(Event Flags Group ) ThreadX中的事件标志组(Event Flags Group ) 文章目录
1、事件标志介绍 事件标志为线程同步提供了强大的工具。 事件标志可以由任何线程设置或清除,并且可以由任何线程检查。线程可以在等待设置某些事件标志组合时挂起。 每个事件标志由单个位表示。事件标志以 32 个为一组排列,如下图所示:
线程可以同时对组中的所有 32 个事件标志进行操作。 要设置或清除事件标志,请使用 tx_event_flags_set 服务,然后使用 tx_event_flags_get 服务获取或等待事件。
设置或清除事件标志是通过当前事件标志和新事件标志之间的逻辑 AND 或 OR 运算来执行的。 用户在调用 tx_event_flags_set 服务时指定逻辑运算的类型(AND 或 OR)。
获取事件标志有类似的逻辑选项。 获取请求可以指定所有指定的事件标志都是必需的(逻辑与)。 或者,获取请求可以指定任何指定的事件标志将满足请求(逻辑 OR)。 用户在 tx_event_flags_get 调用中指定逻辑操作的类型。
如果请求指定选项 TX_OR_CLEAR 或 TX_AND_CLEAR,则清除满足获取请求的事件标志。 当在获取请求中使用 TX_AND 或 TX_OR 选项时,标志值保持不变。
每个事件标志组都是公共资源。 ThreadX 对如何使用事件标志组没有任何限制。
应用程序可以在初始化期间或运行时创建事件标志组。在创建时,组中的所有事件标志都初始化为零。应用程序可以使用的事件标志组的数量没有限制。
应用程序线程可以在尝试从组中获取事件标志的任何逻辑组合时挂起。 设置组的一个或多个标志后,ThreadX 立即审查在该事件标志组上挂起的所有线程的获取请求。 set 操作满足 get 请求的所有线程都将恢复。
如上所述,当组的至少一个标志已设置时,ThreadX 会检查该组上挂起的所有线程。 此审查过程会产生开销,因此请尝试将使用同一组的线程数限制在合理的数量内。
2、事件标志组控制块 事件组控制块包含诸如当前事件标志的值、重置搜索标志、指向该事件标志组的挂起列表的指针以及该组挂起的线程数等信息。ThreadX中通过使用数据结构TX_EVENT_FLAGS_GROUP描述事件标志组。
事件标志组控制块 (Event Flags Group Control Block,ECB) 可以位于内存中的任何位置,但通常通过在任何函数范围之外定义控制块来使控制块成为全局结构。 当使用 TX_EVENT_FLAGS 数据类型声明事件标志组时,将创建 ECB。例如:
1 2 TX_EVENT_FLAGS_GROUP my_event_flags_group;
TX_EVENT_FLAGS_GROUP如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 /\* Define the event flags group structure utilized by the application. \*/ typedef struct TX\_EVENT\_FLAGS\_GROUP\_STRUCT { /\* Define the event flags group ID used for error checking. \*/ ULONG tx_event_flags_group_id; /\* Define the event flags group's name. \*/ CHAR \*tx_event_flags_group_name; /\* Define the actual current event flags in this group. A zero in a particular bit indicates the event flag is not set. \*/ ULONG tx_event_flags_group_current; /\* Define the reset search flag that is set when an ISR sets flags during the search of the suspended threads list. \*/ UINT tx_event_flags_group_reset_search; /\* Define the event flags group suspension list head along with a count of how many threads are suspended. \*/ struct TX\_THREAD\_STRUCT \*tx_event_flags_group_suspension_list; UINT tx_event_flags_group_suspended_count; /\* Define the created list next and previous pointers. \*/ struct TX\_EVENT\_FLAGS\_GROUP\_STRUCT \*tx_event_flags_group_created_next, \*tx_event_flags_group_created_previous; /\* Define the delayed clearing event flags. \*/ ULONG tx_event_flags_group_delayed_clear; #ifdef TX\_EVENT\_FLAGS\_ENABLE\_PERFORMANCE\_INFO /\* Define the number of event flag sets. \*/ ULONG tx_event_flags_group_performance_set_count; /\* Define the number of event flag gets. \*/ ULONG tx_event_flags_group__performance_get_count; /\* Define the number of event flag suspensions. \*/ ULONG tx_event_flags_group___performance_suspension_count; /\* Define the number of event flag timeouts. \*/ ULONG tx_event_flags_group____performance_timeout_count; #endif #ifndef TX\_DISABLE\_NOTIFY\_CALLBACKS /\* Define the application callback routine used to notify the application when an event flag is set. \*/ VOID (\*tx_event_flags_group_set_notify)(struct TX\_EVENT\_FLAGS\_GROUP\_STRUCT \*group_ptr); #endif /\* Define the port extension in the event flags group control block. This is typically defined to whitespace in tx\_port.h. \*/ TX_EVENT_FLAGS_GROUP_EXTENSION } TX_EVENT_FLAGS_GROUP;
事件标志组的声明通常出现在程序的声明和定义部分。
3、事件标志组服务 3.1 创建事件标志组 事件标志组使用 TX_EVENT_FLAGS_GROUP 数据类型声明,并使用 tx_event_flags_create 服务定义。 定义事件标志组时,必须指定其控制块和事件标志组的名称。 创建时,组的所有事件标志都初始化为零。其原型如下:
UINT tx_event_flags_create(TX_EVENT_FLAGS_GROUP *group_ptr,CHAR *name_ptr);
其中:
group_ptr :指向事件标志组控制块的指针
name_ptr :指向事件标志组名称的指针
当成功创建事件标志组时,函数返回TX_SUCCESS。
简单示例如下:
1 2 3 4 5 TX_EVENT_FLAGS_GROUP my_event_group; UINT status; status = tx\_event\_flags\_create(&my_event_group,"my\_event\_group\_name");
变量status的值为TX_SUCCESS时,表示创建成功。
3.2 删除事件标志组 tx_event_flags_delete 服务删除事件标志组。 当一个组被删除时,所有挂起的线程都会恢复并收到一个 TX_DELETED 返回状态。 确保不要尝试使用已删除的事件标志组。其原型如下:
UINT tx_event_flags_delete(TX_EVENT_FLAGS_GROUP *group_ptr);
简单示例如下:
1 2 3 4 5 6 7 8 TX_EVENT_FLAGS_GROUP my_event_group; UINT status; ... status = tx\_event\_flags\_delete(&my_event_group);
变量status的值为TX_SUCCESS时,成功删除事件标志组。
3.3 检索或等待事件 tx_event_flags_get 服务“get”或等待来自事件标志组的事件标志。如果请求的标志已在指定的事件标志中设置,则满足获取请求。其原型如下:
UINT tx_event_flags_get(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG requested_flags, UINT get_option, ULONG *actual_flags_ptr, ULONG wait_option);
其中:
group_ptr :指向事件标志组控制块的指针
requested_flags :请求事件标志
get_option :指定And/OR逻辑清除选项。其取值如下:
Get Option
描述
TX_AND
必须在指定的事件标志组中设置所有请求的事件标志
TX_AND_CLEAR
所有请求的事件标志都必须设置在指定的事件标志组中; 满足请求的事件标志被清除
TX_OR
必须在指定的事件标志组中设置至少一个请求的事件标志
TX_OR_CLEAR
必须在指定的事件标志组中设置至少一个请求的事件标志; 满足请求的事件标志被清除
actual_flags_ptr :用于放置服务检索到的实际标志的指针
wait_option :等待选项
如果获取成功,函数返回TX_SUCCESS。
例如,假设我们要确定事件标志 0、4 和 8 是否都已设置。 此外,如果这些标志都设置了,那么我们希望它们都被清除。如下图所示:
这对应于十六进制值 0x111,我们将在示例获取操作中使用它。 如果在发出请求时未设置所有所需的事件标志,那么我们将指定最长等待 20 个计时器滴答以使它们被设置。如下面代码所示:
1 2 3 4 5 6 7 8 9 10 TX_EVENT_FLAGS_GROUP my_event_group; ULONG actual_events; UINT status; ... status = tx\_event\_flags\_get(&my_event_group, 0x111, TX_AND_CLEAR, &actual_events, 20);
在示例代码中,通过调用tx_event_flags_get 服务来尝试确定事件标志 0、4 和 8 是否都已设置。
如果status等于 TX_SUCCESS,则发现事件标志 0、4 和 8 处于设置状态,并且这些标志随后被清除。 变量 actual_events 包含在清除之前找到的那些标志的状态,以及来自事件标志组的剩余标志的状态。
假设事件标志组的值为 0x537,如下图所示:
调用了示例中的 tx_event_flags_get 服务后,新的事件标志组的值为0x426。如下图所示:
变量 actual_events 现在包含 0x537,它是事件标志组的原始值。相反,如果 get_option 是 TX_AND(而不是 TX_AND_CLEAR),则 get 操作也将得到满足,并且事件标志组将保持不变,值为 0x537。 在这种情况下,变量 actual_events 在服务返回后值为 0x537。
前面的示例使用 TX_AND 和 TX_AND_CLEAR get_options。 下面将考虑另一个示例来说明 TX_OR 和 TX_OR_CLEAR的效果。 假设我们要确定是否设置了事件标志 0、5 和 10 中的至少一个。 此外,我们将清除所有设置的标志。如下图所示:
事件标志组为0x421 的十六进制值,我们将在 get 操作中使用它。如果在发出 get 请求时没有设置任何事件标志,那么我们将无限期地等待其中至少一个被设置。
假设事件标志组的值为 0x537。 我们将使用 TX_OR 调用 tx_event_flags_get 服务来确定是否设置了事件标志 0、5 和 10 中的一个或多个。
1 2 3 4 5 6 7 8 9 TX_EVENT_FLAGS_GROUP my_event_group; ULONG actual_events; UINT status; ... status = tx\_event\_flags\_get(&my_event_group, 0x421, TX_OR,&actual_events, TX_WAIT_FOREVER);
如果status等于 TX_SUCCESS,则至少设置了事件标志 0、5 和 10 之一,并且事件标志组的值保持不变。 变量 actual_events 包含值 0x537,它是事件标志组的原始值。
假设事件标志组的值为 0xFF0C,如下图所示:
按上面示例代码调用tx_event_flags_get服务,由于设置了标志 10,因此满足 get 操作。 事件标志组的值保持不变,变量 actual_events 包含该值的副本。但是,如果我们使用 TX_OR_CLEAR,则事件标志组将更改为值 0xFB0C,如下图所示,第10个标志位将被清除。
变量 actual_events 的值为 0xFF0C,这是事件标志组的原始值。
3.4 事件标志组设置 tx_event_flags_set 服务设置或清除组中的一个或多个事件标志。 当执行设置服务并实际设置一个或多个标志时,调度程序检查是否有任何线程为该事件标志组挂起。 如果有线程为该组的结果值挂起,则恢复这些线程。其原型如下:
UINT tx_event_flags_set(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG flags_to_set, UINT set_option);
其中:
group_ptr :指向事件标志组控制块指针
flags_to_set :需要设置的事件标志
set_option :设置方式,其取值如下:
TX_AND :指定的事件标志与当前事件标志组进行与运算; 此选项通常用于清除组中的事件标志
TX_OR :指定的事件标志与当前事件标志组进行或运算
设置成功,函数返回TX_SUCCESS。
例如,假设我们要清除除标志 0、4 和 8 之外的所有标志,其中事件标志组的当前值为 0xFF0C。我们将传递值 0x111(即事件标志 0、4 和 8)并使用 TX_AND 选项,如下图所示:
事件标志组的新值是 0x100,因为标志 8 是值 0xFF0C 和 0x112 的唯一共同标志。 但是,如果使用 TX_OR 选项,则新的事件标志组值为 0xFF1D,如下图所示:
示例代码如下:
1 2 3 4 5 6 7 8 TX_EVENT_FLAGS_GROUP my_event_group; UINT status; ... /\*设置事件标志0,4,8\*/ status = tx\_event\_flags\_set(&my_event_group,0x111, TX_OR);
如果变量status的值为 TX_SUCCESS,则已设置请求的事件标志。 在这些事件标志上挂起的任何线程都已恢复。
3.5 事件标志组信息检索 可以通过三种服务检索有关事件标志组的重要信息:
tx_event_flags_info_get :从事件标志组控制块中检索信息子集。此信息提供特定时刻的**快照(Snapshot)**,即调用服务时。
其他两个服务提供基于收集的运行时性能数据的摘要信息:
tx_event_flags_performance_info_get :提供特定事件标志组的信息摘要,直至调用该服务
tx_event_flags_performance_system_info_get :检索系统中所有事件标志组的信息摘要,直至调用服务。这些服务有助于分析系统的行为并确定是否存在潜在的问题区域
这三个服务的原型如下:
UINT tx_event_flags_info_get(TX_EVENT_FLAGS_GROUP *group_ptr, CHAR **name, ULONG *current_flags, TX_THREAD **first_suspended, ULONG *suspended_count, TX_EVENT_FLAGS_GROUP **next_group);
UINT tx_event_flags_performance_info_get(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG *sets, ULONG *gets, ULONG *suspensions, ULONG *timeouts);
UINT tx_event_flags_performance_system_info_get(ULONG *sets, ULONG *gets, ULONG *suspensions, ULONG *timeouts);
简单示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 TX_EVENT_FLAGS_GROUP my_event_group; CHAR \*name; ULONG current_flags; TX_THREAD \*first_suspended; ULONG suspended_count; TX_EVENT_FLAGS_GROUP \*next_group; UINT status; ... status = tx\_event\_flags\_info\_get(&my_event_group, &name, ¤t_flags, &first_suspended, &suspended_count, &next_group);
如果变量status的值为TX_SUCCESS,则表示检索成功。
3.6 事件标志组通知 tx_event_flags_set_notify 服务注册一个通知回调函数,只要在指定的事件标志组中设置了一个或多个事件标志,就会调用该函数。 通知回调的处理由应用程序定义。 这是一个事件链示例,其中通知服务用于将各种同步事件链接在一起。 当单个线程必须处理多个同步事件时,这通常很有用。其原型如下:
UINT tx_event_flags_set_notify(TX_EVENT_FLAGS_GROUP *group_ptr, VOID (*events_set_notify)(TX_EVENT_FLAGS_GROUP *));
4、完整示例 在本节中,将演示事件标志组如何使用。示例一共由三个线程组成,一个用于发送不同的事件,另外两个线程用于接收事件。
4.1 应用程序 1)基本定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 /\* \* app.h \* \* Created on: May 3, 2022 \* Author: jenson \*/ #ifndef \_\_APP\_H\_\_ #define \_\_APP\_H\_\_ #include "tx\_api.h" // 事件标志组 extern TX_EVENT_FLAGS_GROUP app_event_flags_group; // 事件定义 #define APP\_EVENT\_WRITE 0x01 #define APP\_EVENT\_READ 0x10 void app\_start(void); uint16\_t create\_task\_stack(void\*\* statck,uint32\_t size); #endif /\* \_\_APP\_H\_\_ \*/
2)定义实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 /\* \* app.c \* \* Created on: May 3, 2022 \* Author: jenson \*/ #include <stdio.h> #include "main.h" #include "app.h" #include "tx\_api.h" #include "tx\_thread.h" #include <stdbool.h> #include "tasks/consumer\_task.h" #include "tasks/producer\_task.h" // 事件标志组 TX_EVENT_FLAGS_GROUP app_event_flags_group; // 10k应用程序内存 #define APP\_MEMORY\_SIZE 1024 \* 10 // 字节内存句柄 static TX_BYTE_POOL __s_app_statc_pool; static uint8\_t __app_memory_area[APP_MEMORY_SIZE]; // 创建字节内存池 uint16\_t create\_app\_byte\_pool() { UINT status; // 创建字节内存池 status = tx\_byte\_pool\_create(&__s_app_statc_pool, "app\_byte\_pool", __app_memory_area, APP_MEMORY_SIZE); return status; } // 创建字节栈 uint16\_t create\_task\_stack(void \*\*statck, uint32\_t size) { UINT status; // 分配字节内存 status = tx\_byte\_allocate(&__s_app_statc_pool, statck, size, TX_NO_WAIT); return status; } void tx\_application\_define(void \*first_unused_memory) { uint16\_t status = create\_app\_byte\_pool(); if (status != TX_SUCCESS) { printf("create app memory byte pool failed:code = %d\r\n", status); while (true) ; } // 创建事件标志组 status = tx\_event\_flags\_create(&app_event_flags_group,"app\_event\_flags\_group"); if (status != TX_SUCCESS) { printf("create event flags group failed:code = %d\r\n", status); while (true) ; } create\_producer\_task(); create\_consumer\_task(); } void app\_start(void) { // 启用内核调度 tx\_kernel\_enter(); }
4.2 事件发送线程 1)基本定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 /\* \* producer\_task.h \* \* Created on: May 3, 2022 \* Author: jenson \*/ #ifndef \_\_PRODUCER\_TASK\_H\_\_ #define \_\_PRODUCER\_TASK\_H\_\_ void create\_producer\_task(void); #endif /\* \_\_PRODUCER\_TASK\_H\_\_ \*/
2)定义实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 /\* \* producer\_task.c \* \* Created on: May 3, 2022 \* Author: jenson \*/ #include "tx\_api.h" #include "tx\_thread.h" #include <stdio.h> #include <tasks/producer\_task.h> #include "app.h" #define PRODUCER\_THREAD\_STACK\_SIZE 512 TX_THREAD producer_thread_handle; uint8\_t \* producer_thread_stack = NULL; void producer\_task\_entry(void \*params) { printf("[task]producer started\r\n"); int counter = 0; for (;;) { counter++; if(counter % 2 == 0){ tx\_event\_flags\_set(&app_event_flags_group,APP_EVENT_WRITE,TX_OR); printf("producer send write event\r\n"); }else{ tx\_event\_flags\_set(&app_event_flags_group,APP_EVENT_READ,TX_OR); printf("producer send read event\r\n"); } tx\_thread\_sleep(500); } } void create\_producer\_task(void){ uint16\_t status = create\_task\_stack(&producer_thread_stack, PRODUCER_THREAD_STACK_SIZE); if(status != TX_SUCCESS){ printf("cannot create producer task stack\r\n"); return; } tx\_thread\_create(/\*创建线程\*/ &producer_thread_handle, /\*线程句柄\*/ "producer\_task", /\*线程名称\*/ producer_task_entry, /\*线程执行函数\*/ NULL, /\*线程函数\*/ producer_thread_stack, /\*线程堆栈入口\*/ PRODUCER_THREAD_STACK_SIZE, /\*线程堆栈大小\*/ 2, /\*优先级\*/ 2, /\*抢占阈值\*/ TX_NO_TIME_SLICE, /\*线程时间切片类型\*/ TX_AUTO_START /\*线程启动类型:自动启动\*/ ); printf("created producer task\r\n"); }
4.3 事件接收线程 1)基本定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 /\* \* consumer\_task.h \* \* Created on: May 3, 2022 \* Author: jenson \*/ #ifndef \_\_CONSUMER\_TASK\_H\_\_ #define \_\_CONSUMER\_TASK\_H\_\_ void create\_consumer\_task(void); #endif /\* \_\_CONSUMER\_TASK\_H\_\_ \*/
2)定义实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 /\* \* consumer\_task.c \* \* Created on: May 3, 2022 \* Author: jenson \*/ #include "tx\_api.h" #include "tx\_thread.h" #include <stdio.h> #include <tasks/consumer\_task.h> #include "app.h" #define CONSUMER\_THREAD\_STACK\_SIZE 512 TX_THREAD consumer1_thread_handle; uint8\_t \*consumer1_thread_stack = NULL; TX_THREAD consumer2_thread_handle; uint8\_t \*consumer2_thread_stack = NULL; void consumer1\_task\_entry(void \*params) { printf("[task]consumer 1 started\r\n"); uint32\_t actual_event = 0x00; UINT status; for (;;) { status = tx\_event\_flags\_get(&app_event_flags_group, APP_EVENT_WRITE, TX_AND_CLEAR, &actual_event, TX_WAIT_FOREVER); if (status == TX_SUCCESS) { printf("consumer 1 received write event\r\n"); } tx\_thread\_sleep(10); } } void consumer2\_task\_entry(void \*params) { printf("[task]consumer 2 started\r\n"); uint32\_t actual_event = 0x00; UINT status; for (;;) { status = tx\_event\_flags\_get(&app_event_flags_group, APP_EVENT_READ, TX_AND_CLEAR, &actual_event, TX_WAIT_FOREVER); if (status == TX_SUCCESS) { printf("consumer 2 received read event\r\n"); } tx\_thread\_sleep(10); } } void create\_consumer\_task(void) { uint16\_t status = create\_task\_stack(&consumer1_thread_stack, CONSUMER_THREAD_STACK_SIZE); if (status != TX_SUCCESS) { printf("cannot create consumer 1 task stack\r\n"); return; } status = create\_task\_stack(&consumer2_thread_stack, CONSUMER_THREAD_STACK_SIZE); if (status != TX_SUCCESS) { printf("cannot create consumer 2 task stack\r\n"); return; } tx\_thread\_create(/\*创建线程\*/ &consumer1_thread_handle, /\*线程句柄\*/ "consumer1\_task", /\*线程名称\*/ consumer1_task_entry, /\*线程执行函数\*/ NULL, /\*线程参数\*/ consumer1_thread_stack, /\*线程堆栈入口\*/ CONSUMER_THREAD_STACK_SIZE, /\*线程堆栈大小\*/ 3, /\*优先级\*/ 3, /\*抢占阈值\*/ TX_NO_TIME_SLICE, /\*线程时间切片类型\*/ TX_AUTO_START /\*线程启动类型:自动启动\*/ ); tx\_thread\_create(/\*创建线程\*/ &consumer2_thread_handle, /\*线程句柄\*/ "consumer2\_task", /\*线程名称\*/ consumer2_task_entry, /\*线程执行函数\*/ NULL, /\*线程参数\*/ consumer2_thread_stack, /\*线程堆栈入口\*/ CONSUMER_THREAD_STACK_SIZE, /\*线程堆栈大小\*/ 3, /\*优先级\*/ 3, /\*抢占阈值\*/ TX_NO_TIME_SLICE, /\*线程时间切片类型\*/ TX_AUTO_START /\*线程启动类型:自动启动\*/ ); printf("created consumer task\r\n"); }
4.4 主程序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 /\* Private includes ----------------------------------------------------------\*/ /\* USER CODE BEGIN Includes \*/ #include "app.h" #include <stdio.h> /\* USER CODE END Includes \*/ int main(void) { /\* USER CODE BEGIN 1 \*/ /\* USER CODE END 1 \*/ /\* MCU Configuration--------------------------------------------------------\*/ /\* Reset of all peripherals, Initializes the Flash interface and the Systick. \*/ HAL\_Init(); /\* USER CODE BEGIN Init \*/ /\* USER CODE END Init \*/ /\* Configure the system clock \*/ SystemClock\_Config(); /\* USER CODE BEGIN SysInit \*/ /\* USER CODE END SysInit \*/ /\* Initialize all configured peripherals \*/ MX\_GPIO\_Init(); MX\_USART1\_UART\_Init(); /\* USER CODE BEGIN 2 \*/ printf("\*\*\*\*STM32CubeIDE:ThreadX Demo\*\*\*\*\r\n"); app\_start(); /\* USER CODE END 2 \*/ /\* Infinite loop \*/ /\* USER CODE BEGIN WHILE \*/ while (1) { /\* USER CODE END WHILE \*/ /\* USER CODE BEGIN 3 \*/ } /\* USER CODE END 3 \*/ }
运行结果:
文章来源: https://iotsmart.blog.csdn.net/article/details/125161961