国产久操视频-国产久草视频-国产久热精品-国产久热香蕉在线观看-青青青青娱乐-青青青青在线成人视99

  • 方案介紹
  • 附件下載
  • 相關推薦
申請入駐 產業(yè)圖譜

22.6-實現(xiàn)裸機的功能-(通過全局變量同步) FreeRTOS

02/15 08:17
1347
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

聯(lián)系方式.txt

共1個文件

這個是全網最詳細的STM32項目教學視頻。
第一篇CSDN文章在這里在這里:
75


STM32智能小車V3-STM32入門教程-openmv與STM32循跡小車-stm32f103c8t6-電賽 嵌入式學習 PID控制算法 編碼器電機 跟隨

V3:HAL庫開發(fā)、手把手教學下面功能:PID速度控制、PID循跡、PID跟隨、遙控、避障、PID角度控制、openmv視覺控制、電磁循跡、FreeRTOS、K210視覺智能車(更新中)、K230視覺智能車(更新中)、MSPM0G3507視覺智能車(更新中)

在這里插入圖片描述

22.6-實現(xiàn)裸機的功能-(通過全局變量同步)

開始調試實現(xiàn)之前裸機時候的六個模式,我們先使用全局變量同步和通信,再下面的章節(jié)講解消息隊列。

復制一份22-5_LED_FreeRTOS的代碼,命名22-6_LED_FreeRTOS

為了方便理解我們需要一個執(zhí)行模式0的任務,就是用來停止電機的任務,、
在這里插入圖片描述
我們給之前的默認任務修改優(yōu)先級和任務名字
在這里插入圖片描述
然后設置新的任務名字和優(yōu)先級為高,重新生成代碼在這里插入圖片描述
OLED刷新任務的電機停止函數注釋掉
在這里插入圖片描述
在停止任務中增加 電機停止和串口輸出信息

在這里插入圖片描述

/**
  * @brief  Function implementing the StopTask thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartStopTask */
void StartStopTask(void const * argument)
{
  /* USER CODE BEGIN StartStopTask */
  /* Infinite loop */
  for(;;)
  {
		UBaseType_t stackHighWaterMark = uxTaskGetStackHighWaterMark(NULL);// 獲取當前任務的棧高水位值
		printf("StartStopTask Mark: %u wordsn", (unsigned int)stackHighWaterMark);
		size_t freeHeapSize = xPortGetFreeHeapSize();// 獲取系統(tǒng)的可用堆空間
		printf("StartStopTask Free Heap Size: %u bytesn", (unsigned int)freeHeapSize);
		
		if(g_ucMode == 0)
		{
			motorPidSetSpeed(0,0);			//設置小車速度為0
		}
		
    osDelay(10);
  }
  /* USER CODE END StartStopTask */
}

發(fā)現(xiàn)模式6的顯示openmv發(fā)送過來數據的顯示位置,被之前顯示位置占用,所以我們換個,顯示在更下面的一行,
在這里插入圖片描述

			sprintf((char*)OledString, "lHW:%d  ", g_lHW_State);//視覺識別結果
			OLED_ShowString(0,7,OledString,12);//這個是oled驅動里面的,是顯示位置的一個函數,

調試發(fā)現(xiàn)OLED刷新有時候比較亂,因為StartOledTask任務里面的OLED刷新合串口輸出都比較費時間,為避免影響到其他任務執(zhí)行,我們降低任務執(zhí)行頻率,設置延時時間osDelay(100)
在這里插入圖片描述
并且把OLED刷新的操作的放到一個任務中執(zhí)行,把openmv視覺識別結果的值放到OLED刷新任務中執(zhí)行,把模式6里面的視覺識別結果OLED刷新的注釋掉。
在這里插入圖片描述
OLED刷新任務中加入 視覺結果刷新。

		sprintf((char*)OledString, "lHW:%d  ", g_lHW_State);//視覺識別結果
		OLED_ShowString(0,7,OledString,12);//這個是oled驅動里面的,是顯示位置的一個函數,

在這里插入圖片描述
因為我們已經通過串口輸出測試了,每個任務的棧高水位值,還有獲取了系統(tǒng)可用的??臻g都是可用正常執(zhí)行的,所以為了提高系統(tǒng)執(zhí)行效率就把四個任務里面的相關任務??臻g和系統(tǒng)堆空間注釋掉。
在這里插入圖片描述
這樣修改后四個任務內容如下:

void StartStopTask(void const * argument)
{
  /* USER CODE BEGIN StartStopTask */
  /* Infinite loop */
  for(;;)
  {
//		UBaseType_t stackHighWaterMark = uxTaskGetStackHighWaterMark(NULL);// 獲取當前任務的棧高水位值
//		printf("StartLedTask Mark: %u wordsn", (unsigned int)stackHighWaterMark);
//		size_t freeHeapSize = xPortGetFreeHeapSize();// 獲取系統(tǒng)的可用堆空間
//		printf("StartLedTask Free Heap Size: %u bytesn", (unsigned int)freeHeapSize);
		
		if(g_ucMode == 0)
		{
			motorPidSetSpeed(0,0);			//設置小車速度為0
		}
		
    osDelay(10);
  }
  /* USER CODE END StartStopTask */
}
void StartLedTask(void const * argument)
{
  /* USER CODE BEGIN StartLedTask */
  /* Infinite loop */
  for(;;)
  {
//		UBaseType_t stackHighWaterMark = uxTaskGetStackHighWaterMark(NULL);// 獲取當前任務的棧高水位值
//		printf("StartLedTask Mark: %u wordsn", (unsigned int)stackHighWaterMark);
//		size_t freeHeapSize = xPortGetFreeHeapSize();// 獲取系統(tǒng)的可用堆空間
//		printf("StartLedTask Free Heap Size: %u bytesn", (unsigned int)freeHeapSize);
		
		HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);//切換LED GPIO狀態(tài)
    osDelay(300);
  }
  /* USER CODE END StartLedTask */
}
void StartOledTask(void const * argument)
{
  /* USER CODE BEGIN StartOledTask */
  /* Infinite loop */
  for(;;)
  {
		
//		UBaseType_t stackHighWaterMark = uxTaskGetStackHighWaterMark(NULL);// 獲取當前任務的棧高水位值
//		printf("StartOledTask Mark: %u wordsn", (unsigned int)stackHighWaterMark);
//		size_t freeHeapSize = xPortGetFreeHeapSize();// 獲取系統(tǒng)的可用堆空間
//		printf("StartOledTask Free Heap Size: %u bytesn", (unsigned int)freeHeapSize);
		
		sprintf((char *)OledString," g_ucMode:%d",g_ucMode);//顯示g_ucMode 當前模式
		OLED_ShowString(0,6,OledString,12);	//顯示在OLED上
		
		sprintf((char*)OledString, "lHW:%d  ", g_lHW_State);//視覺識別結果
		OLED_ShowString(0,7,OledString,12);//這個是oled驅動里面的,是顯示位置的一個函數,
	
		sprintf((char *)Usart3String," g_ucMode:%d",g_ucMode);//藍牙APP顯示
		HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const  char  *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計算字符串大小
		
			//0LED顯示功能
		sprintf((char*)OledString, "V1:%.2fV2:%.2f", Motor1Speed,Motor2Speed);//顯示速度
		OLED_ShowString(0,0,OledString,12);//這個是oled驅動里面的,是顯示位置的一個函數,
		
		sprintf((char*)OledString, "Mileage:%.2f", Mileage);//顯示里程
		OLED_ShowString(0,1,OledString,12);//這個是oled驅動里面的,是顯示位置的一個函數,
		
		sprintf((char*)OledString, "U:%.2fV", adcGetBatteryVoltage());//顯示電池電壓
		OLED_ShowString(0,2,OledString,12);//這個是oled驅動里面的,是顯示位置的一個函數,
		
		sprintf((char *)OledString,"HC_SR04:%.2fcmrn",HC_SR04_Read());//顯示超聲波數據
		OLED_ShowString(0,3,OledString,12);//這個是oled驅動里面的,是顯示位置的一個函數,
		
		sprintf((char *)OledString,"p:%.2f r:%.2f rn",pitch,roll);//顯示6050數據 俯仰角 橫滾角
		OLED_ShowString(0,4,OledString,12);//這個是oled驅動里面的,是顯示位置的一個函數,
		
		sprintf((char *)OledString,"y:%.2f  rn",yaw);//顯示6050數據  航向角
		OLED_ShowString(0,5,OledString,12);//這個是oled驅動里面的,是顯示位置的一個函數,
		
	//藍牙APP顯示
		sprintf((char*)Usart3String, "V1:%.2fV2:%.2f", Motor1Speed,Motor2Speed);//顯示速度
		HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const  char  *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計算字符串大小
		//阻塞方式發(fā)送可以保證數據發(fā)送完畢,中斷發(fā)送不一定可以保證數據已經發(fā)送完畢才啟動下一次發(fā)送
		sprintf((char*)Usart3String, "Mileage:%.2f", Mileage);//顯示里程
		HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const  char  *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計算字符串大小
		
		sprintf((char*)Usart3String, "U:%.2fV", adcGetBatteryVoltage());//顯示電池電壓
		HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const  char  *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計算字符串大小
		
		sprintf((char *)Usart3String,"HC_SR04:%.2fcmrn",HC_SR04_Read());//顯示超聲波數據
		HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const  char  *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計算字符串大小
		
		sprintf((char *)Usart3String,"p:%.2f r:%.2f rn",pitch,roll);//顯示6050數據 俯仰角 橫滾角
		HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const  char  *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計算字符串大小
		
		sprintf((char *)Usart3String,"y:%.2f  rn",yaw);//顯示6050數據  航向角
		HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const  char  *)Usart3String),50);//阻塞式發(fā)送通過串口三輸出字符 strlen:計算字符串大小
	
		//獲得6050數據
