IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> GPIO小综合-按键实验 -> 正文阅读

[嵌入式]GPIO小综合-按键实验

之前用寄存器操作实现了跑马灯和蜂鸣器。这次接着输入寄存器IDR捕获按键。并且综合亮灯和发出声音,作为寄存器GPIO小综合练习。

首先查KEY的电路图,分别用到了ACD几个时钟。KEY0对应PC8,KEY1对应PC9,KEY2对应PD2,KEYUP对应PA0
在这里插入图片描述
然后对应的时钟就是APB2的245位
在这里插入图片描述

按文档设置为上下拉输出模式(即1000对应16进制的8)
在这里插入图片描述

按IDR寄存器读相应端口的电平即可
在这里插入图片描述

代码实现如下:

key.h

//定义宏,防止头文件重复引用
#ifndef __KEY
#define __KEY
//初始化按键的环境
void InitKeyEnv(void);

//测试按键
void TestKey(void);

//得到按下的按键
//continuePress:是否允许连按。0:必须从不按状态按才算。 1:只要是按着的就算
//返回0就是按下KEY0,返回1就是按下KEY1,返回2就是按下KEY2,返回3就是按下KEY_UP,返回-1就是没按
int GetPressKey(int continuePress);
#endif


key.c

#include "key.h"
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "beep.h"

//初始化按键的环境
void InitKeyEnv(void)
{
	//设置ABP2外设时钟第2位为1,即可用,对应GPIOA时钟(KEY_UP)
	//1<<2:1左移2位为0010,与APB2ENR寄存器值或运算就是第2位设置1,其他不变的意思
	RCC->APB2ENR|=1<<2;
	
	//设置ABP2外设时钟第4位为1,即可用,对应GPIOC时钟(KEY0,KEY1)
	//1<<4:1左移4位为1000,与APB2ENR寄存器值或运算就是第4位设置1,其他不变的意思
	RCC->APB2ENR|=1<<4;
	
	//设置ABP2外设时钟第5位为1,即可用,对应GPIOD时钟(KEY2)
	//1<<5:1左移5位为10000,与APB2ENR寄存器值或运算就是第5位设置1,其他不变的意思
	RCC->APB2ENR|=1<<5;
	
	//KEY_UP  PA0对应CRL低位寄存器
	//设置1000上下拉输入模式,对应16进制8
	GPIOA->CRL&=0XFFFFFFF0;
	GPIOA->CRL|=0X00000008;
	
	//KEY0 PC8对应CRH高位寄存器
	//设置1000上下拉输入模式,对应16进制8
	GPIOC->CRH&=0XFFFFFFF0;
	GPIOC->CRH|=0X00000008;
	//默认设置高电平,没按下按键
	GPIOC->ODR|=1<<8;	  
	
	
	//KEY1 PC9对应CRH高位寄存器
	//设置1000上下拉输入模式,对应16进制8
	GPIOC->CRH&=0XFFFFFF0F;
	GPIOC->CRH|=0X00000080;
	//默认设置高电平,没按下按键
	GPIOC->ODR|=1<<9;	   
	
	//KEY2 PD2对应CRL低位寄存器
	//设置1000上下拉输入模式,对应16进制8
	GPIOD->CRL&=0XFFFFF0FF;
	GPIOD->CRL|=0X00000800;
	//默认设置高电平,没按下按键
	GPIOD->ODR|=1<<2;	   	
}

