问题:

在嵌入式系统开发中,Modbus协议是工业控制系统中广泛应用的一种协议。本题用来简单模拟Modbus协议,只需根据条件生成符合该协议的数据帧,并解析所获取的数据。
假设设备使用的协议发送数据格式如下:
<SlaveAddress, 1 Byte> <Function, 1 Byte> <Start Address, 2 Bytes> <NumberofBytes, 2 Bytes> <Checksum, 2 Bytes>
其中前四项将在输入条件中给出,最后一项为CRC校验和,需根据前四项的数据,按照CRC算法进行计算。注意数据的长度,多于1byte的高位在前,低位在后。该CRC校验算法的描述如下:
1)将CRC赋值0xFFFF。
2)取初始信息的第一个字节(8位)与CRC进行异或运算,将结果赋给CRC。
3)将CRC数据右移一位,最前位(左边)补0。
4)如果右移前,CRC最低位(最右端)为1,则将右移后的CRC与0xA001进行异或运算,且将结果赋给CRC。否则,跳过此步。
5)重复3,4步8次(即右边8位)。
6)对初始信息的下一个字节,同样执行2,3,4,5步,直到信息中所有字节都执行了同样的步骤。
7)将此时得到的CRC值的高8位和低8位交换,即得到CRC校验和。

对应的接收格式如下:
<SlaveAddress,1Byte> <Function,1Byte> <NumberofBytes,1Byte> <DataIEEE32,xByte> <Checksum,2Bytes>
其中DataIEEE32为一个或多个按IEEE754标准定义的32位浮点数,具体的数据长度由NumberofBytes项来决定(比如NumberofBytes为4,则DataIEEE32项为4 bytes,正好表示一个浮点数;如为8,则DataIEEE32项为8 bytes,可表示两个浮点数)。本题要求编程实现从IEEE32数据(如“420B999A”)到浮点数(如34.9)的转换,从而解析出浮点数值。

提示:你可以根据IEEE754标准自行设计转换算法;或者直接利用C语言float类型的实现特性:x86 linux下,gcc编译器将C语言代码“float f = 34.9;”编译成汇编代码“movl $0x420b999a, -4(%ebp)” (AT&T x86汇编格式),也就是说,单精度浮点数34.9在内存中就是由整数0x420b999a来表示的,你可以利用这一特性来完成转换。

Input
输入包含多组数据,以EOF结束
每组数据共两行。
第一行共四个十进制整数,分别为协议格式要求的:<SlaveAddress, 1 Byte>,<Function, 1 Byte>,<Start Address, 2 Bytes>,<NumberofBytes, 2 Bytes>,以逗号“,”分开。
如:1,4,40,2
其中:1为SlaveAddress;4为Function;40为Start Address;2为NumberofBytes。
第二行为符合接收格式的数据帧(16进制表示),需从其中解析所接收的数据,其长度小于64个字符,浮点数数据最多为4个(即DataIEEE32数据项最多为32bytes)。
如: 010404420B999A7405
其中:01为SlaveAddress;04为Function;04为NumberofBytes; 420B999A 为DataIEEE32;7405为Checksum。

Output
每组数据输出共两行。
第一行:根据输入结果的第一行,输出完整的符合该协议发送格式的数据帧,数据用16进制大写表示,每部分的长度都要求符合协议格式,比如Start Address项如果不到2 bytes,则需要在左边补零。
如:010400280002F1C3
其中:01为SlaveAddress;04 为Function;0028为Start Address;0002为NumberofBytes;F1C3为Checksum。

第二行:根据输入结果的第二行,依次解析IEEE32数据,将其转换成浮点数并打印结果(小数点后保留一位)。解析之前需检查CRC校验和,如校验失败则直接打印CRC_ERROR。如有多个数据,用逗号分隔。
如:34.9
该浮点值为420B999A所对应的值。

Sample Input
1,4,40,2  
010404420B999A7405  
1,4,40,2
010404420B999A7404
2,4,383,4
02040841CC0000477F2100DF85

Sample Output
010400280002F1C3
34.9
010400280002F1C3
CRC_ERROR
0204017F0004C1DE
25.5,65313.0

回答:

#include <string.h>

