【單片機】— {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);		//[email protected] 串行口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)		//[email protected]
{
	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此時卻沒有了電平指示(既不是高電平,低電平,也不是高阻態或者短路)
在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章