Modebus通信协议 温控器示例

2024-06-05 12:36

本文主要是介绍Modebus通信协议 温控器示例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1 指令解释

2 获取动态的CRC

3 crc在线验证

4 16进制正负温度互转

4.2 16进制转温度

4.2 温度转16进制

5 完整工具类


最近安卓工作接了很多硬件,其他的都是发个固定指令,比较有代表性就是温控器和打印机自定义内容所以这个记录接入示例,纯搞安卓或者没有搞过的同学可能还是有点云里雾里,因为很多参数需要自己算,我这里记录一下,有什么疑问留言讨论

1,指令解释

注意协议可能有所不同,但协议思想是差不多 我们以为例

01(从机地址) 03(功能码) 00 00(温度查询) 00 01(寄存个数) 84 0A(校验码 动态)为查询温度举例    

参数(例)含义解释
0x01 从机地址为1基本固定 查厂家文档确认下
0x03 功能码读一个寄存器查询 功能表     
0X0014 起始地址为20 查询地址 20转16进制为14,这里举例20 是为了解释16进制的 
0X0001寄存个数1 基本固定 查厂家文档确认下
0X**CRC16低位CRC根据前面12位生成
0X** CRC16高位CRC根据前面12位生成

    

2,获取动态的CRC

注意这里是说01 03 00 00 00 01生成的84 0A,如果我们写入程序中则需要动态计算,因为前面的参数根据功能不同在变化,所以后面也是变化的,我理解这其实简单理解类似请求参数加密,确保参数没有更改。

傻瓜式使用示例

1.确定 01 03 00 00 ** ** ** ** 地址和功能码

2.再确定 01 03 00 00 00 01 ** ** 转化好的温度

3.再将01 03 00 00 00 01 丢入 getCRC 为 84 0A高低位已经替换到

