【PROTEUS-51单片机串口通信仿真】

概要

本次实验对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中断位允许

总结

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

  • 7
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值