gmajvfhpa 发表于 2013-11-14 12:58:04

51单片机 调试通过的 modbus RTU 源码

本帖最后由 gmajvfhpa 于 2013-11-14 13:25 编辑

东拼西凑的程序。
STC12C5A60S2 单片机24M晶振,别的单片机可能要更改 串口初始化函数中波特率相关代码   与中断0 中断时间相关的代码
总体思想:在串口中断中判断数据 是否接收到 完整的帧,是则关中断。在主循环中 处理接收到的帧,处理好后开口中断。
#define OUTTIME        15//两数据帧最小间隔毫秒
#define        MOD_ADDR        1 //本modbus 地址
uint8        receCount;          //接收到的字节个数
uint8        idata receBuf; //发送接收缓冲区
uint8        idata receTimeOut;                //接收超时

// 串行中断程序
void uartIntProc() interrupt 4
{
        if(RI)
        {
                RI = 0;

                if(receTimeOut==0)//两次接收的间隔时间大于OUTTIME        receTimeOut在中断中每隔1ms减1
                {
                        if(receCount>3)        //如已收到的字节大于3个, 则认为已接到一帧数据,关中断等待解析函数处理   解析函数判断 接收到的字节数与 是否超时 就可确定是否有数据包
                        {                                //解析完后,接到的到字节数receCount清零
                                ES = 0;    //关串口中断        如已收到一个数据包,则要到处理好之后 由处理函数打开
                                return;
                        }
                        else
                                receCount = 0;
                }                                       
                receTimeOut = OUTTIME;//置计时寄存器 该寄存器 在中断0中,每隔1ms自动减1               
                receBuf = SBUF;       
//                ACC = SBUF;
//                if(P != RB8)
//                        checkoutError = 2;        //偶校验出错
                receCount++;          //已接收到的数据量加1
                receCount &= 0x0f;    //最多一次只能接收16个字节
        }
}

/**************************************************************************************************
NAME : function_MODBUS       //检查与处理uart0数据
INPUT : NO
OUTPUT : NO
FUNCTION :
           执行MODBUS功能函数
**************************************************************************************************/
void function_MODBUS(void)
{
        bit bt;

        if(receCount > 3) //接收到的数据大于4
        {                                       
                if(receTimeOut==0) // 离上次接收到数据的最大间隔时 限 已等于0
                {                               
                        bt = !checkPACK_MODBUS();//        校验接收数据包的正确性        正确返回零,错误返回非零值。                       
                        if((receBuf == MOD_ADDR) && bt ) //是本机地址
                        {       
                                switch(receBuf)
                                {
                                        case 1://读取线圈状态(读取点 16位以内)
                                                break;
                                        case 3://读取保持寄存器(一个或多个)
                                                read_reg();//读寄存器
                                                sendPACK_MODBUS( );        //将CRC加入数据尾部,并发送数据包
                                                break;
                                        case 5://强制单个线圈
                                        case 6://设置单个寄存器
                                                   TX_NByte(receBuf,receCount);
                                                break;
                                                                       
                                        default:
                                                break;                       
                                }
                        }
                        receCount =0;//处理好数据后,接收到的字节个数清零
                        ES = 1;    //开串口中断        如已收到一个数据包,则要到处理好之后才能再开接收数据                
                }
        }
}
代码基本调通,已可以与 Modbus调试精灵 通信。不过有一疑问 ,在波特率9600时,理论上 “OUTTIME        15//两数据帧最小间隔毫秒”为3ms就够,实际要设到9以上才行,好久没搞懂

oufuqiang 发表于 2013-11-14 13:00:47

纯顶支持。

rantingting 发表于 2013-11-14 13:04:23

关中断就不能保证每一帧都能接收到了啊

zhuangchao12 发表于 2013-11-14 13:06:18

支持搂主,学习一下

gmajvfhpa 发表于 2013-11-14 13:07:49

rantingting 发表于 2013-11-14 13:04 static/image/common/back.gif
关中断就不能保证每一帧都能接收到了啊

在已接收到的一帧没处理前,确实是这样的。也想知道这样处理还会有什么别的不良后果

rantingting 发表于 2013-11-14 13:09:32

gmajvfhpa 发表于 2013-11-14 13:07 static/image/common/back.gif
在已接收到的一帧没处理前,确实是这样的。也想知道这样处理还会有什么别的不良后果 ...

开缓冲区吧,中断一直接收,主程序读程序就行,不会丢数据,需要耗一些ram

gmajvfhpa 发表于 2013-11-14 13:12:48

rantingting 发表于 2013-11-14 13:09 static/image/common/back.gif
开缓冲区吧,中断一直接收,主程序读程序就行,不会丢数据,需要耗一些ram ...

嗯,这是个好办法。一般要开几个帧的缓存?
谢谢

smartmeter 发表于 2013-11-14 13:33:58

只有接收中断,发送不在中断的发

gmajvfhpa 发表于 2013-11-14 13:36:15

smartmeter 发表于 2013-11-14 13:33 static/image/common/back.gif
只有接收中断,发送不在中断的发

发送在 处理函数内

smartmeter 发表于 2013-11-14 13:44:47

在处理函数发,发送时就不能做别的事情了,程序结构不好。

gmajvfhpa 发表于 2013-11-14 13:56:44

smartmeter 发表于 2013-11-14 13:44 static/image/common/back.gif
在处理函数发,发送时就不能做别的事情了,程序结构不好。

这还真是个不足,看到人家代码就是在 中断中发送的,还以为没什么用,把它改过来了{:mad:}

pcwinner 发表于 2013-11-14 15:21:10

中断中发可以的,关键是你怎样处理数据。。。。。用发送中断吧!

WM_CH 发表于 2013-11-14 16:03:15

介个Modbus调试精灵我收了。谢谢 呵呵呵

rantingting 发表于 2013-11-14 17:03:48

gmajvfhpa 发表于 2013-11-14 13:12 static/image/common/back.gif
嗯,这是个好办法。一般要开几个帧的缓存?
谢谢

看你ram大小了,我一般开5个帧以上,{:lol:} ,如果你能及时处理数据,帧又比较大的话,其实两个帧就够了,因为串口还是比较慢的

ouyangchao 发表于 2013-11-14 19:18:37

路过收下,

jetli 发表于 2013-11-14 21:03:43

{:sweat:} 少了3个dll,精灵没法运行! 是偶的系统问题? 顺便传上来:


SCS_Super 发表于 2013-12-30 21:53:52

收了!非常感谢

519382868 发表于 2014-3-7 18:15:14

最近在学习Modbus,学习学习

Smartist 发表于 2014-3-12 12:17:51

感谢分享,楼主继续给力

lastwesting 发表于 2015-2-1 02:31:03

非常感谢分享!

chaojikoushuige 发表于 2015-2-1 10:47:35

我有个传感器是modbus通信的

lonesomely 发表于 2015-2-7 16:22:18

关中断易造成接收数据丢失,可以采用乒乓缓冲方法

远远的路 发表于 2015-2-10 19:25:43

一直在研究这方面的东西,学习学习。非常感谢
页: [1]
查看完整版本: 51单片机 调试通过的 modbus RTU 源码