Output :输出 Input :输入 Set :置位 Reset :复位 / 清零 port:端口 data:数据 register:寄存器 Read:读取
一、库函数
RCC
STM32 的外设默认是关闭时钟的,必须通过该函数手动开启对应外设的时钟,否则外设无法工作。
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
RCC_APB2Periph``uint32_t
要配置的 APB2 外设预定义宏,如RCC_APB2Periph_GPIOA(GPIOA 时钟)、RCC_APB2Periph_USART1(USART1 时钟)、RCC_APB2Periph_SPI1(SPI1 时钟)
NewState``FunctionalState
时钟状态枚举类型,仅两个取值:- ENABLE:使能外设时钟- DISABLE:失能外设时钟
GPIO
GPIO 初始化函数
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
根据初始化结构体的配置,初始化指定 GPIO 端口的指定引脚(模式、速度、上下拉等)
- 第一个参数
GPIOx:指定要初始化的 GPIO 端口(比如 GPIOA、GPIOB、GPIOC 等); - 第二个参数
GPIO_InitStruct:指向 GPIO 配置结构体的指针,包含了具体的初始化参数。
GPIO 读取函数
读取指定 GPIO 端口的单个引脚输入状态
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
读取指定 GPIO 端口所有 16 个引脚的输入状态
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
读取指定 GPIO 端口的单个引脚输出寄存器状态
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
GPIO_ReadOutputData读取指定 GPIO 端口所有引脚的输出寄存器状态
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
GPIO 写入函数
将指定 GPIO 端口的单个 / 多个引脚置高
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
将指定 GPIO 端口的单个 / 多个引脚置低
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
给指定 GPIO 引脚写入自定义值(SET/RESET)
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
GPIO_Write给指定 GPIO 端口所有 16 个引脚写入状态
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
二、LED
1、流水灯
将前面建立的工程模板复制重命名,在新的工程文件夹中建立System文件夹,将STM32入门教程资料\程序源码\STM32Project-有注释版\1-3 Delay函数模块中的延时函数复制到System文件夹中,并在工程中添加分组、文件、文件地址。再在工程文件中建立Hardware文件夹用来装硬件驱动函数。
建立LED.c\.h文件

点击右下角的'...',找到当前工程文件中的Hardware文件夹选中

.h文件的固定形式,1检查__LED_H这个宏是否未被定义 2如果未定义,就定义这个宏,防止头文件被重复包含 4结束条件编译

LED初始化
void LED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
- 时钟使能:外设工作的前提
-
STM32 的所有外设默认都是时钟关闭状态,这是为了降低功耗。
-
必须先开启对应 GPIO 端口的时钟,否则后续的配置都不会生效。
-
这里我们开启的是 APB2 总线上的 GPIOA 时钟,因为 GPIOA 挂载在 APB2 总线上。
- 配置结构体:参数化设计的优势
-
模式选择:
GPIO_Mode_Out_PP代表推挽输出模式,这是驱动 LED 的最佳选择,因为它可以输出强高低电平,带负载能力更强。 -
引脚批量配置:GPIO_Pin_All,配置GPIOA所有16个引脚
-
速度配置:
GPIO_Speed_50MHz表示引脚电平切换的最大速率,对于 LED 这类低速设备,50MHz 是完全够用的,也可以根据实际需求选择 2MHz 或 10MHz。
- 应用配置:写入硬件寄存器
-
这一步会把结构体里的配置参数写入到 GPIOA 的硬件寄存器中,完成硬件层面的初始化。
-
标准库通过封装底层寄存器操作,让我们不用直接操作寄存器,提高了代码的可移植性和可读性。
模式
模拟输入模式:GPIO_Mode_AIN = 0x0,
浮空输入模式 GPIO_Mode_IN_FLOATING = 0x04,
下拉输入模式GPIO_Mode_IPD = 0x28,
上拉输入模式 GPIO_Mode_IPU = 0x48,
开漏输出模式GPIO_Mode_Out_OD = 0x14,
推挽输出模式GPIO_Mode_Out_PP = 0x10,
复用开漏模式GPIO_Mode_AF_OD = 0x1C,
复用推挽模式GPIO_Mode_AF_PP = 0x18
声明
在.h中声明,并在main中调用LED.h

