【按键介绍】
按键:常用输出设备,按下导通,松手断开。
按键抖动:按键内部是机械式弹簧片,在按下和松手瞬间有抖动。
一般按键都是低电平导通,也有高电平导通的。
【C语言宏定义define】
关键字: #define
用途: 用一个字符代替一个数字,便于理解防出错,提取程序中常出现的参数,便于快速修改。
示例代码:
#define ABC 12345 //用ABC字符串代替12345
int a = ABC; //等效为 int a = 12345
【C语言typedef】
关键字: typedef
用途: 将一个比较长的变量类型换个名字,便于使用
示例代码:
typedef unsigned char uint8_t;//用uint8_t代替unsigned char
uint8_t a; //等效为unsigned char a
——
注意define和typedef的区别:
1、define的新名字在左边,typedef的新名字在右边
2、define完成后不需要分号,typedef完成后末尾要加分号
3、define任何名字都可以换,typedef只能给专门的变量类型换名字
4、对变量类型重命名而言,typedef更安全,typedef换名字之后原来的名字依旧可以用
【C语言结构体】
关键字:struct
用途:数据打包,不同变量整合到一起的一个集合
结构体变量类型一般较长,通常会用typedef更改变量类型名
示例代码:
struct {char x; int y; float z;}StructName;
//引用结构体成员
structName.x = 'a';
structName.y = '45';
structName.z = '2.33';
——
【C语言的枚举】
关键字:enum
用途:定义一个取值受限的整型变量,用于限制变量取值范围。
(比如一个星期只有1-7,但是整型变量可以取到任意一个值,比如星期8,这就不合理了,先不要给它限制一下)
枚举变量也可以当一个宏定义的的集合。
示例代码:
typedef enum {
MONDAY = 1,
TUESDAY =2,
WEDNESDAY =3 //后面类推到7,就不写完整了
} week_t;
week_t week; //之后week只能在1-7的整数之间取值
week = MONDAY; //week = 1
———————————————————————————————
【按键控制LED】
#include "stm32f10x.h"
uint8_t KeyNUM;//声明一个全局变量,全函数都能用,函数内定义的只能本函数内使用
//微秒延时函数 参考江科大直接拿来用
void Delay_us(uint32_t xus)
{
SysTick -> LOAD = 72 * xus;
SysTick -> VAL = 0x00;
SysTick -> CTRL = 0x00000005;
while(!(SysTick->CTRL & 0x00010000));
SysTick -> CTRL = 0x00000004;
}
//毫秒延时函数
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}
//LED初始化
void LED_Init(void)
{
//开启APB2外设时钟控制
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE) ; //ENABLE开启时钟
//定义结构体
GPIO_InitTypeDef GPIO_InitStructure;
//结构体参数
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; // 推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3; // 配置P1、P3口
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ; // 50MHz频率
//端口初始化,&取地址的符号
GPIO_Init(GPIOA,&GPIO_InitStructure);
//这个是将LED设置为高电平,我们LED是低电平点亮,没有这句代码的话,LED默认低电平全部点亮
//当然大家可以删除这句代码来检验一下LED是否亮了
GPIO_SetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_3);
}
//下面进行模块化编程
//LED1状态翻转函数
void LED1_turn(void)
{
if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_1)==0) //读取PA1端口输出的值
{
GPIO_SetBits(GPIOA,GPIO_Pin_1); //若为0,则置高电平1
}
else
{
GPIO_ResetBits(GPIOA,GPIO_Pin_1); //否则置0
}
}
//LED3状态翻转
void LED3_turn(void)
{
if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_3)==0) //读取PA11端口输出的值
{
GPIO_SetBits(GPIOA,GPIO_Pin_3); //若为0,则置高电平1
}
else
{
GPIO_ResetBits(GPIOA,GPIO_Pin_3); //否则置0
}
}
//定义一个LED1点亮函数
void LED_1_On(void)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_1); //点亮LED1
}
//再定义一个LED1熄灭函数
void LED_1_Off(void)
{
GPIO_SetBits(GPIOA,GPIO_Pin_1); //熄灭LED1
}
//--------------------------------
//定义一个LED3点亮函数
void LED_3_On(void)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_3); //点亮LED3
}
//再定义一个LED3熄灭函数
void LED_3_Off(void)
{
GPIO_SetBits(GPIOA,GPIO_Pin_3); //熄灭LED3
}
//--------------------------------
//按键初始化
void KEY_init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE) ; //按键是在PB口配置的
//定义结构体
GPIO_InitTypeDef GPIO_InitStructure;
//结构体参数
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD ; // 读取按键,下拉输入,我的按键一头接了VCC要下拉,松手低电平,按下高电平
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;//我的按键分别是在P10、P11口
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ; // 50MHz频率 ,在输入模式下其实这个参数没用
//端口初始化,&取地址的符号
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
//按键读取函数
uint8_t Key_ReadNUM(void) //uint_8就是上文讲过的unsigned char的意思
{
uint8_t KeyNUM = 0; //按键键码默认给0
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)==1) //打开GPIO.h文件找这个读取输入的函数
{
Delay_ms(20); //按键消抖
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)==1); //当按键一直按下时,停在这
Delay_ms(20); //松手后,按键消抖
KeyNUM = 1; // 键码给1
}
//这一块就是PB10的按键检测
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)==1) //我是上拉输入,高电平接通点亮
{
Delay_ms(20); //按键消抖
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)==1); //当按键一直按下时,停在这
Delay_ms(20); //松手后,按键消抖
KeyNUM = 2; // 键码给1
}
//这一块就是PB11的按键检测
return KeyNUM; //返回值给函数
}
int main(void)
{
LED_Init();
KEY_init();
while(1)
{
KeyNUM = Key_ReadNUM();//不断读取键码值,给到KeyNUM,这里的KeyNUM是全局变量声明的
if(KeyNUM ==1)
{
LED1_turn();
}
if(KeyNUM ==2)
{
LED3_turn();
}
}
}
最后的效果:——按下按键10,LED1亮,再按一下,LED1灭
按下按键11,LED3亮,再按一下,LED3灭
总结及心得:
1、在编写按键初始化函数代码时,始终没有注意到我的按键是上拉输入还是下拉输入,在想,唉,怎么一直按这个按键没反应呢,导致一直在找其它代码的错误,大意了,反复看了元件引脚图才灵光一现,直接妙手回春。
2、延时不要给太大,不然延迟很折磨人,这个问题不大。
3、在打 if 条件语句的时候,不要忘记少括号。
4、LED_1_On和LED_1_off的函数我编写了,但是没有在主函数内用,LED3的也是,大家可以自己尝试用一下。
劫后小礼物:
模拟输入:GPIO_Mode_AIN ——(Analog IN)
浮空输入:GPIO_Mode_IN_FLOATING
下拉输入:GPIO_Mode_IPD ——(In Pull Down)
上拉输入:GPIO_Mode_AIU ——(In Pull Up)
————————
开漏输出:GPIO_Mode_Out_OD
推挽输出:GPIO_Mode_Out_PP
复用开漏:GPIO_Mode_AF_OD
复用推挽:GPIO_Mode_AF_PP