# 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說可以就可以。

再決定一個UART讓`printf`能夠印到我的電腦上(等等再解釋),所以點擊左方connectivity/UART1,並且設定參數,如紅框框顯示的mode、baud rate、word length等參數

然後是Timer的設置,為了讓開發更方便一點,我設定Tim6所連結的APB1為50MHz,等等在程式中寫一個`delay();`程式讓開發更方便,設定方法為點擊上方Clock Configuration,點需要的Clock設定其頻率,電腦會自動找到能用頻率解。

以上設定完成就能按下save,生成code!
> ### 小重點 - printf設定
> 在沒有外接螢幕或顯示器的情況下,無法將資訊直接寫成`printf("...");`來讓我們看到,超不方便,所以通常我會用一個UART通道來傳我想要印的東東到電腦,利用PuTTy或是Arduino程式開啟COM monitor來看到我傳的資料,以PuTTy為例,確定電腦連接後,開啟電腦的裝置管理員,確認STM在哪一個COM。
> 我的電腦上為COM3,開啟[PuTTy](https://www.putty.org/),設定成serial,名稱編輯為COM3,並輸入剛剛設定的baud rate,完成後按下右下角open,就會跳出像是terminal的視窗,等等main.c中寫好UART設定後,程式只要有`printf();`就會顯示到電腦!
> 
## 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 */
```