//		while(mpu_dmp_get_data(&pitch,&roll,&yaw)!=0){}  //這個可以解決經常讀不出數據的問題
		
		//在顯示模式電機停轉 設置小車速度為0
		//motorPidSetSpeed(0,0);
		
    osDelay(100);
  }
  /* USER CODE END StartOledTask */
}
void StartMultiModTask(void const * argument)
{
  /* USER CODE BEGIN StartMultiModTask */
  /* Infinite loop */
  for(;;)
  {
//		UBaseType_t stackHighWaterMark = uxTaskGetStackHighWaterMark(NULL);// 獲取當前任務的棧高水位值
//		printf("StartMultiModTask Mark: %u wordsn", (unsigned int)stackHighWaterMark);
//		size_t freeHeapSize = xPortGetFreeHeapSize();// 獲取系統(tǒng)的可用堆空間
//		printf("StartMultiModTask Free Heap Size: %u bytesn", (unsigned int)freeHeapSize);
		
		if(g_ucMode == 1)
		{
		///****    紅外PID循跡功能******************/
		g_ucaHW_Read[0] = READ_HW_OUT_1;//讀取紅外對管狀態(tài)、這樣相比于寫在if里面更高效
		g_ucaHW_Read[1] = READ_HW_OUT_2;
		g_ucaHW_Read[2] = READ_HW_OUT_3;
		g_ucaHW_Read[3] = READ_HW_OUT_4;

		if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 0 )
		{
	//		printf("應該前進rn");//注釋掉更加高效,減少無必要程序執(zhí)行
			g_cThisState = 0;//前進
		}
		else if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 1&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 0 )//使用else if更加合理高效
		{
	//		printf("應該右轉rn");
			g_cThisState = -1;//應該右轉
		}
		else if(g_ucaHW_Read[0] == 1&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 0 )
		{
	//		printf("快速右轉rn");
			g_cThisState = -2;//快速右轉
		}
		else if(g_ucaHW_Read[0] == 1&&g_ucaHW_Read[1] == 1&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 0)
		{
	//		printf("快速右轉rn");
			g_cThisState = -3;//快速右轉
		}
		else if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 1&&g_ucaHW_Read[3] == 0 )
		{
	//		printf("應該左轉rn");
			g_cThisState = 1;//應該左轉	
		}
		else if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 1 )
		{
	//		printf("快速左轉rn");
			g_cThisState = 2;//快速左轉
		}
		else if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 1&&g_ucaHW_Read[3] == 1)
		{
	//	    printf("快速左轉rn");
			g_cThisState = 3;//快速左轉
		}
		g_fHW_PID_Out = PID_realize(&pidHW_Tracking,g_cThisState);//PID計算輸出目標速度 這個速度,會和基礎速度加減

		g_fHW_PID_Out1 = 3 + g_fHW_PID_Out;//電機1速度=基礎速度+循跡PID輸出速度
		g_fHW_PID_Out2 = 3 - g_fHW_PID_Out;//電機1速度=基礎速度-循跡PID輸出速度
		if(g_fHW_PID_Out1 >5) g_fHW_PID_Out1 =5;//進行限幅 限幅速度在0-5之間
		if(g_fHW_PID_Out1 <0) g_fHW_PID_Out1 =0;
		if(g_fHW_PID_Out2 >5) g_fHW_PID_Out2 =5;//進行限幅 限幅速度在0-5之間
		if(g_fHW_PID_Out2 <0) g_fHW_PID_Out2 =0;
		if(g_cThisState != g_cLastState)//如何這次狀態(tài)不等于上次狀態(tài)、就進行改變目標速度和控制電機、在定時器中依舊定時控制電機
		{
			motorPidSetSpeed(g_fHW_PID_Out1,g_fHW_PID_Out2);//通過計算的速度控制電機
		}
		
		g_cLastState = g_cThisState;//保存上次紅外對管狀態(tài)	

		}
		if(g_ucMode == 2)
		{
			
			//***************遙控模式***********************//
			//遙控模式的控制在串口三的中斷里面
		}
		if(g_ucMode == 3)
		{
			//******超聲波避障模式*********************//
	避障邏輯
			if(HC_SR04_Read() > 25)//前方無障礙物
			{
				motorPidSetSpeed(1,1);//前運動
				osDelay(100);
			}
			else{	//前方有障礙物
				motorPidSetSpeed(-1,1);//右邊運動 原地	
				osDelay(500);
				if(HC_SR04_Read() > 25)//右邊無障礙物
				{
					motorPidSetSpeed(1,1);//前運動
					osDelay(100);
				}
				else{//右邊有障礙物
					motorPidSetSpeed(1,-1);//左邊運動 原地
					osDelay(1000);
					if(HC_SR04_Read() >25)//左邊無障礙物
					{
						 motorPidSetSpeed(1,1);//前運動
						osDelay(100);
					}
					else{
						motorPidSetSpeed(-1,-1);//后運動
						osDelay(1000);
						motorPidSetSpeed(-1,1);//右邊運動
						osDelay(50);
					}
				}
			}
		}
		if(g_ucMode == 4)
		{
		//**********PID跟隨功能***********//
			g_fHC_SR04_Read=HC_SR04_Read();//讀取前方障礙物距離
			if(g_fHC_SR04_Read < 60){  //如果前60cm 有東西就啟動跟隨
				g_fFollow_PID_Out = PID_realize(&pidFollow,g_fHC_SR04_Read);//PID計算輸出目標速度 這個速度,會和基礎速度加減
				if(g_fFollow_PID_Out > 6) g_fFollow_PID_Out = 6;//對輸出速度限幅
				if(g_fFollow_PID_Out < -6) g_fFollow_PID_Out = -6;
				motorPidSetSpeed(g_fFollow_PID_Out,g_fFollow_PID_Out);//速度作用與電機上
			}
			else motorPidSetSpeed(0,0);//如果前面60cm 沒有東西就停止
			osDelay(10);//讀取超聲波傳感器不能過快
		}
		if(g_ucMode == 5)
		{
		//*************MPU6050航向角 PID轉向控制*****************//

			sprintf((char *)Usart3String,"pitch:%.2f roll:%.2f yaw:%.2frn",pitch,roll,yaw);//顯示6050數據 俯仰角 橫滾角 航向角
			HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const  char  *)Usart3String),0xFFFF);//通過串口三輸出字符 strlen:計算字符串大小	
			 
	//	    mpu_dmp_get_data(&pitch,&roll,&yaw);//返回值:0,DMP成功解出歐拉角
	//		while(mpu_dmp_get_data(&pitch,&roll,&yaw)!=0){}  //這個可以解決經常讀不出數據的問題
			
			
			g_fMPU6050YawMovePidOut = PID_realize(&pidMPU6050YawMovement,yaw);//PID計算輸出目標速度 這個速度,會和基礎速度加減

			g_fMPU6050YawMovePidOut1 = 1.5 + g_fMPU6050YawMovePidOut;//基礎速度加減PID輸出速度
			g_fMPU6050YawMovePidOut2 = 1.5 - g_fMPU6050YawMovePidOut;
			if(g_fMPU6050YawMovePidOut1 >3.5) g_fMPU6050YawMovePidOut1 =3.5;//進行限幅
			if(g_fMPU6050YawMovePidOut1 <0) g_fMPU6050YawMovePidOut1 =0;
			if(g_fMPU6050YawMovePidOut2 >3.5) g_fMPU6050YawMovePidOut2 =3.5;//進行限幅
			if(g_fMPU6050YawMovePidOut2 <0) g_fMPU6050YawMovePidOut2 =0;
			motorPidSetSpeed(g_fMPU6050YawMovePidOut1,g_fMPU6050YawMovePidOut2);//將最后計算的目標速度 通過motorPidSetSpeed控制電機
		
		}
		if(g_ucMode == 6)
		{

//			sprintf((char*)OledString, "lHW:%d  ", g_lHW_State);//視覺識別結果
//			OLED_ShowString(0,7,OledString,12);//這個是oled驅動里面的,是顯示位置的一個函數,
			
			g_fHW_PID_Out = PID_realize(&pidOpenmv_Tracking,g_cThisState);//PID計算輸出目標速度 這個速度,會和基礎速度加減

			g_fHW_PID_Out1 = 0.5 + g_fHW_PID_Out;//電機1速度=基礎速度+循跡PID輸出速度
			g_fHW_PID_Out2 = 0.5 - g_fHW_PID_Out;//電機1速度=基礎速度-循跡PID輸出速度
			if(g_fHW_PID_Out1 >1.2) g_fHW_PID_Out1 =1.2;//進行限幅 限幅速度在0-1.2之間
			if(g_fHW_PID_Out1 <0) g_fHW_PID_Out1 =0;
			if(g_fHW_PID_Out2 >1.2) g_fHW_PID_Out2 =1.2;//進行限幅 限幅速度在0-1.2之間
			if(g_fHW_PID_Out2 <0) g_fHW_PID_Out2 =0;
			if(g_cThisState != g_cLastState)//如何這次狀態(tài)不等于上次狀態(tài)、就進行改變目標速度和控制電機、在定時器中依舊定時控制電機
			{
				motorPidSetSpeed(g_fHW_PID_Out1,g_fHW_PID_Out2);//通過計算的速度控制電機
			}
			g_cLastState = g_cThisState;//保存上次紅外對管狀態(tài)	

		}
    osDelay(1);
  }
  /* USER CODE END StartMultiModTask */
}

