51单片机RS485通讯程序仿真与MODBUS RTU静止时间详解

发布者:数字小巨人最新更新时间:2019-12-16 来源: 51hei关键字:51单片机  RS485通讯  MODBUS  RTU  静止时间 手机看文章 扫描二维码
随时随地手机看文章

仿真原理图如下

由于MODBUS-RTU 要求每帧信息中的数据间隔时间不得超过1.5字符的静止时间。 

因此: 
(1)、当串口产生接收中断后,立即重装“超时定时器”的初始值。(注:超时定时器的初始值和波特率有关) 

问题如下:  
(a)、由于要求在串口接收中断中重装超时定时器初始值,那么,该超时定时器就只能采用“溢出模式”,而不能采用“CTC模式” 
(b)、超时定时器必须在程序初始化时就一直开启。 
我的理解对吗? 

(2)两帧之间的3.5字符的静止时间该如何实现呢? 
接收到每个字节的时候,初始化定时器就行,最后一个字节后,定时器就溢出了
利用单独的软件定时器,来判断一帧接收报文结束,可以防止若报文接收不完整,该帧通信任务无法结束而影响下一帧的接收。 

由于一帧报文中字节与字节之间的时间间隔和帧与帧之间的时间间隔相比要小得多,因此每当接收一个新字节,就启动软件定时器开始计时,定时器的时间设定为帧与帧的最小时间间隔。波特率不同,该时间间隔也不同。若不到预定的时间内又接收到下一个字节,则说明一帧报文未结束,定时器重新计时;若定时器顺利计数到预定时间,就会触发相应的中断号,在该定时器中断子程序中设定帧结束标志字节,表明一帧报文接收完毕。当主程序内检测到一帧报文接收完毕后,会通过核查从方地址及循环冗余校验字节是否正确来判断该帧的有效性。若确定接收到的是一帧发送给已方的正确报文,则会根据报文内的功能码对该帧命令进行相应的处理,并准备发送帧。

上面就是解决以下两个问题的方法 
(1)、当前帧两个字节之间的1.5字符静止时间 
(2)、两帧之间3.5字符的静止时间 

这里有个SPI串口扩展芯片uCSU122P,内置MODBUS引擎,DIP28,或许对你有用点击此处下载  (原文件名:ucmu2_dat_v122.pdf)

其实这个时间不用这么准确啦,因为是问答式的协议,你可以以某个定时时间查询串口缓冲区字符的长度,如果两次读入的长度一样就认为一帧结束了,这个查询间隔根据波特率微调,就是3.5个字符时间。


7楼的做法不严格,如果第一次定时查询的时候正在收最后一个字节,第二次查显然收完了,第三次查数据不变,那么就导致了7个字符的间隔,如果对方在3.5~7字符之间又来了数据,就麻烦了; 

T1.5和T3.5最严格的方法还是开定时器,但是可以灵活一点;低波特率(<19200)的时候严格定时,和波特率相关;高波特率(>19200)的时候就固定定时(T1.5=750us,T3.5=1750us),这样降低了CPU中断响应的负担。
给你这个程序片段应该可以解决你的问题,我的程序经过严格的测试,高扫描周期、波特率19200下连续运行了一个星期,没出一个错误 


#pragma interrupt_handler Timer1:iv_TIMER1_OVF  
void Timer1(void) 

  unsigned short CRC; 
  TCNT1=65525-51*11;//65535-(11*(ubbr+1)) 波特率9600   
  if(CNT<8) 
  { 
     CNT++;        
     if(CNT==4) 
     { 
    ModBusQueryDataLong=IsrCount; 
    IsrCount=0; 
     } 
     else if(CNT==8) 
     {    
    if(ModBusQueryDataLong>2) 
{  
    
       CRC=CRC16((unsigned char *)&ModbusFunctionUnion,ModBusQueryDataLong-2); 
   if((ModbusFunctionUnion.Data[ModBusQueryDataLong-2]==MSB(CRC))&& 
          (ModbusFunctionUnion.Data[ModBusQueryDataLong-1]==LSB(CRC))) 
{   
              FrameStatu=1; 
    }    
    }    
     } 
  }   

