# STM32CubeIDE - 2:使用方法與觀念+DHT11感測器實作 > ## 做任何開發必須必須必須必須必須要去看要用的元件的Datasheet > ~~或是直接找網路上人家做好的範例~~ ## 1. 架構 開發流程通常為: * 編輯.ioc檔案,決定會使用到的Pin、Connectivity、Timer等等參數 * 點擊file/save,生成程式碼 * 回到main.c或是要編輯的程式檔案撰寫需要的函數與邏輯 * 連接開發板到電腦,上方功能列按下run編譯並執行程式,此時會將程式燒錄到開發板 * 一定超多問題所以開始debug * 瘋狂debug * debuuuuuuuug * 不知道改了甚麼鬼總之突然就好了 * 開心地完成 ## 2. .ioc檔案設定 憑空講這有點難,所以用我寫過的DHT11溫溼度感測器來說,其Pin為Vcc、GND、Sig,Sig輸出為數位訊號,使用GPIO即可收取其資料,所以我需要一個GPIO_OUT來使用,先按照datasheet trigger感測器再用程式更改成GPIO_IN來接收資料,我決定將PA1設置為GPIO_OUT,設置方法為點擊那個Pin,選擇你要的功能,如果不要PA1,也可以用其他的隨便,反正datasheet說可以就可以。 ![螢幕擷取畫面 2024-12-30 164253](https://hackmd.io/_uploads/HyxNT0yUkg.png) 再決定一個UART讓`printf`能夠印到我的電腦上(等等再解釋),所以點擊左方connectivity/UART1,並且設定參數,如紅框框顯示的mode、baud rate、word length等參數 ![image](https://hackmd.io/_uploads/rJBfJ1lUkg.png) 然後是Timer的設置,為了讓開發更方便一點,我設定Tim6所連結的APB1為50MHz,等等在程式中寫一個`delay();`程式讓開發更方便,設定方法為點擊上方Clock Configuration,點需要的Clock設定其頻率,電腦會自動找到能用頻率解。 ![螢幕擷取畫面 2024-12-30 170445](https://hackmd.io/_uploads/SyvLMJg81e.png) 以上設定完成就能按下save,生成code! > ### 小重點 - printf設定 > 在沒有外接螢幕或顯示器的情況下,無法將資訊直接寫成`printf("...");`來讓我們看到,超不方便,所以通常我會用一個UART通道來傳我想要印的東東到電腦,利用PuTTy或是Arduino程式開啟COM monitor來看到我傳的資料,以PuTTy為例,確定電腦連接後,開啟電腦的裝置管理員,確認STM在哪一個COM。![螢幕擷取畫面 2024-12-30 171025](https://hackmd.io/_uploads/Skb6Q1gIJx.png) > 我的電腦上為COM3,開啟[PuTTy](https://www.putty.org/),設定成serial,名稱編輯為COM3,並輸入剛剛設定的baud rate,完成後按下右下角open,就會跳出像是terminal的視窗,等等main.c中寫好UART設定後,程式只要有`printf();`就會顯示到電腦! > ![螢幕擷取畫面 2024-12-30 171223](https://hackmd.io/_uploads/BkSs5-eUyg.png) ## 3. main.c程式碼 歷經千辛萬苦終於要開始寫程式了,撰寫STM32CubeIDE程式,**一大大大大重點,務必寫在預設程式碼User的欄位中,例如開啟main.c後,會發現有一堆註解,那些註解千萬千萬千萬不要刪除,這個註解是在指示分區用的,我們能寫程式的區塊會標註** ``` /* USER CODE BEGIN */ /* USER CODE END */ ``` 這些區塊中間就是提供撰寫的地方,如果寫在其他地方,恭喜你獲得再練習一次的機會。 ### printf 設定程式 非常簡單,參考[STM官方(?](https://community.st.com/t5/stm32-mcus/how-to-redirect-the-printf-function-to-a-uart-for-debug-messages/ta-p/49865)在main.c以下欄位增加程式碼,注意UART所使用的channel編號 ``` /* USER CODE BEGIN PFP */ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) /* USER CODE END PFP */ … /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ … /* USER CODE BEGIN 4 */ /** * @brief Retargets the C library printf function to the USART. * None * @retval None */ PUTCHAR_PROTOTYPE { /* Place your implementation of fputc here */ /* e.g. write a character to the USART1 and Loop until the end of transmission */ HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF); return ch; } /* USER CODE END 4 */ ``` ### delay();函數設定 [參考連結](https://controllerstech.com/create-1-microsecond-delay-stm32/#google_vignette) 目的讓我們能隨時用delay控制開發板執行程序,程式碼如下 ``` void delay (uint16_t time) { /*set delay by tim6*/ __HAL_TIM_SET_COUNTER(&htim6,0); // set the counter value a 0 while (__HAL_TIM_GET_COUNTER(&htim6) < time); // wait for the counter to reach the us input in the parameter } ``` 並在int main()函數中加入啟動timer程式 ``` int main () { .... HAL_TIM_Base_Start(&htim6); while (1) { .... } } ``` ### DHT11 程式碼 參考[此網站](https://controllerstech.com/using-dht11-sensor-with-stm32/)製作,其解釋十分詳細,我就懶得打了 附上我撰寫的main.c完整程式(在最下面) ## 4. 總結 流程大致是這樣,接下來就是熟悉度的問題,(包含我)許多元件的使用方式與stm32的配合需要去練習,HAL函式庫的用法與各種參數設定方式需要邊查資料邊做,好難難難難~~~~ ``` /* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2024 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "stdio.h" /* 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 ---------------------------------------------------------*/ TIM_HandleTypeDef htim6; UART_HandleTypeDef huart1; UART_HandleTypeDef huart2; /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART2_UART_Init(void); static void MX_USART1_UART_Init(void); static void MX_TIM6_Init(void); /* USER CODE BEGIN PFP */ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ void delay (uint16_t time) { /*set delay by tim6*/ __HAL_TIM_SET_COUNTER(&htim6,0); // set the counter value a 0 while (__HAL_TIM_GET_COUNTER(&htim6) < time); // wait for the counter to reach the us input in the parameter } uint8_t Rh_byte1, Rh_byte2, Temp_byte1, Temp_byte2; uint16_t SUM, RH, TEMP; float Temperature = 0; float Humidity = 0; uint8_t Presence = 0; void Set_Pin_Output (GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin){ GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOx, &GPIO_InitStruct); } void Set_Pin_Input (GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin){ GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Speed = GPIO_NOPULL; HAL_GPIO_Init(GPIOx, &GPIO_InitStruct); } #define DHT11_PORT GPIOA #define DHT11_PIN GPIO_PIN_1 void DHT11_Start (void) { Set_Pin_Output (DHT11_PORT, DHT11_PIN); // set the pin as output HAL_GPIO_WritePin (DHT11_PORT, DHT11_PIN, 0); // pull the pin low delay (18000); // wait for 18ms HAL_GPIO_WritePin (DHT11_PORT, DHT11_PIN, 1); delay(30); Set_Pin_Input(DHT11_PORT, DHT11_PIN); // set as input } uint8_t DHT11_Check_Response (void) { uint8_t Response = 0; delay (40); if (!(HAL_GPIO_ReadPin (DHT11_PORT, DHT11_PIN))) { delay (80); if ((HAL_GPIO_ReadPin (DHT11_PORT, DHT11_PIN))) Response = 1; else Response = -1; //255 } while ((HAL_GPIO_ReadPin (DHT11_PORT, DHT11_PIN))); // wait for the pin to go low return Response; } uint8_t DHT11_Read (void) { uint8_t i,j; for (j=0;j<8;j++) { while (!(HAL_GPIO_ReadPin (DHT11_PORT, DHT11_PIN))); // wait for the pin to go high delay (40); // wait for 40 us if (!(HAL_GPIO_ReadPin (DHT11_PORT, DHT11_PIN))) // if the pin is low { i&= ~(1<<(7-j)); // write 0 } else i|= (1<<(7-j)); // if the pin is high, write 1 while ((HAL_GPIO_ReadPin (DHT11_PORT, DHT11_PIN))); // wait for the pin to go low } return i; } /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ 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(); MX_USART2_UART_Init(); MX_USART1_UART_Init(); MX_TIM6_Init(); /* USER CODE BEGIN 2 */ HAL_TIM_Base_Start(&htim6); printf("initializing timer\r\n"); HAL_Delay(2000); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { DHT11_Start(); Presence = DHT11_Check_Response(); Rh_byte1 = DHT11_Read (); Rh_byte2 = DHT11_Read (); Temp_byte1 = DHT11_Read (); Temp_byte2 = DHT11_Read (); SUM = DHT11_Read(); TEMP = Temp_byte1; RH = Rh_byte1; Temperature = (float) TEMP; Humidity = (float) RH; printf("temp:%f\r\n",Temperature); printf("hum:%f\r\n",Humidity); HAL_Delay(3000); /* 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 = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Configure the main internal regulator output voltage */ if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) { Error_Handler(); } /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 2; RCC_OscInitStruct.PLL.PLLN = 25; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7; RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV4; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses 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; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK) { Error_Handler(); } } /** * @brief TIM6 Initialization Function * @param None * @retval None */ static void MX_TIM6_Init(void) { /* USER CODE BEGIN TIM6_Init 0 */ /* USER CODE END TIM6_Init 0 */ TIM_MasterConfigTypeDef sMasterConfig = {0}; /* USER CODE BEGIN TIM6_Init 1 */ /* USER CODE END TIM6_Init 1 */ htim6.Instance = TIM6; htim6.Init.Prescaler = 50-1; htim6.Init.CounterMode = TIM_COUNTERMODE_UP; htim6.Init.Period = 0xffff-1; htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim6) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM6_Init 2 */ /* USER CODE END TIM6_Init 2 */ } /** * @brief USART1 Initialization Function * @param None * @retval None */ static void MX_USART1_UART_Init(void) { /* USER CODE BEGIN USART1_Init 0 */ /* USER CODE END USART1_Init 0 */ /* USER CODE BEGIN USART1_Init 1 */ /* USER CODE END USART1_Init 1 */ huart1.Instance = USART1; huart1.Init.BaudRate = 115200; huart1.Init.WordLength = UART_WORDLENGTH_7B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN USART1_Init 2 */ /* USER CODE END USART1_Init 2 */ } /** * @brief USART2 Initialization Function * @param None * @retval None */ static void MX_USART2_UART_Init(void) { /* USER CODE BEGIN USART2_Init 0 */ /* USER CODE END USART2_Init 0 */ /* USER CODE BEGIN USART2_Init 1 */ /* USER CODE END USART2_Init 1 */ huart2.Instance = USART2; huart2.Init.BaudRate = 115200; huart2.Init.WordLength = UART_WORDLENGTH_8B; huart2.Init.StopBits = UART_STOPBITS_1; huart2.Init.Parity = UART_PARITY_NONE; huart2.Init.Mode = UART_MODE_TX_RX; huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart2.Init.OverSampling = UART_OVERSAMPLING_16; huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart2) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN USART2_Init 2 */ /* USER CODE END USART2_Init 2 */ } /** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* USER CODE BEGIN MX_GPIO_Init_1 */ /* USER CODE END MX_GPIO_Init_1 */ /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1|LD2_Pin, GPIO_PIN_RESET); /*Configure GPIO pin : B1_Pin */ GPIO_InitStruct.Pin = B1_Pin; GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct); /*Configure GPIO pins : PA1 LD2_Pin */ GPIO_InitStruct.Pin = GPIO_PIN_1|LD2_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USER CODE BEGIN MX_GPIO_Init_2 */ /* USER CODE END MX_GPIO_Init_2 */ } /* USER CODE BEGIN 4 */ /** * @brief Retargets the C library printf function to the USART. * None * @retval None */ PUTCHAR_PROTOTYPE { /* Place your implementation of fputc here */ /* e.g. write a character to the USART1 and Loop until the end of transmission */ HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF); return ch; } /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); 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. * @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, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ ```