STM32单片机:推挽输出和开漏输出,按键控制LED灯亮灭
key.h文件key.c文件main.c文件。
目录
代码分享
key.h文件
#ifndef _KEY_H
#define _KEY_H
#include "stm32f10x.h"
void Key_Init(void);
uint8_t Key_GetNum(void);
#endif
key.c文件
#include "stm32f10x.h"
#include"Delay.h"
#include"key.h"
void Key_Init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIO_InitStrucure;
GPIO_InitStrucure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStrucure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_4|GPIO_Pin_5;
GPIO_Init(GPIOB,&GPIO_InitStrucure);
}
uint8_t Key_GetNum(void)
{
uint8_t KeyNum=0;
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==0)
{
Delay_ms(20);
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==0);
Delay_ms(20);
KeyNum=1;
}
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0)
{
Delay_ms(20);
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0);
Delay_ms(20);
KeyNum=2;
}
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4)==0)
{
Delay_ms(20);
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4)==0);
Delay_ms(20);
KeyNum=3;
}
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)==0)
{
Delay_ms(20);
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)==0);
Delay_ms(20);
KeyNum=4;
}
return KeyNum;
}
main.c文件
#include "stm32f10x.h"
#include "Delay.h"
#include "key.h"
uint8_t KeyNum;
int main(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 使能GPIOA和AFIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
// 重映射PA15为普通IO口
GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);
// 初始化LED引脚(GPIOA_Pin_8)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; // PA8
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 50MHz速度
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 初始状态:LED熄灭(假设低电平点亮,高电平熄灭)
GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_SET);
// 初始化按键
Key_Init();
while (1)
{
// 获取按键值
KeyNum = Key_GetNum();
// 当按键1被按下时
if (KeyNum == 1)
{
// 切换LED状态
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_8) == Bit_SET)
{
// 当前是高电平(熄灭),切换为低电平(点亮)
GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_RESET);
}
else
{
// 当前是低电平(点亮),切换为高电平(熄灭)
GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_SET);
}
}
}
}
代码说明
1.LED初始化:
将GPIOA的Pin8配置为推挽输出模式
初始状态设置为高电平(假设LED是低电平点亮,所以初始状态为熄灭)
2.按键检测:
调用Key_Init()初始化按键引脚(GPIOB的Pin0、Pin1、Pin4、Pin5)
在While(1)循环中持续检测按键状态
3.LED状态切换:
当检测到按键1(GPIOB_Pin_0)被按下时:
读取当前LED引脚的状态
如果是高电平(熄灭),切换为低电平(点亮)
如果是低电平(点亮),切换为高电平(熄灭)
4.消抖处理:
按键消抖已在key.c文件中通过DeLay_ms(20)实现,确保按键操作稳定
硬件连接说明
LED :连接到GPIOA的Pin8引脚,建议串联一个220Ω电阻到GND
按键 :连接到GPIOB的Pin0引脚,一端接GPIOB_Pin0,另一端接GND
扩展功能(可选)
如果需要使用其他按键(如GPIOB_Pin_1、Pin_4、Pin_5)控制不同功能,可以在 key.c 中完善 Key_GetNum() 函数,返回不同的按键值,然后在 main.c 中添加对应的处理逻辑。例如:
// 在key.c中完善Key_GetNum()函数
uint8_t Key_GetNum(void)
{
uint8_t KeyNum = 0;
// 检测按键1(Pin0)
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
{
Delay_ms(20);
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0);
Delay_ms(20);
KeyNum = 1;
}
// 检测按键2(Pin1)
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
{
Delay_ms(20);
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);
Delay_ms(20);
KeyNum = 2;
}
// 检测按键3(Pin4)
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4) == 0)
{
Delay_ms(20);
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4) == 0);
Delay_ms(20);
KeyNum = 3;
}
// 检测按键4(Pin5)
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5) == 0)
{
Delay_ms(20);
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5) == 0);
Delay_ms(20);
KeyNum = 4;
}
return KeyNum;
}
然后在 main.c 中添加对应的处理:
while (1)
{
KeyNum = Key_GetNum();
switch (KeyNum)
{
case 1:
// 切换LED状态
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_8) == Bit_SET)
{
GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_RESET);
}
else
{
GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_SET);
}
break;
case 2:
// 其他功能...
break;
// 其他按键处理...
}
}
推挽输出与开漏输出
工作原理对比
1.推挽输出(GPIO Mode_Out PP)
高电平输出: P-MOS管导通,N-MOS管截止,直接输出VDD(如3.3V)
低电平输出: N-MOS管导通,P-MOS管截止,直接输出GND(0V)
驱动能力: 高低电平都有较强的驱动能力(可直接驱动LED、继电器等负载)
外部电路: 无需外部上拉电阻
2.开漏输出(GPIo_Mode_Out_OD)
高电平输出: MOS管截止,引脚处于高阻态(需要外部上拉电阻才能输出高电平)
低电平输出: MOS管导通,输出GND(0V)
驱动能力: 仅低电平有驱动能力,高电平驱动能力取决于外部上拉电阻外部电路: 必须外接上拉电阻(否则高电平状态不确定)
LED控制场景分析
1.推挽输出的适用性
对于LED控制,推挽输出通常是首选,原因如下:
无需外部元件: 直接驱动LED,电路简洁
电平稳定: 高低电平由GPIO直接输出,电压稳定
驱动能力强: 可驱动多个LED或亮度更高的LED
响应速度快: 无外部上拉电阻的延迟
2.开漏输出的适用性
开漏输出在LED控制中可以使用,但有条件:
必须加外部上拉电阻:否则高电平无法正常输出,LED可能闪烁或不亮
适合电平匹配:如果LED使用的电源与MCU不同(如5V LED),可通过上拉电阻连接到5V,实现电平转换
高低电平影响的考虑
在LED控制中,高低电平的影响主要体现在:
1.LED连接方式
共阴接法(LED负极接地):需要GPIO输出低电平点亮,高电平熄灭
推挽输出:低电平直接GND,驱动可靠
开漏输出:低电平直接GND,但高电平需上拉电阻
共阳接法(LED正极接VDD):需要GPIO输出高电平点亮,低电平熄灭
推挽输出:高电平直接VDD,驱动可靠
开漏输出:高电平必须依赖上拉电阻,否则无法点亮
2.驱动能力
推挽输出:
高电平驱动能力:约20mA(具体取决于MCU型号)
低电平驱动能力:约20mA
开漏输出:
高电平驱动能力:由上拉电阻和电源决定(I=(Vcc-Vout/R上拉)
低电平驱动能力:与推挽输出相近(约20mA)
代码示例对比
推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
开漏输出(需外部上拉电阻)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; // 开漏输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 外部需接:GPIOA8 -> 上拉电阻(1kΩ) -> VDD
更多推荐

所有评论(0)