PROTEUS-51单片机串口通信仿真教程

proteus-51单片机仿真之双机通信

  • 概要
  • 仿真实图
  • 程序
  • 知识链接
  • 1、串口相关寄存器
  • SCON串口控制寄存器
  • TCON定时器控制寄存器
  • TMOD定时器/计数器模式控制寄存器
  • PCON电源控制寄存器
  • IE中断使能寄存器
  • 总结
  • 概要

    本次实验对51单片机的串口进行了双机通信的仿真,实现了51单片机的简单双机通信;现对本次仿真的结构及实现的功能做简要的介绍,
    本次仿真主要构成:主机U1-MASTER、从机U2-SLAVE、以及LED显示部分(第一部分显示主机接收到的信息、第二部分显示从机接收到的信号);
    实现的功能:主机通过串口发送信息给从机,从机接收到信息后通过从机旁边LED显示;从机通过串口发送信息给主机,主机收到后通过旁边LED显示。
    简单的通信协议:通信双方均选用9600波特的传输速率,系统的主频为11.0952MHz,主机的呼叫号为0,即主机地址;从机的呼叫号为1,即从机地址,发送的数据以$为结束符号;通信时发送的数据为两部分,一是通信对象,二是内容。

    仿真实图

    1、主机部分:
    主机及LED显示
    2、从机部分: 从机部分及LED显示
    3、仿真效果图
    主机发送”168;从机发送"2$"给主机,显示过程与主机的一样。

    程序

    1、主机程序
    

    uart.c

    #include "uart.h"
    
    u8 RXstart; //开始接收
    u16 RXData; //接收数据位
    u16 temp[10] = {0};  //数组接收
    int j = 0;
    
    
    //串口初始化,定时器1模式2,波特率为9600bps,晶振频率11.592MHz
    void UartInit()
    {
    	SCON = 0XD0;  //串口模式3,主从+波特率可变,允许接收,清空收发中断标志位
    								//主机SM2不置位,从机SM2要置位
    	
    	TMOD = 0x20;  //设置定时器1为模式2,8位自动重装载模式
    	TH1 = 0xfd;   //波特率计算式:[256-(K*Fosc)/(384*BaudeRate)]h
    	TL1 = 0XFD;   
    	TR1 = 1;     //开定时器1中断
    	
    	REN = 1;  //允许串口接收
    	PCON &= 0X7F; //禁止波特率倍增K=1;
    	ES = 1;   //开串口中断
    	
    	EA = 1;   //开总中断
    	
    }
    
    //主机数据发送函数以$结束,主机先发地址TB8=1,后发数据TB8=0;
    void UartSendData(u8 addr,u8 *str)
    {
    
    	TB8 = 1;  //发送地址
    	SBUF = addr;  //通过SBUF发送出去
    	while(!TI);  //判断是否发送成功,成功发送TI被置1,要手动复位
    	TI = 0;  //复位
    	
    	TB8 = 0;  //发送数据
    	while(*str != '\0')  //发送数组
    	{
    		SBUF = (*str);
    		while(!TI);  //判断是否发送完一组数据
    		TI = 0;
    		str++;
    	}
    }
    
    
    //主机接收数据,串口中断服务函数
    void UartRData() interrupt 4  //串口中断服务函数
    {
    	
    	ES = 0;  //关闭串口中断
    	
    	if(RI)   //再判断是否接收到数据,接收到数据RI会被置1
    	{
    		RXData = SBUF;  //接收数据
    		
    		if(RXData == MasterAddr0)  //判断是否呼叫本机
    		{
    			RXstart = 1;  //开始接收数据
    			SM2 = 0;      //配置为接收数据模式
    			j = 0;
    		}
    
    		if(RXstart) //判断是否接收过本地址
    		{
    			if(RXData != '$')  //判断是否接收到数据结束标志$
    			{
    				temp[j] = RXData;  //没有接收到结束标志$,正常保存数据
    				j++;
    			}
    			else   //接收到数据结束标志$
    			{
    				RXstart = 0;  //数据接收结束
    				SM2 = 1;   //重新配置为只接收地址,下次发送TB8=1才中断
    				j = 0;
    			}
    		}
    	}
    	RI = 0;  //清除接收中断标志位
    	ES = 1;  // 开串口中断
    }
    

    uart.h

    #ifndef __UART_H
    #define __UART_H
    
    #include "reg52.h"
    
    #ifndef u16
    #define u16 unsigned int
    #endif
    
    #ifndef u8
    #define u8 unsigned char
    #endif
    
    #define MasterAddr0 0   //主机号/地址
    
    extern u16 temp[10];  //数组接收
    
    
    
    void UartInit();
    void UartSendData(u8 addr,u8 *str);
    void UartRData();
    
    
    
    
    #endif
    

    main.c

    #include "reg52.h"
    #include "uart.h"
    
    //从机地址SlaveAddr:0~9
    #define SlaveAddr1 1   //从机号(地址)
    
    extern u16 temp[10];  //数组接收
    #define LED P0
    
    void delay(u16 i);
    
    
    void main()
    {
    	u8 i;
    	
    	UartInit();
    	while(1)
    	{
    		
    		UartSendData(SlaveAddr1,"168$");
    		
    		for(i=0;i<10;i++)
    		{
    			LED = temp[i];
    			delay(50000);
    		}
    	}
    }
    
    void delay(u16 i)
    {
    	while(i--);
    }
    
    
    
    2、从机程序
    

    uart.c

    #include "uart.h"
    
    u8 RXData;  //接收数据
    u8 RXstart; //接收标志
    u16 temp[10] = {0};  //数据缓存
    int j;
    
    
    //串口初始化函数,定时器1模式2,波特率9600bps,晶振频率11.0592MHz
    void UartInit()
    {
    	SCON = 0XF0; //串口模式3,SM2接收地址,允许接收EN,清空收发标志
    	
    	TMOD = 0X20; //定时器1模式2,8位重装载模式
    	TH1 = 0XFD;
    	TL1 = 0XFD;
    	TR1 = 1; //开定时器中断1
    	
    	PCON &= 0X7F;  //波特率不倍增
    	ES = 1;  //开串口中断
    	EA = 1;  //开总中断
    	
    }
    
    
    //从机发送函数,从机发送给主机的数据帧要以字符‘0’开头,标识这是发给主机的
    void SendData(u8 addr,u8 *str)
    {
    	TB8 = 1;//发送地址
    	SBUF = addr;  //通过SBUF发送出去
    	while(!TI);  //判断是否发送成功
    	TI = 0;  //清除发送中断标志位
    	TB8 = 0;  //发送数据
    	
    	while(*str != '\0')  //发送数组
    	{
    		SBUF = (*str);
    		while(!TI);
    		TI = 0;
    		str++;
    	}
    }
    
    //从机数据接收函数,$是结束标志
    void ReData() interrupt 4  //串口中断服务函数
    {
    	ES = 0;  //关闭串口中断
    	
    	if(RI)  //再判断是否接收到数据
    	{
    		RXData = SBUF;  
    		if(RXstart)  //判断是否接收过本地址
    		{
    			if(RXData != '\$')  //判断是否接收到结束标志$
    			{
    				temp[j] = RXData;  //没有接收到$,正常接收数据
    				j++;
    			}
    			else
    			{
    				RXstart = 0;  //本次接收结束
    				SM2 = 1;  //重新配置为只接收地址,下次发送TB8=1才中断
    				j = 0;
    			}
    		}
    		if(RXData == SlaveAddr)  //判断是否呼叫本机,地址范围:000-254(00-FE)
    		{
    			RXstart = 1;   //开始接收数据
    			SM2 = 0;      //配置为接收数据模式
    			j = 0;
    		}
    	}
    	
    	RI = 0;  //清除接收中断标志位
    	ES = 1;  //重开串口中断
    }
    
    
    
    
    

    uart.h

    #ifndef __UART_H
    #define __UART_H
    
    #include "reg52.h"
    
    #ifndef u16
    #define u16 unsigned int
    #endif
    
    #ifndef u8
    #define u8 unsigned char
    #endif
    
    #define SlaveAddr 1  //从机号/地址
    
    extern u16 temp[10];  //数据缓存
    
    
    
    void UartInit();
    void SendData(u8 addr,u8 *str);
    void ReData();
    
    
    
    
    #endif
    
    
    

    main.c

    #include "reg52.h"
    #include "uart.h"
    
    #define MasterAddr0 0  //主机号(地址)
    
    extern u16 temp[10];  //数据缓存
    
    #define LED P0
    
    void delay(u16 i);
    
    void main()
    {
    	u8 i;
    	
    	UartInit();
    	while(1)
    	{
    		
    		for(i=0;i<10;i++)
    		{
    			LED = temp[i];
    			delay(50000);
    		}
    		SendData(MasterAddr0,"2$");
    	}
    }
    
    void delay(u16 i)
    {
    	while(i--);
    }
    
    
    

    知识链接

    1、串口相关寄存器

    SCON串口控制寄存器;
    TCON定时器控制寄存器
    TMOD定时器/计数器模式控制寄存器
    PCON电源控制寄存器
    IE中断使用寄存器
    串口相关寄存器

    SCON串口控制寄存器

    SCON
    串口工作方式
    SM0、SM1:串口工作方式控制位
    SM2:多机通信控制位(方式2、3),1允许,0不允许
    REN:允许/禁止串行接收控制位
    TB8:要发送的第9位数据,由软件清零,多机通信中地址(1)或数据(0)标志位
    RB8:接收到的第九位数据
    TI:发送中断请求标志位,软件复位
    RI:接收中断请求标志位,软件复位

    TCON定时器控制寄存器

    定时器计数器0、1相关寄存器
    TF1:定时器/计数器1溢出标志
    TR1:定时器1运行控制位,软件控制
    TF0:定时器/计数器0溢出标志
    TR0:定时器0运行控制位,软件控制
    IE1:外部中断1使能位
    IT1:外部中断1触发方式控制位
    IE0:外部中断0使能位
    IT0:外部中断0触发方式控制位

    TMOD定时器/计数器模式控制寄存器

    GATE:定时器1门控制位
    C/T:计数器/定时器1选择位
    M1、M0:定时器计数器1模式控制位
    后四位为定时器0相关位

    PCON电源控制寄存器

    PCON
    SMOD:波特率选择位,1加倍,0不加倍

    IE中断使能寄存器

    IE
    EA:总中断允许位
    ES:串口中断允许位
    ET1:定时器1溢出中断允许位
    EX1:外部中断1中断位允许
    ET0:定时器0溢出中断允许位
    EX0:外部中断0中断位允许

    总结

    这一个拖了好久,一直没整,原因就不多说了,归纳了一下:还是要多尝试,试错的成本可能不低,但错过机会的成本更高,所以还是要多去尝试,不管结果如何。试过总是还是有机会的,没试过就一定没机会。
    感觉还不是很熟悉,还是要多看多练习,多总结。

    物联沃分享整理
    物联沃-IOTWORD物联网 » PROTEUS-51单片机串口通信仿真教程

    发表评论