搜索
bottom↓
回复: 5

超简单的用状态机实现的modbus从机模式来啦

[复制链接]

出0入0汤圆

发表于 2019-1-9 13:05:33 | 显示全部楼层 |阅读模式
本帖最后由 zhanan 于 2019-1-9 13:14 编辑

上次写了个主机模式:  https://www.amobbs.com/forum.php ... amp;_dsign=c924640c

从机模式和主机模式不一样,从机模式是被动的,收到相关的信息后,处理然后回传,接着再等待。
用状态机的写法是一样的,主要是功能处理要啰嗦一些。我把常用的功能收到什么、回传什么整理好了,照着套吧。

不多说了,上图,然后上程序

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

 楼主| 发表于 2019-1-9 13:06:07 | 显示全部楼层
void mb_gncl(void);  // 功能处理

#define MBID 2 /* 从机站号 */
#define MBZJG 1 /* 帧间隔时间(按波特率调整) */
#define MBSIZE 14  /* 缓存大小 */
uchar mmbbuf[MBSIZE]; // mod缓存
uchar mmbgs;  // mod数据个数,从1开始
uchar mmbjs;  // mod帧间计时(用于判断帧尾)/出错码/mod发送指针(从0开始)
uchar mmbzt;  // mod状态

#define DEkz PORTD.2 /* PD2为485发送控制 */
#define Dreg UDR     /* 收发数据寄存器 */
/***/
interrupt [USART_RXC] void mb_rx(void)  // 接收缓存非空中断
{
  uchar nrxd=Dreg; // 读接受缓存
  if(mmbzt<=2)
  {
    mmbjs=0;  // 复位帧间计时
    switch (mmbzt)
    {
      case 0:
        mmbgs=1;
        mmbbuf[0]=nrxd; // 站点ID
        if(nrxd==MBID) mmbzt=1; else mmbzt=2; // 是本机站号转后续字节,否则等待帧结束
        break;
      case 1:
        if(mmbgs<(MBSIZE-1)) mmbbuf[mmbgs++]=nrxd; else mmbzt=2; // 装入后续字节,超量则等待帧结束
        break;
    }
  }
}
/***/
interrupt [USART_TXC] void mb_tx(void)  // TXC发送完成中断 DRE→Dreg空中断
{
  同主机模式
}
/***/
void mb_zjjs(void)  // 帧间计时判断
{
  同主机模式
}
/***/
void mb_slave(void)
{
  uint ncrc;
  if(mmbzt==8) // 收到一帧数据
  {
    if(mmbgs>=5) // 至少5字节
    {
      if(mb_crc16(mmbbuf,mmbgs)==0) // crc校验正确
      {
        mmbjs=0;  // 出错码清0
        mb_gncl(); // 功能处理
        if(mmbjs) // 如果有错误
        {
          mmbbuf[1]|=0x80; // 功能码最高位置1
          mmbbuf[2]=mmbjs; // 错误码
          mmbgs=3;
        }
        ncrc=mb_crc16(mmbbuf,mmbgs); // 计算crc
        mmbbuf[mmbgs++]=ncrc;    // crc低字节
        mmbbuf[mmbgs++]=ncrc>>8; // crc高字节
        mmbjs=0; // 发送指针
        DEkz=1; Dreg=mmbbuf[mmbjs++]; // 485芯片DE高电平,启动发送
        mmbzt=6; // 置为发送状态
        return;
      }
    }
    mmbzt=0; // 回空闲状态
  }
}
/***/

出0入0汤圆

 楼主| 发表于 2019-1-9 13:06:48 | 显示全部楼层
/*** 从机模式功能处理 ***/
void mb_gncl(void)  // 功能处理,若出错则mmbjs为错误码
{
  switch (mmbbuf[1])  // 按功能码转
  {
    case 1: case 2:  // 读n个线圈、读n个位输入
        // 处理
          // buf[2][3] 线圈/位首地址
          // buf[4][5] 线圈/位个数
          // ......
        // 回传
        mmbbuf[2]=1;  // 回传字节数=n/8+1
        mmbbuf[3]=mxsd; // 显示灯  线圈/位7-0 ,0对应线圈/位首地址
        mmbgs=4;
        break;
    case  5:  // 写1个线圈
        // 处理
          // buf[2][3] 线圈地址
          // buf[4]: 0xFF 置1,0x00 置0
          // buf[5]: 0x00
          // ......
        // 回传:原样回传
        mmbgs=6;  //
        break;
    case 15:  // 写n个线圈
        // 处理
          // buf[2][3] 线圈首地址
          // buf[4][5] 线圈个数
          // buf[6] 数据字节数
          // buf[7]=0x00; // 线圈位7-0 ,位0对应线圈首地址
          // buf[8]=0x00; // 15-8
          // ......
        // 回传:前6个字节(buf[0]-[5])原样回传
        mmbgs=6;  //
        break;
    case  3: case 4:  // 读n个、读1个寄存器
        // 处理
          // buf[2][3] 寄存器首地址
          // buf[4][5] 寄存器个数,读一个=1
          // ......
        // 回传
        mmbbuf[2]=2;  // 回传字节数,读一个寄存器字=2
        mmbbuf[3]=mwd>>8; // 温度值高字节
        mmbbuf[4]=mwd;    // 温度值低字节
        mmbgs=5;
        break;
    case  6:  // 写1个寄存器
        // 处理
          // buf[2][3] 寄存器地址
          // buf[4][5] 寄存器数据
          // ......
        mwd=((uint)mmbbuf[4]<<8)|mmbbuf[5];  // 改写温度值
        // 回传:原样回传
        mmbgs=6;
        break;
    case 16:  // 写n个寄存器
        // 处理
          // buf[2][3] 寄存器首地址
          // buf[4][5] 寄存器个数
          // buf[6] 数据字节数
          // buf[7][8]  寄存器1数据
          // buf[9][10] 寄存器2数据
          // buf[11][12]寄存器3数据
          // ......
        mwd=((uint)mmbbuf[7]<<8)|mmbbuf[8];  // 改写温度值
        // 回传:前6个字节(buf[0]-[5])原样回传
        mmbgs=6;
        break;
    default:  // 无效功能
        mmbjs=1; // 功能码错误
        break;
  } // endcase
}
/***/

出0入0汤圆

发表于 2020-6-28 11:01:35 | 显示全部楼层
这种处理方式 比较好  我喜欢

出0入0汤圆

发表于 2020-9-15 15:27:55 | 显示全部楼层
非常不错,

出235入8汤圆

发表于 2022-3-11 11:39:36 | 显示全部楼层
mmbzt = 8    时,是在哪里处理的。如果状态为8时,UART接收中断是否需要中止接收数据
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-27 04:22

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表