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()
: 初始化ADCHAL_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()
: 初始化UARTHAL_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()
: 初始化I2CHAL_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()
: 初始化SPIHAL_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库编程中常用外设的配置和使用方法,包括:
- GPIO:输入输出控制,LED和按钮操作
- ADC:模拟信号采集和转换
- UART:串口通信,中断接收和printf重定向
- TIM:基本定时器和PWM输出
- I2C:I2C通信,OLED显示屏控制
- SPI:SPI通信,Flash存储操作
通过这些基础外设的学习,可以进一步开发更复杂的STM32应用程序。在实际开发中,可以根据需要组合使用这些外设,实现各种功能。
Gitee 仓库地址
10. 参考资料
- STM32F1xx HAL库用户手册
- STM32F103数据手册
- STM32CubeMX用户指南