CodeSys中编程实现串口通讯
第一步:Linux中启用串口设备。【以树莓派4B为例】
树莓派4B有6个串口,参考上一篇《》,在 /boot/config.txt 中添加一行,开启 uart2 功能:
dtoverlay=uart2
重启后,查看是否有多出来一个 /dev/AMA1 设备:
$ ls -l /dev/tty*
crw-rw---- 1 root dialout 204, 64 Jul 20 11:52 /dev/ttyAMA0
crw-rw---- 1 root dialout 204, 65 Jul 20 11:59 /dev/ttyAMA1
crw------- 1 root root 5, 3 Jul 20 11:52 /dev/ttyprintk
crw--w---- 1 root tty 4, 64 Jul 20 11:52 /dev/ttyS0
也可以config.txt 中添加多行(uart2,uart3,uart4,uart5)启动多个串口功能 (对应 ttyAMA1,ttyAMA2,ttyAMA3 和 ttyAMA4).
可以用下面命令查看 uart2 对应的GPIO针脚映射:
# dtoverlay -h uart2
Name: uart2
Info: Enable uart 2 on GPIOs 0-3. BCM2711 only.
Usage: dtoverlay=uart2,<param>
Params: ctsrts Enable CTS/RTS on GPIOs 2-3 (default off)
从输出可见,GPIO针脚为0-3, 其中针脚0和1分别为TxD和RxD,针脚2-3为流控 CTS/RTS. 此处针脚0-1为BCM编码号,物理引脚号为27-28.
第二步: 使用python代码,测试 uart2 功能是否正确
硬件接线: 将 GPIO引脚0 和 1 短接,实现自发自收。
软件测试:python控制台中,执行如下代码测试
>>> import serial
>>> ted = serial.Serial(port="/dev/ttyAMA1", baudrate=9600)
>>> ted.write("Hello World".encode("gbk"))
11
>>> ted.read(11)
b'Hello World'
>>>
能收到字串‘Hello World’表示 uart2 功能和接线均一切正常。
第三步:编辑 CodeSys 配置文件,映射 /dev/ttyAMA* 到 COMx 端口号。
在老版本的CodeSys 中,需要编辑 "/ect/CODESYSControl.cfg" 末尾添加:
[SysCom]
Linux.Devicefile = /dev/ttyUSB
portnum := COM.SysCom.SYS_COMPORT1;
这样,在codesys中指定串口号1,代表使用的设备为 /dev/ttyUSB0, 非常不直观。
从codesys v3.5 SP15 起(据说),改为在文件 /etc/CODESYSControl_User.cfg 里这么设置:
[SysCom]
Linux.Devicefile.1=/dev/ttyS0
Linux.Devicefile.2=/dev/ttyAMA1
Linux.Devicefile.4=/dev/ttyUSB0
这样, Com1 即为 ttyS0, Com2即为 ttyAMA1, Com4 即为 ttyUSB0,依次类推。支持多个串口,方便多了。
如上面设置,映射关系 uart2 --> ttyAMA1 ---> Com2, 所以codesys中指定端口号为 2 (即Com2)即可。
第四步: CodeSys中编程实现串口收发功能
参考 youtube 上的学习视频: https://www.youtube.com/watch?v=NFREG2U07Rg
只需参考codesys编程部分即可,代码我在他基础上又做了修改完善,
(1)程序块导入3个库: Memory, Serial Communication, Util
(2)定义部分:
PROGRAM SerialPort
VAR
(*打开端口部分*)
Open_0: COM.Open;
Open_xExecute: BOOL := TRUE; //默认打开端口
aParams : ARRAY [1..7] OF COM.PARAMETER := [
(udiParameterId := COM.CAA_Parameter_Constants.udiPort, udiValue := 2),
(udiParameterId := COM.CAA_Parameter_Constants.udiBaudrate, udiValue := 9600),
(udiParameterId := COM.CAA_Parameter_Constants.udiParity, udiValue := INT_TO_UDINT(COM.PARITY.NONE) ),
(udiParameterId := COM.CAA_Parameter_Constants.udiStopBits, udiValue := INT_TO_UDINT(COM.STOPBIT.ONESTOPBIT) ),
(udiParameterId := COM.CAA_Parameter_Constants.udiTimeout, udiValue := 0),
(udiParameterId := COM.CAA_Parameter_Constants.udiByteSize, udiValue := 8),
(udiParameterId := COM.CAA_Parameter_Constants.udiBinary, udiValue := 0)
];
hCom: CAA.HANDLE;
(* read模块 *)
BLINK0: BLINK;
Read_0: COM.Read;
bReadData : ARRAY[1..80] OF BYTE;
read_szSize: CAA.SIZE;
sReadData : STRING;
(* write模块 *)
Write_0: COM.Write;
write_xExecute: BOOL; //执行write操作
bWriteData : ARRAY[1..80] OF BYTE;
sWriteData : STRING;
sWriteDataLast : STRING; //上一次 Write值
END_VAR
(3)梯形图部分
先要 打开串口 (串口参数在定义部分已预设定):

