基于Proteus仿真51单片机串口通讯实验

一、实验目的 1.掌握单片机串行口通信的程序设计,及简易三线式通讯的方法。 
2.了解实现串行通讯的硬环境、数据格式的协议、数据交换的协议。 
3.学习串口通讯的中断方式的程序编写方法。 
4.进一步熟悉利用 PROTEUS、Keil uVision5 等软件进行单片机系统仿真设计的方法。
二、实验任务 
1.基本任务 
(1)已知甲机接 8 个开关,乙机接 8 个发光二极管,利用它们的串口方式 1,波
特率自定义,实现:将甲机中 8 个开关所代表的数据传送到乙机,并在乙机的 8 个 LED
灯显示。请在 Proteus 中画出电路原理图,并编写程序仿真实现上述功能。 
(2)已知单片机的 P0 口接了 8 个发光二极管 LED0~LED7,现要求通过单片机的
串口收发上位机的命令,实现对这 8 个发光二极管的控制。PC 端采用串口调试程序进
行数据发送(如使用 stc-isp 烧写软件向单片机发送“88 FB AF XX FC FC”6 个字节的
命令,其中“88 FB AF”及“FC FC”为数据的帧头和帧尾,“XX”为 00~07 数据。 )单片机
使用串口中断进行数据接收,同时需要判断帧头和帧尾的正确性。判断帧头和帧尾完毕
后,若正确的话再判断“XX” 数据,对应“XX” 数据对 LED0~LED7 进行点亮、熄灭控
制;若不正确丢掉数据, 转入等待接收。 请在 Proteus 中画出电路原理图,并编写程
序仿真实现上述功能。 
2.拓展任务 
在以上基本任务 1 的基础上,奇校验,实现甲机和乙机的全双工通信,即甲机和乙
机都分别接 8 个开关和 8 个发光二极管,甲机 8 个开关所代表的数据能传送到乙机并在
乙机的 8 个 LED 灯显示,同时乙机 8 个开关所代表的数据能传送到甲机并在甲机的 8
个 LED 灯显示,若校验出错则指示灯(自定义)闪烁。请在 Proteus 中画出电路原理图,
并编写程序仿真实现上述功能。 

 

//-----------------------发送端---------------------------//
#include  "STC15.H" 
bit busy=0;
//-----------------------串口初始化子函数-------------------------//
void Uart1_Init(void)	 //[email protected]         
{
	SCON = 0x40;		//8位数据,可变波特率 方式1 
	AUXR |= 0x40;		//定时器1时钟为Fosc,即1T
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设定定时器1为16位自动重装方式
	TL1 = 0xE0;		//设定定时初值
	TH1 = 0xFE;		//设定定时初值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
	ES = 1;     //启动串口中断
}
//-----------------------数据发送子函数---------------------------//
void SendData(unsigned char dat)
{
  while(busy);   
  SBUF=dat;     
  busy=1;      
}
//---------------------------中断函数------------------------------//
void UART1_isr (void) interrupt 4
{
  if(TI)        
  { 
    TI=0;    //清除标志位           
    busy=0;  //清除忙标志位              
  }
}
//---------------------------主函数------------------------------//
void main()                                    
{ 
  Uart1_Init();   //串口初始化
  EA=1;	    //打开总中断
  while(1)
	{
		SendData(P1);   //发送P1口数值
	}
}
//-----------------------接收端---------------------------//
#include  "STC15.H" 
unsigned int temp; 
//-----------------------串口初始化子函数-------------------------//
void Uart1_Init(void)	 //[email protected]         
{
	SCON = 0x50;		//8位数据,可变波特率 REN=1处于接受状态
	AUXR |= 0x40;		//定时器1时钟为Fosc,即1T
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设定定时器1为16位自动重装方式
	TL1 = 0xE0;		//设定定时初值
	TH1 = 0xFE;		//设定定时初值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
	ES = 1;     //启动串口中断
}
//-------------------------中断函数------------------------------//
void UART1_isr (void) interrupt 4
{
  if(RI)                                      
   {
	   RI=0;    //标志位清0
		 temp=SBUF;   //数据暂存
		 P0=temp;		 //P0接收发送端数据
   }
}
//---------------------------主函数------------------------------//
void main()                                    
{ 
  Uart1_Init();    //串口初始化
  EA=1;	     //打开总中断
  while(1);
}

