STM32 HAL庫外設編程學習筆記

STM32 HAL庫外設編程

1. 概述

本文檔是基于STM32 HAL庫的外設編程學習筆記,主要包括以下外設的配置和使用方法:

  • GPIO:通用輸入輸出接口
  • ADC:模數轉換器
  • UART:通用異步收發器
  • TIM:定時器
  • I2C:內部集成電路總線
  • SPI:串行外設接口

本筆記基于STM32F1系列微控制器,使用HAL庫進行開發。

2. GPIO (通用輸入輸出接口)

2.1 GPIO初始化

void MX_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOD_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);/*Configure GPIO pin : PC13 - LED */GPIO_InitStruct.Pin = GPIO_PIN_13;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;  // 推挽輸出模式GPIO_InitStruct.Pull = GPIO_NOPULL;         // 無上拉下拉GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速模式HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);/*Configure GPIO pin : PA0 - Button */GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;     // 輸入模式GPIO_InitStruct.Pull = GPIO_PULLUP;         // 上拉HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

2.2 GPIO操作函數

// LED控制函數
void led_ON(void)
{HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); // 低電平點亮
}void led_OFF(void)
{HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);  // 高電平熄滅
}void led_Tog(void)
{HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);  // 翻轉LED狀態
}// 按鈕讀取函數(帶消抖)
uint8_t read_button(void)
{if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){HAL_Delay(10);  // 消抖延時while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET); // 等待按鈕釋放HAL_Delay(10);  // 釋放消抖return 1;}return 0;
}

2.3 GPIO常用API

  • HAL_GPIO_Init(): 初始化GPIO引腳
  • HAL_GPIO_DeInit(): 復位GPIO引腳
  • HAL_GPIO_ReadPin(): 讀取GPIO引腳狀態
  • HAL_GPIO_WritePin(): 設置GPIO引腳狀態
  • HAL_GPIO_TogglePin(): 翻轉GPIO引腳狀態
  • HAL_GPIO_LockPin(): 鎖定GPIO引腳配置

3. ADC (模數轉換器)

在這里插入圖片描述
在這里插入圖片描述

3.1 ADC初始化

void MX_ADC1_Init(void)
{ADC_ChannelConfTypeDef sConfig = {0};/* ADC1基本配置 */hadc1.Instance = ADC1;hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;           // 禁用掃描模式hadc1.Init.ContinuousConvMode = DISABLE;              // 禁用連續轉換hadc1.Init.DiscontinuousConvMode = DISABLE;           // 禁用不連續模式hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T3_TRGO; // 外部觸發源為TIM3hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;          // 數據右對齊hadc1.Init.NbrOfConversion = 1;                       // 轉換通道數為1HAL_ADC_Init(&hadc1);/* ADC通道配置 */sConfig.Channel = ADC_CHANNEL_1;                      // 選擇通道1sConfig.Rank = ADC_REGULAR_RANK_1;                    // 設置為第1個轉換sConfig.SamplingTime = ADC_SAMPLETIME_13CYCLES_5;     // 采樣時間為13.5個周期HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}

3.2 ADC引腳配置

void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(adcHandle->Instance==ADC1){/* ADC1時鐘使能 */__HAL_RCC_ADC1_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/* ADC1 GPIO配置: PA1 -> ADC1_IN1 */GPIO_InitStruct.Pin = GPIO_PIN_1;GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;  // 模擬輸入模式HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);}
}

3.3 ADC使用示例

// 獲取ADC值并轉換為電壓值
float get_adc_value(void)
{HAL_ADC_Start(&hadc1);  // 啟動ADC轉換HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);  // 等待轉換完成uint32_t dr = HAL_ADC_GetValue(&hadc1);  // 獲取轉換結果return dr * ((3.3f - 0.0f) / 4095.0f);  // 轉換為電壓值(0-3.3V)
}// 使用定時器觸發的ADC轉換
float get_adc_value_print(void)
{HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);  // 等待轉換完成uint32_t dr = HAL_ADC_GetValue(&hadc1);  // 獲取轉換結果return dr * ((3.3f - 0.0f) / 4095.0f);  // 轉換為電壓值(0-3.3V)
}