//测试按键
void TestKey(void)
{
	//初始化LED灯
    InitLedEnv();	
	//初始化蜂鸣器灯
    InitBeepEnv();
	
	InitKeyEnv();
	
	//LED0状态
	int LED0Stat=0;
	//LED1状态
	int LED1Stat=0;
	//LED2状态
	int LED2Stat=0;
	//LED3状态
	int LED3Stat=0;
	
	//死循环
	while(1)
	{
		//得到按键值
		int key=GetPressKey(0);
		
		//按了KEY0
		if(key>=0)
		{
			//按下了KEY0,点亮LED0
			if(key==0)
			{
				//点亮灯鸣喇叭
				if(LED0Stat==0)
				{
					//点亮LED0
					GPIOC->ODR&=~(1<<0);
					//通过操作ODR寄存器设置9位置为0即低电平,响
					GPIOB->ODR&=~(1<<8);
					LED0Stat=1;
					delay_ms(100); 
					//通过操作ODR寄存器设置9位置为1即高电平,不响
					GPIOB->ODR|=1<<8;
				}
				else
				{
					//熄灭LED0
					GPIOC->ODR|=1<<0;
					//通过操作ODR寄存器设置9位置为0即低电平,响
					GPIOB->ODR&=~(1<<8);
					LED0Stat=0;
					delay_ms(100); 
					//通过操作ODR寄存器设置9位置为1即高电平,不响
					GPIOB->ODR|=1<<8;
				}
			}
			
			
			//按下了KEY1,点亮LED1
			if(key==1)
			{
				//点亮灯鸣喇叭
				if(LED1Stat==0)
				{
					//点亮LED1
					GPIOC->ODR&=~(1<<1);
					//通过操作ODR寄存器设置9位置为0即低电平,响
					GPIOB->ODR&=~(1<<8);
					LED1Stat=1;
					delay_ms(100); 
					//通过操作ODR寄存器设置9位置为1即高电平,不响
					GPIOB->ODR|=1<<8;
				}
				else
				{
					//熄灭LED1
					GPIOC->ODR|=1<<1;
					//通过操作ODR寄存器设置9位置为0即低电平,响
					GPIOB->ODR&=~(1<<8);
					LED1Stat=0;
					delay_ms(100); 
					//通过操作ODR寄存器设置9位置为1即高电平,不响
					GPIOB->ODR|=1<<8;
				}
			}
			
			
			//按下了KEY2,点亮LED2
			if(key==2)
			{
				//点亮灯鸣喇叭
				if(LED2Stat==0)
				{
					//点亮LED2
					GPIOC->ODR&=~(1<<2);
					//通过操作ODR寄存器设置9位置为0即低电平,响
					GPIOB->ODR&=~(1<<8);
					LED2Stat=1;
					delay_ms(100); 
					//通过操作ODR寄存器设置9位置为1即高电平,不响
					GPIOB->ODR|=1<<8;
				}
				else
				{
					//熄灭LED2
					GPIOC->ODR|=1<<2;
					//通过操作ODR寄存器设置9位置为0即低电平,响
					GPIOB->ODR&=~(1<<8);
					LED2Stat=0;
					delay_ms(100); 
					//通过操作ODR寄存器设置9位置为1即高电平,不响
					GPIOB->ODR|=1<<8;
				}
			}
			
			
			//按下了KEYUP,点亮LED3
			if(key==3)
			{
				//点亮灯鸣喇叭
				if(LED3Stat==0)
				{
					//点亮LED3
					GPIOC->ODR&=~(1<<3);
					//通过操作ODR寄存器设置9位置为0即低电平,响
					GPIOB->ODR&=~(1<<8);
					LED3Stat=1;
					delay_ms(100); 
					//通过操作ODR寄存器设置9位置为1即高电平,不响
					GPIOB->ODR|=1<<8;
				}
				else
				{
					//熄灭LED3
					GPIOC->ODR|=1<<3;
					//通过操作ODR寄存器设置9位置为0即低电平,响
					GPIOB->ODR&=~(1<<8);
					LED3Stat=0;
					delay_ms(100); 
					//通过操作ODR寄存器设置9位置为1即高电平,不响
					GPIOB->ODR|=1<<8;
				}
			}
			
			
		}
		
		//延迟
		delay_ms(10); 
	}

	
}

