串口服务器 linux,基于Linux的串口服务器设计与实现

2023-05-16

随着互联网的迅猛发展,在使用计算机进行网络互联的同时,各种家电设备、仪器仪表以及工业生产中的数据采集和控制设备也在逐步地走向网络化,以便共享网络资源。所以,在电子设备日趋网络化的今天,利用串口服务器来实现网络通信具有十分重要的意义。利用基于TCP/IP的串口数据流传输的实现来控制管理设备,无需投资大量的人力、物力即可完成对传统设备的管理、更换或者升级。

串口服务器的功能

串口服务器是一种通信协议转换器,它设有两类通信端口:一类是标准的RS232/422/485格式的串行端口,远程的RTU(远程终端设备)监控模块通过串行控制总线接入串口服务器的此类端口;另一类是以太网口,通过网线将串口服务器接入局域网的交换机等设备中。

串口服务器在工作中可自动将RS232/422/485格式的串行数据与基于TCP/IP协议的以太网数据包进行透明转换。一方面,串口服务器收到来自某一串行端口的现场数据,将其转换为TCP/IP格式的数据,通过以太网口进行网络上传;另一方面,串口服务器在局域网中捕获合法的数据协议包,通过解包来解析出有效的控制信息,通过监控机指定的串行端口将控制命令以串行数据的方式传送给远程RTU.

硬件平台

此系统的硬件平台如图1所示,它是以AT91RM9200芯片构建的Multibus-CPU开发板。MultiBus-CPU系统是基于AT91RM9200微控制器的智能化多总线测控系统,该系统可以建立基于Modbus-RTU总线协议的总线通信,使系统设备可以无缝地接入到基于Modbus-RTU模式的总线系统,以及可靠、实时并准确地完成工业现场的数据采集和信号输出等功能。系统支持Modbus-RTU协议,同时,系统还支持多种总线通信,包括RS485总线,工业以太网(UDP协议),串口RS232通信接口和USB通信接口。

d6af169505405cc203f3d3f4ea165e2d.png

图1:CPU模块原理图。

软件平台

本设计采用嵌入式Linux作为操作系统。ARM上的Linux的主要优势:可扩展的完整操作系统提供了可靠的多任务环境,基于开源模型(GPL),利用多种UNIX和开源应用程序以及用于基于ARM技术的多种设计(包括网络和无线领域)。

Modbus协议

Modbus协议是应用于电子控制器的一种通信语言。利用这个协议,控制器相互之间以及控制器通过网络(例如以太网)和其他设备之间进行通信。

主流的Modbus协议为标准Modbus协议(Modbus RTU协议)和Modbus TCP协议。标准的Modbus通信协议定义了报文帧的每一字节,定义了怎样将数据打包成报文帧以及如何解码。报文帧包括一个字节的地址码,一个字节的功能码,数据和两个字节的校验码。其中,校验码采用CRC校验。

Modbus TCP协议是在标准Modbus协议的基础上进一步发展而来的。它是将Modbus协议嵌入到底层TCP/IP协议中构成的,这样就在TCP/IP的以太网上实现了客户机-服务器架构的Modbus报文通信。二者的数据帧结构如图2所示。

cdc0c11ff3fc49e02c68d65cc3237e12.png

图2:标准Modbus与Modbus_TCP数据帧结构对比。

分析Modbus TCP协议和RTU协议,可以非常清楚地看出两者的主要区别。与Modbus RTU协议相比,Modbus TCP数据帧里已不再有CRC校验,而这部分校验的任务是由TCP/IP协议和以太网的链路层来完成的。另外,Modbus TCP较标准的Modbus协议还加入了一个MBAP报文头,由它来解释说明Modbus的参数和功能。其他部分两者可以互相通用。如果TCP协议转换为RTU协议,那么,只需要把TCP协议MBAP头中的“单元标识域”和后续字节组成一帧,再加上此帧的CRC校验就可以组成RTU协议,而在串行链路上进行发送。如果是RTU协议转换到TCP协议的话,那么要根据实际情况组建一个MBAP头。