3.4 ADC常用API

  • HAL_ADC_Init(): 初始化ADC
  • HAL_ADC_ConfigChannel(): 配置ADC通道
  • HAL_ADC_Start(): 啟動ADC轉換
  • HAL_ADC_Stop(): 停止ADC轉換
  • HAL_ADC_PollForConversion(): 輪詢等待轉換完成
  • HAL_ADC_GetValue(): 獲取轉換結果
  • HAL_ADC_Start_IT(): 啟動中斷模式ADC轉換
  • HAL_ADC_Start_DMA(): 啟動DMA模式ADC轉換

4. UART (通用異步收發器)

在這里插入圖片描述
在這里插入圖片描述

4.1 UART初始化

void MX_USART1_UART_Init(void)
{huart1.Instance = USART1;huart1.Init.BaudRate = 115200;                  // 波特率115200huart1.Init.WordLength = UART_WORDLENGTH_8B;    // 8位數據位huart1.Init.StopBits = UART_STOPBITS_1;         // 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; // 16倍過采樣HAL_UART_Init(&huart1);
}

4.2 UART引腳配置

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(uartHandle->Instance==USART1){/* USART1時鐘使能 */__HAL_RCC_USART1_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/* USART1 GPIO配置PA9     ------> USART1_TXPA10    ------> USART1_RX */GPIO_InitStruct.Pin = GPIO_PIN_9;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;       // 復用推挽輸出GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_10;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;        // 輸入模式GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/* USART1中斷配置 */HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);HAL_NVIC_EnableIRQ(USART1_IRQn);}
}

4.3 UART中斷接收實現

// 全局變量
uint16_t UART1_INDEX = 0;         // 緩沖區索引
uint8_t UART1_STATE = 0;           // 狀態機狀態
uint8_t UART1_BUFFER[256];         // 接收緩沖區
uint8_t UART1_TEMP_CHAR;           // 臨時接收字符// 啟動UART1中斷接收
void uart1_start_it(void)
{HAL_UART_Receive_IT(&huart1, &UART1_TEMP_CHAR, 1); // 啟動接收中斷
}// UART接收完成回調函數
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if (huart == &huart1){// 狀態機處理switch (UART1_STATE){case 0:  // 正常接收狀態if (UART1_TEMP_CHAR == '\r')  // 接收到回車{UART1_STATE = 1;  // 進入等待換行狀態}else{if (UART1_INDEX < UART1_BUFFER_SIZE - 1){UART1_BUFFER[UART1_INDEX++] = UART1_TEMP_CHAR;  // 存儲字符}}break;case 1:  // 等待換行狀態if (UART1_TEMP_CHAR == '\n')  // 接收到換行{UART1_BUFFER[UART1_INDEX] = '\0';  // 字符串結束符UART1_STATE = 2;  // 進入數據就緒狀態}else{// 不是換行,補存\r和當前字符if (UART1_INDEX < UART1_BUFFER_SIZE - 2){UART1_BUFFER[UART1_INDEX++] = '\r';UART1_BUFFER[UART1_INDEX++] = UART1_TEMP_CHAR;}UART1_STATE = 0;  // 回到正常接收狀態}break;}// 緩沖區溢出處理if (UART1_INDEX >= UART1_BUFFER_SIZE - 1){UART1_INDEX = 0;                            // 重置索引UART1_STATE = 0;                             // 重置狀態memset(UART1_BUFFER, 0, UART1_BUFFER_SIZE);  // 清空緩沖區}// 重啟接收中斷HAL_UART_Receive_IT(&huart1, &UART1_TEMP_CHAR, 1);}
}

4.4 printf重定向實現

// 重定向printf到UART2
int fputc(int ch, FILE *f)
{if (f == stdout)  // 僅處理標準輸出{HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 100);  // 阻塞發送if (ch == '\n')  // 發送\n時自動補充\rHAL_UART_Transmit(&huart2, (uint8_t *)"\r", 1, 100);}return ch;
}// 調試日志函數
void DEBUG_LOG(char *file, char *info)
{printf("Time: %d, File: %s, Info: %s\r\n", CURRENT_TIME, file, info);
}

4.5 UART常用API

  • HAL_UART_Init(): 初始化UART
  • HAL_UART_Transmit(): 阻塞模式發送數據
  • HAL_UART_Receive(): 阻塞模式接收數據
  • HAL_UART_Transmit_IT(): 中斷模式發送數據
  • HAL_UART_Receive_IT(): 中斷模式接收數據
  • HAL_UART_Transmit_DMA(): DMA模式發送數據
  • HAL_UART_Receive_DMA(): DMA模式接收數據

5. TIM (定時器)

在這里插入圖片描述

5.1 基本定時器初始化

void MX_TIM1_Init(void)
{TIM_ClockConfigTypeDef sClockSourceConfig = {0};TIM_MasterConfigTypeDef sMasterConfig = {0};/* TIM1基本配置 */htim1.Instance = TIM1;htim1.Init.Prescaler = 7200-1;                    // 預分頻值,72MHz/7200=10KHzhtim1.Init.CounterMode = TIM_COUNTERMODE_UP;      // 向上計數模式htim1.Init.Period = 10000;                        // 周期值,10KHz/10000=1Hzhtim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 時鐘分頻因子htim1.Init.RepetitionCounter = 0;                 // 重復計數器值htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; // 禁用自動重裝載預裝載HAL_TIM_Base_Init(&htim1);/* 時鐘源配置 */sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; // 內部時鐘源HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig);/* 主模式配置 */sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; // 復位觸發輸出sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; // 禁用主從模式HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);
}

5.2 PWM定時器初始化

在這里插入圖片描述

void MX_TIM3_Init(void)
{TIM_MasterConfigTypeDef sMasterConfig = {0};TIM_OC_InitTypeDef sConfigOC = {0};/* TIM3基本配置 */htim3.Instance = TIM3;htim3.Init.Prescaler = 72-1;                     // 預分頻值,72MHz/72=1MHzhtim3.Init.CounterMode = TIM_COUNTERMODE_UP;     // 向上計數模式htim3.Init.Period = 1000;                        // 周期值,1MHz/1000=1KHzhtim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 時鐘分頻因子htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; // 禁用自動重裝載預裝載HAL_TIM_PWM_Init(&htim3);/* 主模式配置 */sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; // 更新事件觸發輸出sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; // 禁用主從模式HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig);/* PWM通道配置 */sConfigOC.OCMode = TIM_OCMODE_PWM1;             // PWM模式1sConfigOC.Pulse = 0;                             // 初始占空比為0sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;      // 輸出極性為高sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;       // 禁用快速模式HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_3); // 配置通道3為PWM
}

5.3 定時器中斷處理

// 全局變量
uint32_t CURRENT_TIME;  // 當前時間計數// 定時器周期中斷回調函數
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if (htim->Instance == TIM1){CURRENT_TIME++;  // 時間計數遞增led_Tog();       // 翻轉LED狀態}
}// 啟動定時器中斷
void tim_start(void)
{HAL_TIM_Base_Start_IT(&htim1);  // 啟動基本定時器中斷DEBUG_LOG("tim", "TIM1 started");
}

5.4 PWM控制函數

// 啟動PWM輸出
void pwm_start(void)
{HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3);  // 啟動PWM輸出
}// 更新PWM占空比
void pwm_update(int duty)
{__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, duty);  // 設置比較值
}