//得到按下的按键
//continuePress:是否允许连按。0:必须从不按状态按才算。 1:只要是按着的就算
//返回0就是按下KEY0,返回1就是按下KEY1,返回2就是按下KEY2,返回3就是按下KEY_UP,返回-1就是没按
int GetPressKey(int continuePress)
{
	static int keyNotPress=1;
	//允许连着按就任务按键之前一直是没按
	if(continuePress==1)
	{
		keyNotPress=1;
	}
	//之前不是按键状态
	if(keyNotPress==1)
	{
		//判断KEY0,把IDR寄存器值和0X100000000与操作,那么其他位置都是0,第9位原来是什么就是什么
		int key0=(GPIOC->IDR&(1<<8))>>8;
		//key0是按下的
		if(key0==0)
		{
			//延迟10毫秒
			delay_ms(10); 
			key0=(GPIOC->IDR&(1<<8))>>8;
			if(key0==0)
			{
				keyNotPress=0;
				return 0;
			}
		}
		
		//判断KEY1,把IDR寄存器值和0X1000000000与操作,那么其他位置都是0,第10位原来是什么就是什么,然后再右移一位
		int key1=(GPIOC->IDR&(1<<9))>>9;
		//key1是按下的
		if(key1==0)
		{
			//延迟10毫秒
			delay_ms(10); 
			key1=(GPIOC->IDR&(1<<9))>>9;
			if(key1==0)
			{
				keyNotPress=0;
				return 1;
			}
		}
		
		
		//判断KEY2,把IDR寄存器值和0X00000100与操作,那么其他位置都是0,第3位原来是什么就是什么,然后再右移2位
		int key2=(GPIOD->IDR&(1<<2))>>2;
		//key2是按下的
		if(key2==0)
		{
			//延迟10毫秒
			delay_ms(10); 
			key2=(GPIOD->IDR&(1<<2))>>2;
			if(key2==0)
			{
				keyNotPress=0;
				return 2;
			}
		}
			
		//判断KEY_UP,把IDR寄存器值和0X00000001与操作,那么其他位置都是0,第1位原来是什么就是什么
		int keyUp=(GPIOA->IDR&(1<<0))>>0;
		//keyUp是按下的
		if(keyUp==1)
		{
			//延迟10毫秒
			delay_ms(10); 
			keyUp=(GPIOA->IDR&(1<<0))>>0;
			if(keyUp==1)
			{
				keyNotPress=0;
				return 3;
			}
		}
		
	}
	//没有按键就恢复keyNotPress值
	else
	{
		int key0=(GPIOC->IDR&(1<<8))>>8;
		int key1=(GPIOC->IDR&(1<<9))>>9;
		int key2=(GPIOD->IDR&(1<<2))>>2;
		int keyUp=(GPIOA->IDR&(1<<0))>>0;
		if(key0==1&&key1==1&&key2==1&&keyUp==0)
		{
			keyNotPress=1;
		}
	}
	return -1;
}


led.h

//定义宏,防止头文件重复引用
#ifndef __LED
#define __LED
//初始化LED的环境
void InitLedEnv(void);

//测试LED
void TestLed(void);
#endif


led.c

#include "led.h"
#include "sys.h"
#include "delay.h"

//初始化LED环境
void InitLedEnv(void)
{
	//设置ABP2外设时钟第4位为1,即可用,对应GPIOC时钟
	//1<<4:1左移4位位1000,与APB2ENR寄存器值或运算就是第4位设置1,其他不变的意思
	RCC->APB2ENR|=1<<4;
	
	
	//设置LED0为推挽输出模式
	//CRL寄存器和十六进制的值且运算,设置指定位置的电平为指定4位位0000
	GPIOC->CRL&=0XFFFFFFF0;
	//CRL寄存器和十六进制的值或运算,设置指定位置的电平为指定4位位0011,四位里面高两位00表示通用推挽输出。低两位11表示输出模式,最大速度50MHz
	GPIOC->CRL|=0X00000003;
	
	//依次设置其他7个LED输出空为推挽输出模式
	//LED1
	GPIOC->CRL&=0XFFFFFF0F;
	GPIOC->CRL|=0X00000030;
	
	//LED2
	GPIOC->CRL&=0XFFFFF0FF;
	GPIOC->CRL|=0X00000300;
	
	//LED3
	GPIOC->CRL&=0XFFFF0FFF;
	GPIOC->CRL|=0X00003000;
	
	//LED4
	GPIOC->CRL&=0XFFF0FFFF;
	GPIOC->CRL|=0X00030000;
	
	//LED5
	GPIOC->CRL&=0XFF0FFFFF;
	GPIOC->CRL|=0X00300000;
	
	//LED6
	GPIOC->CRL&=0XF0FFFFFF;
	GPIOC->CRL|=0X03000000;
	
	//LED7
	GPIOC->CRL&=0X0FFFFFFF;
	GPIOC->CRL|=0X30000000;
	
	//通过操作ODR寄存器设置每个LED位置为1即高电平,不亮
	GPIOC->ODR|=1<<0;
	GPIOC->ODR|=1<<1;
	GPIOC->ODR|=1<<2;
	GPIOC->ODR|=1<<3;
	GPIOC->ODR|=1<<4;
	GPIOC->ODR|=1<<5;
	GPIOC->ODR|=1<<6;
	GPIOC->ODR|=1<<7;
	
}