获取配置信息GetConfigValue功能的设计与实现

在设计串口服务器之前,首先要配置相应的设备号并给设备配置相应的串口服务器IP地址、TCP通信端口号和串口参数等,这些配置信息放在一个txt文件当中。

我们设计了一个Configinfo。txt文件,当我们需要向一个设备传递信息时,需要首先从文件中读取配置信息,对相应的串口及工控板的网络进行配置,然后再进行相应的操作。这时,我们在其中用到了两个自定义函数:GetConfigValue和GetCFGValue.其中GetConfigValue的功能是将Configinfo。txt中的信息配置给串口服务器,它调用GetCFGValue函数,在Configinfo。txt中寻找相应的配置信息项,并截取相应的配置信息。它们的程序框图如图3(a)和3(b)所示。

7df2c2953a12bd876eec254307482def.png

图3:GetConfigValue函数程序流程图(a)和GetCFGValue函数程序流程图(b)。

串口操作函数封装的设计与实现

在对串口进行相应的操作时,首先要打开串口并配置串口的波特率、数据位、停止位和工作模式等。这些关于串口的操作都封装在一个文件当中,以使结构清晰,方便检查以及修改或增加更多的操作函数。所进行的包括以下几种操作。

串口的打开和关闭:打开串口时,需要首先判断串口的类型,然后以一定的方式打开串口并保存原来的串口配置信息,最后对串口进行波特率、数据位、停止位和奇偶校验位的设置。关闭串口时,需要将原来保存的终端信息恢复,使串口回到打开前的状态。

对串口进行数据读写:串口的读写操作是串口服务器最基本的功能,当有数据传送过来时,需要通过串口发送。写串口操作会把内存中的数据写入所指的文件,读串口操作会把串口送来的数据写入内存中。分别用writecomport和readcomport来实现。

对串口进行设置:需要设置波特率、数据位、停止位和奇偶校验位。调用定义的封装函数,来完成这些操作。串口的工作模式通过termios函数的配置来控制。

Modbus TCP/RTU相互转换功能的实现

这一步是串口服务器设计的关键,其转换重点在于CRC校验和MBPA报头的变换。在这里,定义mod2tcp函数来完成Modbus RTU到TCP格式的转换,定义tcp2mod函数来完成Modbus TCP到RTU格式的数据转换。例如,来自Modbus主站的TCP协议请求,经串口服务器转换成Modbus RTU格式,经485口发送给从站,并将从站相应数据经485接口送入串口服务器,转换成Modbus TCP格式信息返回主站(图4)。

4f53d174a744efb1c31fac2a29e991cd.png

图4:Modbus TCP/RTU相互转换示例。

程序流程如图5(a)和5(b)所示。

4ff187a45a9ab6155fb380fe7d5e3909.png

图5:Modbus RTU 到TCP格式数据转换程序流程(a)和Modbus TCP 到RTU格式数据转换程序流程(b)。

由此可见,TCP格式字节数=RTU格式字节数-2+6,获取的可用数据均相同,因此其程序实现就不再是难题了。

CRC校验功能

CRC即循环冗余校验码,它是数据通信领域中最常用的一种差错校验码。RTU方式时,CRC校验传送的全部数据,它忽略信息中单个字符数据的奇偶校验方法。CRC校验的关键在于数据的匹配,将得到的数据如何正确的套用到CRC校验当中是其中的关键。

CRC校验有既定的规则,其程序实现非常简单,只需要以下几步:CRC字节的初始化;将数据导入进行CRC计算;返回计算出的CRC值。

串口服务器的设计与实现

此部分介绍整个程序的main()函数,它会调用前文介绍的函数来实现串口服务器功能,故其头文件中要包含前文所述的各函数文件。程序流程如图6所示。