5.5 定時器常用API

  • HAL_TIM_Base_Init(): 初始化基本定時器
  • HAL_TIM_PWM_Init(): 初始化PWM定時器
  • HAL_TIM_Base_Start(): 啟動基本定時器
  • HAL_TIM_Base_Stop(): 停止基本定時器
  • HAL_TIM_Base_Start_IT(): 啟動基本定時器中斷
  • HAL_TIM_PWM_Start(): 啟動PWM輸出
  • HAL_TIM_PWM_Stop(): 停止PWM輸出
  • HAL_TIM_PWM_ConfigChannel(): 配置PWM通道

6. I2C (內部集成電路總線)

在這里插入圖片描述

6.1 I2C初始化

void MX_I2C1_Init(void)
{hi2c1.Instance = I2C1;hi2c1.Init.ClockSpeed = 400000;                // 時鐘速度400KHzhi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;        // 占空比2:1hi2c1.Init.OwnAddress1 = 0;                    // 自身地址1hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; // 7位地址模式hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; // 禁用雙地址模式hi2c1.Init.OwnAddress2 = 0;                    // 自身地址2hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; // 禁用廣播呼叫模式hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; // 禁用時鐘延展模式HAL_I2C_Init(&hi2c1);
}

6.2 I2C OLED顯示屏操作

