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

2020-01-20 19:11发布

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

东拼西凑的程序。
STC12C5A60S2 单片机  24M晶振,别的单片机可能要更改 串口初始化函数中波特率相关代码   与中断0 中断时间相关的代码
总体思想:在串口中断中判断数据 是否接收到 完整的帧,是则关中断。在主循环中 处理接收到的帧,处理好后开口中断。

  1. #define OUTTIME        15//两数据帧最小间隔  毫秒
  2. #define        MOD_ADDR        1 //本modbus 地址
  3. uint8        receCount;            //接收到的字节个数
  4. uint8        idata receBuf[16]; //发送接收缓冲区
  5. uint8        idata receTimeOut;                //接收超时

  6. // 串行中断程序
  7. void uartIntProc() interrupt 4
  8. {
  9.         if(RI)
  10.         {
  11.                 RI = 0;
  12.   
  13.                 if(receTimeOut==0)//两次接收的间隔时间大于OUTTIME        receTimeOut在中断中每隔1ms减1
  14.                 {
  15.                         if(receCount>3)        //如已收到的字节大于3个, 则认为已接到一帧数据,关中断  等待解析函数处理   解析函数判断 接收到的字节数与 是否超时 就可确定是否有数据包
  16.                         {                                //解析完后,接到的到字节数receCount清零
  17.                                 ES = 0;    //关串口中断        如已收到一个数据包,则要到处理好之后 由处理函数打开
  18.                                 return;
  19.                         }
  20.                         else
  21.                                 receCount = 0;
  22.                 }                                       
  23.                 receTimeOut = OUTTIME;//置计时寄存器 该寄存器 在中断0中,每隔1ms自动减1               
  24.                 receBuf[receCount] = SBUF;       
  25. //                ACC = SBUF;
  26. //                if(P != RB8)
  27. //                        checkoutError = 2;        //偶校验出错
  28.                 receCount++;          //已接收到的数据量加1
  29.                 receCount &= 0x0f;    //最多一次只能接收16个字节
  30.         }
  31. }

  32. /**************************************************************************************************
  33. NAME : function_MODBUS         //检查与处理uart0数据
  34. INPUT : NO
  35. OUTPUT : NO
  36. FUNCTION :
  37.            执行MODBUS功能函数
  38. **************************************************************************************************/
  39. void function_MODBUS(void)
  40. {
  41.         bit bt;

  42.         if(receCount > 3) //接收到的数据大于4
  43.         {                                       
  44.                 if(receTimeOut==0) // 离上次接收到数据的最大间隔时 限 已等于0
  45.                 {                               
  46.                         bt = !checkPACK_MODBUS();//        校验接收数据包的正确性        正确返回零,错误返回非零值。                         
  47.                         if((receBuf[0] == MOD_ADDR) && bt ) //是本机地址
  48.                         {       
  49.                                 switch(receBuf[1])
  50.                                 {
  51.                                         case 1://读取线圈状态(读取点 16位以内)
  52.                                                 break;
  53.                                         case 3://读取保持寄存器(一个或多个)
  54.                                                 read_reg();//读寄存器
  55.                                                 sendPACK_MODBUS( );        //将CRC加入数据尾部,并发送数据包
  56.                                                 break;
  57.                                         case 5://强制单个线圈
  58.                                         case 6://设置单个寄存器
  59.                                                    TX_NByte(receBuf,receCount);
  60.                                                 break;
  61.                                                                        
  62.                                         default:
  63.                                                 break;                       
  64.                                 }
  65.                         }
  66.                         receCount =0;//处理好数据后,接收到的字节个数清零
  67.                         ES = 1;    //开串口中断        如已收到一个数据包,则要到处理好之后才能再开接收数据                
  68.                 }  
  69.         }
  70. }
复制代码代码基本调通,已可以与 Modbus调试精灵 通信。不过有一疑问 ,在波特率9600时,理论上 “OUTTIME        15//两数据帧最小间隔  毫秒”为3ms就够,实际要设到9以上才行,好久没搞懂
modbus已调通.rar (111.63 KB, 下载次数: 339) 2013-11-14 12:58 上传 点击文件名下载附件
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。