//需要C语言基础
开始
在之前的两篇文章中,讲了如何创建工程,如何控制GPIO输出,都是手把手一步一步的来,在io篇已经学了输出,接下来就是输入,这篇文章记录我学习的最简单的io输入按钮控制。这一篇我尽量写的简单点。
[STM32从0开始]GPIO基本输入输出初步认识,从0开始点亮LED灯,简单详细[STM32从0开始]STM32F10x系列工程创建与最小系统板板载LED PC13使用,详细又简单
创建工程
如果你是新手,请从工程创建这一片博文开始看[STM32从0开始]STM32F10x系列工程创建 ,在这里,我们直接复制之前创建并备份的原工程。
GPIO基本知识
STM32GPIO输入基本原理是通过读取引脚的电平状态来确定输入信号的高低电平。
STM32微控制器的GPIO引脚可以配置为输入模式。在输入模式下,引脚可以读取外部信号的电平状态。当外部信号的电平高于或等于引脚的输入电平阈值时,引脚被认为是高电平状态;当外部信号的电平低于引脚的输入电平阈值时,引脚被认为是低电平状态。
在进行GPIO输入时,首先需要将引脚配置为输入模式。可以通过设置相应的寄存器来实现。然后,可以读取引脚的电平状态,通常是通过读取GPIO输入数据寄存器来实现。读取该寄存器后,可以通过判断寄存器的特定位来确定引脚的状态是高电平还是低电平。
上拉输入(Pull-up Input)是指在电路中,输入引脚通过上拉电阻连接到电源电压(通常为Vcc)。当外部信号没有被连接到输入引脚时,上拉电阻将使输入引脚维持在高电平(通常为Vcc)。当外部信号被连接到输入引脚时,外部信号的电平将被读取。上拉输入通常用于输入信号的默认状态为高电平的情况。
下拉输入(Pull-down Input)则是指输入引脚通过下拉电阻连接到地(GND)。当外部信号没有被连接到输入引脚时,下拉电阻将使输入引脚维持在低电平(通常为GND)。当外部信号被连接到输入引脚时,外部信号的电平将被读取。下拉输入通常用于输入信号的默认状态为低电平的情况。
(这是AI写的)
简单来说,如果你按下后接通的是高电平,就用下拉模式,否则用上拉模式,我使用下拉模式,接线是这样的。
工程代码
新建两个文件,分别命名为key.c与key.h,将其保存并导入到User目录下,同时在User目录中导入上一篇文章写的led.c文件。
在key.c中,将之前led.c的代码复制过来稍微进行修改,选用GPIOA组5引脚做按钮输入口,初始化为下拉模式,不需要进行置位与速率选择操作。
void KEY_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //开启GPIOA分组的时钟阀门
GPIO_InitTypeDef GPIO_InitType; //GPIO配置结构体声明
GPIO_InitType.GPIO_Mode = GPIO_Mode_IPD;//下拉输入
GPIO_InitType.GPIO_Pin = GPIO_Pin_5; //PA5
GPIO_Init(GPIOA,&GPIO_InitType);//初始化
}
在key.h中声明需要用到函数与常量,使用GPIO_ReadInputDataBit获取输入端口状态,
#define KEY_IN GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5)
#define KEY_DOWN 1
#define KEY_UP 0
作为新手,你在我这里学到的将是最最简单的写法,下一步既是按键的判断,按键单击切换led灯的状态,在main.c中引用key.h,然后在while中写如下代码,为了方便大家,我这里直接使用板载led灯。获取输入端口的当前状态,当状态发生改变时执行相应操作,while等待状态改变,这里可以理解为消抖+等待按键松开,
单击
if(KEY_IN)
{
while(KEY_IN);//这一步是消抖最简单有效的写法
if(GPIO_ReadOutputDataBit(GPIOC,GPIO_Pin_13))
{
GPIO_ResetBits(GPIOC,GPIO_Pin_13);
}
else
{
GPIO_SetBits(GPIOC,GPIO_Pin_13);
}
}
长按
在while循环中执行你想要的操作,按键松开时自动退出while循环,这里写的是长按亮灯,否则熄灭。
if(KEY_IN)
{
while(KEY_IN)//这一步是消抖最简单有效的写法
{
GPIO_ResetBits(GPIOC,GPIO_Pin_13);
}
GPIO_SetBits(GPIOC,GPIO_Pin_13);
}
连击
按键连击有一种通用写法,你学会后不管是双击还是3连击4连击都可以轻松掌握
定义三个变量,分别连击间隔时间,按键次数,最终按键次数,连击间隔时间是用来判断两次按键的间隔,如果大于0.3s将被判断为两次,否则算一次内的N连击。
delay(1);//用来减缓时间速度
//连击
if(KEY_IN==KEY_DOWN)
{
while(KEY_IN==KEY_DOWN);
if(KEY_IN==KEY_UP)
{
key_tim=1;//复位按键时间
key_cnt++;//记录按键次数
}
}
if(key_tim)
{
if(++key_tim>=300)//约300ms
{
key_over = key_cnt;//获取最终按键次数
key_cnt=key_tim=0;//停止计时,复位按键次数,下一次按键又是新的一轮
}
}
//执行按键效果
if(key_over!=0)
{
//单击
if(key_over==1)
{
GPIO_ResetBits(GPIOC,GPIO_Pin_13);
}
//双击
if(key_over==2)
{
GPIO_SetBits(GPIOC,GPIO_Pin_13);
}
//N连击
// if(key_over==N)
// {
// ...
// }
key_over=0;
}
完整代码
main.c
#include "stm32f10x.h"
#include "led.h"
#include "key.h"
void delay(int a)
{
int b;
while(a--)
{
b=478;
while(b--);
}
}
int key_tim=0,key_cnt=0,key_over=0;
int main()
{
RCC_DeInit();
KEY_Init();
LED_Init();
while(1)
{
delay(1);//用来减缓时间速度
//连击
if(KEY_IN==KEY_DOWN)
{
while(KEY_IN==KEY_DOWN);
if(KEY_IN==KEY_UP)
{
key_tim=1;//复位按键时间
key_cnt++;//记录按键次数
}
}
if(key_tim)
{
if(++key_tim>=300)//约300ms
{
key_over = key_cnt;//获取最终按键次数
key_cnt=key_tim=0;//停止计时,复位按键次数,下一次按键又是新的一轮
}
}
//执行按键效果
if(key_over!=0)
{
//单击
if(key_over==1)
{
GPIO_ResetBits(GPIOC,GPIO_Pin_13);
}
//双击
if(key_over==2)
{
GPIO_SetBits(GPIOC,GPIO_Pin_13);
}
//N连击
// if(key_over==N)
// {
// ...
// }
key_over=0;
}
}
}
key.c与key.h
#include "stm32f10x.h"
#include "key.h"
void KEY_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //开启GPIOA分组的时钟阀门
GPIO_InitTypeDef GPIO_InitType; //GPIO配置结构体声明
GPIO_InitType.GPIO_Mode = GPIO_Mode_IPD;//下拉输入
GPIO_InitType.GPIO_Pin = GPIO_Pin_5; //PA5
GPIO_Init(GPIOA,&GPIO_InitType);//初始化
}
-------------------------------------
#ifndef __KEY_H
#define __KEY_H
#define KEY_IN GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5)
#define KEY_DOWN 1
#define KEY_UP 0
#endif
void KEY_Init(void);
led.c与led.h
#include "stm32f10x.h"
#include "led.h"
void LED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB| \
RCC_APB2Periph_GPIOC,ENABLE); //开启GPIO分组的时钟阀门
GPIO_InitTypeDef GPIO_InitType; //GPIO配置结构体声明
GPIO_InitType.GPIO_Mode = GPIO_Mode_Out_PP;//设置为输出模式
GPIO_InitType.GPIO_Pin = GPIO_Pin_All;//所有引脚
GPIO_InitType.GPIO_Speed = GPIO_Speed_50MHz;//最高速度
//初始化组A、B、C所有引脚为输出模式
GPIO_Init(GPIOB,&GPIO_InitType);
GPIO_Init(GPIOC,&GPIO_InitType);
//默认关闭LED灯
GPIO_SetBits(GPIOB,GPIO_Pin_All);
GPIO_SetBits(GPIOC,GPIO_Pin_All);
}
--------------------------------------------------------------------
#ifndef __LED_H
#define __LED_H
#endif
void LED_Init(void);
最后
最后,按键的io输出输入算是写完了,在按键这边我是踩了坑的,你们按照我的步骤走不会错,避免有的跟我一样的新手不懂得如何接线,我把接线图画出来再配上实际照片,可以说是保姆级教程了吧,这个stm32从0开始系列也是我的学习进度路线,我之前学过cc2530,所以上手会比较快,不是什么大佬,你有问题留言或者私信我都没问题,我会就回答你,不会我也没办法。
希望看到这里的你和我一起共同进步,加油~