stm32单片机应用与全案例实践程序
stm32单片机应用与全案例实践程序
好的,这里提供一些STM32单片机应用开发的核心概念、常用外设案例以及实践程序框架(使用HAL库和STM32CubeMX),全部用中文说明。
核心思想:
- 硬件抽象层 (HAL): ST官方提供的库,简化了底层寄存器操作,提供统一的API访问外设。开发首选。
- STM32CubeMX: 图形化配置工具,用于初始化时钟、引脚、外设、中间件(如FreeRTOS, FATFS),并生成初始化代码框架。强烈推荐使用!
- 开发环境: Keil MDK-ARM (uVision), IAR Embedded Workbench, STM32CubeIDE (免费,ST官方基于Eclipse) 是主流选择。
- 调试: ST-Link/V2 是最常用的调试器和编程器。
常用外设基础案例与实践程序框架 (基于STM32F1系列/HAL库/STM32CubeMX生成):
案例 1:点亮LED (GPIO输出)**
- 功能: 控制一个LED灯周期性闪烁。
- 硬件: STM32F103C8T6 (Blue Pill板常见), LED串联限流电阻接在某个GPIO引脚(如PC13)和GND之间。
- STM32CubeMX配置:
- 选择芯片型号。
- 系统核心 (SYS): 调试接口选
Serial Wire(SWD)。 - 时钟配置 (RCC): HSE (外部高速时钟) 选
Crystal/Ceramic Resonator(如果板子有外部晶振)。 - GPIO: 选择PC13引脚,模式设为
GPIO_Output。 - 时钟树: 配置系统时钟为HSE,倍频到72MHz (F1系列常见)。
- 生成代码: 选择IDE (如Keil),设置项目名和路径。
- 代码 (在
main.c的while(1)循环中添加):
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); // 翻转PC13引脚电平
HAL_Delay(500); // 延时500ms
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
- 关键点:
HAL_GPIO_TogglePin(),HAL_Delay()。
**
案例 2:按键检测 (GPIO输入)**
- 功能: 检测一个按键是否按下,按下时点亮LED,松开时熄灭。
- 硬件: 在案例基础上,增加一个按键(接在某个GPIO引脚,如PA0,和GND之间),通常需要上拉电阻(STM32内部可配置上拉)。
- STM32CubeMX配置:
- 在GPIO设置中,配置PA0引脚:
- 模式:
GPIO_Input - 下拉/上拉: 选择
Pull-up(如果按键按下时接地) 或Pull-down(如果按键按下时接VCC)。通常选Pull-up。
- 模式:
- 在GPIO设置中,配置PA0引脚:
- 代码 (在
main.c的while(1)循环中添加):
/* USER CODE BEGIN WHILE */
while (1)
{
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) // 检测PA0是否为低电平 (按键按下)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); // 点亮LED (假设LED高电平点亮)
}
else
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); // 熄灭LED
}
HAL_Delay(10); // 简单消抖,实际应用可能需要更复杂的消抖逻辑
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
- 关键点:
HAL_GPIO_ReadPin(),HAL_GPIO_WritePin(), 按键消抖。
**
案例 3:串口通信 (UART) - 发送和接收**
-
功能: 通过串口发送数据到PC(通过USB转TTL模块),并接收PC发来的数据,回显(Echo)回去。
-
硬件: 连接USB转TTL模块的TX到STM32的RX (如PA10), RX到STM32的TX (如PA9), GND接GND。
-
STM32CubeMX配置:
- 在
Connectivity中选择USART1(或其他可用UART)。 - 模式:
Asynchronous(异步模式)。 - 参数: 波特率 (如115200), 字长 (8位), 停止位 (1位), 无校验。
- 使能中断: 在
NVIC Settings标签页勾选USART1 global interrupt(用于接收中断)。 - GPIO: 自动配置PA9为
USART1_TX, PA10为USART1_RX。
- 在
-
代码:
-
发送数据 (在需要的地方调用,例如按键按下时):
char message[] = "Hello, STM32 UART!\r\n"; // \r\n 是换行符 HAL_UART_Transmit(&huart1, (uint8_t*)message, strlen(message), HAL_MAX_DELAY); -
接收数据 (使用中断方式):
-
在
main.c中声明接收缓冲区和接收完成标志:/* USER CODE BEGIN PV */ uint8_t rx_buffer[1]; // 单字节接收缓冲区 volatile uint8_t uart_rx_done = 0; // 接收完成标志 /* USER CODE END PV */ -
在
main()函数初始化部分启动接收中断:/* USER CODE BEGIN 2 */ HAL_UART_Receive_IT(&huart1, rx_buffer, 1); // 启动接收中断,每次接收1字节 /* USER CODE END 2 */ -
在
stm32f1xx_it.c中找到USART1_IRQHandler函数,添加处理代码:void USART1_IRQHandler(void) { /* USER CODE BEGIN USART1_IRQn 0 */ if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) != RESET) // 检查接收寄存器非空标志 { HAL_UART_IRQHandler(&huart1); // 调用HAL库中断处理函数,它会调用回调函数 } /* USER CODE END USART1_IRQn 0 */ ... } -
在
main.c中重写接收完成回调函数HAL_UART_RxCpltCallback:/* USER CODE BEGIN 4 */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart->Instance == USART1) // 判断是哪个串口 { uart_rx_done = 1; // 设置接收完成 } } /* USER CODE END 4 */ -
在
main.c的while(1)循环中处理接收到的数据并回显:/* USER CODE BEGIN WHILE */ while (1) { if (uart_rx_done) // 如果收到一个字节 { uart_rx_done = 0; // 清除标志 HAL_UART_Transmit(&huart1, rx_buffer, 1, HAL_MAX_DELAY); // 回显接收到的字节 HAL_UART_Receive_IT(&huart1, rx_buffer, 1); // 重新启动接收中断 } /* USER CODE END WHILE */ ... }
-
-
-
关键点:
HAL_UART_Transmit(),HAL_UART_Receive_IT(),HAL_UART_RxCpltCallback(), 串口配置 (波特率等), 中断处理流程。
**
案例 4:定时器中断 (TIM) - 精确计时**
-
功能: 使用定时器产生精确的1ms中断,在中断服务程序里累加一个计数器,在主循环中根据计数器值控制LED以更精确的周期闪烁(例如1Hz)。
-
硬件: 同案例1。
-
STM32CubeMX配置:
- 在
Timers中选择一个定时器 (如TIM2)。 - 时钟源:
Internal Clock(内部时钟)。 - 参数配置:
- Prescaler (预分频器): 计算值。假设系统时钟72MHz,目标计数频率1MHz (1us计数一次),则 PSC = 72MHz / 1MHz - 1 = 71**。
- Counter Mode:
Up(向上计数)。 - Counter Period (自动重装载值 ARR): 1000 - 1 (计数1000次,即1000us = 1ms)。
- 使能中断: 在
NVIC Settings标签页勾选TIM2 global interrupt。
- 在
-
代码:
-
在
main.c中声明全局计数器:/* USER CODE BEGIN PV */ volatile uint32_t timer_ms_count = 0; // 1ms计数器 /* USER CODE END PV */ -
在
main()函数初始化部分启动定时器:/* USER CODE BEGIN 2 */ HAL_TIM_Base_Start_IT(&htim2); // 启动定时器并开启中断 /* USER CODE END 2 */ -
在
stm32f1xx_it.c中找到TIM2_IRQHandler函数,添加处理代码:void TIM2_IRQHandler(void) { /* USER CODE BEGIN TIM2_IRQn 0 */ if (__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_UPDATE) != RESET) // 检查更新中断标志 { __HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_UPDATE); // 清除中断标志 timer_ms_count++; // 1ms计数器加1 } /* USER CODE END TIM2_IRQn 0 */ HAL_TIM_IRQHandler(&htim2); /* USER CODE BEGIN TIM2_IRQn 1 */ /* USER CODE END TIM2_IRQn 1 */ } -
在
main.c的while(1)循环中使用计数器控制LED:/* USER CODE BEGIN WHILE */ while (1) { static uint32_t last_tick = 0; if (timer_ms_count - last_tick >= 500) // 每500ms { last_tick = timer_ms_count; HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); // 翻转LED } /* USER CODE END WHILE */ ... }
-
-
关键点: 定时器配置 (PSC, ARR),
HAL_TIM_Base_Start_IT(),TIMx_IRQHandler(), 清除中断标志, 使用volatile变量在中断和主程序间通信。
**
案例 5:PWM输出 (TIM) - 控制LED亮度/舵机**
-
功能: 使用定时器的PWM模式控制LED亮度(呼吸灯效果)或舵机角度。
-
硬件: LED接带限流电阻的PWM引脚 (如PA8 - TIM1_CH1)。舵机信号线接PWM引脚,电源和地接好。
-
STM32CubeMX配置 (以TIM1_CH1为例):
- 在
Timers中选择TIM1。 - 时钟源:
Internal Clock。 - 通道配置: 选择
Channel 1,模式设为PWM Generation CH1。 - 参数配置:
- Prescaler (PSC): 计算值。假设系统时钟72MHz,目标PWM频率1KHz (周期1ms),则计数频率 = 72MHz / (PSC + 1)。设PSC = 71,则计数频率为1MHz。
- Counter Mode:
Up。 - Counter Period (ARR): 1000 - 1 (对应1KHz频率)。
- Pulse (初始占空比): 设为0 (初始低电平)。
- GPIO: 自动配置PA8为
TIM1_CH1。
- 在
-
代码 (实现呼吸灯):
-
在
main.c的while(1)循环中启动PWM并改变占空比:/* USER CODE BEGIN 2 */ HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); // 启动PWM输出 /* USER CODE END 2 */ /* USER CODE BEGIN WHILE */ uint16_t pulse = 0; int8_t dir = 1; // 方向,1增加,-1减少 while (1) { pulse += dir * 10; // 每次改变10个计数值 if (pulse >= 1000) // 达到最大值 { pulse = 1000; dir = -1; } else if (pulse <= 0) // 达到最小值 { pulse = 0; dir = 1; } __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, pulse); // 设置新的比较值(占空比) HAL_Delay(10); // 延时控制呼吸速度 /* USER CODE END WHILE */ ... }
-
-
关键点: PWM模式配置 (通道, 模式),
HAL_TIM_PWM_Start(),__HAL_TIM_SET_COMPARE(), 占空比计算 (Pulse / (ARR + 1))。
**
案例 6:模数转换 (ADC) - 读取电位器电压**
-
功能: 使用ADC读取连接在某个模拟输入引脚(如PA0)上的电位器电压值,并通过串口发送到PC显示。
-
硬件: 电位器两端接VCC和GND,中间抽头接PA0 (ADC通道0)。
-
STM32CubeMX配置:
- 在
Analog中选择ADC1。 - 参数配置:
- 模式:
Independent mode。 - 扫描转换模式:
Disabled(单通道)。 - 连续转换模式:
Enabled(连续采样)。 - 数据对齐:
Right alignment(右对齐)。 - 外部触发:
Regular Conversion launched by software。
- 模式:
- 通道配置: 在
Rank 1选择Channel 0(对应PA0),采样时间设置一个合适的值 (如55.5 Cycles,根据信号源阻抗和精度要求调整)。 - GPIO: 自动配置PA0为
ADC1_IN0。
- 在
-
代码:
-
在
main.c中声明变量:/* USER CODE BEGIN PV */ uint32_t adc_value = 0; float voltage = 0.0f; /* USER CODE END PV */ -
在
main()函数初始化部分启动ADC:/* USER CODE BEGIN 2 */ HAL_ADC_Start(&hadc1); // 启动ADC连续转换 /* USER CODE END 2 */ -
在
main.c的while(1)循环中读取ADC值并计算电压:/* USER CODE BEGIN WHILE */ while (1) { if (HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY) == HAL_OK) // 等待转换完成 { adc_value = HAL_ADC_GetValue(&hadc1); // 获取ADC原始值 (0-4095 for 12-bit ADC) voltage = (float)adc_value * 3.3f / 4095.0f; // 计算电压值 (假设参考电压VREF+ = 3.3V) // 通过串口发送电压值 (参考案例3的发送代码) printf("ADC Value: %lu, Voltage: %.2f V\r\n", adc_value, voltage); // 需要重定向printf } HAL_Delay(200); // 延时200ms /* USER CODE END WHILE */ ... }
-
-
关键点: ADC配置 (模式, 采样时间),
HAL_ADC_Start(),HAL_ADC_PollForConversion(),HAL_ADC_GetValue(), ADC值到电压的转换,printf重定向 (需要额外实现int __io_putchar(int ch)函数)。
实践建议与进阶方向:
- 善用STM32CubeMX: 这是初始化配置的利器,能节省大量时间并减少低级错误。务必掌握。
- 理解HAL库函数: 查阅ST提供的HAL库文档 (
stm32f1xx_hal_xxx.h/.c) 了解每个外设可用的函数和参数。 - 调试技巧:
- 使用
printf通过串口输出调试信息 (需要重定向)。 - 熟练使用IDE的调试器设置断点、单步执行、查看变量和寄存器。
- 使用逻辑分析仪观察GPIO、PWM、UART等波形。
- 使用
- 模块化编程: 将不同功能(LED、按键、UART、ADC等)封装成独立的
.c/.h文件,提高代码可读性和复用性。 - 中断管理:
- 理解中断优先级 (
NVIC)。 - 中断服务程序 (ISR) 要尽量短小,避免复杂操作和长时间阻塞。通常只设置标志位,在主循环中处理。
- 注意共享变量的
volatile修饰和临界区保护 (简单应用可暂时用__disable_irq()/__enable_irq(),复杂应用需用信号量等)。
- 理解中断优先级 (
- 进阶学习:
- 实时操作系统 (RTOS): FreeRTOS (STM32CubeMX支持集成),用于管理多任务、资源同步。
- 直接存储器访问 (DMA): 实现外设(如ADC, UART, SPI)与内存间的高效数据传输,不占用CPU。
- 高级外设: SPI (连接屏幕、FLASH、SD卡), I2C (连接传感器、EEPROM), CAN (工业通信), USB (设备/主机), 以太网等。
- 文件系统: FATFS (STM32CubeMX支持),用于SD卡读写。
- 图形界面: LVGL, emWin, TouchGFX (ST提供) 用于TFT LCD显示。
- 低功耗模式: 电池供电应用的关键。
重要提示:
- 具体引脚和可用外设: 以上案例基于常见的STM32F103C8T6 (Blue Pill) 开发板。不同型号的STM32芯片,其可用外设、引脚功能、时钟树结构可能不同,请务必查阅你所使用芯片的数据手册 (Datasheet) 和参考手册 (Reference Manual)。
- 时钟配置: 系统时钟的配置是基础且关键的步骤,务必在CubeMX中正确配置时钟源(HSE/HSI/PLL)和分频系数,使系统运行在期望的频率。
- 库版本: HAL库和CubeMX版本会更新,函数名或配置选项可能有细微差别,以你使用的版本文档为准。
- 硬件连接: 务必仔细检查电路连接,特别是电源、地、复位和调试接口(SWDIO, SWCLK)。
这些案例覆盖了STM32开发中最基础也最常用的外设操作。通过动手实践这些案例,结合查阅官方文档和资料,你就能逐步掌握STM32单片机的应用开发。祝你学习顺利!
使用STM32单片机和51单片机实现HC04超声波测距模块的程序免费下载
本文档的主要内容详细介绍的是使用STM32单片机和51单片机实现HC04超声波模块测距的
资料下载
佚名
2019-08-21 17:31:00
换一换
- 如何分清usb-c和type-c的区别
- 中国芯片现状怎样?芯片发展分析
- vga接口接线图及vga接口定义
- 芯片的工作原理是什么?
- 华为harmonyos是什么意思,看懂鸿蒙OS系统!
- 什么是蓝牙?它的主要作用是什么?
- ssd是什么意思
- 汽车电子包含哪些领域?
- TWS蓝牙耳机是什么意思?你真的了解吗
- 什么是单片机?有什么用?
- 升压电路图汇总解析
- plc的工作原理是什么?
- 再次免费公开一肖一吗
- 充电桩一般是如何收费的?有哪些收费标准?
- ADC是什么?高精度ADC是什么意思?
- dtmb信号覆盖城市查询
- EDA是什么?有什么作用?
- 苹果手机哪几个支持无线充电的?
- type-c四根线接法图解
- 华为芯片为什么受制于美国?
- 怎样挑选路由器?
- 元宇宙概念股龙头一览
- 锂电池和铅酸电池哪个好?
- 什么是场效应管?它的作用是什么?
- 如何进行编码器的正确接线?接线方法介绍
- 虚短与虚断的概念介绍及区别
- 晶振的作用是什么?
- 大疆无人机的价格贵吗?大约在什么价位?
- 苹果nfc功能怎么复制门禁卡
- amoled屏幕和oled区别
- 单片机和嵌入式的区别是什么
- 复位电路的原理及作用
- BLDC电机技术分析
- dsp是什么意思?有什么作用?
- 苹果无线充电器怎么使用?
- iphone13promax电池容量是多少毫安
- 芯片的组成材料有什么
- 特斯拉充电桩充电是如何收费的?收费标准是什么?
- 直流电机驱动电路及原理图
- 传感器常见类型有哪些?
- 自举电路图
- 通讯隔离作用
- 苹果笔记本macbookpro18款与19款区别
- 新斯的指纹芯片供哪些客户
- 伺服电机是如何进行工作的?它的原理是什么?
- 无人机价钱多少?为什么说无人机烧钱?
- 以太网VPN技术概述
- 手机nfc功能打开好还是关闭好
- 十大公认音质好的无线蓝牙耳机
- 元宇宙概念龙头股一览