就和我们小时候背课文一样,有些代码也是需要背的(有点夸张,但至少也需要很熟悉).今天把STM32的threadX的演示代码贴在这,以便让我再熟悉一点.
这段代码的说明(翻译自官方说明文档)
此应用程序提供了一个Azure RTOS ThreadX堆栈使用示例,它展示了如何使用ThreadX线程管理API开发应用程序. 它演示了如何使用Azure RTOS ThreadX APIs 创建和销毁多个线程.此外,它还演示了如何在线程之间使用抢占阈值并动态更改优先级. 在ThreadX内核启动过程中ThreadX调用主入口函数 tx_application_define(), 在这个阶段,应用程序创建了3个拥有不同优先级的线程:
- MainThread (优先级 : 5; 抢占阈值 : 5)
- ThreadOne (优先级 : 10; 抢占阈值 : 9)
- ThreadTwo (优先级 : 10; 抢占阈值 : 10)
目前我还没有搞清楚抢占阈值的意思,暂时认为是抢占优先级.等我搞清楚了,我会专门说明一下优先级和抢占阈值的关系.
一旦开始, MainThread 被挂起,然后等待事件标记. ThreadOne开始以500ms的间隔反复开关绿灯 LED_GREEN , ThreadTwo 由于它的抢占优先级(抢占阈值)小于ThreadOne的,所以没有开始执行. 5秒后,它发送一个THREAD_ONE_EVT的事件标记给 MainThread.
收到 THREAD_ONE_EVT后, MainThread 更改 ThreadTwo优先级到 8 ,它的抢占优先级到8,这时它的抢占优先级高于ThreadOne的,接着等待事件.
现在, ThreadTwo 能挤掉 ThreadOne来开始以200ms的间隔反复开关绿灯LED_GREEN5秒. 结束后它发送 THREAD_TWO_EVT事件给 MainThread. 一旦MainThread收到 ThreadTwo_Evt事件标记就恢复ThreadTwo的优先级和抢占优先级到最初的值(10, 10), ThreadOne 被重新调用,然后从新执行上边这一套动作. 当以上动作被执行3次以后, MainThread 销毁 ThreadOne 和 ThreadTwo,然后一直以1秒的间隔反复开关绿灯LED_GREEN.
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file app_threadx.c
* @author MCD Application Team
* @brief ThreadX applicative file
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "app_threadx.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
TX_THREAD MainThread;
TX_THREAD ThreadOne;
TX_THREAD ThreadTwo;
TX_EVENT_FLAGS_GROUP EventFlag;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
void ThreadOne_Entry(ULONG thread_input);
void ThreadTwo_Entry(ULONG thread_input);
void MainThread_Entry(ULONG thread_input);
void App_Delay(uint32_t Delay);
/* USER CODE END PFP */
/**
* @brief Application ThreadX Initialization.
* @param memory_ptr: memory pointer
* @retval int
*/
UINT App_ThreadX_Init(VOID *memory_ptr)
{
UINT ret = TX_SUCCESS;
TX_BYTE_POOL *byte_pool = (TX_BYTE_POOL*)memory_ptr;
/* USER CODE BEGIN App_ThreadX_Init */
CHAR *pointer;
/* Allocate the stack for MainThread. */
if (tx_byte_allocate(byte_pool, (VOID **) &pointer,
APP_STACK_SIZE, TX_NO_WAIT) != TX_SUCCESS)
{
ret = TX_POOL_ERROR;
}
/* Create MainThread. */
if (tx_thread_create(&MainThread, "Main Thread", MainThread_Entry, 0,
pointer, APP_STACK_SIZE,
MAIN_THREAD_PRIO, MAIN_THREAD_PREEMPTION_THRESHOLD,
TX_NO_TIME_SLICE, TX_AUTO_START) != TX_SUCCESS)
{
ret = TX_THREAD_ERROR;
}
/* Allocate the stack for ThreadOne. */
if (tx_byte_allocate(byte_pool, (VOID **) &pointer,
APP_STACK_SIZE, TX_NO_WAIT) != TX_SUCCESS)
{
ret = TX_POOL_ERROR;
}
/* Create ThreadOne. */
if (tx_thread_create(&ThreadOne, "Thread One", ThreadOne_Entry, 0,
pointer, APP_STACK_SIZE,
THREAD_ONE_PRIO, THREAD_ONE_PREEMPTION_THRESHOLD,
TX_NO_TIME_SLICE, TX_AUTO_START) != TX_SUCCESS)
{
ret = TX_THREAD_ERROR;
}
/* Allocate the stack for ThreadTwo. */
if (tx_byte_allocate(byte_pool, (VOID **) &pointer,
APP_STACK_SIZE, TX_NO_WAIT) != TX_SUCCESS)
{
ret = TX_POOL_ERROR;
}
/* Create ThreadTwo. */
if (tx_thread_create(&ThreadTwo, "Thread Two", ThreadTwo_Entry, 0,
pointer, APP_STACK_SIZE,
THREAD_TWO_PRIO, THREAD_TWO_PREEMPTION_THRESHOLD,
TX_NO_TIME_SLICE, TX_AUTO_START) != TX_SUCCESS)
{
ret = TX_THREAD_ERROR;
}
/* Create the event flags group. */
if (tx_event_flags_create(&EventFlag, "Event Flag") != TX_SUCCESS)
{
ret = TX_GROUP_ERROR;
}
/* USER CODE END App_ThreadX_Init */
return ret;
}
/* USER CODE BEGIN 1 */
/**
* @brief Function implementing the MainThread thread.
* @param thread_input: Not used
* @retval None
*/
void MainThread_Entry(ULONG thread_input)
{
float t=0;
UINT old_prio = 0;
UINT old_pre_threshold = 0;
ULONG actual_flags = 0;
uint8_t count = 0;
(void) thread_input;
while (count < 3)
{
count++;
if (tx_event_flags_get(&EventFlag, THREAD_ONE_EVT, TX_OR_CLEAR,
&actual_flags, TX_WAIT_FOREVER) != TX_SUCCESS)
{
Error_Handler();
}
else
{
/* Update the priority and preemption threshold of ThreadTwo
to allow the preemption of ThreadOne */
tx_thread_priority_change(&ThreadTwo, NEW_THREAD_TWO_PRIO, &old_prio);
tx_thread_preemption_change(&ThreadTwo, NEW_THREAD_TWO_PREEMPTION_THRESHOLD, &old_pre_threshold);
if (tx_event_flags_get(&EventFlag, THREAD_TWO_EVT, TX_OR_CLEAR,
&actual_flags, TX_WAIT_FOREVER) != TX_SUCCESS)
{
Error_Handler();
}
else
{
/* Reset the priority and preemption threshold of ThreadTwo */
tx_thread_priority_change(&ThreadTwo, THREAD_TWO_PRIO, &old_prio);
tx_thread_preemption_change(&ThreadTwo, THREAD_TWO_PREEMPTION_THRESHOLD, &old_pre_threshold);
}
}
}
/* Destroy ThreadOne and ThreadTwo */
tx_thread_terminate(&ThreadOne);
tx_thread_terminate(&ThreadTwo);
/* Infinite loop */
while(1)
{
BSP_LED_Toggle(LED_GREEN);
OLED_ShowNum(10,10,t,5,RED);
t+=0.01;
/* Thread sleep for 1s */
tx_thread_sleep(1000);
}
}
/**
* @brief Function implementing the ThreadOne thread.
* @param thread_input: Not used
* @retval None
*/
void ThreadOne_Entry(ULONG thread_input)
{
(void) thread_input;
uint8_t count = 0;
/* Infinite loop */
while(1)
{
BSP_LED_Toggle(LED_GREEN);
/* Delay for 500ms (App_Delay is used to avoid context change). */
App_Delay(500);
count ++;
if (count == 10)
{
count = 0;
if (tx_event_flags_set(&EventFlag, THREAD_ONE_EVT, TX_OR) != TX_SUCCESS)
{
Error_Handler();
}
}
}
}
/**
* @brief Function implementing the ThreadTwo thread.
* @param thread_input: Not used
* @retval None
*/
void ThreadTwo_Entry(ULONG thread_input)
{
(void) thread_input;
uint8_t count = 0;
/* Infinite loop */
while (1)
{
BSP_LED_Toggle(LED_GREEN);
/* Delay for 200ms (App_Delay is used to avoid context change). */
App_Delay(20);
count ++;
if (count == 25)
{
count = 0;
if (tx_event_flags_set(&EventFlag, THREAD_TWO_EVT, TX_OR) != TX_SUCCESS)
{
Error_Handler();
}
}
}
}
/**
* @brief Application Delay function.
* @param Delay : number of ticks to wait
* @retval None
*/
void App_Delay(uint32_t Delay)
{
UINT initial_time = tx_time_get();
while ((tx_time_get() - initial_time) < Delay);
}
/* USER CODE END 1 */