#include "stc15.h" 
#define uchar unsigned int      //对数据类型进行声明定义
volatile bit Flag=0;
uchar i,val;
uchar arr[6];
//-----------------------串口初始化子函数-------------------------//
void Uart1_init()  //[email protected]
{	
	PCON &= 0x7F;   //波特率不加倍控制/帧错误检测
	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
	ES=1;       // 串口1中断打开
	EA=1;       //全局中断使能
}
//---------------------------中断函数------------------------------//
void Uart1_INT() interrupt 4
{
	ES=0;      //串口1中断关闭
	if(RI)
	{
	Flag=1;    //接收到数据,接收标识符有效
	RI=0;      //串口接收标志位清0
	arr[i]=SBUF;      //将接收到的数据赋给数组中判断        
	if(arr[i]==0x88)  //判断数组
     {
        arr[0]=arr[i];
        i=0;
     }
     i++;
     if(i==6)
       {
        i=0;
        if(arr[0]==0x88&&arr[1]==0xFB&&arr[2]==0xAF&&arr[4]==0xFC&&arr[5]==0xFC)
        {
            val=arr[3];
             switch (val)
            {
                case 0x00:P0=0XFE;break;
                case 0x01:P0=0XFD;break;
                case 0x02:P0=0XFB;break;
                case 0x03:P0=0XF7;break;
                case 0x04:P0=0XEF;break;
                case 0x05:P0=0XDF;break;
                case 0x06:P0=0XBF;break;
                case 0x07:P0=0X7F;break;
            } 
        }
      }
	}
	 ES=1;             // 串口1中断打开
}
//---------------------------主函数------------------------------//
void main()
{
	Uart1_init();      //串口初始化
	while(1);          //循环运行
}

#include "stc15.h"
#include "intrins.h"
volatile bit Flag=1;
//---------------------------延时函数------------------------------//
void Delay150ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	_nop_();
	i = 7;
	j = 78;
	k = 167;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
//-----------------------串口初始化子函数-------------------------//
void Uart1_Init(void)		//[email protected]
{
	SCON = 0x90;		//9位数据,方式2,可变波特率,带TB8/RB8奇偶校验位
	AUXR |= 0x40;		//定时器1时钟为Fosc,即1T
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设定定时器1为16位自动重装方式
	TL1 = 0xE0;		  //设定定时初值
	TH1 = 0xFE;			//设定定时初值
	ET1 = 0;				//禁止定时器1中断
	TR1 = 1;				//启动定时器1
	ES = 1;     		//使能串口中断
	EA=1;           //全局中断使能
}
//-------------------------数据发送函数-----------------------------//
/*********************************************************************
 * 由于PSW中的P可以表达累加器ACC中“1”的个数奇偶性,P=1,A中“1”的个数为 *
 * 奇数,P=0,A中“1”的个数为偶数                                       *
 *********************************************************************/
void Send_Data(unsigned char dat)
{
	ACC=dat;    //将数据赋给累加器ACC
	TB8=P;      //发送从累加器得到的第9位数据
	SBUF=dat;   //发送数据到数据缓冲器
	while(TI==0);//当TI标志位等于零时 
	TI=0;       //TI标志位清零
}
//-------------------------数据传送函数-----------------------------//
void UART1_Puts(void)
{
	if(Flag)
	{
		ES=0;       //串口1中断关闭
		Send_Data(P1);  //发送P1接收到的数据
		ES=1;       //串口1中断开启
		Flag=0;     //清除接收标识符
	}
}
//---------------------------中断函数------------------------------//
void Uart1_Isr(void) interrupt 4
{
	ES=0;         //串口1中断关闭
	if(RI)			  //RI为1,接收数据
	{
		RI=0;		    //RI标志位清零
		Flag=1;     //接收到数据,接收标识符有效
		if(RB8==1)	//接收第9位数据校验结果是否为奇数
		{
			P0=SBUF;  //将接收到的数据赋给P0端
		}
		else 				//校验结果不为奇数时,出错执行P0端LED全亮全灭
		{
				P0=0x00;
				Delay150ms();
				P0=0xFF;
				Delay150ms();
		}
	}
		if(TI)			//TI为1,发送数据
	{
		TI=0;		    //TI标志位清零
	}
	  ES=1;       //串口1中断打开
}
//---------------------------主函数------------------------------//
void main()
{
	Uart1_Init();	  //串口初始化
	while(1)        //循环运行
	{
		UART1_Puts(); //数据传送
	}
}

猜你喜欢

转载自blog.csdn.net/u010356933/article/details/106931607