這個(gè)是全網(wǎng)最詳細(xì)的STM32項(xiàng)目教學(xué)視頻。
第一篇在這里:
視頻在這里
**V3:HAL庫開發(fā)、手把手教學(xué)下面功能:PID速度控制、PID循跡、PID跟隨、遙控、避障、PID角度控制、openmv視覺控制、電磁循跡、FreeRTOS、K210視覺智能車(更新中)、K230視覺智能車(更新中)、MSPM0G3507視覺智能車(更新中)**
22.2-任務(wù)的創(chuàng)建(有代碼示例)
任務(wù)創(chuàng)建生成的代碼
上一個(gè)章節(jié)我們創(chuàng)建了LED的任務(wù)這節(jié)我們分析一下相關(guān)代碼,然后再創(chuàng)建一個(gè)OLED刷新也就是模式零的任務(wù)
可以看到STM32cubemx軟件生成RTOS代碼調(diào)用的CMSIS-RTOS的函數(shù)(以os開通的函數(shù)都是CMSIS-RTOS的函數(shù))
我們很容易就找到函數(shù)原型其實(shí)是
函數(shù)原型:
函數(shù)描述:
函數(shù) xTaskCreate 用于實(shí)現(xiàn) FreeRTOS 操作系統(tǒng)的任務(wù)創(chuàng)建,并且還可以自定義任務(wù)棧的大小。
- 第 一 個(gè)參數(shù)填創(chuàng)建任務(wù)的函數(shù)名
- 第 二 個(gè)參數(shù)是任務(wù)名,這個(gè)參數(shù)主要用于調(diào)試的時(shí)候方便看是哪個(gè)任務(wù)
- 第 三 個(gè)參數(shù)是任務(wù)棧大小,單位 word,也就是 4 字節(jié)
- 第 四 個(gè)參數(shù)是創(chuàng)建的任務(wù)函數(shù)的形參
- 第 五 個(gè)參數(shù)是定義任務(wù)優(yōu)先級
- 第 六 個(gè)參數(shù)是任務(wù)句柄,用于區(qū)分不同的任務(wù)
然后我們看一下,我們生成的代碼都有那些
生成的的代碼里面會定義任務(wù)的句柄
動手再創(chuàng)建一個(gè)任務(wù)
我們復(fù)制上一節(jié)21-2_LED_FreeRTOS文件 命名為22-2_LED_FreeRTOS
然后點(diǎn)擊LED.ioc
我們這里再新建一個(gè)任務(wù)用于OLED刷新,也就是我們之前裸機(jī)時(shí)候的模式0大部分功能
由于OLED刷新的任務(wù)對實(shí)時(shí)性要求不高,所以我們優(yōu)先級設(shè)置低一些
這里優(yōu)先級設(shè)置低于正常優(yōu)先級
然后點(diǎn)擊生成代碼,可以觀察到已經(jīng)生成新的代碼,
這個(gè)就是我們OLED刷新任務(wù)對應(yīng)的函數(shù),我們在該函數(shù)中增加OLED刷新代碼
將之前模式零的代碼復(fù)制過去
//0LED顯示功能
sprintf((char*)OledString, "V1:%.2fV2:%.2f", Motor1Speed,Motor2Speed);//顯示速度
OLED_ShowString(0,0,OledString,12);//這個(gè)是oled驅(qū)動里面的,是顯示位置的一個(gè)函數(shù),
sprintf((char*)OledString, "Mileage:%.2f", Mileage);//顯示里程
OLED_ShowString(0,1,OledString,12);//這個(gè)是oled驅(qū)動里面的,是顯示位置的一個(gè)函數(shù),
sprintf((char*)OledString, "U:%.2fV", adcGetBatteryVoltage());//顯示電池電壓
OLED_ShowString(0,2,OledString,12);//這個(gè)是oled驅(qū)動里面的,是顯示位置的一個(gè)函數(shù),
sprintf((char *)OledString,"HC_SR04:%.2fcmrn",HC_SR04_Read());//顯示超聲波數(shù)據(jù)
OLED_ShowString(0,3,OledString,12);//這個(gè)是oled驅(qū)動里面的,是顯示位置的一個(gè)函數(shù),
sprintf((char *)OledString,"p:%.2f r:%.2f rn",pitch,roll);//顯示6050數(shù)據(jù) 俯仰角 橫滾角
OLED_ShowString(0,4,OledString,12);//這個(gè)是oled驅(qū)動里面的,是顯示位置的一個(gè)函數(shù),
sprintf((char *)OledString,"y:%.2f rn",yaw);//顯示6050數(shù)據(jù) 航向角
OLED_ShowString(0,5,OledString,12);//這個(gè)是oled驅(qū)動里面的,是顯示位置的一個(gè)函數(shù),
//藍(lán)牙APP顯示
sprintf((char*)Usart3String, "V1:%.2fV2:%.2f", Motor1Speed,Motor2Speed);//顯示速度
HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計(jì)算字符串大小
//阻塞方式發(fā)送可以保證數(shù)據(jù)發(fā)送完畢,中斷發(fā)送不一定可以保證數(shù)據(jù)已經(jīng)發(fā)送完畢才啟動下一次發(fā)送
sprintf((char*)Usart3String, "Mileage:%.2f", Mileage);//顯示里程
HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計(jì)算字符串大小
sprintf((char*)Usart3String, "U:%.2fV", adcGetBatteryVoltage());//顯示電池電壓
HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計(jì)算字符串大小
sprintf((char *)Usart3String,"HC_SR04:%.2fcmrn",HC_SR04_Read());//顯示超聲波數(shù)據(jù)
HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計(jì)算字符串大小
sprintf((char *)Usart3String,"p:%.2f r:%.2f rn",pitch,roll);//顯示6050數(shù)據(jù) 俯仰角 橫滾角
HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計(jì)算字符串大小
sprintf((char *)Usart3String,"y:%.2f rn",yaw);//顯示6050數(shù)據(jù) 航向角
HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計(jì)算字符串大小
//獲得6050數(shù)據(jù)
// while(mpu_dmp_get_data(&pitch,&roll,&yaw)!=0){} //這個(gè)可以解決經(jīng)常讀不出數(shù)據(jù)的問題
//在顯示模式電機(jī)停轉(zhuǎn) 設(shè)置小車速度為0
motorPidSetSpeed(0,0);
有很多錯(cuò)誤,我們解決一些,freeRTOS.c增加頭文件
#include "oled.h"
#include "stdio.h"
#include "motor.h"
#include "niming.h"
#include "pid.h"
#include "cJSON.h"
#include <string.h>
#include "HC_SR04.h"
#include "mpu6050.h"
#include "inv_mpu.h"
#include "inv_mpu_dmp_motion_driver.h"
#include "adc.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
然后把main.c里面定義和聲明的變量到Freertos.c中都聲明一下, 主要聲明的時(shí)候不要賦值
extern short Encode1Count ;//電機(jī)1編碼器計(jì)數(shù)值 short的類型
extern short Encode2Count ;//電機(jī)2編碼器計(jì)數(shù)值 short的類型
extern float Motor1Speed ;//電機(jī)1速度 轉(zhuǎn)/s
extern float Motor2Speed ;//電機(jī)2速度 轉(zhuǎn)/s
extern uint16_t TimerCount ;//中斷計(jì)數(shù)變量
extern tPid pidMotor1Speed;//聲明電機(jī)1PID速度控制結(jié)構(gòu)體類型變量
extern tPid pidMotor2Speed;
extern tPid pidFollow; //定距離跟隨PID
extern tPid pidMPU6050YawMovement; //利用6050偏航角 進(jìn)行姿態(tài)控制的PID
extern uint8_t Usart1_ReadBuf[255]; //串口1 緩沖數(shù)組
extern float p,i,d,a,b;//使用JSON時(shí)候使用的變量
extern uint8_t OledString[50];//OLED顯示使用的字符串?dāng)?shù)組
extern float Mileage;//里程數(shù)
extern tPid pidHW_Tracking;//紅外循跡的PID
extern tPid pidOpenmv_Tracking;//攝像頭的PID
extern uint8_t g_ucaHW_Read[4] ;//保存紅外對管電平的數(shù)組
extern int8_t g_cThisState ;//這次狀態(tài)
extern int8_t g_cLastState ; //上次狀態(tài)
extern float g_fHW_PID_Out;//紅外對管PID計(jì)算輸出速度
extern float g_fHW_PID_Out1;//電機(jī)1的最后循跡PID控制速度
extern float g_fHW_PID_Out2;//電機(jī)2的最后循跡PID控制速度
extern uint8_t g_ucUsart3ReceiveData; //保存串口三接收的數(shù)據(jù)
extern uint8_t g_ucUsart2ReceiveData; //保存串口二接收的數(shù)據(jù)
extern uint8_t Usart3String[50];//串口三輸出字符串使用的字符串?dāng)?shù)組
extern float g_fHC_SR04_Read;//超聲波傳感器讀取障礙物數(shù)據(jù)
extern float g_fFollow_PID_Out;//定距離跟隨PID計(jì)算輸出速度
extern float pitch,roll,yaw; //俯仰角 橫滾角 航向角
extern float g_fMPU6050YawMovePidOut ; //姿態(tài)PID運(yùn)算輸出
extern float g_fMPU6050YawMovePidOut1 ; //第一個(gè)電機(jī)控制輸出
extern float g_fMPU6050YawMovePidOut2 ; //第一個(gè)電機(jī)控制輸出
extern uint8_t g_ucMode ;
extern int g_lHW_State;//幫助視覺調(diào)試 用于表示紅外對管或者視覺攝像頭識別狀態(tài)
編譯一下就沒有錯(cuò)誤了,然后我們把代碼燒錄觀察現(xiàn)象
下面能夠觀察到OLED屏幕在快速刷新,同時(shí)LED函數(shù)
注意如果注釋掉MPU6050初始化和數(shù)據(jù)獲取函數(shù),那么OLED上是不會顯示6050數(shù)據(jù)值的。
而且OLED刷新的任務(wù)中一定要有osDelay 確保任務(wù)能供定期進(jìn)入阻塞狀態(tài),使得其他任務(wù)能得到調(diào)度。
修改一下延時(shí)時(shí)間