22.6.1-實際測試幾個功能是否正常

先燒錄一下 "22-6_LED_FreeRTOS"的代碼

然后進行測試,測試結果如下

模式0-可以正常刷新屏幕(除了6050數據外)

模式1-可以完成紅外對管PID循跡

模式2-可以進行藍牙遙控

模式3-可以進行超聲波避障 偶爾出現(xiàn)超聲波測距值錯誤

模式4-可以進行PID跟隨 但是有些抖動

模式5-不能進行MPU6050角度控制

模式6-可以進行openmv視覺循跡

  • 聯(lián)系方式.txt
    下載
意法半導體

意法半導體

意法半導體(ST)集團于1987年6月成立,是由意大利的SGS微電子公司和法國Thomson半導體公司合并而成。1998年5月,SGS-THOMSON Microelectronics將公司名稱改為意法半導體有限公司。意法半導體是世界最大的半導體公司之一,公司銷售收入在半導體工業(yè)五大高速增長市場之間分布均衡(五大市場占2007年銷售收入的百分比):通信(35%),消費(17%),計算機(16%),汽車(16%),工業(yè)(16%)。 據最新的工業(yè)統(tǒng)計數據,意法半導體是全球第五大半導體廠商,在很多市場居世界領先水平。例如,意法半導體是世界第一大專用模擬芯片和電源轉換芯片制造商,世界第一大工業(yè)半導體和機頂盒芯片供應商,而且在分立器件、手機相機模塊和車用集成電路領域居世界前列.

