【4FreeRTOS完整的分析一下程式碼】二值訊號量
1,主要的就是分析下面的程式碼
/* Includes ------------------------------------------------------------------*/ #include "main.h" //包含了三個標頭檔案 #include "stm32f1xx_hal.h" #include "cmsis_os.h" /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private variables 私有變數 ---------------------------------------------------------*/ osThreadId PeriodicHandle;//實時系統的執行緒(任務)的識別碼(身份證) //osThreadId 》typedef TaskHandle_t osThreadId;》typedef void * TaskHandle_t; //最終的目標還是 TaskHandle_t 手冊上看看什麼意思 osThreadId HandlerHandle; osSemaphoreId bSem01Handle;//訊號量任務的身份證 /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ /* USER CODE END PV */ /* Private function prototypes 私有函式原型 -----------------------------------------------*/ void SystemClock_Config(void); //系統時鐘的配置 static void MX_GPIO_Init(void);//GPIO的初始化 void PeriodicTask(void const * argument);//返回值為空,在MX中設定的函式PeriodicTask宣告 void HandlerTask(void const * argument); /* USER CODE BEGIN PFP */ /* Private function prototypes -----------------------------------------------*/ /* USER CODE END PFP */ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * * @retval None */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration-- MCU配置 ----------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ /* 復位所有外設,初始化FLASH介面和系統滴答時鐘 */ 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(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* USER CODE BEGIN RTOS_MUTEX */ /* add mutexes, 新增互斥 ... */ /* USER CODE END RTOS_MUTEX */ /* Create the semaphores(s) */ /* definition and creation of bSem01 */ /* 定義和建立訊號量bSem01 */ osSemaphoreDef(bSem01); bSem01Handle = osSemaphoreCreate(osSemaphore(bSem01), 1); /* USER CODE BEGIN RTOS_SEMAPHORES */ /* add semaphores, ... */ /* USER CODE END RTOS_SEMAPHORES */ /* USER CODE BEGIN RTOS_TIMERS */ /* start timers, add new ones,新增軟體定時器 ... */ /* USER CODE END RTOS_TIMERS */ /* Create the thread(s) */ /* definition and creation of Periodic */ /*定義和建立Periodic任務*/ osThreadDef(Periodic, PeriodicTask, osPriorityNormal, 0, 128); PeriodicHandle = osThreadCreate(osThread(Periodic), NULL); /* definition and creation of Handler */ osThreadDef(Handler, HandlerTask, osPriorityIdle, 0, 128); HandlerHandle = osThreadCreate(osThread(Handler), NULL); /* USER CODE BEGIN RTOS_THREADS */ /* add threads, ... */ /* USER CODE END RTOS_THREADS */ /* USER CODE BEGIN RTOS_QUEUES */ /* add queues, ... */ /* USER CODE END RTOS_QUEUES */ /* Start scheduler 開始任務排程管理器 */ osKernelStart(); /* We should never get here as control is now taken by the scheduler */ /*當任務排程管理器執行的時候,我們將永遠不會執行到這裡(下面的while)*/ /* Infinite loop 無限迴圈 */ /* USER CODE BEGIN WHILE */ while (1)// /*當任務排程管理器執行的時候,我們將永遠不會執行到這裡*/ { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct; /**Initializes the CPU, AHB and APB busses clocks 初始化CPU,AHB,APB匯流排的時鐘 */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;//復位與時鐘控制器(Reset Clock Controller),高速 RCC_OscInitStruct.HSEState = RCC_HSE_ON;//高速時鐘狀態開啟 RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;//預分頻值為1 RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;//PLL狀態為開啟 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;//倍頻為9 if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;//AHB時鐘匯流排 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;//APB1時鐘匯流排 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;//APB2時鐘匯流排 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure the Systick interrupt time 配置系統滴答中斷時間 */ HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);//1000分頻 /**Configure the Systick */ HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); /* SysTick_IRQn interrupt configuration */ /* IRQ=Interrupt request中斷請求 。系統中斷請求配置 NVIC:中斷巢狀配置 */ HAL_NVIC_SetPriority(SysTick_IRQn, 15, 0); } /** Configure pins as 將埠配置為模擬量、輸入、輸出、事件輸出、中斷 * Analog * Input * Output * EVENT_OUT * EXTI */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; /* GPIO Ports Clock Enable GPIO埠時鐘使能 */ __HAL_RCC_GPIOB_CLK_ENABLE(); /*Configure GPIO pin Output Level */ //配置GPIO引腳的輸出電平 HAL_GPIO_WritePin(GPIOB, LED0_Pin|LED1_Pin, GPIO_PIN_RESET); /*Configure GPIO pins : LED0_Pin LED1_Pin */ GPIO_InitStruct.Pin = LED0_Pin|LED1_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;//推輓輸出 GPIO_InitStruct.Pull = GPIO_PULLUP;//上拉輸出 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /* PeriodicTask function 詳細定義函式*/ void PeriodicTask(void const * argument) { /* USER CODE BEGIN 5 */ /* Infinite loop */ for(;;) { osDelay(1);//系統自帶延時函式,不會一直佔用CPU的資源 } /* USER CODE END 5 */ } /* HandlerTask function */ void HandlerTask(void const * argument) { /* USER CODE BEGIN HandlerTask */ /* Infinite loop */ for(;;) { osDelay(1); } /* USER CODE END HandlerTask */ } /** * @brief Period elapsed callback in non blocking mode 中斷回撥函式 * @note This function is called when TIM4 interrupt took place, inside * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment * a global variable "uwTick" used as application time base. *當TIM4中斷髮生時,在HAL_TIM_IRQHandler()內部呼叫此函式。 它直接呼叫HAL_IncTick()來增加一個用作應用程式時基的全域性變數“uwTick” * @param htim : TIM handle * @retval None */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { /* USER CODE BEGIN Callback 0 */ /* USER CODE END Callback 0 */ if (htim->Instance == TIM4) { HAL_IncTick(); } /* USER CODE BEGIN Callback 1 */ /* USER CODE END Callback 1 */ } /** * @brief This function is executed in case of error occurrence. *當錯誤發生的時候執行這個函式 * @param file: The file name as string. * @param line: The line in file as a number. * @retval None */ void _Error_Handler(char *file, int line) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ while(1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. *報告原始檔的名稱和源行號 發生assert_param(斷言引數)錯誤的地方。 * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t* file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
2,分析結構
2-1 包含三個標頭檔案
#include "main.h" //包含了三個標頭檔案
#include "stm32f1xx_hal.h"
#include "cmsis_os.h"
2-2 定義私有變數
osThreadId PeriodicHandle;//實時系統的執行緒(任務)的識別碼(身份證)
//osThreadId 》typedef TaskHandle_t osThreadId;》typedef void * TaskHandle_t;
typedef TaskHandle_t osThreadId;
注意 #define PI 3.1415926 兩個位置相反
typedef void * TaskHandle_t 空返回值
就是用HANDLE來代表void*,也可理解為 HANDLE == void*
void型別的指標表示可以指向任意型別的資料,但是void型別指標不能直接使用,使用前必須先轉換成某種確定的型別。
osThreadId HandlerHandle ->TaskHandle_t HandlerHandle ->void * HandlerHandle
//最終的目標還是 TaskHandle_t 手冊上看看什麼意思osThreadId HandlerHandle;
osSemaphoreId bSem01Handle;//訊號量任務的身份證
osSemaphoreId->typedef SemaphoreHandle_t osSemaphoreId;->typedef QueueHandle_t SemaphoreHandle_t;
->typedef void * QueueHandle_t;
注意:在MX中第一任務時,只是第一了task name :Periodic . 而任務控制代碼PeriodicHandle是自動生成的
2-3 宣告私有函式
/* Private function prototypes 私有函式原型 -----------------------------------------------*/
void SystemClock_Config (void); //系統時鐘的配置
static void MX_GPIO_Init (void);//GPIO的初始化
void PeriodicTask (void const * argument);//返回值為空,在MX中設定的函式PeriodicTask宣告
void HandlerTask (void const * argument);
2-4 int main(void)
先對HAL_Init()、 SystemClock_Config()、 MX_GPIO_Init();初始化配置
再/* 定義和建立訊號量bSem01 */
osSemaphoreDef(bSem01);
bSem01Handle = osSemaphoreCreate(osSemaphore(bSem01), 1);
/* Create the thread(s) */
/* definition and creation of Periodic */
/*定義和建立Periodic任務*/
osThreadDef(Periodic, PeriodicTask, osPriorityNormal, 0, 128);
PeriodicHandle = osThreadCreate(osThread(Periodic), NULL);
最後,開始任務排程管理器
3 ,注意CubeMX的封裝函式和原生API的區別。
MX下有些函式,原生API下面沒有