*实验三* 单片机I/O口的应用设计——输入控制

文章介绍了使用单片机进行I/O口控制的实验,包括独立键盘、矩阵键盘和蜂鸣器的应用,重点讲解了按键消抖、矩阵按键扫描原理及LED灯与数码管的交互操作,要求在Proteus中进行软件仿真和硬件验证。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、实验内容:单片机 I/O 口的应用设计——输入控制

(1)独立键盘的使用

(2)矩阵键盘的使用

(3)蜂鸣器实验

2、参考资料:

(1) 教材;(2)百度网盘中实验板相关资料。

3、预习内容:

(1) 教材 5.7 键盘接口设计

(2) 参看开发板光盘视频材料及相关示例代码:独立按键;矩阵按键;蜂鸣器

4、 重难点:

(1) 实现按键消抖的方法。

(2) 扫描检测矩阵按键的原理与方法。

(3) 使蜂鸣器发出响亮声音的编程方法。

5、实验任务:要求用 Proteus 画原理图进行软件仿真,并下载到开发板上硬件验证。

任务(1):在参考示例代码的基础上修改,用独立按键 K1,K2,K3,K4 控制一个 LED 灯。 即按

下 K1 时,LED 灯闪烁;按下 K2 时,蜂鸣器发出叮咚门铃声。按下 K3 时,LED 灯左移;按下 K4 时,

LED 灯右移。

任务(2):理解参考代码,按下图所示修改矩阵键盘布局,每按一个按键,用1个数码管显示其键名(0-F)。在这里插入图片描述

注意:在 Proteus仿真时,用 sperker(sounder)来代表蜂鸣器。

任务一

在参考示例代码的基础上修改,用独立按键 K1,K2,K3,K4 控制一个 LED 灯。 即按

下 K1 时,LED 灯闪烁;按下 K2 时,蜂鸣器发出叮咚门铃声。按下 K3 时,LED 灯左移;按下 K4 时,

可于Proteus中作仿真图如下:

在这里插入图片描述

代码实现如下:

#include<reg52.h>
#include<intrins.h>
typedef unsigned char u8;
typedef unsigned int u16;
#define LED P2
/*宏定义按键赋值,方便按键检测操作*/
#define KEY1 1
#define KEY2 2
#define KEY3 3
#define KEY4 4
/*定义蜂鸣器以及按键操作位*/
sbit beep=P1^5;
sbit K1=P3^1;
sbit K2=P3^0;
sbit K3=P3^2;
sbit K4=P3^3;
u8 code led[8] = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};//只点亮一个灯亮的状态
u16 shanshuo = 0;//标记闪烁状态
u8 num = 0;//标记对应位数的LED
u8 ding,dong,flag,stop;//计数标志
u16 time;//计时标志
/*延时函数*/
void delay(u16 i)
{
	while(i--);
}
void delay500ms(void)   //误差 0us
{
    unsigned char a,b,c;
    for(c=23;c>0;c--)
        for(b=152;b>0;b--)
            for(a=70;a>0;a--);
}

void time0init()	  //定时器0初始化
{
	TMOD=0X01;	 //定时器0 方式1
	TH0=0Xff;
	TL0=0X06; //定时250us
//	TR0=1;
	EA=1;
	ET0=1;
}
void biaohaoinit()	   //各个标号初始化
{
	ding=0;		//叮声音  计数标志
	dong=0;		//咚声音  计数标志
	time=0;		//定时0.5s标志
	flag=0;
	stop=0;	   //结束标志
}
/*按键扫描*/
u8 KeyScan(u8 mode)//mode=0 单次   1:连续
{
	static u8 keyen=1;
	if(mode==1)
	{
		keyen=1;
	}
	if(keyen==1&&(K1==0||K2==0||K3==0||K4==0))
	{
		delay(1000);  //消抖处理
		keyen=0;
		if(K1==0)return KEY1;
		else if(K2==0)return KEY2;
		else if(K3==0)return KEY3;
		else if(K4==0)return KEY4;				
	}
	else if(K1==1&&K2==1&&K3==1&&K4==1)
	{
		keyen=1;
	}
	return 0;	
}
/*按键处理*/
void KeyPros(u8 key)
{	
	if(key==KEY1)	   //LED闪烁
		{
			shanshuo=(shanshuo+1)%2;
			delay(1000);
		}
		if(key==KEY2)	   //蜂鸣器发出叮咚门铃声
		{
			if(K2==0)
			{
				TR0=1;	//打开定时器0
				while(!stop);
			}
		}
		if(key==KEY3)	   //LED左移
		{
			num++;
			LED = _crol_(0xfe,num%8);
		}	
		if(key==KEY4)	   //LED右移
		{
			num--;
			LED = _crol_(0xfe,num%8);
		}		
}
/*主函数*/
void main()
{
	time0init();
	biaohaoinit();
	LED = 0xfe;
	while(1)
	{
		u8 key;//存放KeyScan()的返回值
		key=KeyScan(0);
		KeyPros(key);
		if(shanshuo==1)//在主函数中实现闪烁开启/关闭
		{
			delay500ms();
			LED = 0xff;
			key=KeyScan(0);//LED闪烁间隙再次扫描
			KeyPros(key);
			delay500ms();
		}		
		LED = _crol_(0xfe,num%8);
	}
}
void time0() interrupt 1
{
	time++;
	TH0=0Xff;
	TL0=0X06; //250us
	if(time==2000)		//定时0.5s  叮响0.5秒,咚响0.5秒
	{
		time=0;
		if(flag==0)
		{
			flag=~flag;
		}
		else
		{
			flag=0;
			stop=1;
			TR0=0;	  //关闭定时器0
		}
	}
	if(flag==0)
	{					   //通过改变定时计数时间可以改变门铃的声音
		ding++;			  //叮
		if(ding==1)
		{
			ding=0;
			beep=~beep;
		}
	}
	else
	{
		dong++;
		if(dong==2)		  //咚
		{
			dong=0;
			beep=~beep;
		}	
	}
}