main()函数应用Linux C函数编程,其中应尤其注意socket的应用,socket要先建立再bind();在信号量中的参数要配置正确;进程的管理方面,要注意进程退出时先退出子进程,在所有进程都完成之后再关闭socket.

51591f76552c5a3f667d6b6e71d081a1.png

图6:串口服务器main()函数程序流程图。

问题及解决

串口服务器测试过程中,有时会出现TCP到RTU发送时数据包错误,不能正确地将TCP数据转换为RTU数据。

原因在于,测试过程中,Windows下的PC终端向Linux工控板发送数据,但是Windows的实时性并不很好,不能及时地发送数据,有时会出现一次发送两包数据给串口服务器的现象;另外,工控板中Linux下的TCP/IP协议剪裁封装不是很完善,导致其接收处理数据的能力比较差。

当多帧数据同时到达时,串口服务器未能正确将后一帧数据发送出去,而把一帧数据分割到两帧,导致数据帧错误。这就是发生上述数据完全错误的原因。这时,需要给串口服务器添加数据的分帧处理功能,在接收到数据时,先判断数据帧是否是有效数据帧,确保每次发送的数据都能是完整的一帧,不会出现数据帧错位,而导致数据的完全错误。

本文小结

本文的目标是在以AT91RM9200芯片构建的Multibus-CPU开发板上实现串口服务器功能。该串口服务器应用Modbus相关协议,将传统的以RS485/232串口通信设备接入工业以太网,实现上位机和设备之间的信息交互。本串口服务器程序已经能够在开发板上正确运行。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

