{"id":8634,"date":"2021-10-03T10:39:00","date_gmt":"2021-10-03T02:39:00","guid":{"rendered":"https:\/\/blog.hoyo.idv.tw\/?p=8634"},"modified":"2021-10-19T08:21:02","modified_gmt":"2021-10-19T00:21:02","slug":"python-rs485-modbus-%e5%8d%8a%e9%9b%99%e5%b7%a5","status":"publish","type":"post","link":"https:\/\/blog.hoyo.idv.tw\/?p=8634","title":{"rendered":"Python - RS485 + Modbus UART \u534a\u96d9\u5de5\u5207\u63db\u50b3\u9001\u3001\u63a5\u6536\u6559\u5b78"},"content":{"rendered":"<p>--<\/p>\n<h2>RS485<\/h2>\n<ul>\n<li><a href=\"https:\/\/zh.wikipedia.org\/wiki\/EIA-485\" target=\"_blank\" rel=\"noopener\">EIA-485 - \u7dad\u57fa\u767e\u79d1\uff0c\u81ea\u7531\u7684\u767e\u79d1\u5168\u66f8<\/a><\/li>\n<\/ul>\n<p>\u96d9\u7dda\u3001\u534a\u96d9\u5de5\uff0c\u5982\u679c\u4f7f\u7528\u7684\u662f TTL, UART \u9019\u985e\u7684\u8a0a\u865f\u8f49\u63db\u5668\uff0c\u9700\u8981\u81ea\u5df1\u63a7\u5236\u50b3\u9001\u3001\u63a5\u6536\u5207\u63db\uff0c\u5207\u63db\u7684\u597d\u4e0d\u597d\u662f\u95dc\u9375<\/p>\n<p>--<\/p>\n<h2>Modbus<\/h2>\n<ul>\n<li><a href=\"https:\/\/en.wikipedia.org\/wiki\/Modbus\" target=\"_blank\" rel=\"noopener\">Modbus - Wikipedia<\/a><\/li>\n<\/ul>\n<p>RS485 \u5927\u591a\u4f7f\u7528 Modbus RTU\uff0c\u683c\u5f0f\u5982\u4e0b<\/p>\n<table class=\"wikitable\">\n<tbody>\n<tr>\n<th>Name<\/th>\n<th>Length (bits)<\/th>\n<th>Function<\/th>\n<\/tr>\n<tr>\n<th>Start<\/th>\n<td>28<\/td>\n<td>At least 3\u00bd character times of silence (mark condition)<\/td>\n<\/tr>\n<tr>\n<th>Address<\/th>\n<td>8<\/td>\n<td>Station address<\/td>\n<\/tr>\n<tr>\n<th>Function<\/th>\n<td>8<\/td>\n<td>Indicates the function code; e.g., read coils\/holding registers<\/td>\n<\/tr>\n<tr>\n<th>Data<\/th>\n<td><i>n<\/i>\u00a0\u00d7 8<\/td>\n<td>Data + length will be filled depending on the message type<\/td>\n<\/tr>\n<tr>\n<th>CRC<\/th>\n<td>16<\/td>\n<td><a title=\"Cyclic redundancy check\" href=\"https:\/\/en.wikipedia.org\/wiki\/Cyclic_redundancy_check\" target=\"_blank\" rel=\"noopener\">Cyclic redundancy check<\/a><\/td>\n<\/tr>\n<tr>\n<th>End<\/th>\n<td>28<\/td>\n<td>At least 3\u00bd character times of silence between frames<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>--<\/p>\n<h2>CRC \u53c3\u8003\u8cc7\u6e90<\/h2>\n<ul>\n<li><a href=\"https:\/\/blog.csdn.net\/wang_hugh\/article\/details\/83995604\" target=\"_blank\" rel=\"noopener\">Python Modbus CRC16 \u6821\u9a8c \u5176\u5b83CRC\u6821\u9a8c\u8bf4\u660e<\/a><\/li>\n<li><a href=\"https:\/\/www.twblogs.net\/a\/5c8b5b50bd9eee35fc14d963\" target=\"_blank\" rel=\"noopener\">[\u6578\u64da\u7d50\u69cb\u548c\u7b97\u6cd5]CRC8\/CRC16\/CRC32\u5e38\u898b\u5e7e\u500b\u6a19\u6e96\u7684\u7b97\u6cd5\u53caC\u8a9e\u8a00\u5be6\u73fe<\/a><\/li>\n<\/ul>\n<p>Modbus \u901a\u8a0a\u7b2c\u4e00\u500b\u7a0b\u5f0f\u9580\u6abb\u5c31\u662f\u8a08\u7b97 CRC\uff0c\u9019\u88e1\u6709\u5927\u5927\u5beb\u597d\u7684\u53ef\u4ee5\u76f4\u63a5\u5957\u7528<\/p>\n<p>--<\/p>\n<h2>\u539f\u59cb\u7bc4\u4f8b<\/h2>\n<pre class=\"lang:python decode:true\">from binascii import *\r\nfrom crcmod import *\r\n \r\n# CRC16-MODBUS\r\ndef crc16Add(read):\r\n    crc16 =crcmod.mkCrcFun(0x18005,rev=True,initCrc=0xFFFF,xorOut=0x0000)\r\n    data = read.replace(\" \",\"\")\r\n    readcrcout=hex(crc16(unhexlify(data))).upper()\r\n    str_list = list(readcrcout)\r\n    if len(str_list) &lt; 6:\r\n        str_list.insert(2, '0'*(6-len(str_list)))  # \u4f4d\u6570\u4e0d\u8db3\u88650\r\n    crc_data = \"\".join(str_list)\r\n    print(crc_data)\r\n    read = read.strip()+' '+crc_data[4:]+' '+crc_data[2:4]\r\n    print('CRC16\u6821\u9a8c:',crc_data[4:]+' '+crc_data[2:4])\r\n    print('\u589e\u52a0Modbus CRC16\u6821\u9a8c\uff1a&gt;&gt;&gt;',read)\r\n    return read\r\n \r\nif __name__ == '__main__':\r\n    crc16Add(\"01 03 08 00 01 00 01 00 01 00 01\")\r\n    crc16Add(\"ff\")<\/pre>\n<p>--<\/p>\n<h2>list \u9663\u5217\u7248<\/h2>\n<ul>\n<li><a class=\"question-hyperlink\" href=\"https:\/\/stackoverflow.com\/questions\/15036551\/best-way-to-split-a-hexadecimal\" target=\"_blank\" rel=\"noopener\">Best way to split a hexadecimal?<\/a><\/li>\n<\/ul>\n<p>Python \u4f7f\u7528 list \u8cc7\u6599\u578b\u614b\u7a0b\u5f0f\u6703\u6bd4\u8f03\u9748\u6d3b\uff0c\u56e0\u6b64\u5be6\u52d9\u4e0a\u4f7f\u7528\u90fd\u662f\u76f4\u63a5\u4f7f\u7528 list<\/p>\n<pre class=\"lang:python decode:true\">from crcmod import *\r\n\r\n\r\ndef crc16_maxim(read):\r\n    r = bytes(bytearray(read))\r\n    crc16 = crcmod.mkCrcFun(0x18005, rev=True, initCrc=0xFFFF, xorOut=0x0000)\r\n    crc_hex = hex(crc16(r))\r\n    crc = divmod(int(crc_hex, 16), 0x100)\r\n    return [crc[1], crc[0]]\r\n\r\n\r\nif __name__ == '__main__':\r\n    r = [1, 3, 0, 0, 0, 2]\r\n    rs_crc = crc16_maxim(r)\r\n    full_rs = r + rs_crc\r\n    print(full_rs)  # [1, 3, 0, 0, 0, 2, 196, 11]\r\n<\/pre>\n<p>--<\/p>\n<h2>\u5b8c\u6574\u7684 Modbus \u7bc4\u4f8b<\/h2>\n<p>RS485 \u70ba\u534a\u96d9\u5de5\u901a\u8a0a\uff0c\u8b80\u53d6\u3001\u5beb\u5165\u5fc5\u9808\u81ea\u5df1\u6839\u64da\u5b57\u5143\u6578\u8a08\u7b97\u5f8c\u63a7\u5236\u6a21\u5f0f\uff0c\u6642\u5e8f\u63a7\u5236\u975e\u5e38\u91cd\u8981\uff0c<strong>\u4e0d\u80fd<\/strong>\u4f7f\u7528 .flush()\uff0c\u90a3\u662f\u5168\u96d9\u5de5\u7528\u7684\u529f\u80fd<\/p>\n<pre class=\"lang:python decode:true\">from crcmod import *\r\n\r\nimport gpio\r\nimport serial\r\nimport time\r\n\r\nrs_control = 6\r\ngpio.setup(rs_control, 'out')  # TR Pin\r\n\r\n\r\ndef crc16_maxim(read):\r\n    r = bytes(bytearray(read))\r\n    crc16 = crcmod.mkCrcFun(0x18005, rev=True, initCrc=0xFFFF, xorOut=0x0000)\r\n    crc_hex = hex(crc16(r))\r\n    crc = divmod(int(crc_hex, 16), 0x100)\r\n    return [crc[1], crc[0]]\r\n\r\n\r\nif __name__ == '__main__':\r\n    r = [31, 3, 0, 0, 0, 2]\r\n    rs_crc = crc16_maxim(r)\r\n    full_rs = r + rs_crc\r\n    print(full_rs)  # [31, 3, 0, 0, 0, 2, 199, 181]\r\n    py_serial = serial.Serial(\"\/dev\/ttyS1\", baudrate=9600, timeout=0.5, writeTimeout=0.5, bytesize=8, parity='N', stopbits=1, rtscts=True, dsrdtr=True)\r\n    read_count = full_rs[5] * 2 + 5  # \u8a08\u7b97\u63a5\u6536\u5b57\u6578\r\n    gpio.set(rs_control, 1)  # RS485 \u5207\u63db\u6210 out \u9001\u51fa\r\n    py_serial.write(full_rs)  # \u5beb\u5165\u8cc7\u6599\r\n    # py_serial.flush()  # flush() \u70ba\u5168\u96d9\u5de5\u4f7f\u7528\u529f\u80fd\uff0cRS485 \u4f7f\u7528\u6703\u6709\u592a\u665a\u5207\u63db\u6389\u8cc7\u6599\u554f\u984c\r\n    time.sleep(0.001 * (len(full_rs)))  # \u8a08\u7b97\u5beb\u5165\u7b49\u5f85\u6642\u9593 \u5b57\u6578*\u9b91\u7387\r\n    gpio.set(rs_control, 0)  # RS485 \u5207\u63db\u6210 in \u63a5\u6536\r\n    read_data = b''\r\n    while 1:\r\n        r = py_serial.read()\r\n        read_data += r\r\n        if len(r) == 0:\r\n            break\r\n        else:\r\n            py_serial.timeout = 0.001 * 10\r\n    print(list(read_data))  # [31, 3, 4, 0, 25, 0, 25, 20, 63]\r\n<\/pre>\n<p>--<\/p>\n<div class=\"pvc_clear\"><\/div>\n<p class=\"pvc_stats all \" data-element-id=\"8634\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> &nbsp;5,210&nbsp;total views, &nbsp;2&nbsp;views today<\/p>\n<div class=\"pvc_clear\"><\/div>\n","protected":false},"excerpt":{"rendered":"<p>-- RS485 EIA-48...<\/p>\n<div class=\"pvc_clear\"><\/div>\n<p class=\"pvc_stats all \" data-element-id=\"8634\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> &nbsp;5,210&nbsp;total views, &nbsp;2&nbsp;views today<\/p>\n<div class=\"pvc_clear\"><\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[31],"tags":[],"_links":{"self":[{"href":"https:\/\/blog.hoyo.idv.tw\/index.php?rest_route=\/wp\/v2\/posts\/8634"}],"collection":[{"href":"https:\/\/blog.hoyo.idv.tw\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.hoyo.idv.tw\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.hoyo.idv.tw\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.hoyo.idv.tw\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=8634"}],"version-history":[{"count":14,"href":"https:\/\/blog.hoyo.idv.tw\/index.php?rest_route=\/wp\/v2\/posts\/8634\/revisions"}],"predecessor-version":[{"id":8928,"href":"https:\/\/blog.hoyo.idv.tw\/index.php?rest_route=\/wp\/v2\/posts\/8634\/revisions\/8928"}],"wp:attachment":[{"href":"https:\/\/blog.hoyo.idv.tw\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=8634"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.hoyo.idv.tw\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=8634"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.hoyo.idv.tw\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=8634"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}