ps:第二次学习又有了新的收获,之前没怎么考虑过不同的GPIO口输入模式的区别,今天狠狠的了解了一下,还重新看了一遍芯片手册,看见了之前没有注意的地方,重新写了代码并且验证了自己的想法。
我们直接上代码,代码功能实现了按一下按键灯就反转状态。led初始化那部分就不说了,上篇文章已经探讨了。浅浅的看一下。我的led灯是GPIOBpin5,写代码的时候养成定义宏的习惯,方便后续修改引用。
led.c
#include "led.h"
void LED_init()
{
RCC_APB2PeriphClockCmd(LED_GPIO_RCC,ENABLE);
GPIO_InitTypeDef GPIO_struct;
GPIO_struct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_struct.GPIO_Pin=LED_GPIO_PIN;
GPIO_struct.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_Init(LED_GPIO_PORT,&GPIO_struct);
GPIO_SetBits(LED_GPIO_PORT,LED_GPIO_PIN);
}
void LED_on(void)
{
GPIO_ResetBits(LED_GPIO_PORT,LED_GPIO_PIN);
}
void LED_off(void)
{
GPIO_SetBits(LED_GPIO_PORT,LED_GPIO_PIN);
}
led.h
#ifndef USER_LED
#define USER_LED
#include "stm32f10x.h"
#define LED_GPIO_RCC RCC_APB2Periph_GPIOB
#define LED_GPIO_PIN GPIO_Pin_5
#define LED_GPIO_PORT GPIOB
void LED_init(void);
void LED_off(void);
void LED_on(void);
#endif
我们来研究一下我们的原理图。我选用的key0,key0是低电平导通而且是它没有上拉电阻或下拉电阻,甚至没有接滤波电容,如果这个时候我们选择了输入模式为浮空输入,我们按下去肯定是读取低电平,但是我们没有按下去的时候它什么都不接,处于一直悬空,那他就有可能受到一些玄学因素的影响。
所以我们io口的输入模式应该选上拉输入(如果我们是高电平导通那就应该是下拉输入),这样我们不按的时候它就是一个稳定的高电平状态不会受到外界影响。
我们来看一下它的I/O端口位的基本结构。
如果我们选上拉输入那它的走向应该就是这样的,上拉电阻的开关会闭合,再按键没按下的时候就能提供一个稳定的高电平(据说是3.3v),如果我们选用下拉输入会发生什么事情咧,理论上来讲按键就一直处于低电平状态读的也是低电平,按了也没有勇,没有变化就不能反转电平了,我试了一下确实是这样的,另外还有一个浮空输入GPIO_Mode_IN_FLOATING就有意思了,选了浮空输入的话,会出现反应迟钝的现象,要过一小会led才会有反应,是为什么我也不知道,可能这就是玄学因素吧。(建议把gpio_mode也宏定义,这边我忘记定义了)
另外我们之前说过我们电路里面是没有滤波电容的,如果不加延时函数的话,按键按下去产生的按键抖动就会影响我们控制led,有时候按下去会不亮,有时候还没松就亮了。加一个延时8ms的函数就基本没问题。
led电平的反转我们采用ODR寄存器和GPIO_Pin异或的方式,与1异或,不管是多少,每次异或都会改变状态,其他位与0异或不管是0还是1异或完都没变化。
key.c
#include"key.h"
//粗延时函数,微秒
void delay_us(u16 time)
{
u16 i=0;
while(time--)
{
i=10; //自己定义
while(i--) ;
}
}
//毫秒级的延时
void delay_ms(u16 time)
{
u16 i=0;
while(time--)
{
i=12000; //自己定义
while(i--) ;
}
}
void KEY0_init()
{
RCC_APB2PeriphClockCmd(KEY0_GPIO_RCC,ENABLE);
GPIO_InitTypeDef GPIO_struct;
GPIO_struct.GPIO_Mode=GPIO_Mode_IPU;
GPIO_struct.GPIO_Pin=KEY0_GPIO_PIN;
GPIO_Init(KEY0_GPIO_PORT,&GPIO_struct);
}
uint8_t KEY_scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin_x)
{
if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin_x) == key_on)
{
delay_ms(8);
if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin_x)!=key_on)
{
return 1;
}
else
{
return 0;
}
}
else
return 0;
}
/*level reversal--GPIO电平反转*/
void level_reversal(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin_x)
{
GPIOx->ODR^=GPIO_Pin_x;
}
key.h
#ifndef USER_KEY
#define USER_KEY
#include "stm32f10x.h"
#define KEY0_GPIO_RCC RCC_APB2Periph_GPIOE
#define KEY0_GPIO_PIN GPIO_Pin_4
#define KEY0_GPIO_PORT GPIOE
#define key_on 0
#define key_off 1
void KEY0_init(void);
uint8_t KEY_scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin_x);
void level_reversal(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin_x);
#endif
main.c
#include "stm32f10x.h" // Device header
#include "led.h"
#include "key.h"
int main()
{
LED_init();
KEY0_init();
while(1)
{
if(KEY_scan(KEY0_GPIO_PORT,KEY0_GPIO_PIN)==1)
{
level_reversal(LED_GPIO_PORT,LED_GPIO_PIN);
}
}
}
本文到此结束,如有错误,望指正!