// OLED寫命令
void OLED_WriteCommand(uint8_t Command)
{uint8_t cmd[] = {0x00, Command};  // 0x00表示命令HAL_I2C_Master_Transmit(&hi2c1, 0x78, cmd, sizeof(cmd), HAL_MAX_DELAY);
}// OLED寫數據
void OLED_WriteData(uint8_t Data)
{uint8_t cmd[] = {0x40, Data};     // 0x40表示數據HAL_I2C_Master_Transmit(&hi2c1, 0x78, cmd, sizeof(cmd), HAL_MAX_DELAY);
}// OLED設置光標位置
void OLED_SetCursor(uint8_t Y, uint8_t X)
{OLED_WriteCommand(0xB0 | Y);                    // 設置Y位置OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4));    // 設置X位置高4位OLED_WriteCommand(0x00 | (X & 0x0F));           // 設置X位置低4位
}// OLED清屏
void OLED_Clear(void)
{  uint8_t i, j;for (j = 0; j < 8; j++){OLED_SetCursor(j, 0);for(i = 0; i < 128; i++){OLED_WriteData(0x00);}}
}// OLED顯示字符
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{      uint8_t i;OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);        // 設置光標位置在上半部分for (i = 0; i < 8; i++){OLED_WriteData(OLED_F8x16[Char - ' '][i]);           // 顯示上半部分內容}OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);    // 設置光標位置在下半部分for (i = 0; i < 8; i++){OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);       // 顯示下半部分內容}
}// OLED顯示字符串
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{uint8_t i;for (i = 0; String[i] != '\0'; i++){OLED_ShowChar(Line, Column + i, String[i]);}
}// OLED顯示數字
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{uint8_t i;for (i = 0; i < Length; i++)                            {OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');}
}// OLED初始化
void OLED_start(void)
{// 上電延時uint32_t i, j;for (i = 0; i < 1000; i++){for (j = 0; j < 1000; j++);}// 初始化命令序列OLED_WriteCommand(0xAE);    // 關閉顯示OLED_WriteCommand(0xD5);    // 設置顯示時鐘分頻比/振蕩器頻率OLED_WriteCommand(0x80);OLED_WriteCommand(0xA8);    // 設置多路復用率OLED_WriteCommand(0x3F);OLED_WriteCommand(0xD3);    // 設置顯示偏移OLED_WriteCommand(0x00);OLED_WriteCommand(0x40);    // 設置顯示開始行OLED_WriteCommand(0xA1);    // 設置左右方向,0xA1正常 0xA0左右反置OLED_WriteCommand(0xC8);    // 設置上下方向,0xC8正常 0xC0上下反置OLED_WriteCommand(0xDA);    // 設置COM引腳硬件配置OLED_WriteCommand(0x12);OLED_WriteCommand(0x81);    // 設置對比度控制OLED_WriteCommand(0xCF);OLED_WriteCommand(0xD9);    // 設置預充電周期OLED_WriteCommand(0xF1);OLED_WriteCommand(0xDB);    // 設置VCOMH取消選擇級別OLED_WriteCommand(0x30);OLED_WriteCommand(0xA4);    // 設置整個顯示打開/關閉OLED_WriteCommand(0xA6);    // 設置正常/倒轉顯示OLED_WriteCommand(0x8D);    // 設置充電泵OLED_WriteCommand(0x14);OLED_WriteCommand(0xAF);    // 開啟顯示OLED_Clear();               // OLED清屏
}

6.3 I2C常用API

  • HAL_I2C_Init(): 初始化I2C
  • HAL_I2C_Master_Transmit(): 主機模式發送數據
  • HAL_I2C_Master_Receive(): 主機模式接收數據
  • HAL_I2C_Slave_Transmit(): 從機模式發送數據
  • HAL_I2C_Slave_Receive(): 從機模式接收數據
  • HAL_I2C_Mem_Write(): 寫入設備內部地址
  • HAL_I2C_Mem_Read(): 讀取設備內部地址

7. SPI (串行外設接口)

在這里插入圖片描述

7.1 SPI初始化

void MX_SPI1_Init(void)
{hspi1.Instance = SPI1;hspi1.Init.Mode = SPI_MODE_MASTER;                // 主機模式hspi1.Init.Direction = SPI_DIRECTION_2LINES;      // 雙線全雙工hspi1.Init.DataSize = SPI_DATASIZE_8BIT;          // 8位數據位hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;       // 時鐘極性高hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;            // 第二個邊沿采樣hspi1.Init.NSS = SPI_NSS_SOFT;                    // 軟件NSS控制hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; // 波特率預分頻hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;           // 高位先行hspi1.Init.TIMode = SPI_TIMODE_DISABLE;           // 禁用TI模式hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; // 禁用CRC計算hspi1.Init.CRCPolynomial = 10;                    // CRC多項式HAL_SPI_Init(&hspi1);
}

7.2 SPI Flash操作示例

// 保存LED狀態到Flash
void save_led_state(uint8_t led_state)
{// 1. 寫使能uint8_t write_cmd[] = {0x06};HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);  // CS拉低HAL_SPI_Transmit(&hspi1, write_cmd, sizeof(write_cmd), HAL_MAX_DELAY);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);    // CS拉高// 2. 扇區擦除uint8_t sector_erase[] = {0x20, 0x00, 0x00, 0x00};    // 擦除0地址扇區HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);HAL_SPI_Transmit(&hspi1, sector_erase, sizeof(sector_erase), HAL_MAX_DELAY);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);HAL_Delay(200);  // 等待擦除完成// 3. 寫使能HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);HAL_SPI_Transmit(&hspi1, write_cmd, sizeof(write_cmd), HAL_MAX_DELAY);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);// 4. 頁編程uint8_t page_cmd[] = {0x02, 0x00, 0x00, 0x00, led_state};  // 寫入數據HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);HAL_SPI_Transmit(&hspi1, page_cmd, sizeof(page_cmd), HAL_MAX_DELAY);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);HAL_Delay(100);  // 等待寫入完成
}// 從Flash讀取LED狀態
uint8_t load_led_state(void)
{uint8_t read_cmd[] = {0x03, 0x00, 0x00, 0x00};  // 讀取命令uint8_t led_state = 0xff;HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);  // CS拉低HAL_SPI_Transmit(&hspi1, read_cmd, sizeof(read_cmd), HAL_MAX_DELAY);HAL_SPI_Receive(&hspi1, &led_state, 1, HAL_MAX_DELAY);  // 接收數據HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);    // CS拉高return led_state;
}

7.3 SPI常用API

  • HAL_SPI_Init(): 初始化SPI
  • HAL_SPI_Transmit(): 發送數據
  • HAL_SPI_Receive(): 接收數據
  • HAL_SPI_TransmitReceive(): 同時發送和接收數據
  • HAL_SPI_Transmit_IT(): 中斷模式發送數據
  • HAL_SPI_Receive_IT(): 中斷模式接收數據
  • HAL_SPI_TransmitReceive_IT(): 中斷模式同時發送和接收數據
  • HAL_SPI_Transmit_DMA(): DMA模式發送數據
  • HAL_SPI_Receive_DMA(): DMA模式接收數據

8. 綜合應用示例

8.1 主函數初始化部分

int main(void)
{/* 復位所有外設,初始化Flash接口和Systick */HAL_Init();/* 配置系統時鐘 */SystemClock_Config();/* 初始化所有配置的外設 */MX_GPIO_Init();MX_TIM1_Init();MX_TIM3_Init();MX_USART1_UART_Init();MX_USART2_UART_Init();MX_SPI1_Init();MX_I2C1_Init();MX_ADC1_Init();/* 用戶代碼初始化 */HAL_UART_Transmit(&huart2, (uint8_t *)"hh", 2, 100);  // 測試UART發送tim_start();                // 啟動定時器uart1_start_it();           // 啟動UART1接收中斷led_OFF();                  // 關閉LEDOLED_start();               // 初始化OLEDHAL_TIM_Base_Start(&htim3); // 啟動TIM3基本定時器HAL_ADC_Start(&hadc1);      // 啟動ADC/* 從Flash讀取LED狀態并設置 */uint8_t led_state = load_led_state();if (led_state == 1){led_ON();} else{led_OFF();}/* OLED顯示初始信息 */OLED_ShowString(2, 2, "hello");OLED_ShowNum(1, 1, led_state, 1);/* 無限循環 */while (1){/* ADC讀取并打印 */float value = get_adc_value_print();printf("%.3f\n", value);}
}

8.2 條件編譯示例

// UART接收處理示例
#if 0
if (UART1_STATE == 2) // 檢查是否接收到完整的字符串
{// 處理接收到的字符串printf("Received: %s\n", UART1_BUFFER); // 打印接收到的字符串UART1_INDEX = UART1_STATE = 0;memset(UART1_BUFFER, 0, sizeof(UART1_BUFFER));
}
#endif// 按鈕控制LED示例
#if 0
if (read_button() == 1)
{led_state = !led_state;switch_led(led_state);save_led_state(led_state);
}
#endif// ADC控制LED示例
#if 0
float value = get_adc_value();
//OLED_ShowNum(1, 1, value, 5);
if (value < 1.5) led_ON();
else led_OFF();
#endif

9. 總結

本文檔詳細介紹了STM32 HAL庫編程中常用外設的配置和使用方法,包括:

  1. GPIO:輸入輸出控制,LED和按鈕操作
  2. ADC:模擬信號采集和轉換
  3. UART:串口通信,中斷接收和printf重定向
  4. TIM:基本定時器和PWM輸出
  5. I2C:I2C通信,OLED顯示屏控制
  6. SPI:SPI通信,Flash存儲操作

通過這些基礎外設的學習,可以進一步開發更復雜的STM32應用程序。在實際開發中,可以根據需要組合使用這些外設,實現各種功能。
Gitee 倉庫地址

10. 參考資料

  1. STM32F1xx HAL庫用戶手冊
  2. STM32F103數據手冊
  3. STM32CubeMX用戶指南

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/95116.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/95116.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/95116.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

DHCP服務配置與管理實戰指南

DHCP 服務配置與管理筆記 一、DHCP 核心概念 1. DHCP 定義與功能 DHCP (Dynamic Host Configuration Protocol)&#xff1a;動態主機配置協議核心功能&#xff1a; 自動分配 IP 地址提供子網掩碼、網關、DNS 等網絡參數管理 IP 地址租約周期 典型應用&#xff1a;ADSL撥號、企業…

WebSocket 在多線程環境下處理 Session并發

WebSocket 在多線程環境下處理 Session并發時&#xff0c;常見問題包括狀態沖突&#xff08;如 IllegalStateException&#xff09;、消息亂序、連接超時等。以下是綜合各技術方案的解決方案&#xff0c;分為單機多線程和分布式集群兩類場景&#xff1a;&#x1f512; 一、單機…

JDBC的連接過程(超詳細)

JDBC&#xff08;Java Database Connectivity&#xff09;是 Java 用于訪問數據庫的標準 API&#xff0c;它允許 Java 程序與各種不同類型的數據庫進行交互&#xff0c; 其連接數據庫的過程主要包含以下幾個步驟&#xff1a;1. 導入 JDBC 驅動依賴在使用 JDBC 連接數據庫之前&a…

本地WSL部署接入 whisper + ollama qwen3:14b 總結字幕校對增強版

1. 實現功能 M4-4: 校對增強版 (最終完全體) 本腳本是整個 Module 的最終形態&#xff0c;采用了“代碼預處理 LLM校對”的終極方案&#xff1a; 代碼預處理: 確定性地在每個語音片段后添加逗號&#xff0c;生成一份“標點草稿”。LLM校對: LLM 的任務被簡化為“校對和修正”這…

MySQL數據庫簡介

1 簡介 MySQL是一個關系型數據庫管理系統&#xff0c;由瑞典 MySQL AB公司開發&#xff0c;屬于 Oracle 旗下產品&#xff0c;是當今最流行的關系型數據庫管理系統之一&#xff0c;在 WEB應用方面&#xff0c;MySQL是最好的RDBMS (Relational Database Management System&#…

[Oracle] UNPIVOT 列轉行

Oracle數據庫中的UNPIVOT是一種用于將列轉換為行的SQL操作&#xff0c;它允許用戶將多個列的數據轉換為多行的形式&#xff0c;以便進行更靈活的數據分析和報表生成UNPIVOT主要用于將寬表(多列)轉換為長表(多行)&#xff0c;減少表的列數&#xff0c;增加行數語法格式SELECT pi…

node.js 學習筆記3 HTTP

path模塊 path模塊主要用于操作路徑。要使用path&#xff0c;首先需要引入path模塊。require(path) path.resolve 用于拼接規范的絕對路徑。 如果想拼接一個路徑&#xff0c;有時候是使用字符串手動拼接的&#xff0c;但由于系統的規范不同&#xff0c;路徑中的\和/無法統一…

Flutter Dialog、BottomSheet

屬性說明title標題content內容actions按鈕applicationName說明文字applicationVersion版本applicationLegalese版本基本使用class MyState extends State {AlertDialog delDialog(BuildContext context) {AlertDialog alertDialog AlertDialog(title: Text("提示"),…

《算法導論》第 19 章 - 斐波那契堆

引言斐波那契堆&#xff08;Fibonacci Heap&#xff09;是一種高效的可合并堆數據結構&#xff0c;由 Michael L. Fredman 和 Robert E. Tarjan 于 1984 年提出。它在許多優先隊列操作中提供了極佳的 amortized&#xff08;攤還&#xff09;時間復雜度&#xff0c;尤其適用于需…

MySQL-日志

MySQL-日志前言一、錯誤日志&#xff08;error log&#xff09;二、慢查詢日志(slow query log)三 、一般查詢日志(general log)四、 事務日志重做日志&#xff08;redo log&#xff09;回滾日志&#xff08;undo log&#xff09;五、 二進制日志(bin log)/歸檔日志 > 數據同…

嵌入式C語言編程:策略模式、狀態模式和狀態機的應用

概述 在沒有面向對象語法的C語言中&#xff0c;策略&#xff08;Strategy&#xff09;模式和狀態&#xff08;State&#xff09;模式都通過“上下文 接口”組合來模擬多態。 它們在代碼結構上幾乎一致&#xff0c;但設計意圖和應用場景卻差異很大。 本文分三部分深入剖析&…

人工智能、機器學習、深度學習:2025技術革命的深度解析

目錄 人工智能、機器學習、深度學習&#xff1a;技術革命的深度解析 引言 第一部分&#xff1a;人工智能的起源與演進 1.1 人工智能的定義 1.2 人工智能的歷史 1.3 人工智能的關鍵概念 a.知識表示&#xff08;Knowledge Representation&#xff09; b.搜索算法&#xf…

【Python】常用內置模塊

1.os 文件目錄 import os# 創建文件夾 os.mkdir(dir) # 判斷文件是否存在 os.path.exists(path) # 列出文件夾下文件列表 os.listdir(dir)""" 常用 """ # 當前文件相對路徑 os.getcwd()# 當前文件絕對路徑 os.path.abspath(__file__)# 當前文…

(Python)爬蟲進階(Python爬蟲教程)(CSS選擇器)

源代碼&#xff1a;#導入庫 import requests from bs4 import BeautifulSoup import pandas as pd#爬蟲函數 def scrape_books():#1.基本網址連接base_url "http://books.toscrape.com"#2.獲取基本網址responserequests.get(base_url)#3.檢查是否正常訪問if respons…

第七節 自然語言處理與Bert

自然語言處理與BERT模型&#xff1a;從基礎到實踐入門 自然語言處理&#xff08;NLP&#xff09;的核心目標之一是讓計算機理解人類語言的語義和上下文。本文將從基礎的字詞表示出發&#xff0c;逐步解析傳統模型的局限性、Self-attention的突破性思想&#xff0c;以及BERT如何…

攻擊者瞄準加密技術的基礎:智能合約

雖然利用許多智能合約中的安全漏洞已經成為網絡攻擊者的長期目標&#xff0c;但越來越多的安全公司開始關注使用欺詐性或混淆的智能合約從加密貨幣賬戶中竊取資金的騙局。 根據網絡安全公司 SentinelOne 本周發布的分析報告&#xff0c;在最近一次引人注目的攻擊中&#xff0c…

基于開源AI大模型、AI智能名片與S2B2C商城小程序的零售智能化升級路徑研究

摘要&#xff1a;在零售業數字化轉型浪潮中&#xff0c;人工智能技術正從“輔助工具”向“核心生產力”演進。本文聚焦開源AI大模型、AI智能名片與S2B2C商城小程序的協同應用&#xff0c;提出“數據感知-關系重構-生態協同”的三維創新框架。通過分析智能傳感、動態畫像與供應鏈…

機器學習 樸素貝葉斯

目錄 一.什么是樸素貝葉斯 1.1 從 “概率” 到 “分類” 二.樸素貝葉斯的數學基礎&#xff1a;貝葉斯定理 2.1 貝葉斯定理公式 2.2 從貝葉斯定理到樸素貝葉斯分類 2.3 “樸素” 的關鍵&#xff1a;特征獨立性假設 三、樸素貝葉斯的三種常見類型 3.1 高斯樸素貝葉斯&…

A Logical Calculus of the Ideas Immanent in Nervous Activity(神經網絡早期的M-P模型)

哈嘍&#xff0c;各位朋友大家上午好&#xff01;今天我們要一起啃下這篇神經科學與邏輯學交叉領域的奠基之作——McCulloch和Pitts的《A Logical Calculus of the Ideas Immanent in Nervous Activity》。這篇論文篇幅不長&#xff0c;但每一個定理、每一個假設都像精密齒輪&a…

大語言模型提示工程與應用:提示工程-提升模型準確性與減少偏見的方法

語言模型可靠性優化 學習目標 在本課程中&#xff0c;我們將學習通過提示工程提升模型事實準確性、減少偏見的有效方法。 相關知識點 語言模型可靠性優化 學習內容 1 語言模型可靠性優化 1.1 事實準確性增強 LLM可能生成看似合理但實際虛構的內容。優化策略包括&#x…