#pragma interrupt_handler UART_isr:iv_USART0_RX 
void UART_isr(void) 
{  
  CNT=0;  
  while(!(UCSR0A&(1<  ModbusFunctionUnion.Data[IsrCount++]=UDR0; 




单片机源程序如下:

/*------------------------------------------------------------------------------

MEASURE.C:  Remote Measurement Recorder using the C51 COMPILER


Copyright 1990-2005 Keil Software, Inc.

------------------------------------------------------------------------------*/

#include "includes.h"


sbit       CS=P1^0;                                  //看门狗端口

sbit       ctrl_485=P1^5;         //RS485控制端口


unsigned char RxBuf[LenRxBuf];           //接收缓冲区

unsigned char *inRxBuf,*outRxBuf; //接收缓冲区指针

/***************判断静止字符**************/

unsigned char  time_3;

unsigned char  time_2;

bit                  rt_rxbuf; 

bit                   rt_ctrl;

/***************接收字符**************/

unsigned char  ComBuf[MaxLenComBuf+1] ;

unsigned char  ch;

unsigned char  k1;

unsigned char  n1;

int          i=-1;

int State=StatInputCom;



/*

*********************************************************************************************************

*                                                                                 串口初始化函数

*********************************************************************************************************

*/

void InitSerial()

{

        TMOD=TMOD&0x0F;

        TMOD=TMOD|0x20;

        TH1=0xF4;//2400 , 11.0592MHz

        TL1=0xF4,

        SCON=0x50;PCON=0x00;

        TR1=1;

}

/*

*********************************************************************************************************

*                                                             缓冲区初始化(只定义接收缓冲区)

*********************************************************************************************************

*/

void InitSerialBuffer(void)                   //串口缓冲区初始化

{

        inRxBuf=RxBuf;outRxBuf=RxBuf;

        ctrl_485=0;                              //接收模式

        ES=1;

        EA=1;

}

/*

*********************************************************************************************************

*                                                                  定时器函数

*********************************************************************************************************

*/

void timefunc(void)

{        unsigned char k;

        unsigned char *tt;


        if(!rt_ctrl)  time_2++;          //判断静止时间,配合下面添加结束符

    time_3++;


        if(time_2>20&&!rt_ctrl)

        {   //ES=0;

                for(k=0;k<4;k++)

                {

                        tt=inRxBuf;tt++;                        //数据暂存        5555

                        if(tt==RxBuf+LenRxBuf) tt=RxBuf;        //                5555

                        if(tt==outRxBuf) {break;}          //如果缓冲期满停止加结束标志  5555

                        else

                        {

                                if(k==0)*inRxBuf=0x4A ;

                                if(k==1)*inRxBuf=0x59 ;

                                if(k==2)*inRxBuf=0x48 ;

                                if(k==3)*inRxBuf=0x59 ;

                                inRxBuf=tt;

                        }        //          5555

                }        

                         rt_ctrl=1;

                                                         //  ES=1;                                                          

        }


//        time_1++;

//        time_4++;//接收数据时间判断


}

/*

*********************************************************************************************************

*                                                                串口接收

*********************************************************************************************************

*/

void serial(void) //串口中断服务子程序

{  

        unsigned char *t;


        if(RI)

        {

                RI=0;

                if(time_3>4)   //判断静止时间

                { time_3=0;

                        //         rt_rxbuf=0;

                        rt_rxbuf=1;        // if(SBUF==0x01)rt_rxbuf=1;

                                        // time_3的作用是为判断静止字符之后必须为i本机地址,否则不接受数据,判断下一个静止字符 

                }

[1] [2] [3]
关键字:51单片机  RS485通讯  MODBUS  RTU  静止时间 引用地址:51单片机RS485通讯程序仿真与MODBUS RTU静止时间详解

上一篇:51单片机汇编学习例程(1)——KEY篇
下一篇:自己制作的单片机万年历 程序+原理图

推荐阅读最新更新时间:2024-11-09 17:11

51单片机心形灯实现串口通信编程
心形灯原理图 编译软件:Keil uVision5 (如有需要可点此链接下载:https://download.csdn.net/download/qq_36931762/11343174) 单片机程序下载软件:STC-ISP (如有需要可点此链接下载:https://download.csdn.net/download/qq_36931762/11343157) 程序代码: 灯状态处于0亮1灭 发送方: #include reg52.h sbit k1=P3^2; sbit k2=P3^3; sbit k3=P3^4; sbit k4=P3^5; #define LED1 P0 #define LED2 P2
[单片机]
<font color='red'>51单片机</font>心形灯实现串口通信编程
51单片机上用定时器实现按键长按、短按功能
我们在项目中常常需要在只有一个按键的情况下,来实现长按执行某个功能,短按执行另一个功能。 鉴于此,用51搭的核心板实测,亲测可行。好了,废话少说,简单粗暴,直接贴上程序结构。 主函数() { } 在进入while大循环中,先要配置定时器。 在while中核心是:使用两个if块判断,第一个if块判断按键是否按下,在第一个if块里面只进行按键按下标志位设置和定时器计数。 在第二个if块里根据第一个if块定时器计数来执行长短按功能,记得在退出第二个if块时,按键按下标志位(press_flag)和定时器 计数变量(count)都要清零。 …… 定时器配置和中断服务程序就不贴出来了。
[单片机]
在<font color='red'>51单片机</font>上用定时器实现按键长按、短按功能
51单片机-输入捕获
1.捕获高电平时间 我们利用定时器0的计数功能实现捕获外部引脚的高电平时间。定时器在不同用法里有不同称呼,比如我们这次是想得知某段过程持续了多长时间,用定时器的计数方式的话就叫做计数器。 我们这次选用的外部引脚还是P1.6,初始时先让该引脚输出低电平。 我们之前没有说过当TMOD低四位里的第三位GATE为1时是什么作用,这里说明一下,当这个位被置1的话,如果此时有“TR0=1;”,且P3.2必须为高电平的时候,才会触发定时器0的计数(P3.2为低电平时不会触发),也就是TL0每隔(12/11059200)秒就会加1,加到256变为0之后TH0就加1。一直加到65535就会有“TL0=255;”和“TH0=255;”,再加
[单片机]
<font color='red'>51单片机</font>-输入捕获
基于MCS-51单片机的三个存储空间及划分解析
1.前言 MCS-51的存储器有片内RAM、片外RAM 和 ROM 三个空间。 MCS-51单片机在物理结构上有四个存储空间 1、片内程序存储器(片内ROM) 2、片外程序存储器(片外ROM) 3、片内数据存储器(片内RAM) 4、片外数据存储器(片外RAM) 在逻辑上(即从用户的角度上)MCS-51单片机有三个存储空间 1、片内外统一编址的64K的程序存储器(ROM)地址空间(MOVC) 2、256B的片内数据存储器(片内RAM)的地址空间(MOV) 3、以及64K片外数据存储器(片外RAM)的地址空间(MOVX) 注:在访问三个不同的逻辑空间时,应采用不同形式的指令以产生不同的存储器空间的选通信号。 2.存储空间划分
[单片机]
51单片机学习:DAC模数转换实验
实验名称:DAC模数转换实验 接线说明: 实验现象:下载程序后,DAC(PWM)模块上的指示灯DA1呈呼吸灯效果,由暗变亮再由亮变暗 注意事项: ***************************************************************************************/ #include public.h #include pwm.h /******************************************************************************* * 函 数 名 : main * 函数功能 : 主函数 * 输 入 : 无 * 输
[单片机]
利用C51单片机模拟SPI进行双机通信
1.1SPI协议简述 SPI,是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。由Motorola首创。SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工,同步的通信总线。 优缺点: 1.协议简单,相对数据速率高。 2.占用的Pin口较多 3.没有指定的流控制,没有应答机制确认是否接收到数据。 SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。也是所有基于SPI的设备共有的,它们是SDI,SDO,S
[单片机]
利用C<font color='red'>51单片机</font>模拟SPI进行双机通信
MCS51单片机的数据复制程序(ASM)
MCS51单片机的数据复制程序(ASM) ;内部RAM数据复制程序 ;入口 :R0,R7 ;占用资源:A ;堆栈需求:2字节 ;出口 :R1 IBMOV :MOV A,R0 ADD A,R7 MOV R0,A MOV A,R1 ADD A,R7 MOV R1,A IBM1 :DEC R0 DEC R1 MOV A,@R0 MOV @R1,A DJNZ R7,IBM1 RET ;外部RAM数据复制程序 ;入口 :ADDPH,ADDPL,R7 ;占用资源:ACC ;堆栈需求:2字节 ;出口 :R0
[单片机]
51单片机系列——通过位运算符来实现流水灯
基础知识 1)首先认识一个寄存器(例如P1)占一个字节,而一个字节多数是8位,例如P1 = 11111111,即P1^0 到P1^7都是1。 我们可以看成一个字节的二进制数代表我们的8个IO口如下表所示 2)其次要知道LED灯为1时(LED = 1)即高电平,灯熄灭。相反(LED = 0)低电平,则灯亮。 3)移位运算符效果: /*默认P1 = b11111111*/ P1 = P1 1 ; /*执行一次结果为 11111110 ,即整体左移一位 最右边用低电平0来替代 */ 4)头文件intrins的函数使用 _crol_(xx,m) xx寄存器字符循环左移m位 _cror_(xx,m) xx寄存
[单片机]
<font color='red'>51单片机</font>系列——通过位运算符来实现流水灯
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved