单片机STC15双机通信&矩阵键盘&异步串行通信&Proteus

●题目

在这里插入图片描述
在这里插入图片描述

●原理图

 1、CPU

   STC15W4K32S4系列

STC15W4K32S4系列内含多种具体型号的单片机。下图摘自数据手册。
在这里插入图片描述

在这里插入图片描述

!!! Proteus的网络标号不区分大小写
乙机为区别甲机,乙机的标号前端加了下划线 _

 2、矩阵键盘

   ●矩阵键盘并没有按照 示意图接限流电阻(图中300欧姆的电阻,可能是限流,不理解该处电阻的作用);也未接上拉电阻(感觉没必要)。
   ●示意图中矩阵键盘的扫描接口接的是P0口,后经DL指点P0有BUG,测试见文末,改为P6口。
   ●四路与门是在调试矩阵键盘时,为中断扫描所连接的;在这个实验中矩阵键盘的接法为查询扫描&多行扫描

在这里插入图片描述

附:在Proteus的库中有已经封装好的矩阵键盘模块。
在这里插入图片描述

关于矩阵键盘可详见: 矩阵键盘.

 3、显示部分

  ●LED、数码管

   ●4个LED采用灌电流接法,经300欧姆排阻接VCC。
   ●使用了4个一位八段共阴数码管。
   ●LED对应按键值0—15,亮为1,灭为0,以8421BCD码显示按键值。
   ●数码管显示十进制0—15。
在这里插入图片描述

  ●数码管驱动电路(74HC573锁存器)

   ●数码管采用静态驱动,为节省IO口资源外接了锁存器。
在这里插入图片描述
在这里插入图片描述

●程序

代码为完整代码,关于双机通信单独的例子以及课本例程测试,可见 双机通信.

#include<STC15.H>
#include<intrins.h>

#define uchar unsigned char
#define uint unsigned int
#define KeyBus P6    //定义矩阵键盘接口

uchar Key_res =0; 
uchar i=0;
uchar temp=0XFF;     //串行发送临时传递参数
uchar temp1=0XFF;    //串行接收临时传递参数 
uchar busy;     //正忙标志(数据正在传输)
code uchar A[10]={0X3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F};  //无点,数码管驱动数组

void GPIO(void);    //IO口初始化函数
void Delay5ms();		//@11.0592MHz
void UartInit(void);		//9600bps@11.0592MHz 串行口1初始化函数
uchar Key16_Scan(void);//矩阵键盘扫描函数子程序
void Key16_Function(void); //矩阵键盘服务(功能)子函数
void SendData(void);  //发送串口数据 (串行发送采用查询方式)

void main(void)
{
	GPIO();     //IO口初始化函数
    UartInit(); //串行口1初始化函数
	ES=1;       //允许串行口1中断
	EA=1;       //总中断允许控制位
	while(1) 
	{
		Key_res =0; 
		i=Key16_Scan();   //矩阵键盘扫描函数子程序
        switch(i)
			{
			  case  1: temp=0X00;break;
			  case  2: temp=0X01;break;
		      case  3: temp=0X02;break;
		      case  4: temp=0X03;break;
			  case  5: temp=0X04;break;
			  case  6: temp=0X05;break;
			  case  7: temp=0X06;break;
			  case  8: temp=0X07;break;
			  case  9: temp=0X08;break;
			  case 10: temp=0X09;break;
			  case 11: temp=0X0A;break;
			  case 12: temp=0X0B;break;
			  case 13: temp=0X0C;break;
			  case 14: temp=0X0D;break;
			  case 15: temp=0X0E;break;
			  case 16: temp=0X0F;break;
			  default: break;
			}
        SendData();  //发送串口数据
	}
}

//-----------------------------------IO口初始化函数-----------------------------//
void GPIO(void)
{
	P0M1=0;
	P0M0=0;
	P1M1=0;
	P1M0=0;
	P2M1=0;
	P2M0=0;
	P3M1=0;
	P3M0=0;
	P4M1=0;
	P4M0=0;
	P5M1=0;
	P5M0=0;
}
//------------------------------------软件延时---------------------------------------//
void Delay5ms()		//@11.0592MHz
{
	unsigned char i, j;
	i = 54;
	j = 199;
	do
	{
	  while (--j);
	} while (--i);
}
//-------------------------------------串行口1初始化函数-----------------------------//
void UartInit(void)		//9600bps@11.0592MHz
{
	SCON = 0x50;		 //8位数据,可变波特率
	AUXR |= 0x40;		 //定时器1时钟为Fosc,即1T
	AUXR &= 0xFE;		 //串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		 //设定定时器1为16位自动重装方式
	TL1 = 0xE0;		   //设定定时初值
	TH1 = 0xFE;		   //设定定时初值
	ET1 = 0;		     //禁止定时器1中断
	TR1 = 1;		     //启动定时器1
}


//---------------------------------------矩阵键盘扫描函数子程序-------------------------//

uchar Key16_Scan(void)
{
	uchar X_temp = 0,Y_temp = 0;
	uchar Key_down = 0;
	
	KeyBus = 0XFF;	
	KeyBus = 0X0F;	//高4位置0,低4位置1,此时有按键按下时,低四位的某一位会被拉低,由此定位按下的按键在第几列
	Y_temp = KeyBus&0X0F;
	
	if(Y_temp!=0X0F)	//如果检测到某列有按键按下(有按键按下时,低四位会有一位被拉低)
	{
		Delay5ms();    //按键消抖(不知道有无必要)
		KeyBus = 0X0F; 	
	    Y_temp = KeyBus&0X0F;//将KeyBus低四位的按键信息赋值给Y_temp
		if(Y_temp!=0X0F)
		{
			KeyBus = 0X0F;
			Y_temp = KeyBus&0X0F;  //将KeyBus低四位的按键信息赋值给Y_temp,反应列信息
			KeyBus = 0XF0;
			X_temp = KeyBus&0XF0;  //将KeyBus高四位的按键信息赋值给X_temp,反应行信息
			if(Key_down == 0)      //按键抬起检测,	
			{
			  switch(Y_temp)    //判断列
			  {
				  case 0X07: Key_res=1; break;
				  case 0X0B: Key_res=2; break;
				  case 0X0D: Key_res=3; break;
				  case 0X0E: Key_res=4; break;
				  default: return 0;    //无按键按下,返回0
			  }
			 switch(X_temp)    //判断行
			  {
				 case 0X70: return Key_res+12;break;
			     case 0XB0: return Key_res+ 8;break;
                 case 0XD0: return Key_res+ 4;break;
                 case 0XE0: return Key_res;   break;
                 default: return 0;	 //无按键按下,返回0	
			 }
		 }
	 }
	}
	else
		Key_down = 0;	//按键被松开
	if(Key_res)
		Key_down = 1;	//标志按键被按下,防止重入
	return Key_res;
}
    

//-----------------------------------矩阵键盘服务(功能)子函数-------------------//
void Key16_Function(void) 
{
	if(i != 0)    //按键按下
		{
			switch(i)
			{
			  case  1: P1=0XFE;P2=0XFF;break;
			  case  2: P1=0XFD;P2=0XFF;break;
		      case  3: P1=0XFB;P2=0XFF;break;
		      case  4: P1=0XF7;P2=0XFF;break;
			  case  5: P1=0XEF;P2=0XFF;break;
			  case  6: P1=0XDF;P2=0XFF;break;
			  case  7: P1=0XBF;P2=0XFF;break;
			  case  8: P1=0X7F;P2=0XFF;break;
			  case  9: P1=0XFF;P2=0XFE;break;
			  case 10: P1=0XFF;P2=0XFD;break;
			  case 11: P1=0XFF;P2=0XFB;break;
			  case 12: P1=0XFF;P2=0XF7;break;
			  case 13: P1=0XFF;P2=0XEF;break;
			  case 14: P1=0XFF;P2=0XDF;break;
			  case 15: P1=0XFF;P2=0XBF;break;
			  case 16: P1=0XFF;P2=0X7F;break;
			  default:P1=0X00;P2=0X00;break;
			}
	}
}