char strout[100], recv[100], recv_hd[100];
unsigned short slaveAdd, func, nb, startAdd;
unsigned short crc;
float result[5];
char *pt;

do_cyc(unsigned short data)
{
    int i;
    unsigned short tmp;

crc = data ^ crc;
    for (i=0 ; i<8 ; i++)
    {
        tmp = crc & (0x0001);
        crc = crc >> 1;
        if (tmp == 1)
        {
            crc = 0xa001 ^ crc;
        }
    }
}

unsigned short get_crc()
{
    crc = 0xffff;

do_cyc(slaveAdd & 0x00ff);
    do_cyc(func & 0x00ff);
    do_cyc((startAdd & 0xff00) >> 8);
    do_cyc(startAdd & 0x00ff);
    do_cyc((nb & 0xff00) >> 8);
    do_cyc(nb & 0x00ff);

unsigned short swap;
    swap = crc;
    crc = (crc >> 8) & 0x00ff;
    crc = crc | ((swap << 8) & 0xff00);
}

float conv(int data)
{
    float ret;
    memcpy(&ret, &data, sizeof(int));
    return ret;
}

void pre_handle()
{
    int i, data;
    pt = recv;
    crc = 0xffff;

strncpy(recv_hd, pt, 2);
    recv_hd[2] = '\0';
    sscanf(recv_hd, "%hX", &slaveAdd);
    pt += 2;
    do_cyc(slaveAdd & 0x00ff);

strncpy(recv_hd, pt, 2);
    recv_hd[2] = '\0';
    sscanf(recv_hd, "%hX", &func);
    pt += 2;
    do_cyc(func & 0x00ff);

strncpy(recv_hd, pt, 2);
    recv_hd[2] = '\0';
    sscanf(recv_hd, "%hX", &nb);
    pt += 2;
    do_cyc(nb & 0x00ff);

for (i=0 ; i<nb/4 ; i++)
    {
        strncpy(recv_hd, pt, 8);
        sscanf(recv_hd, "%X", &data);
        result[i] = conv(data);
        do_cyc((unsigned short)((data & 0xff000000) >> 24));
        do_cyc((unsigned short)((data & 0x00ff0000) >> 16));
        do_cyc((unsigned short)((data & 0x0000ff00) >> 8));
        do_cyc((unsigned short)(data & 0x000000ff));
        pt += 8;
    }
    unsigned short swap;
    swap = crc;
    crc = (crc >> 8) & 0x00ff;
    crc = crc | ((swap << 8) & 0xff00);
}

int main(int argc, char *argv[])
{
    char cmp[10];

while (EOF != scanf("%hd,%hd,%hd,%hd", &slaveAdd, &func, &startAdd, &nb))
    {
        get_crc();
        sprintf(strout, "%02X%02X%04X%04X%04X", slaveAdd, func, startAdd, nb, crc);
        printf("%s\n", strout);
        scanf("%s", recv);
        pre_handle(recv);
        sprintf(cmp, "%hX", crc);
        if (0 != strcmp(cmp, pt))
        {
            printf("CRC_ERROR\n");
            continue;
        }
        int i;
        for (i=0 ; i<nb/4-1 ; i++)
            printf("%.1f,", result[i]);
        printf("%.1f\n", result[i]);
    }
}

