个人学习笔记:按键实验
一.所使用的函数
1.时钟使能函数
RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
2.引脚初始化函数
GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
3.对IO口置1
GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
4.对IO口置0
GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
5.读取引脚输入数据的函数
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
二.代码编写过程整理
1.编写button.h文件
# ifndef __Button_H
# define __Button_H
void button_Init(void);
uint8_t Botton_scan(uint8_t); //在原始的文档中写的是u8,但是在新的stm32f10x.h头文件中未定义,所以无法直接使用
#endif
2.编写button.c文件
void button_Init(void)
{
GPIO_InitTypeDef GPIO_Initstructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE); //使能GPIOE的时钟
GPIO_Initstructure.GPIO_Mode = GPIO_Mode_IPU; //设置模式为上拉输入
GPIO_Initstructure.GPIO_Pin = GPIO_Pin_3;
GPIO_Initstructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE,&GPIO_Initstructure); //初始化PE3
GPIO_Initstructure.GPIO_Mode = GPIO_Mode_IPU; //设置模式为上拉输入
GPIO_Initstructure.GPIO_Pin = GPIO_Pin_4;
GPIO_Initstructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE,&GPIO_Initstructure); //初始化PE4
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能GPIOA的时钟
GPIO_Initstructure.GPIO_Mode = GPIO_Mode_IPD; //设置模式为下拉输入
GPIO_Initstructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Initstructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_Initstructure); //初始化PA0
}
正点原子的精英板一共有三个按键:WK_UP、KEY1、KEY2 ,其中KEY1和KEY2分别对应PE3和PE4,WK_UP对应的是PA0.在无按键按下时PE3和PE4对应引脚的数据是1,按下按键时PE3和PE4对应引脚输入的数据是0,为上拉输入,所以在模式选择的时候我们选择了上拉输入GPIO_Mode_IPU;在无按键按下时WK_UP对应引脚的数据是0,按下按键时WK_UP对应引脚输入的数据是1,为上拉输入,所以在模式选择的时候我们选择了下拉输入GPIO_Mode_IPD.
总结 上拉输入和下拉输入:当一个按键按下的时候,对应的引脚输入数据是0或1是不确定的,还要看外部电路的组成是上拉还是下拉,当外部电路时上拉的时候,即外部接正的时候,读入的数据是1;当外部电路是下拉的时候,读入的数据是0.所以上拉输入就是无按键按下时是1,有按键按下时是0;而下拉输入就是无按键按下时是0,有按键按下时是1.
uint8_t Botton_scan(uint8_t mode)
{
static uint8_t button_up = 1;
if(mode == 1)
button_up = 1; //模式1支持连续按键,无论之前button_up的值为多少,这里都将其置1,不管button_up之前的数据
if(button_up == 1&&(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3) == 0|GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4) == 0|GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == 1))
{
button_up =0; //不支持连续按键模式时,按下按钮时置0,为了保存按键状态
delay_ms(10); //软件消抖
if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3) == 0)
return 1;
if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4) == 0)
return 2;
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == 1)
return 3;
}
else if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3) == 1|GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4) == 1|GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == 0)
{
button_up = 1; //无按键按下
}
return 0;
}
这个是正点原子所提供的按键代码,为了让这段代码更方便分析,我把它所有的宏定义都替换掉了。这个按键代码是集“支持连续按键”和“不支持连续按键”功能于一身,连续按键:当mode等于1时它支持连续按键,原因是那一句if让button_up = 1,这样子它就可以不管static保存上一次调用代码所得的值,也就是不管按键之前的状态,只要按下就返回其对应的值,从而实现连续按键。不支持连续按键:不支持连续按键的关键是将button_up设置为一个static值,它可以保存上一次调用该函数,最后button_up的值。不支持连续按键,就是上一次如果是非按下状态,那么在这次检测到的按下状态就可以返回对应按钮所对应的值;但是如果上次是按下状态,在这次检测到的状态还是按下状态,它就不会返回对应的值而是返回0。下面我把该代码拆成两部分,这样可以更清楚地了解二者不同之处:
uint8_t Botton_scan(uint8_t mode) //连续按键
{
button_up = 1;
if(button_up == 1&&(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3) == 0|GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4) == 0|GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == 1))
{
delay_ms(10); //软件消抖
if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3) == 0)
return 1;
if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4) == 0)
return 2;
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == 1)
return 3;
}
}
uint8_t Botton_scan(uint8_t mode) //不支持连续按键
{
static uint8_t button_up = 1;
if(button_up == 1&&(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3) == 0|GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4) == 0|GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == 1))
{
button_up =0;
delay_ms(10); //软件消抖
if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3) == 0)
return 1;
if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4) == 0)
return 2;
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == 1)
return 3;
}
else if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3) == 1|GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4) == 1|GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == 0)
{
button_up = 1; //无按键按下
}
return 0;
}
3.编写main.c函数
# include "Button.h"
# include "Led.h"
# include "Beep.h"
# include "stm32f10x.h"
# include "delay.h"
int main(void)
{
button_Init();
delay_init();
led_Init();
beep_Init();
while(1)
{
uint8_t button = 0;
button = Botton_scan(0); //选择不支持连续按键模式
if (button != 0)
{
switch(button)
{
case 1 :
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
break;
case 2 :
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
break;
case 3 :
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
GPIO_SetBits(GPIOB,GPIO_Pin_8);
break;
}
}
else delay_ms(10);
}
}
在主函数中我为了让按键效果可以体现出来,让KEY1按下LED0亮,让KEY2按下LED1亮,按下KEY_UP时,LED0和LED1同时亮,并且有蜂鸣器响,点亮led和让蜂鸣器响的代码前两天分享过了,大家可以自己结合一下。
三.发现的问题
在自己写代码的时候发现了那些视频可能是几年前的视频了,在我的stm32f10x.h头文件中它没有了对uint8_t的宏定义,所以我在移植代码的时候使用u8会报错。
总的来说,st定义无符号8位整形数据有很多种表示方法:
1 unsigned int 8——标准写法;
2 uint8_t ;
3 u8; ——有问题
这个错误我找到的原因是这个,如果有其他的原因希望大家可以帮我指出。