//------------------------串行接收中断函数 (串行接收采用中断方式)---------------------//
void uart_isr() interrupt 4
{
	if(RI)
	{
	    RI=0;       //清除RI位
        temp1=SBUF;
        switch(temp1)
	   	 {
			   case 0x00:P4=0XFF;P2=0X01;P7=A[0];P2=0X02;P7=A[0];break;
			   case 0x01:P4=0XFE;P2=0X01;P7=A[0];P2=0X02;P7=A[1];break;
			   case 0x02:P4=0XFD;P2=0X01;P7=A[0];P2=0X02;P7=A[2];break;
			   case 0x03:P4=0XFC;P2=0X01;P7=A[0];P2=0X02;P7=A[3];break;
			   case 0x04:P4=0XFB;P2=0X01;P7=A[0];P2=0X02;P7=A[4];break;
		       case 0x05:P4=0XFA;P2=0X01;P7=A[0];P2=0X02;P7=A[5];break;
			   case 0x06:P4=0XF9;P2=0X01;P7=A[0];P2=0X02;P7=A[6];break;
			   case 0x07:P4=0XF8;P2=0X01;P7=A[0];P2=0X02;P7=A[7];break;
			   case 0x08:P4=0XF7;P2=0X01;P7=A[0];P2=0X02;P7=A[8];break;
			   case 0x09:P4=0XF6;P2=0X01;P7=A[0];P2=0X02;P7=A[9];break;
			   case 0x0A:P4=0XF5;P2=0X01;P7=A[1];P2=0X02;P7=A[0];break;
		       case 0x0B:P4=0XF4;P2=0X01;P7=A[1];P2=0X02;P7=A[1];break;
			   case 0x0C:P4=0XF3;P2=0X01;P7=A[1];P2=0X02;P7=A[2];break;
			   case 0x0D:P4=0XF2;P2=0X01;P7=A[1];P2=0X02;P7=A[3];break;
		       case 0x0E:P4=0XF1;P2=0X01;P7=A[1];P2=0X02;P7=A[4];break;
		       case 0x0F:P4=0XF0;P2=0X01;P7=A[1];P2=0X02;P7=A[5];break;
			   default:P4=0XFF;break;
		  }		
   }
	 if(TI)
    {
       TI = 0;         //清除TI位
       busy = 0;       //清零正忙标志
    }

}
//-----------------------发送串口数据(串行发送采用查询方式)-------------------------------//
void SendData(void)
{
    while(busy);          //等待前面的数据发送完成
    busy = 1;             //将正忙标志置1,
	SBUF = temp;          //串行发送
}

●P0口BUG

  刚开始按照示意图使用P0口作为矩阵键盘的检测扫描接口,并没有实现功能。过程中发现P0口部分IO口不会被正常拉低、拉高,而是产生短路。尝试之后发现,只有P01和P03会和其它P0端的IO口发生短路,其他IO口正常。
(具体分析ing)
正常拉低:
在这里插入图片描述

发生短路:
在这里插入图片描述
在这里插入图片描述
外接上拉电阻后,P01,P03的短路情况得到改变,能够被正常拉低。但是P04和P06此时却没有了电平指示(既不是高电平,低电平,也不是高阻态或者短路)
在这里插入图片描述
在这里插入图片描述

  • 6
    点赞
  • 8
    评论
  • 15
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