模拟Modbus协议问题的更多相关文章

  1. Socket编程之聊天程序 - 模拟Fins/ModBus协议通信过程

    设备控制软件编程涉及到的基本通信方式主要有TCP/IP与串口,用到的数据通信协议有Fins与ModBus. 更高级别的通信如.net中的Remoting与WCF在进行C/S架构软件开发时会采用. 本篇 ...

  2. 基于AVR128单纯Modbus协议实施

    Modbus通信协议Modicon公司1979在发展中,适用于工业现场总线协议控制.Modbus通信系统包含芯片的节点,并与组合物可编程控制的公共传输线,它的目的是收集和监视多个节点的数据.Modbu ...

  3. RS485通信和Modbus协议(转)

    转自:http://www.51hei.com/bbs/dpj-23230-1.html 在工业控制.电力通讯.智能仪表等领域,通常情况下是采用串口通信的方式进行数据交换.最初采用的方式是RS232接 ...

  4. 工控安全入门(一)—— Modbus协议

    modbus基础知识 modbus协议最初是由Modicon公司在1971年推出的全球第一款真正意义上用于工业现场的总线协议,最初是为了实现串行通信,运用在串口(如RS232.RS485等)传输上的, ...

  5. Modbus协议和应用开发介绍

    因业务需要了解Modbus协议的使用,因此对Modbus的协议,以及相应的C#处理应用进行了解,针对协议的几种方式(RTU.ASCII.TCPIP)进行了封装,以及对Modbus的各种功能码的特点进行 ...

  6. modbus协议开关量采集模块

    modbus协议开关量采集模块是指的使用Modbus协议的进行信号的采集与控制的一种设备. Modbus 协议设备都具有唯一的 Modbus 地址,众山 DTU 默认 Modbus 地址为 100,用 ...

  7. modbus协议讲义

        Modbus 一个工业上常用的通讯协议.一种通讯约定.Modbus协议包括RTU.ASCII.TCP.其中MODBUS-RTU最常用,比较简单,在单片机上很容易实现.虽然RTU比较简单,但是看 ...

  8. Android 模拟HTTP协议的编码问题 Android默认编码UTF-8

    Android通过GET和POST方法请求服务器和浏览器请求的过程是不一样的. 浏览器请求服务器的时候会先将中文进行UTF-8编码,然后再发送到服务器端. Android编程下我们需要通过URLEnc ...

  9. 各种非标232,485协议,自定义协议转modbus协议模块定制开发,各种流量计协议转modbus,

    工业现场经常会碰到通过485或者232采集各类仪表数据,但是很多早期的仪表和设备不支持标准modbus协议,而是采用自定义的协议,这些协议数据由plc或者dcs系统来实现采集,不仅费时麻烦,而且不方便 ...

随机推荐

  1. Unity 2D Sprite Lighting

    2D游戏中也可以使用灯光?这真是一个好消息,接下来,我将为大家写一下教程 操作步骤 1.创建一个Materilas,修改Shader为 2.创建一个Sprite(使用黑色的图片) 3.创建一个Poin ...

  2. Unity3D开发之搭建Mac OS开发环境

    运行图 首先上几张图 IOS模拟器 坚屏 横屏 打包任务 摸索了一上午,才搞定在模拟器中运行.至于在Iphone真机中运行,虽然有开发者证书,目前还没在Xcode中配置好. 我今天第一次接触并使用MA ...

  3. java 14-11 对象数组

    有5个学生,请把这个5个学生的信息存储到数组中,并遍历数组,获取得到每一个学生信息. 创建学生类: 学生:Student 成员变量:name,age 构造方法:无参,带参 成员方法:getXxx()/ ...

  4. 关于表格前面checkbox复选框不打勾的问题

    当点击左边的树节点的时候,让右边的表格自动选中相应的行,但是选中的行前面如果有checkbox,可能复选框虽然选中了但是不打上勾,解决方案,将遍历表格数据那段代码用延时器包裹一下.

  5. struts2中简单的文件上传

    2016-08-31 一.       文件上传 利用commons-fileupload-1.2.1.jar实现简单的上传文件,首先在页面上填写表单,记得加上enctype="multip ...

  6. Socket Programming in C#--Getting Started

    Getting Started You can argue that one can overcome these shortcomings by multithreading meaning tha ...

  7. Maximum Subarray

    Find the contiguous subarray within an array (containing at least one number) which has the largest ...

  8. php基础26:文件与目录1

    <meta charset="utf-8"> <?php //绝对路径 $path = "E:\AppServ\www\php\/33-catalog. ...

  9. Andorid-15k+的面试题。

    andorid开发也做了3年有余了,也面试很多加企业,借此机会分享一下,我们中遇到过的问题以及解决方案吧,希望能够对正在找工作的andoird程序员有一定的帮助. 特别献上整理过的50道面试题目 1. ...

  10. 20145316GDB调试汇编堆栈

    GDB调试例子的汇编堆栈 代码 直接-m32编译出现问题 编译64位Linux版本32位的二进制文件,需要安装一个库,使用指令sudo apt-get install libc6-dev-i386 编 ...