注意此处,参数 xExecute 需始终为 True,否则 会关闭串口 hCom=0 !
读串口部分的代码:

使用 blink 定期读取,读出的内容放到数组 bReadData 中,读出长度为 read_szSize.
为了防止读入空(读出为空是常态,有内容 是少数)时 覆盖掉前面值,非空时才拷贝和更新到某个string,代码如下:

这样,仅在有新内容读出时,才更新值到 sReadData 中。末尾的 MEM.MemFill() 用于写入 string 的结束字符 '\0' .
下面到了 写串口 的部分。基本思路也是差不多,字符串中有新值时,才将 字符串内容 拷贝到 数组中用于写出,并使能一次写动作,代码如下:

之后开始真正的 串口写 动作:

代码后半行,如果写成功,就把此次内容保存到 sWriteDataLast 字串里,用于下一次比较,内容不同时才触发一次 COM.Write() 写动作。
需要注意的是,若写动作发生error,会一直卡住 不更新 sWriteDataLast,所以加上并联条件 Write_0.xError , 不管成功/Error失败 均结束此次写动作!就算写失败,想再一次尝试,也必须将 sWriteData 改为其他才能再次触发 写动作。
(4)CodeSys中测试串口读写功能
若串口正确打开, 则 hCom 的值非空,否则 hCom=0 表示失败。
blink产生的信号定时读一遍数据,有新内容显示在字串 sReadData 中;
字串 sWriteData 中的内容会通过串口写出去,只有更新 sWriteData 值的瞬间才会触发一次写操作,不管是否写出成功。
以上代码,使用 树莓派4B, Codesys 3.5.18.2 ,Codesys Control for Linux ARM64 SL 测试通过。