4.所以查询温度直接输入 01 03 00 00 00 01 84 0A

  /*** 计算CRC16校验码** @param bytes* 字节数组* @return [String] 校验码* @since 1.0*/fun getCRC(bytes: ByteArray): String {// CRC寄存器全为1var CRC = 0x0000ffff// 多项式校验值val POLYNOMIAL = 0x0000a001var i: Intvar j: Inti = 0while (i < bytes.size) {CRC = CRC xor (bytes[i].toInt() and 0x000000ff)j = 0while (j < 8) {if (CRC and 0x00000001 != 0) {CRC = CRC shr 1CRC = CRC xor POLYNOMIAL} else {CRC = CRC shr 1}j++}i++}// 结果转换为16进制var result = Integer.toHexString(CRC).uppercase(Locale.getDefault())if (result.length != 4) {val sb = StringBuffer("0000")result = sb.replace(4 - result.length, 4, result).toString()}//高位在前地位在后//return result.substring(2, 4) + " " + result.substring(0, 2);// 交换高低位,低位在前高位在后return result.substring(2, 4) + " " + result.substring(0, 2)}

3,crc在线验证

CRC(循环冗余校验)在线计算_ip33.com,注意上面的代码已为你交换好了

查询温度

4,16进制正负温度互转

单次温度查询返回结果示例

origin: {"bRec":[1,3,2,0,-26,57,-50],"sComPort":"/dev/ttyS1","sRecTime":"08:47:29"}

Hex: 010302 00E6 39CE

温度Hex: 00E6

温度解析: 23.0 ℃

前后缀去掉拿到数据,返回数据暂时就不验证了直接用,先转16进制再转10进制,因为单位是0.1℃除以10得到℃,但这个温度存在负数,所以咱们还需要解决 温度和进制转化的问题,不仅在查询的时候需要,再设置温度的时候也更需要  反过来所以下面看看互转

4.2 16进制转温度

例 -25.2=0XFF04 25.2=0X00FC -100.0=0XFC18 500.0=0X1388

首先得判断正负数有的地方是根据FF即16进制极值,而我这里根据实际需求判断一个F即可,

然后负数按位取反+1,inv和~取反你们也可以试试 我这里比较直接,不知道是不是版本问题,先这样算,这里的文档厂家标为0.1℃所以还要除以10

      println("hexToTemp FF04:${hexToTempString("FF04")}℃")println("hexToTemp 00FC:${hexToTempString("00FC")}℃")println("hexToTemp FC18:${hexToTempString("FC18")}℃")println("hexToTemp 1388:${hexToTempString("1388")}℃")/*** 16进制带正负转化为10进制*/private fun hexToTempString(hex: String): Float {println("")println("")println("--------------->$hex")// 判断16进制字符串是否为正负val isNegative = hex.uppercase().startsWith("F")// 如果是负数则转为二进制再按位取反再然后得到10进制数值并加上-号return if (isNegative) {val num = hexToIntTemp(hex)// 除10保留两位小数,单位为0.1℃(-num * 100.00f / 1000)} else {val num = hex.toInt(16)(num * 100.00f / 1000)}}/*** 按位取反+1 获取负数问题*/private fun hexToIntTemp(hex: String): Int {// 将 16 进制转换为二进制val binaryString = hex.toInt(16).toString(2)println("binary:$binaryString")// 按位取反val binaryStringInverted = binaryString.map {if (it == '0') '1' else '0'}.joinToString("")println("binaryInverted:$binaryStringInverted")// 两个二进制字符串相加val sum = binaryStringInverted.toInt(2) + 1println("+1:$sum")return sum}

打印结果

4.2 温度转16进制

举例设置温度为1℃

傻瓜式使用示例

1. 01 06 ** ** ** ** ** ** 功能码 06为写入

2. 01 06 00 14 ** ** ** **  地址 为20转化16进制为00 14

3. 01 06 00 14 00 01 1℃转化(看下面)000A

3. 01 06 00 14 00 0A  getCRC获取验证码 49 C9

4.所以查询温度直接输入 01 06 00 14 00 0A 49 C9

如果失败请检查机器是否有最大最小温度限制

分别用tempToHexString方法验证1和2转化16进制,再用上面的方法验证-2的ffec是否正确

  println("tempToTemp 1℃:${tempToHexString("1")}")println("tempToTemp -2℃:${tempToHexString("-2")}")println("验证-2℃ 逆转 ffec:${hexToTempString("ffec")}℃")/*** 整数直接转16进制负数 -1 按位取反*/private fun tempToHexString(num: String): String {println("")println("")println("--------------->$num")val toFloat = num.toFloat()// 将℃转化为0.1℃val toInt = (toFloat* 10).toInt()if (toInt >= 0){// int 转16进制return toInt.toString(16).uppercase().padStart(4, '0')}else{val temp = abs(toInt) -1println("temp-1:${temp}(0.1温度)")// 不足16位进进行0补全val tempBinary = temp.toString(2).padStart(16, '0')println("binary:${tempBinary}")// 按位取反val binaryStringInverted = tempBinary.map {if (it == '0') '1' else '0'}.joinToString("")println("binaryInverted:${binaryStringInverted}")return  binaryStringInverted.toLong(2).toString(16).uppercase()}}

5,完整工具类

package 改为自己的import 改为自己的log your.LogUtils
import java.util.Locale
import kotlin.math.absobject TempUtils {/*** 业务举例 设置温度封装* @param 温度只支持整数(结合实际需求也可以支持小数)*/fun setTemp(temp: String): String {// 功能地址前缀val header = "01 06 00 14"val tempToHexString = tempToHexString(temp)val start = "$header$tempToHexString"LogUtils.log("start:$start")val crc = getCRC(start)LogUtils.log("crc:$crc")val instruct = "$start $crc"LogUtils.log("setTemp:$temp---------------> \ninstruct:$instruct")return instruct}/*** 整数直接转16进制负数 -1 按位取反 单位℃*/private fun tempToHexString(num: String): String {LogUtils.log("")LogUtils.log("")LogUtils.log("--------------->$num")val toFloat = num.toFloat()// 将℃转化为0.1℃val toInt = (toFloat * 10).toInt()if (toInt >= 0) {// int 转16进制return toInt.toString(16).uppercase().padStart(4, '0')} else {val temp = abs(toInt) - 1LogUtils.log("temp-1:${temp}(0.1温度)")// 不足16位进进行0补全val tempBinary = temp.toString(2).padStart(16, '0')LogUtils.log("binary:${tempBinary}")// 按位取反val binaryStringInverted = tempBinary.map {if (it == '0') '1' else '0'}.joinToString("")LogUtils.log("binaryInverted:${binaryStringInverted}")return binaryStringInverted.toLong(2).toString(16).uppercase()}}/*** 16进制带正负转化为10进制*/fun hexToTempString(hex: String): Float {LogUtils.log("")LogUtils.log("")LogUtils.log("--------------->$hex")// 判断16进制字符串是否为正负val isNegative = hex.startsWith("F")// 如果是负数则转为二进制再按位取反再然后得到10进制数值并加上-号return if (isNegative) {val num = hexToIntTemp(hex)(-num * 100.00f / 1000)} else {val num = hex.toInt(16)(num * 100.00f / 1000)}}/*** 按位取反+1 获取负数问题*/fun hexToIntTemp(hex: String): Int {// 将 16 进制转换为二进制val binaryString = hex.toInt(16).toString(2)LogUtils.log("binary:$binaryString")// 按位取反val binaryStringInverted = binaryString.map {if (it == '0') '1' else '0'}.joinToString("")LogUtils.log("binaryInverted:$binaryStringInverted")// 两个二进制字符串相加val sum = binaryStringInverted.toInt(2) + 1LogUtils.log("+1:$sum")return sum}/*** MODBUS协议 CRC16校验码*/fun getCRC(data: String): String {var data = datadata = data.replace(" ", "")val len = data.lengthif (len % 2 != 0) {return "0000"}val num = len / 2val para = ByteArray(num)for (i in 0 until num) {val value = data.substring(i * 2, 2 * (i + 1)).toInt(16)para[i] = value.toByte()}return getCRC(para)}/*** 计算CRC16校验码** @param bytes* 字节数组* @return [String] 校验码* @since 1.0*/fun getCRC(bytes: ByteArray): String {// CRC寄存器全为1var CRC = 0x0000ffff// 多项式校验值val POLYNOMIAL = 0x0000a001var i: Intvar j: Inti = 0while (i < bytes.size) {CRC = CRC xor (bytes[i].toInt() and 0x000000ff)j = 0while (j < 8) {if (CRC and 0x00000001 != 0) {CRC = CRC shr 1CRC = CRC xor POLYNOMIAL} else {CRC = CRC shr 1}j++}i++}// 结果转换为16进制var result = Integer.toHexString(CRC).uppercase(Locale.getDefault())if (result.length != 4) {val sb = StringBuffer("0000")result = sb.replace(4 - result.length, 4, result).toString()}//高位在前地位在后//return result.substring(2, 4) + " " + result.substring(0, 2);// 交换高低位,低位在前高位在后return result.substring(2, 4) + " " + result.substring(0, 2)}}

这篇关于Modebus通信协议 温控器示例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1033073

相关文章

zeroclipboard 粘贴板的应用示例, 兼容 Chrome、IE等多浏览器

zeroclipboard单个复制按钮和多个复制按钮的实现方法 最近网站改版想让复制代码功能在多个浏览器上都可以实现,最近看网上不少说我们的代码复制功能不好用的,我们最近将会增加代码高亮等功能,希望大家多多支持我们 zeroclipboard是一个跨浏览器的库类 它利用 Flash 进行复制,所以只要浏览器装有 Flash 就可以运行,而且比 IE 的

基于SpringBoot的宠物服务系统+uniapp小程序+LW参考示例

系列文章目录 1.基于SSM的洗衣房管理系统+原生微信小程序+LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统+LW参考示例 3.基于SpringBoot+Vue的企业人事管理系统+LW参考示例 4.基于SSM的高校实验室管理系统+LW参考示例 5.基于SpringBoot的二手数码回收系统+原生微信小程序+LW参考示例 6.基于SSM的民宿预订管理系统+LW参考示例 7.基于

Spring Roo 实站( 一 )部署安装 第一个示例程序

转自:http://blog.csdn.net/jun55xiu/article/details/9380213 一:安装 注:可以参与官网spring-roo: static.springsource.org/spring-roo/reference/html/intro.html#intro-exploring-sampleROO_OPTS http://stati

Java http请求示例

使用HttpURLConnection public static String httpGet(String host) {HttpURLConnection connection = null;try {URL url = new URL(host);connection = (HttpURLConnection) url.openConnection();connection.setReq

2.3多任务编程示例1

1.CUBEMAX配置  2.CODE void StartTask1(void const * argument){/* USER CODE BEGIN StartTask1 */TickType_t pxPreviousWakeTime=xTaskGetTickCount();/* Infinite loop */for(;;){LED1_Turn();// vTaskDelay

mongodb基本命令和Java操作API示例

1.Mongo3.2 java API示例:http://www.cnblogs.com/zhangchaoyang/articles/5146508.html 2.MongoDB基本命:http://www.cnblogs.com/xusir/archive/2012/12/24/2830957.html 3.java MongoDB查询(一)简单查询: http://www.cnblogs

【CH395的简单示例代码】

提供一个基于CH395的简单示例代码,这里将展示如何初始化CH395,并发送一个简单的HTTP请求。请注意,实际使用时还需要根据具体的硬件平台和开发环境调整代码。 假设我们使用的是一个具有SPI接口的微控制器,并且已经将CH395连接到该控制器上。下面是一个使用C语言编写的伪代码示例,展示了如何初始化CH395并通过其发送HTTP请求: #include <stdio.h>#include

CPU亲和性设置 代码示例 sched_setaffinity sched_getaffinity

视频教程在这: cpu亲和性设置,NCCL,sched_setaffinity sched_getaffinity,CPU_ZERO、SET、ISSET、linux_哔哩哔哩_bilibili 一、CPU亲和性简介 CPU亲和性(CPU Affinity)设置是操作系统中一个重要的性能优化手段,它允许程序或进程被绑定到特定的CPU核心上运行。这样做的好处包括减少缓存未命中、降低线程迁移(co

Laravel安全应用模块示例教程

前言 Laravel 是一个流行的 PHP 框架,它提供了一套丰富的功能来帮助开发者构建安全、可维护的应用程序。下面,我将详细解释 Laravel 中关于认证、CSRF 保护、授权、哈希、加密、密码重置等安全模块的实现逻辑、应用场景以及相应的示例代码。 详情见官方中文文档 一. 认证(Authentication) Laravel的认证系统是一个强大且灵活的用户身份验证解决方案,它基于PHP

消息队列创建以及使用示例

消息队列是消息的链接表,存放在内核中并由消息队列标示符标识。 1. 创建或打开一个队列 int msgget(key_t key, int flag); key: 键 由ftok()生成 key_t ftok(const char* path, int id); flag: IPC_CREAT 或 IPC_EXCL  2. 发送消息 int msgsn