意法半導體(ST)集團于1987年6月成立,是由意大利的SGS微電子公司和法國Thomson半導體公司合并而成。1998年5月,SGS-THOMSON Microelectronics將公司名稱改為意法半導體有限公司。意法半導體是世界最大的半導體公司之一,公司銷售收入在半導體工業(yè)五大高速增長市場之間分布均衡(五大市場占2007年銷售收入的百分比):通信(35%),消費(17%),計算機(16%),汽車(16%),工業(yè)(16%)。 據最新的工業(yè)統(tǒng)計數據,意法半導體是全球第五大半導體廠商,在很多市場居世界領先水平。例如,意法半導體是世界第一大專用模擬芯片和電源轉換芯片制造商,世界第一大工業(yè)半導體和機頂盒芯片供應商,而且在分立器件、手機相機模塊和車用集成電路領域居世界前列.收起

查看更多

相關推薦

沂南县| 彭阳县| 旬邑县| 观塘区| 东乡族自治县| 博湖县| 安康市| 清苑县| 北海市| 彩票| 三原县| 宁海县| 桃园县| 吕梁市| 道真| 邹平县| 大方县| 丰顺县| 永胜县| 通海县| 张家界市| 赤峰市| 方正县| 庄河市| 沧源| 新乡县| 德阳市| 东光县| 大洼县| 雅安市| 平阴县| 广州市| 清水河县| 通榆县| 马鞍山市| 鹤峰县| 高台县| 巫山县| 巨野县| 临沂市| 六安市|