使用树莓派 自带的 uart2 (ttyAMA1)和 usb转ttl串口(ttyUSB0) 均测试通过。
2022年7月21日
CodeSys中编程实现串口通讯的更多相关文章
- 树莓派中QT实现串口通讯
树莓派中QT实现串口通讯 开发平台为QT 此博客QT使用的为WiringPi驱动 我使用的串口调试助手为 cutecom 先简单说一些开发过程中需要注意的问题 Linux 下设备为 tty ,对应在 ...
- 用SPCOMM 在 Delphi中实现串口通讯 转
用Delphi 实现串口通讯,常用的几种方法为:使用控件如MSCOMM和SPCOMM,使用API函数或者在Delphi 中调用其它串口通讯程序.利用API编写串口通信程序较为复杂,需要掌握大量通信 ...
- C# 16进制与字符串、字节数组之间的转换(串口通讯中)
1.c#中如何将十进制数的字符串转化成十六进制数的字符串//十进制转二进制 Console.WriteLine("十进制166的二进制表示: "+Convert.ToString( ...
- VS编程,C#串口通讯,通过串口读取数据的一种方法
一.可能需要的软件:1.虚拟串口vspd(Virtual Serial Port Driver,用来在电脑上虚拟出一对串口,模拟通讯. 2.友善串口调试助手,用来发送.读取数据. 二.思路1.查询本机 ...
- 引用kernel32.dll中的API来进行串口通讯
串口通讯可以引出kernel32.dll中的API来操作,相关源码如下:using System;using System.Runtime.InteropServices; namespace Tel ...
- .Net串口通讯中的若干问题(C#多串口硬件识别、热插拔、Close方法报错问题、IsOpen的可靠性问题)
一.需求场景 最近有时间静下心来研究SDK,串口通讯的.要求实现识别cp210x和cp2303驱动的两款硬件,并且2303的优先级高,即有2303识别之,没有再识别210x:要求实现热插拔,拔掉自动断 ...
- C#中的WinFrom技术实现串口通讯助手(附源码)
C#中的WinFrom技术实现串口通讯助手(附源码) 实现的功能: 1.实现自动加载可用串口. 2.打开串口,并且使用C#状态栏显示串口的状态. 3.实现了串口的接收数据和发送数据功能. 4.串口 ...
- 西门子plc串口通讯方式
西门子plc串口通讯的三种方式 时间:2015-10-25 14:31:55编辑:电工栏目:西门子plc 导读:西门子plc串口通讯的三种方式,分为RS485 串口通信.PPI 通信.MPI 通信,自 ...
- 教程-Delphi MSComm 实时串口通讯
Delphi MSComm 实时串口通讯 MSComm控件具有丰富的与串口通信密切相关的属性,提供了对串口进行的多种操作,进而使串行通信变得十分简便.MSComm的控件属性较多,常用的属性如下:1) ...
随机推荐
- ONNXRuntime学习笔记(四)
接上一篇在Python端的onnx模型验证结果,上一篇在Pytorch和onnxruntime-gpu推理库上分别进行效果效率统计分析,结论要比最初设置的50ms高很多,这一篇我将在C++端写个测试代 ...
- Nginx实战|Nginx健康检查
开源Linux 长按二维码加关注~ 上一篇:盘点提高国内访问Github的速度的9种方案 服务治理的一个重要任务是感知服务节点变更,完成服务自动注册及异常节点的自动摘除.这就需要服务治理平台能够:及时 ...
- ElasticSearch7.3学习(二十五)----Doc value、query phase、fetch phase解析
1.Doc value 搜索的时候,要依靠倒排索引: 排序的时候,需要依靠正排索引,看到每个document的每个field,然后进行排序. 所谓的正排索引,其实就是doc values. 在建立索引 ...
- 基于.NetCore开发博客项目 StarBlog - (5) 开始搭建Web项目
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- MyBatis热部署
代码 import java.io.IOException; import java.lang.reflect.Field; import java.util.HashMap; import java ...
- unity---动画基础
旧动画系统 using System.Collections; using System.Collections.Generic; using UnityEngine; public class Mo ...
- Fastflow——基于golang的轻量级工作流框架
Fastflow 是什么?用一句话来定义它:一个 基于golang协程.支持水平扩容的分布式高性能工作流框架. 它具有以下特点: 易用性:工作流模型基于 DAG 来定义,同时还提供开箱即用的 API, ...
- 通过CSS让图片变的清楚
image { width: 100%; height: 100%; border-radius: 10upx; //让图片变清楚 image-rendering: -moz-crisp-edges; ...
- Mac 睡眠唤醒 不睡眠 问题
问题 之前一直有夜晚睡觉前电脑关机的习惯,主要是想着电脑也跟人一样️要休息.然后最近想着自己 Mac 干脆每天睡眠算了,省得每天开关机麻烦,所以就最近这段时间每次夜晚睡觉前主动去点了电脑的 「Slee ...
- 聊聊OOP中的设计原则以及访问者模式
一 设计原则 (SOLID) 1. S - 单一职责原则(Single Responsibllity Principle) 1.1 定义 一个类或者模块只负责完成一个职责(或功能), 认为&qu ...