文章目录
- 按键控制灯和蜂鸣器
- 1 实验要求
- 2 硬件介绍
- 3 软件设计
- 3.1 新建工程
- 3.2 编写代码
- 实验总结
按键控制灯和蜂鸣器
1 实验要求
用开发板上的三个按键分别控制上两次实验点亮的灯和蜂鸣器,按一次键,他们的状态翻转一次,翻转即灯的亮灭转换和蜂鸣器的响和不响的转换。
2 硬件介绍
正点原子STM32F103精英开发板,需要用到两个指示灯,一个蜂鸣器以及控制他们的三个按键。在这块开发板上,KEY0连接在PE4,KEY1连接在PE3,KEY_UP连接在PA0上。原理图如下:
从图中可以看出,KEY0和KEY1检测出低电平表示按下,KEY_UP检测出高电平表示按下。硬件无上下拉电阻需要软件实现。
3 软件设计
3.1 新建工程
把上次蜂鸣器的工程文件夹复制一份,取名为4、按键检测,进入文件夹,在其HARDWARE文件夹里新建KEY文件夹,并在KEY文件夹里创建key.h和key.c文件,最后把beep.uvprojx工程文件改名为key.uvprojx文件。等等,还没完,由于这次按键需要消抖,所以需要延时10ms,这时候之前的简单延时函数就不好用了,所以需要把正点原子自己写的一个SYSTEM文件夹复制进来。如图所示:
正点原子的程序源码都可以在正点原子官网下载。
此时就可以双击key.uvprojx进入工程编写代码了。
进入keil后,把key.c和SYSTEM文件夹以及其中的三个文件添加进去,添加key.h和SYSTEM用到的头文件路径,这些操作应该会了,不赘述了。
3.2 编写代码
LED和蜂鸣器程序都已经写好了,可以直接调用,现在需要写的是key.h,key.c和main.c三个文件的代码。按键检测还是对GPIO进行操作,和前两个实验不同的是GPIO的输入,需要对GPIO的输入数据位进行读取,用到下面这个函数。
key.h
#ifndef __KEY_H
#define __KEY_H
#include "stm32f10x.h"
//KEY0对应PE4
#define KEY_0_PIN GPIO_Pin_4
#define KEY_0_PORT GPIOE
#define KEY_0_CLK RCC_APB2Periph_GPIOE
//KEY1对应PE3
#define KEY_1_PIN GPIO_Pin_3
#define KEY_1_PORT GPIOE
#define KEY_1_CLK RCC_APB2Periph_GPIOE
//KEY_UP对应PA0
#define KEY_UP_PIN GPIO_Pin_0
#define KEY_UP_PORT GPIOA
#define KEY_UP_CLK RCC_APB2Periph_GPIOA
//读取输入数据位
#define KEY0 GPIO_ReadInputDataBit(KEY_0_PORT, KEY_0_PIN)
#define KEY1 GPIO_ReadInputDataBit(KEY_1_PORT, KEY_1_PIN)
#define KEY_UP GPIO_ReadInputDataBit(KEY_UP_PORT, KEY_UP_PIN)
uint8_t KEY_Scan(uint8_t mode); //扫描按键函数声明
void KEY_Init(void); //按键初始化函数声明
#endif
key.c
#include "key.h"
#include "sys.h"
#include "delay.h"
void KEY_Init(void)
{
//实例化配置GPIO模式和速度结构体
GPIO_InitTypeDef GPIO_InitStruct;
//使能key0、key1和key_up的时钟
RCC_APB2PeriphClockCmd(KEY_0_CLK | KEY_1_CLK | KEY_UP_CLK , ENABLE);
//配置KEY0和KEY1引脚为上拉输入,并初始化
GPIO_InitStruct.GPIO_Pin = KEY_0_PIN | KEY_1_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(KEY_0_PORT,&GPIO_InitStruct);
GPIO_Init(KEY_1_PORT,&GPIO_InitStruct);
//配置KEY_UP引脚为上拉输入,并初始化
GPIO_InitStruct.GPIO_Pin = KEY_UP_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(KEY_UP_PORT,&GPIO_InitStruct);
}
/*
定义一个按键扫描函数,通过读取数据位读取到的高低电平来判断按键
是否被按下,函数输入是一个mode变量,可以去0和1,1表示支持连按,
0表示不支持连按。返回值是一个8位整数,返回1、2、3分别表示key0、
key1和key_up被按下。
*/
uint8_t KEY_Scan(uint8_t mode)
{
static uint8_t key_up = 1;//按键按松开标志
if(mode) key_up=1; //支持连按
if(key_up&&(KEY0==0||KEY1==0||KEY_UP==1))
{
delay_ms(10);//去抖动
key_up=0;
if(KEY0==0) return 1;
else if(KEY1==0) return 2;
else if(KEY_UP==1) return 3;
}
else if(KEY0==1&&KEY1==1&&KEY_UP==0)
key_up=1;
return 0; // 无按键按下
}
main.c
#include "stm32f10x.h"
#include "led.h"
#include "beep.h"
#include "key.h"
#include "sys.h"
#include "delay.h"
int main()
{
uint8_t key; //接收键值
delay_init(); //初始化延时函数
LED_Init();
BEEP_Init();
KEY_Init();
while(1)
{
key = KEY_Scan(0);
if(key)
{
switch(key)
{
case 1: LED_0_PORT->ODR^=LED_0_PIN;
break ;
case 2: LED_1_PORT->ODR^=LED_1_PIN;
break ;
case 3: BEEP_PORT->ODR^=BEEP_PIN;
break;
}
}
else
delay_ms(10);
}
}
实验总结
- 实验中有一个问题卡了很久,最后才找到问题,原来是没有调用延时初始化函数。
- 按一下键就反转,用到的是端口输出寄存器,对灯和蜂鸣器的引脚位进行取反操作就行了。