使用GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal)
GPIO_Write(GPIOA, ~0x001);//0000 0000 0000 0001
Delay_ms(500);
GPIO_Write(GPIOA, ~0x002);//0000 0000 0000 0010
Delay_ms(500);
GPIO_Write(GPIOA, ~0x004);//0000 0000 0000 0100
Delay_ms(500);
GPIO_Write(GPIOA, ~0x008);//0000 0000 0000 1000
Delay_ms(500);
GPIO_Write(GPIOA, ~0x010);//0000 0000 0001 0000
Delay_ms(500);
- 第一个参数
GPIOx:指定操作的 GPIO 端口(如 GPIOA、GPIOB); - 第二个参数
PortVal:16 位无符号整数,每一位对应 GPIO 的一个引脚(bit0 对应 Pin0,bit1 对应 Pin1...bit15 对应 Pin15); - 电平规则:
PortVal的某一位为1→ 对应引脚输出高电平;为0→ 对应引脚输出低电平。
因为采用的低电平驱动,所以取反。
2、按键控制LED
使用A1、A2、B1、B11口
LED
封装LED驱动
void LED1_Turn(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
if(GPIO_ReadOutputDataBit(GPIOx, GPIO_Pin) == 0)
{
GPIO_SetBits(GPIOx, GPIO_Pin);
}
else
{
GPIO_ResetBits(GPIOx, GPIO_Pin);
}
}
封装后能大幅提升代码的可读性、可维护性和复用性。
使用GPIO_ReadOutputDataBit读取输出端口的电平,根据当前端口的电平来决定下一输出电平。
如:当前A1口是高电平,下一输出电平就是低电平,这样就可以实现按键控制灯的亮灭
在.h中声明,并且在.h中
#define LED1 GPIO_Pin_1
#define LED2 GPIO_Pin_2
这样可以更明了。
按键
建立Key.c/.h,放在Hardware中。
初始化
采用低电平触发,选择上拉输入。

读取端口电平
uint8_t Key_GetNum(void)
{
uint8_t KeyNum = 0;
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1)== 0)
{
Delay_ms(20);
while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1)== 0);
Delay_ms(20);
KeyNum = 1;
}
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)== 0)
{
Delay_ms(20);
while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)== 0);
Delay_ms(20);
KeyNum = 2;
}
return KeyNum;
}
使用GPIO_ReadInputDataBit函数读取输入端口电平,使用延时函数消抖,判断哪个按键按下然后赋值相应的值,并返回出去。函数在.h中声明。
调用
在main文件中调用相关.h文件,定义一个全局变量uint8_t KeyNum = 0用来装按键的状态,在main中调用按键和LED的启动函数。
int main(void)
{
LED_Init();
Key_Init();
while(1)
{
KeyNum = Key_GetNum();
if(KeyNum == 1)
{
LED1_Turn(GPIOA, LED1);
}
if(KeyNum == 2)
{
LED1_Turn(GPIOA, LED2);
}
}
}
三、蜂鸣器
用光敏传感器控制蜂鸣器,当光照弱时蜂鸣器就响。
蜂鸣器
建立Buzzer.c/.h,放在Hardware中。
初始化

电平翻转
蜂鸣器和LED的代码差不多,直接复制过来改个名字。
void Buzzer_Turn(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
if(GPIO_ReadOutputDataBit(GPIOx, GPIO_Pin) == 0)
{
GPIO_SetBits(GPIOx, GPIO_Pin);
}
else
{
GPIO_ResetBits(GPIOx, GPIO_Pin);
}
}
光敏传感器
建立LightSensor.c/.h,放在Hardware中。
初始化

返回端口的输入电平
uint8_t LightSensor_Get(void)
{
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
}
调用
int main(void)
{
Buzzer_Init();
LightSensor_Init();
while(1)
{
if(LightSensor_Get() == 1)
{
Buzzer_Reset(GPIOB, GPIO_Pin_12);
}
else
{
Buzzer_Set(GPIOB, GPIO_Pin_12);
}
}
}