Proteus仿真二,通过51单片机来实现虚拟串口通信,基于MODBUS_RTU协议(1)

Proteus仿真二,通过51单片机来实现虚拟串口通信,基于MODBUS_RTU协议(1)

这一章,主要介绍的是实现一帧报文的接收内容,下一章将将讲解功能码的实现问题。
本文要用到的软件需要MODBUS三套工具:
在这里插入图片描述
首先搭建电路图:
在这里插入图片描述
进行配置,首先是51单片机的晶振要选用11.0592MHz,因为这样波特率才是精准的。
在这里插入图片描述
然后就是虚拟串口对接通过 “virtual serial port driver”来进行配置
在这里插入图片描述
在这里插入图片描述
连接COM1 和 COM2。
然后配置端口,由于电脑是主机,51单片机是从机。因此,需要用“Modbus PULL”这个软件来进行配置。
在这里插入图片描述
而51单片机的串口号为COM2
在这里插入图片描述

正文:
Modbus协议其实就是通信的规则,就好比马路上的红绿灯。就拿功能码0x03来举例,0x03功能码的作用是读多个寄存器的值,如果我要读取寄存器3的值,则主机发送的报文则是01 03 00 03 00 01 xx xx,其中01我们称为从站地址,即从机的地址。03则是功能码,00 03是寄存器的地址,00 01则是你想读取的寄存器数量(因为0x03的功能就是读取多个寄存器),而xx xx是报文的校验位一般是RTU校验。好,那么如果我不仅仅想读取寄存器3的值我还想读取4,5,6寄存器的值那么报文则是01 03 00 03 00 04 xx xx。知道功能码的用途后,我们需要的就是进行编程对这些报文的每个值进行分析,并作出相应的动作,之后再发送报文给上位机这样就实现了通讯。本文的目的是实现一帧报文的接收,并且实现值得分析。

首先我们要了解什么叫帧,了解帧之前先了解RS232,这是一个硬件协议,也就是一根线
在这里插入图片描述
通过这根线实现TTL电平的转换,能和笔记本相通讯。而数据通讯的格式则是
在这里插入图片描述
我们可以看到有8个数据位,而在我们的51单片机里面是集成了UART,
可以通过SCON来进行配置
在这里插入图片描述
一般是使用模式1。
而帧就是用这样的格式信息的数字字符。一般都是无奇偶校验,无极性,一位停止位,波特率9600,俗称96-n-8-1。而Modbus则是再这样的格式下面再规定书写规范。波特率9600的意思是1秒钟有9600个二进制位的数据传输,这么快的速度下如何才能让51单片机识别一帧的内容呢?这是最重要的一点。
在这里插入图片描述
可以从图中可以看出每一帧之间其实隔着3.5个字符,所以可以理解为只要单片机没有介绍到数据达到3.5个字符就可以断定1帧报文接收完成。那3.5个字符到底是多久呢?我们以波特率9600来进行计算,我们从上文可知一字符有1个起始位,8个数据位,1个停止位,所以至少有10个位,那么3.5个字符就是35个位。又波特率是9600,所以一位的速度是1/9600 s/bit。所以
35*(1/9600)=0.003645s=3.645ms,就算他4ms。所以我们编制时只需要通过定时器定时,当没有接收到数据达到4ms以上则可断定一帧接收完成。

原理理解和硬件调试好后就可以进行软件的编写了:

main.c

#include <REGX52.H>
#include "uart.h"
#include "modbus.h"
#include "time.h"

void main(void)
{
	UART_Init(4800);
	Timer0_Init(1000); //1ms
	Modbus_Init();
	
	while(1)
	{
		UART_Echo();
	}
	
}

modbus.c

#include "modbus.h"

struct MODBUS_DEF Modbus;

void Modbus_Init(void)
{
	Modbus.SlaveID=0x01;   //从站地址
	Modbus.Cnt=0;          //接收的位数
	Modbus.Flag=0;         //启动定时器标志位
	Modbus.ReFlag=0;       //完成一帧的标志位
	Modbus.Tim=0;          //计数
}

modbus.h

#ifndef __MODBUS_H__
#define __MODBUS_H__

#include <REGX52.H>
void Modbus_Init(void);
struct MODBUS_DEF{
	unsigned char SlaveID;
	unsigned char Cnt;
	unsigned char ReBuff[50];
	unsigned char Flag;
	unsigned char Tim;
	unsigned char ReFlag;
};

extern struct MODBUS_DEF Modbus;
#endif

uart.c

#include"uart.h"
#include "modbus.h"
void UART_Init(unsigned int fre)
{
	SCON=0x50;
	PCON=0x00;
	TMOD&=0X0F;
	TMOD|=0X20;
	TH1=256-11059200/12/2/16/fre;
	TL1=256-11059200/12/2/16/fre;
	TR1=1;
	//EA=1;
	//ES=1;

}

void UART_Echo(void)
{
	while(RI==1)
	{
		if(Modbus.ReFlag==1)
			return;
		Modbus.ReBuff[Modbus.Cnt++]=SBUF;
		Modbus.Tim=0;
		if(Modbus.Cnt==1)
		{
			Modbus.Flag=1;
		}
		RI=0;
	}
	
}

uart.h

#ifndef __UART_H__
#define __UART_H__

#include <REGX52.H>
void UART_Init(unsigned int fre);
void UART_Echo(void);
void UART_SendByte(unsigned int num);

#endif

time.c

#include "time.h"
#include "Modbus.h"

void Timer0_Init(unsigned int time)
{
	TMOD&=0XF0;
	TMOD|=0X01;
	TH0=(65525-time)/256;
	TL0=(65525-time)%256;
	TR0=1;
	TF0=0;
	EA=1;
	ET0=1;
}

void Timer0_ISR(void) interrupt 1
{
	if(Modbus.Flag==1)
    {
		Modbus.Tim++;
        if(Modbus.Tim>=8)    
        {
            Modbus.Flag=0;    
            Modbus.ReFlag=1;   
         }
    }

}


time.h

#ifndef __TIME_H__
#define __TIME_H__

#include <REGX52.H>

void Timer0_Init(unsigned int time);


#endif

实验结果:
在这里插入图片描述
在这里插入图片描述
上位机发送的报文 01 03 00 03 00 04 B4 09
下位机接收的报文
在这里插入图片描述
所以实现了一帧报文的接收。

  • 17
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值