普中STM32-F103精灵开发版LED灯闪烁教程(含完整代码与解析)
一、开发环境搭建
1. 硬件准备
• 普中STM32-F103精灵开发板(芯片型号:STM32F103C8)
• USB数据线(用于供电和程序下载)
2. 软件准备
• Keil MDK 5(STM32开发集成环境,下载地址)
• STM32F1系列器件支持包(通过Keil内的Pack Installer安装)
二、硬件原理分析
1. LED灯电路
• 控制方式:通过GPIO端口输出高低电平控制,开发板采用低电平点亮逻辑。
• 示例连接:假设LED灯连接到PA8引脚,当PA8输出低电平时,LED导通点亮;输出高电平时熄灭。
2. 按键电路(可选功能)
• 检测逻辑:按键连接到PB12引脚,开发板内部已配置上拉电阻,按键未按下时PB12为高电平,按下时电平拉低。
三、完整程序代码及分段解析
1. 新建工程步骤
1. 打开Keil MDK,点击 Project → New μVision Project,命名工程(如“LED_Flash”)并选择保存路径。
2. 在器件选择窗口中搜索并选择 STM32F103C8,点击 OK。
3. 在弹出的“Manage Run-Time Environment”中,勾选 CMSIS 和 STM32F1xx Device Family 下的 Startup 文件,点击 OK 完成工程创建。
2. 编写代码及解析
main.c
#include "stm32f10x.h" // 芯片寄存器定义
#include "stm32f10x_conf.h" // 库函数头文件配置
解析:
• #include "stm32f10x.h":包含了STM32F10x系列芯片的寄存器定义,是操作硬件寄存器的基础。
• #include "stm32f10x_conf.h":用于配置工程中需要使用的库函数头文件,在本文件中配置了GPIO和RCC相关的头文件,为后续调用相关库函数做准备。
// 宏定义:LED和按键对应引脚
#define LED_PIN GPIO_Pin_8 // LED连接PA8
#define LED_PORT GPIOA // 端口A
#define KEY_PIN GPIO_Pin_12 // 按键连接PB12(可选功能)
#define KEY_PORT GPIOB // 端口B
解析:
使用宏定义将具体的引脚编号和端口名称进行符号化,方便后续代码的修改和维护。如果开发板上LED或按键的连接引脚发生变化,只需要修改此处的宏定义即可,无需在代码中逐个修改引脚参数。
// 延时函数(基于SysTick定时器,72MHz系统时钟)
void delay_ms(uint32_t ms) {
SysTick->LOAD = (ms * 72000) / 8; // 计算重载值
SysTick->VAL = 0x00; // 清空当前值
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // 使能定时器
while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)); // 等待计数完成
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; // 关闭定时器
}
解析:
• 函数功能:实现毫秒级延时。
• 原理:利用STM32内部的SysTick定时器。SysTick定时器是一个24位的倒计数定时器,当计数值为0时,将从LOAD寄存器中自动重装初值。
• 关键代码解释:
◦ SysTick->LOAD = (ms * 72000) / 8;:计算定时器的重载值。STM32F103默认系统时钟为72MHz,经8分频后,SysTick定时器的时钟频率为9MHz(即每1/9μs计数一次)。为了实现ms毫秒的延时,需要计数ms * 9000次,因此将该值赋给LOAD寄存器。
◦ SysTick->VAL = 0x00;:清空当前计数值,确保定时器从0开始计数。
◦ SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;:使能SysTick定时器。
◦ while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));:等待定时器计数完成,当计数值减为0时,会设置COUNTFLAG标志位,通过循环检测该标志位判断延时是否结束。
◦ SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;:关闭SysTick定时器。
int main(void) {
GPIO_InitTypeDef GPIO_InitStruct; // GPIO初始化结构体
// 1. 使能GPIOA和GPIOB时钟(APB2总线)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
解析:
• GPIO_InitTypeDef GPIO_InitStruct;:定义一个GPIO初始化结构体变量,用于配置GPIO引脚的工作模式、速度等参数。
• RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);:
◦ 功能:使能GPIOA和GPIOB的时钟。在STM32中,外设使用前必须先使能其对应的时钟,GPIOA和GPIOB挂载在APB2总线上,因此通过此函数开启时钟。
◦ 参数解释:
◦ RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB:通过按位或操作同时选择GPIOA和GPIOB两个外设。
◦ ENABLE:表示使能选定的外设时钟。
// 2. 配置LED引脚为推挽输出(50MHz速度)
GPIO_InitStruct.GPIO_Pin = LED_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LED_PORT, &GPIO_InitStruct);
解析:
• 配置LED引脚为推挽输出模式:
◦ GPIO_InitStruct.GPIO_Pin = LED_PIN;:选择要配置的引脚为之前定义的LED_PIN(即PA8)。
◦ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;:设置引脚工作模式为推挽输出。推挽输出模式下,引脚可以输出高电平或低电平,适合直接驱动LED等负载。
◦ GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;:设置引脚的最大输出速度为50MHz,以满足快速切换电平的需求。
◦ GPIO_Init(LED_PORT, &GPIO_InitStruct);:将配置好的参数应用到LED_PORT(即GPIOA)上。
// 3. 配置按键引脚为浮空输入(可选功能)
GPIO_InitStruct.GPIO_Pin = KEY_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入模式
GPIO_Init(KEY_PORT, &GPIO_InitStruct);
解析:
• 配置按键引脚为浮空输入模式:
◦ GPIO_InitStruct.GPIO_Pin = KEY_PIN;:选择要配置的引脚为之前定义的KEY_PIN(即PB12)。
◦ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;:设置引脚工作模式为浮空输入。浮空输入模式下,引脚电平状态完全由外部电路决定,由于开发板内部已为按键引脚配置上拉电阻,按键未按下时引脚为高电平,按下时拉低为低电平。
◦ GPIO_Init(KEY_PORT, &GPIO_InitStruct);:将配置好的参数应用到KEY_PORT(即GPIOB)上。
while (1) {
// 基础功能:LED闪烁(无需按键,独立运行)
GPIO_ResetBits(LED_PORT, LED_PIN); // 低电平点亮LED
delay_ms(500); // 延时500ms
GPIO_SetBits(LED_PORT, LED_PIN); // 高电平熄灭LED
delay_ms(500); // 延时500ms
// 扩展功能:按键控制(单次按下常亮,双击快速闪烁)
// (如需使用,取消下方注释并连接按键电路)
/*
if (GPIO_ReadInputDataBit(KEY_PORT, KEY_PIN) == Bit_RESET) {
delay_ms(10); // 消抖
if (GPIO_ReadInputDataBit(KEY_PORT, KEY_PIN) == Bit_RESET) {
// 单次按下逻辑
GPIO_ResetBits(LED_PORT, LED_PIN); // 常亮
while (GPIO_ReadInputDataBit(KEY_PORT, KEY_PIN) == Bit_RESET);
}
}
*/
}
}
解析:
• 基础功能:LED闪烁:
◦ GPIO_ResetBits(LED_PORT, LED_PIN);:将LED_PIN(PA8)引脚电平置为低电平,点亮LED。
◦ delay_ms(500);:调用延时函数,使LED保持点亮状态500毫秒。
◦ GPIO_SetBits(LED_PORT, LED_PIN);:将LED_PIN(PA8)引脚电平置为高电平,熄灭LED。
◦ delay_ms(500);:再次调用延时函数,使LED保持熄灭状态500毫秒。通过不断循环实现LED的周期性闪烁。
• 扩展功能:按键控制(注释状态,需手动启用):
◦ if (GPIO_ReadInputDataBit(KEY_PORT, KEY_PIN) == Bit_RESET):检测按键是否按下,通过读取KEY_PIN(PB12)引脚电平是否为低电平判断。
◦ delay_ms(10);:软件消抖,防止按键机械抖动导致误判。
◦ 内层if语句:二次确认按键按下,确保检测的有效性。
◦ GPIO_ResetBits(LED_PORT, LED_PIN);:按键按下时,将LED置为常亮状态。
◦ while (GPIO_ReadInputDataBit(KEY_PORT, KEY_PIN) == Bit_RESET);:等待按键释放,阻塞程序直至按键松开。
四、程序编译与下载
1. 编译工程
点击Keil界面上方 Rebuild All,编译成功后生成 .hex 文件(若报错,检查引脚配置或语法错误)。
2. 下载程序
• ST-Link下载(开发板支持ST-Link接口):
1. 用USB线连接开发板与电脑。
2. 打开 ST-Link Utility,点击 Connect 连接开发板。
3. 点击 Open File 选择编译生成的**.hex**文件,点击 Program 下载。
五、功能测试
1. 基础功能(无按键版)
• 下载程序后,开发板上电,LED灯会以500ms间隔闪烁(亮灭交替)。
2. 扩展功能(按键控制版,需连接按键)
• 单次按下:按键按下时LED常亮,松手后恢复闪烁。
• 双击操作:快速连续按下两次,LED以200ms间隔快速闪烁,再次按下任意键恢复默认节奏。
六、常见问题排查
1. LED不亮:
◦ 检查USB供电是否正常(开发板电源指示灯是否亮起)。
◦ 确认代码中LED引脚与开发板实际连接一致(如是否为PA8或其他引脚)。
2. 程序无法下载:
◦ 确保开发板处于待机模式(部分开发板需按下复位键再下载)。
◦ 检查下载工具是否匹配(如使用DAP-Link需更换对应驱动)。
通过本教程,可快速掌握STM32基础开发流程,后续可尝试修改延时参数或添加更多外设(如蜂鸣器、OLED屏幕)扩展功能。