遗憾的是:以我现在的代码能力,要实现小灯闪烁同时能丝滑移位有点困难,目前的解决办法只是在while循环中使用两次按键扫描,但延时的期间必然无法进行检测。以及铃声的实现是移植大佬的代码来的,暂时缺少自己动手摸索的过程。

任务二

理解参考代码,按下图所示修改矩阵键盘布局,每按一个按键,用1个数码管显示其键

名(0-F)。在这里插入图片描述

可于Proteus作仿真图如下:

在这里插入图片描述

代码实现如下:

/*******************************************************************************
* 实 验 名		 : 矩阵键盘控制1位数码管显示
* 使用的IO	     : 数码管使用P0,P2.2,P2.3,P2.4,键盘使用P1
* 实验效果       : 按矩阵键盘分别显示在数码管上面显示十六进制的0到F。
* 注    意		 :
*******************************************************************************/
#include<reg51.h>
/*数码管段选及矩阵键盘管脚定义*/
#define GPIO_DIG P0
#define GPIO_KEY P1
/*数码管位选控制位*/
sbit A0=P2^2;
sbit A1=P2^3;
sbit A2=P2^4;

unsigned char code DIG_CODE[17]={
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//0、1、2、3、4、5、6、7、8、9、A、b、C、d、E、F的显示码
unsigned char KeyValue;//存放读取到的键值
unsigned char KeyState;	//记录按键的状态,0没有,1有

void Delay10ms();   //延时10ms
void KeyDown();		 //检测按键函数
void DigDisplay(); //动态显示函数
/*******************************************************************************
* 函 数 名         : main
* 函数功能		   : 主函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void main(void)
{
	KeyState=0;
	while(1)
	{
		KeyDown();
		A0 = 1;
		A1 = 0;
		A2 = 0;
		GPIO_DIG=DIG_CODE[KeyValue];
		KeyState = 0;
	}				
}

/*******************************************************************************
* 函 数 名         : KeyDown
* 函数功能		   : 检测有按键按下并读取键值
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void KeyDown(void)
{
	unsigned int a=0;
	GPIO_KEY=0x0f;
	if(GPIO_KEY!=0x0f)
  {
		Delay10ms();
		a++;	
		a=0;
		if(GPIO_KEY!=0x0f)
		{
			KeyState=1;//有按键按下
			//测试列
			GPIO_KEY=0X0F;
			switch(GPIO_KEY)
			{
				case(0X07):	KeyValue=0;break;
				case(0X0b):	KeyValue=1;break;
				case(0X0d): KeyValue=2;break;
				case(0X0e):	KeyValue=3;break;
			}
			//测试行
			GPIO_KEY=0XF0;
			Delay10ms();
			switch(GPIO_KEY)
			{
				case(0X70):	KeyValue=KeyValue*4+0;break;
				case(0Xb0):	KeyValue=KeyValue*4+1;break;
				case(0Xd0): KeyValue=KeyValue*4+2;break;
				case(0Xe0):	KeyValue=KeyValue*4+3;break;
			}
//			//测试列
//			GPIO_KEY=0X0F;
//			switch(GPIO_KEY)
//			{
//				case(0X07):	KeyValue=0;break;
//				case(0X0b):	KeyValue=1;break;
//				case(0X0d): KeyValue=2;break;
//				case(0X0e):	KeyValue=3;break;
//			}
//			//测试行
//			GPIO_KEY=0XF0;
//			Delay10ms();
//			switch(GPIO_KEY)
//			{
//				case(0X70):	KeyValue=KeyValue;break;
//				case(0Xb0):	KeyValue=KeyValue+4;break;
//				case(0Xd0): KeyValue=KeyValue+8;break;
//				case(0Xe0):	KeyValue=KeyValue+12;break;
//			}
			while((a<500)&&(GPIO_KEY!=0xf0))	 //按键松手检测
			{
				Delay10ms();
				a++;
			}
			a=0;
		}
	}
}
/*******************************************************************************
* 函 数 名         : Delay10ms
* 函数功能		   : 延时函数,延时10ms
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void Delay10ms(void)   //误差 0us
{
    unsigned char a,b,c;
    for(c=1;c>0;c--)
        for(b=38;b>0;b--)
            for(a=130;a>0;a--);
}

在理解矩阵键盘扫描的原理基础上,简单修改例程即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值