//测试LED
void TestLed(void)
{
	//初始化LED灯
  InitLedEnv();	
	//当前该点亮的LED索引
	int curIndex=0;	
	//死循环
	while(1)
	{
		//改版为点亮所以led做跑马灯
		for(int i=0;i<8;i++)
		{
			//当前该亮的灯点亮
			if(i==curIndex)
			{
				//1左移当前索引位数后取非再做且运算就是把当前位数的电平设置低位。比如i=2即LED2,00000100取非之后为11111011再和ODR的值与运算
				//第3位电平设置低,其他不变
				GPIOC->ODR&=~(1<<i);
			}
			//其他熄灭
			else
			{
				//1左移当前索引位数再做或运算就是把当前位数的电平设置高位。比如i=2即LED2,ODR寄存器值和00000100或运算
				//第3位电平设置高,其他不变
				GPIOC->ODR|=1<<i;
			}
		}
		//下次点亮下一个灯
		curIndex++;
		//8个灯取余数
		curIndex=curIndex%8;
		//延迟半秒
		delay_ms(500); 
		
	}
}



beep.h

//定义宏,防止头文件重复引用
#ifndef __BEEP
#define __BEEP
//初始化蜂鸣器的环境
void InitBeepEnv(void);

//测试蜂鸣器
void TestBeep(void);
#endif


beep.c

#include "beep.h"
#include "sys.h"
#include "delay.h"
#include "led.h"

//初始化蜂鸣器的环境
void InitBeepEnv(void)
{
	//设置ABP2外设时钟第2位为1,即可用,对应GPIOB时钟
	//1<<3:1左移3位位0100,与APB2ENR寄存器值或运算就是第3位设置1,其他不变的意思
	RCC->APB2ENR|=1<<3;
	
	//设置PB8为推挽输出模式
	//CRH寄存器和十六进制的值且运算,设置指定位置的电平为指定4位位0000
	GPIOB->CRH&=0XFFFFFFF0;
	//CRH寄存器和十六进制的值或运算,设置指定位置的电平为指定4位位0011,四位里面高两位00表示通用推挽输出。低两位11表示输出模式,最大速度50MHz
	GPIOB->CRH|=0X00000003;
	
	//通过操作ODR寄存器设置9位置为1即高电平,不响
	GPIOB->ODR|=1<<8;
}

//测试蜂鸣器
void TestBeep(void)
{
	//初始化LED灯
  InitLedEnv();	
	//初始化蜂鸣器
  InitBeepEnv();	
	
	//死循环
	while(1)
	{
		//通过操作ODR寄存器设置9位置为0即低电平,响
		GPIOB->ODR&=~(1<<8);
		//点亮LED0
		GPIOC->ODR&=~(1<<0);
		//延迟半秒
		delay_ms(500); 
		//通过操作ODR寄存器设置9位置为1即高电平,不响
		GPIOB->ODR|=1<<8;
		//关闭LED0
		GPIOC->ODR|=1<<0;
		//延迟半秒
		delay_ms(500); 
		
	}
}


mian.c

#include "delay.h"
#include "led.h"
#include "beep.h"
#include "key.h"

//zlz的stm32学习
int main(void)
{
	//初始化时钟
	Stm32_Clock_Init(9);
	//初始化延时函数
	delay_init(72);	 
	
	//测试LED
	//TestLed();
	
	
	//测试蜂鸣器
	//TestBeep();
	
	//测试按键
	TestKey();
}




实现起来费劲些,搞了个把小时终于搞定了

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-03-30 18:41:35  更:2022-03-30 18:45:10 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:42:00-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码