目錄
創(chuàng)建多線程
freertos.c
main.cpp
main_app.h
二值信號量
相關API介紹
(1) osSemaphoreCreate
(2)osSemaphoreDelete
(3)osSemaphoreRelease
(4)osSemaphoreWait
實際使用
創(chuàng)建信號量(freertos.c)
在頭文件中外部引用(freertos_inc.h)
main.c
關于clion使用printf,參考【教程】手把手教你用Clion進行STM32開發(fā)【如何優(yōu)雅の進行嵌入式開發(fā)】 - 知乎 (zhihu.com)
創(chuàng)建多線程
本文的程序通過STM32CubeMX+Clion完成,使用單片機為Stm32f411CEU6
為了讓自己的程序和生成的程序分開,方便后續(xù)的管理,我我們可以新建一個Src目錄或者User目錄,然后在目錄里新建main_app.cpp/main_app.h,如果有其他傳感器功能的實現(xiàn)或者算法的實現(xiàn)可以再新建一個目錄放到里面,新加的目錄記得在CMakelist里添加路徑。
在include和file里都要添加,尤其是file,不添加也不會報錯容易漏。
然后要知道程序是在哪里運行的,不在main.c中而是在下面這個文件里core/src/freertos.c,在這里寫上自己的主程序函數(shù)就可以成功進入
freertos.c
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
main_app();
vTaskDelete(defaultTaskHandle);
/* USER CODE END StartDefaultTask */
}
接下來創(chuàng)建第一個線程,這里使用cmsis_os.h,記得包含到頭文件里,然后按照以下格式創(chuàng)建即可,要注意的就是設置的棧大小和優(yōu)先級,還有這個任務main_app執(zhí)行完后就結(jié)束了,所以后續(xù)需要使用的變量或者類,不要放到函數(shù)中而是要放在前面,創(chuàng)建全局變量并初始化。
main.cpp
SensorManager sensorManager;//全局變量,記得初始化,在這里直接初始化也可以
osThreadId_t SensorTaskHandle;
void SensorTask(void *pvParameters) {
for(;;) {
LED_B_TogglePin;
osDelay(1000);
}
}
osThreadId_t LCDTaskHandle;
void LCDTask(void *pvParameters) {
for(;;) {
LED_R_TogglePin;
osDelay(1000);
}
}
void main_app()
{
const osThreadAttr_t SensorTask_attributes = {
.name = "SensorTask",
.stack_size = 128 * 8,//??臻g
.priority = (osPriority_t) osPriorityNormal,
};
SensorTaskHandle = osThreadNew(SensorTask, nullptr, &SensorTask_attributes);
const osThreadAttr_t LCDTask_attributes = {
.name = "LCDTask",
.stack_size = 128 * 8,
.priority = (osPriority_t) osPriorityNormal,
};
LCDTaskHandle = osThreadNew(LCDTask, nullptr, &LCDTask_attributes);
// 啟動調(diào)度器
printf("end\n");
}
main_app.h
#ifndef STM32_DEMO2_F4_MAIN_APP_H
#define STM32_DEMO2_F4_MAIN_APP_H
#ifdef __cplusplus
extern "C" {
#endif
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "cmsis_os.h"
#include "main.h"
#include "gpio.h"
#include "usart.h"
void main_app(void);
#ifdef __cplusplus
}
#endif
#endif //STM32_DEMO2_F4_MAIN_APP_H
二值信號量
在多線程時當多個線程同時訪問一個變量時,可能會造成沖突,比如當兩個線程同時使用printf時,出現(xiàn)沖突,結(jié)果就是打印亂碼,因此需要使用信號量來避免這種情況,在使用串口的問題中,我使用二值信號量。
相關API介紹
(1) osSemaphoreCreate
用于創(chuàng)建一個二值信號量,并返回一個ID。
函數(shù) osSemaphoreId osSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t count)
參數(shù) semaphore_def: 引用由osSemaphoreDef定義的信號量 count: 信號量數(shù)量
返回值 成功返回信號量ID,失敗返回0
(2)osSemaphoreDelete
用于刪除一個信號量,包括二值信號量,計數(shù)信號量,互斥量和遞歸互斥量。如果有任務阻塞在該信號量上,那么不要刪除該信號量。
函數(shù) osStatus osSemaphoreDelete (osSemaphoreId semaphore_id)
參數(shù) semaphore_id: 信號量ID
返回值 錯誤碼文章來源地址http://www.zghlxwxcb.cn/news/detail-840351.html
(3)osSemaphoreRelease
用于釋放信號量的宏。釋放的信號量對象必須是已經(jīng)被創(chuàng)建的,可以用于二值信號量、計數(shù)信號量、互斥量的釋放,但不能釋放由函數(shù) xSemaphoreCreateRecursiveMutex() 創(chuàng)建的遞歸互斥量??捎迷谥袛喾粘绦蛑?。
函數(shù) osStatus osSemaphoreRelease (osSemaphoreId semaphore_id)
參數(shù) semaphore_id: 信號量ID
返回值 錯誤碼
(4)osSemaphoreWait
用于獲取信號量,不帶中斷保護。獲取的信號量對象可以是二值信號量、計數(shù)信號量和互斥量,但是遞歸互斥量并不能使用這個 API 函數(shù)獲取??捎迷谥袛喾粘绦蛑小?/p>
函數(shù) int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec)
參數(shù) semaphore_id: 信號量ID millisec:等待信號量可用的最大超時時間,單位為 tick(即系統(tǒng)節(jié)拍周期)。 如果宏 INCLUDE_vTaskSuspend 定義為 1 且形參 xTicksToWait 設置為 portMAX_DELAY ,則任務將一直阻塞在該信號量上(即沒有超時時間)文章來源:http://www.zghlxwxcb.cn/news/detail-840351.html
返回值 錯誤碼
實際使用
創(chuàng)建信號量(freertos.c)
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
osSemaphoreId sem_uart6_rx;
osSemaphoreId sem_uart6_tx;
/* USER CODE END PD */
void MX_FREERTOS_Init(void) {
// Create a semaphore for USB RX, and start with no tokens by removing the starting one.
osSemaphoreDef(sem_usb_rx);
sem_uart6_rx = osSemaphoreNew(1, 0, osSemaphore(sem_usb_rx));
// Create a semaphore for USB TX
osSemaphoreDef(sem_usb_tx);
sem_uart6_tx = osSemaphoreNew(1, 1, osSemaphore(sem_usb_tx));
/* USER CODE END RTOS_SEMAPHORES */
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
}
在頭文件中外部引用(freertos_inc.h)
#ifndef STM32_DEMO2_F4_FREERTOS_INC_H
#define STM32_DEMO2_F4_FREERTOS_INC_H
#ifdef __cplusplus
extern "C" {
#endif
// List of semaphores
extern osSemaphoreId sem_uart6_rx;
extern osSemaphoreId sem_uart6_tx;
// List of Tasks
/*--------------------------------- System Tasks -------------------------------------*/
extern osThreadId_t defaultTaskHandle; // Usage: 4000 Bytes stack
/*---------------------------------- User Tasks --------------------------------------*/
extern osThreadId_t SensorTaskHandle; // Usage: 4000 Bytes stack
extern osThreadId_t LCDTaskHandle; // Usage: 4000 Bytes stack
/*---------------- 24.1K (used) / 64K (for FreeRTOS) / 128K (total) ------------------*/
#ifdef __cplusplus
}
#endif
#endif //STM32_DEMO2_F4_FREERTOS_INC_H
main.c
osThreadId_t SensorTaskHandle;
void SensorTask(void *pvParameters) {
osSemaphoreAcquire(sem_uart6_tx,osWaitForever);
printf("enter SensorTask\n");
osSemaphoreRelease(sem_uart6_tx);
for(;;) {
LED_B_TogglePin;
osDelay(1000);
}
}
osThreadId_t LCDTaskHandle;
void LCDTask(void *pvParameters) {
osSemaphoreAcquire(sem_uart6_tx,osWaitForever);
printf("enter LCDTask\n");
osSemaphoreRelease(sem_uart6_tx);
for(;;) {
LED_R_TogglePin;
osDelay(1000);
}
}
void main_app()
{
const osThreadAttr_t SensorTask_attributes = {
.name = "SensorTask",
.stack_size = 128 * 8,//??臻g
.priority = (osPriority_t) osPriorityNormal,
};
SensorTaskHandle = osThreadNew(SensorTask, nullptr, &SensorTask_attributes);
const osThreadAttr_t LCDTask_attributes = {
.name = "LCDTask",
.stack_size = 128 * 8,
.priority = (osPriority_t) osPriorityNormal,
};
LCDTaskHandle = osThreadNew(LCDTask, nullptr, &LCDTask_attributes);
// 啟動調(diào)度器
printf("end\n");
}
關于clion使用printf,參考【教程】手把手教你用Clion進行STM32開發(fā)【如何優(yōu)雅の進行嵌入式開發(fā)】 - 知乎 (zhihu.com)
到了這里,關于STM32+Clion多線程開發(fā)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!