串口服务器 linux,基于Linux的串口服务器设计与实现 的相关文章

  • 在centos中安装sqlite3 dev和其他包

    我正在尝试使用 cpanel 在 centos 机器上安装 sqlite dev 和其他库 以便能够编译应用程序 我对 debian 比 centos 更熟悉 我知道我需要的库是 libsqlite3 dev libkrb5 dev lib
  • 如何在linux中以编程方式获取dir的大小?

    我想通过 C 程序获取 linux 中特定目录的确切大小 我尝试使用 statfs path struct statfs 但它没有给出确切的大小 我也尝试过 stat 但它返回任何目录的大小为 4096 请建议我如何获取 dir 的确切大小
  • 如何阻止ubuntu在使用apt安装或更新软件包时弹出“Daemons using outdatedlibraries”? [关闭]

    Closed 这个问题是与编程或软件开发无关 help closed questions 目前不接受答案 我最近新安装了 Ubuntu 22 04 LTS 我发现每次使用 apt 安装或更新软件包时 它都会询问我有关Which servic
  • 无需超级用户即可在 Linux 中打开 RAW 套接字

    我必须编写一个在 Linux 上运行的 ping 函数 语言是 C 所以 C 也可以 在网上搜索并查看源代码ping命令 事实证明我应该创建一个原始套接字 icmp sock socket AF INET SOCK RAW IPPROTO
  • CMake 链接 glfw3 lib 错误

    我正在使用 CLion 并且正在使用 glfw3 库编写一个程序 http www glfw org docs latest http www glfw org docs latest 我安装并正确执行了库中的所有操作 我有 a 和 h 文
  • Intel 上的 gcc 中的 _mm_pause 用法

    我参考过这个网页 https software intel com en us articles benefitting power and performance sleep loops https software intel com
  • 为什么opencv videowriter这么慢?

    你好 stackoverflow 社区 我有一个棘手的问题 我需要你的帮助来了解这里发生了什么 我的程序从视频采集卡 Blackmagic 捕获帧 到目前为止 它工作得很好 同时我用 opencv cv imshow 显示捕获的图像 它也工
  • 使用 python 脚本更改 shell 中的工作目录

    我想实现一个用户态命令 它将采用其参数之一 路径 并将目录更改为该目录 程序完成后 我希望 shell 位于该目录中 所以我想实施cd命令 但需要外部程序 可以在 python 脚本中完成还是我必须编写 bash 包装器 Example t
  • 错误:“rjags”的包或命名空间加载失败

    在终端的 conda 环境之一中 我能够成功安装包 rjags 但是 当我在该环境中运行 R 并运行库 rjags 时 出现以下错误 加载所需的包 coda 错误 rjags 的包或命名空间加载失败 rjags 的 loadNamespac
  • Linux 为一组进程保留一个处理器(动态)

    有没有办法将处理器排除在正常调度之外 也就是说 使用sched setaffinity我可以指示线程应该在哪个处理器上运行 但我正在寻找相反的情况 也就是说 我想从正常调度中排除给定的处理器 以便只有已明确调度的进程才能在那里运行 我还知道
  • cdc_acm:无法设置 dtr/rts - 无法与 USB cdc 设备通信

    我试图使用 pic24fj128gb206 枚举 usb cdc 设备 设备似乎已正确枚举 但是当我将设备连接到 Linux PC 时 我从内核收到以下警告消息 cdc acm 1 8 1 6 7 1 0 failed to set dtr
  • 复制目录内容

    我想将目录 tmp1 的内容复制到另一个目录 tmp2 tmp1 可能包含文件和其他目录 我想使用C C 复制tmp1的内容 包括模式 如果 tmp1 包含目录树 我想递归复制它们 最简单的解决方案是什么 我找到了一个解决方案来打开目录并读
  • 无法显示 Laravel 欢迎页面

    我的服务器位于 DigitalOcean 云上 我正在使用 Ubuntu 和 Apache Web 服务器 我的家用计算机运行的是 Windows 7 我使用 putty 作为终端 遵循所有指示https laracasts com ser
  • 嵌入式 Linux – 部署固件更新的机制? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在考虑在 Yocto 项目上开发一个嵌入式 Linux 项目 一个工业应用程序 我有几个问题想问那些有嵌入式 Linux 经验的人 Y
  • 研究缓冲区溢出时应该使用哪些版本的 GCC 或标志?

    最近 作为计算机工程专业的本科生 我一直在研究缓冲区溢出 出于兴趣 我开始研究缓冲区溢出 但在尝试在我的计算机上用 GCC 4 9 1 在 Debian Jessie 中 编译的我自己的 C 程序中实现它们时遇到了困难 我听说较新的编译器中
  • 如何wget目录中最新的文件

    我想编写一个 bash 脚本来下载并安装最新的每日构建程序 RStudio 是否有可能使wget仅下载目录中最新的文件http www rstudio org download daily desktop http www rstudio
  • 具有多处理功能的 Python 代码无法在 Windows 上运行

    以下简单的绝对初学者代码在 Ubuntu 14 04 Python 2 7 6 和 Cygwin Python 2 7 8 上运行 100 但在 Windows 64 位 Python 2 7 8 上挂起 我使用另一个片段观察到了同样的情况
  • 来源和出口有什么区别?

    我正在编写一个 shell 脚本 以读取具有 key value 对的文件并将这些变量设置为环境变量 但我有疑问 如果我这样做source file txt是否会将该文件中定义的变量设置为环境变量 或者我应该逐行读取文件并使用导出命令设置它
  • 如何在Linux中自动启动需要X的应用程序

    我试图在系统进入运行级别 5 时自动启动 X 应用程序 这样做的正确方法是什么 我写了一个脚本并将其放在 etc init d 中 我已运行适当的 chkconfig 命令来设置 etc rcX d 目录中的符号链接 一切工作正常 除了当我
  • 在 C 中运行 setuid 程序的正确方法

    我有一个权限为4750的进程 我的Linux系统中存在两个用户 root 用户和 appz 用户 该进程继承以 appz 用户身份运行的进程管理器的权限 我有两个基本惯例 void do root void int status statu

随机推荐