打赏
文章很值,打赏犒劳作者一下
相关推荐
说明:本文件夹一共提供各类编程实例200多个,由于编者水平有限,所以程序可能有BUG,希望谅解! 全部通过实际试验,正常运行!可以根据程序中的说明,调用各个部分的资源,自行试验。 ******************************************************************************** * 日期: 2007-3-25 * * 版本: 3.0 * * 作者: 深圳学林电子有限公司 专业8051单片机教学站 * * 邮箱: sxj1974@163.com * * 网站: http://www.51c51.com http://www.8951.com 更多例程请登陆网站 * ******************************************************************************** * 硬件:此程序在本公司xlisp系列单片机实验仪运行通过 * ******************************************************************************** * 【版权】 Copyright(C)深圳学林电子有限公司 www.51c51.com All Rights Reserved * * 【声明】 此程序仅用于学习与参考,引用请注明版权和作者信息! * ******************************************************************************** D:\实例\24-93储存器 D:\实例\24-93储存器\2402储存花样流水灯 D:\实例\24-93储存器\2402储存花样流水灯\C语言 D:\实例\24-93储存器\2402储存花样流水灯\C语言\2402DEN.c D:\实例\24-93储存器\2402储存花样流水灯\C语言\2402DEN.hex D:\实例\24-93储存器\2402储存花样流水灯\汇编 D:\实例\24-93储存器\2402储存花样流水灯\汇编\2402DEN.ASM D:\实例\24-93储存器\2402储存花样流水灯\汇编\2402DEN.HEX D:\实例\24-93储存器\2402开机1位计数 D:\实例\24-93储存器\2402开机1位计数\N24C02.ASM D:\实例\24-93储存器\2402开机1位计数\N24C02.HEX D:\实例\24-93储存器\2402开机次数3位计数 D:\实例\24-93储存器\2402开机次数3位计数\C语言 D:\实例\24-93储存器\2402开机次数3位计数\C语言\2402CI.c D:\实例\24-93储存器\2402开机次数3位计数\C语言\2402CI.hex D:\实例\24-93储存器\2402开机次数3位计数\汇编 D:\实例\24-93储存器\2402开机次数3位计数\汇编\2402CI.ASM D:\实例\24-93储存器\2402开机次数3位计数\汇编\2402CI.HEX D:\实例\24-93储存器\2402显示0-7 D:\实例\24-93储存器\2402显示0-7\C语言 D:\实例\24-93储存器\2402显示0-7\C语言\240207.c D:\实例\24-93储存器\2402显示0-7\C语言\240207.hex D:\实例\24-93储存器\2402显示0-7\汇编 D:\实例\24-93储存器\2402显示0-7\汇编\240207.ASM D:\实例\24-93储存器\2402显示0-7\汇编\240207.HEX D:\实例\24-93储存器\93C46储存数字 D:\实例\24-93储存器\93C46储存数字\C语言 D:\实例\24-93储存器\93C46储存数字\C语言\9346SU.c D:\实例\24-93储存器\93C46储存数字\C语言\9346SU.hex D:\实例\24-93储存器\93C46储存数字\汇编 D:\实例\2
01-LedTest -- 实现LED按照一定频率闪烁。主要用来测试LED工作是否正常。P10要接通。 02-CrossLed -- 实现花灯显示。主要学习对软件延时的使用。P10要接通。 03-FlowRight -- 实现流水灯,方向是从左向右。主要学习在C语言里如何实现准确的位操作。P10要接通。 04-FlowLeft -- 实现流水灯,方向是从右向左。主要学习在C语言里如何实现准确的位操作。P10要接通。 05-button -- 独立按键测试,实现按哪个按键然后使用对应LED显示。实现按键的检测和LED的控制。拨码开关要打到OFF位置。 06-boma -- 用LED显示拨码状态。不可以按按键。 07-Relay -- 继电器测试程序,并有LED指示同时伴有蜂鸣器的声音。P8纵向连接上面2个。 08-music -- 用C语言演奏生日快乐歌,使用软件定时。使用软件定时演奏生日快乐歌。P8纵向连接上面2个。 09-musicasm -- 用汇编语言演奏一首民歌,使用硬件定时。主要学习51定时器汇编语言编写中断功能,和如何编写中断服务程序。P8纵向连接上面2个。 10-music2 -- 用C语言中断演奏。主要学习在C语言中定义51内部定时器中断服务程序。P8纵向连接上面2个。 11-disp1234 -- 采用软件延时在数码管上显示1234ABCD。这是比较普遍的数码管显示。P14接通 12-disp1234int -- 采用硬件延时在数码管上显示1234ABCD。利用中断可以节约资源,这个程序比10更好。P14接通 13-adddec -- 使用两个按键S22,S23控制数码管上显示的数加减,具有去抖动功能。主要讲如何进行数码管动态显示并且怎样对键盘去抖动。P14接通。 14-time -- 15-alarm -- 综合实验,实现倒计时结束时使用蜂鸣器报警,编程技巧的组合。P8纵向连接上面2个。 16-uart -- UART发送和接收,实现从PC发送到单片机任何字母和数字,单片机立即向PC发送同样的字母数字可以由超级终端或者串口调试助手调试。 17-uartint -- UART接收采用不占用资源的中断接收,其余同16。推荐使用串口中断方式,使用查询方式太占用资源。 18-18b20 -- 使用温度传感器18B20测温度,并用数码管显示。P14接通。 19-1602 -- 使用LCD1602显示字符。LCD1602接到P4,方向和板子方向相反。 20-24c08 -- 对24c08进行写读操作。并把写进和读到的数用LED显示。P8纵向连接下面2个。 21-matrix -- 调试矩阵键盘,对应LED亮。注意,本程序执行需要把拨码开关打到OFF状态,程序只有矩阵键盘前两行显示,后两行请自行添加代码。 22-DS1302 -- 使用DS1302时钟芯片对预制的时间进行计时。P9横向连接左边两个。 23-chibang -- 演奏《飞舞翅膀的女孩》等音乐的综合程序。 24-wannianli -- 综合程序,用DS1302,LCD1602,温度传感器等板上设备做一个万年历。LCD1602要正确连接,P9横向连接左边两个。使能DS1302。独立按键从左到右功能为,选择设置/加/减/确定,由于去抖动功能和LCD响应时间问题,所以要按时间稍微长一点。 25-demo -- 使用RS-232实现PC与51之间通信,详细操作方法请见相关教程。 26-remote -- 红外功能测试程序,使用普通遥控器和红外接收头协同工作,用板上LED显示接收状态,LED_EN跳线必须接通,否则观察不到LED状态。 27-1602-scroll -- LCD1602动态字幕显示,方便用户理解1602的用户指令集。有时程序不正常,则为LCD1602的RAM没有清空所致,必须给板子重新上电,并按一次复位键。 28-12864 -- LCD12864显示程序。AT89S5x系列单片机需要摘掉LCD下载程序,下载完毕后插上LCD,并按复位键才可以正常显示,带着LCD下载程序会失败。STC单片机则无此问题。 29-12864-pic -- LCD12864的汉字,图形,半屏,反白及动态显示测试程序。注意事项同28。 30-adc0832 -- 扩展ADC0832调试程序,具体扩展口请见程序内说明。
本目录下提供的是《手把手教你学51单片机(C语言版)》教材中所有例程与作业习题的源代码。 请将整个目录复制到电脑硬盘上使用,如直接在光盘路径下打开工程可能会导致软件报错。 运行目录下的Clean.bat可以清理程序编译过程中产生的中间文件和临时文件。 lesson2 (第2章): 点亮一个LED示例,所在章节2.4 lesson3 (第3章): LED闪烁示例,所在章节3.5 lesson4 (第4章): 4_1:用P0口控制LED的示例,所在章节4.8 4_2:用P0口控制实现流水灯效果,所在章节4.8 4_t4:作业题4,逐次右移的流水灯效果,所在章节4.9 4_t5:作业题5,左右往复移动的流水灯效果,所在章节4.9 lesson5 (第5章): 5_1:基于定时器查询模式的LED闪烁,所在章节5.2.3 5_2:静态点亮数码管的某几段,所在章节5.3.2 5_3:数码管静态显示一位字符,所在章节5.3.3 5_t3:作业题3,定时器查询模式实现左右移动的流水灯,所在章节5.4 5_t5:作业题5,变更lesson5_3的正计数为倒计数,所在章节5.4 lesson6 (第6章): 6_1:数码管动态显示原理示例(if...else if...语句示例),所在章节6.4 6_2:数码管动态显示原理示例(switch...case...语句示例),所在章节6.4 6_3:基于中断带消隐的数码管动态显示示例,所在章节6.5 6_t4:作业题4,在lesson6_3多位数字显示的基础上不显示高位的0,所在章节6.6 6_t5:作业题5,变更lesson6_3的正计数为倒计数,所在章节6.6 lesson7 (第7章): 7_1:基于数码管计时程序的静态变量演示,所在章节7.2 7_2:点亮LED点阵上的一个点,所在章节7.3 7_3:点亮LED点阵上的一行,所在章节7.3 7_4:点亮LED点阵上的全部点,所在章节7.3 7_5:LED点阵显示静态图形,所在章节7.4 7_6:LED点阵显示纵向移动的动画,所在章节7.5.1 7_6_h:LED点阵显示横向移动的动画(掉转板子方向的取巧方式),所在章节7.5.2 7_7:LED点阵显示横向移动的动画,所在章节7.5.2 7_t3:作业题3,lesson7_6的向上移动改为向下移动,所在章节7.6 7_t4:作业题4,lesson7_7的向左移动改为向右移动,所在章节7.6 7_t5:作业题5,基于LED点阵的9~0倒计数,所在章节7.6 7_t6:作业题6,独立LED、数码管、点阵LED同时全亮,所在章节7.6 lesson8 (第8章): 8_1:基于数码管计时程序的函数调用演示,所在章节8.2 8_2:按键基本原理演示例程,所在章节8.4.3 8_3:独立按键扫描原理演示例程,所在章节8.4.3 8_4:独立按键消抖原理演示例程,所在章节8.4.4 8_5:独立按键扫描并消抖的演示例程,所在章节8.4.4 8_6:矩阵按键扫描并消抖的演示例程,所在章节8.4.5 8_7:基于矩阵按键和数码管实现的简易加法计算器,所在章节8.5 8_t4:作业题4,变更lesson8_5的递增计数为递减计数,所在章节8.6 8_t5:作业题5,在lesson8_7基础上实现简易加减计算器,所在章节8.6 lesson9 (第9章): 9_1:步进电机驱动的基础示例,所在章节9.3.3 9_2:步进电机转动任意角度的示例,所在章节9.3.4 9_3:实用的步进电机驱动示例,所在章节9.3.5 9_4:按键控制步进电机转动的示例,所在章节9.3.6 9_5:蜂鸣器驱动的基础示例,所在章节9.4 9_6:蜂鸣器演奏简单乐谱&mdash;&mdash;&ldquo;两只老虎&rdquo;,所在章节9.4 lesson10 (第10章): 10_1:基于数码管显示的数字秒表,所在章节10.1 10_2:基于PWM方式控制LED的亮度,所在章节10.2 10_3:基于PWM方式控制LED实现呼吸灯效果,所在章节10.2 10_4:交通信号灯示例,所在章节10.3 10_5:长短按键/连续按键功能实现示例,所在章节10.5 10_t3:作业题3,数码管计时与流水灯同时运行的示例,所在章节10.6 lesson11 (第11章): 11_1:
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页

打赏

#法外狂徒张三

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者