0.前言


本文使用树莓派实现MODBUS RTU从机,借助python库——modbus-tk实现RTU从机。MODBUS是一种灵活可靠的工业通信协议,常用的MODBUS协议包括MODBUS RTU和MODBUS TCP。借助python强大的库函数,可以在树莓派平台上非常方便的实现MODBUS主机和从机,MODBUS RTU和TCP,甚至一个树莓派既可以跑MODBUS RTU主机也可以同时跑MODBUS TCP从机。相比于其他平台(例如STM32),在树莓派上实现modbus真的太简单了。



【有用的参考资料】


【1】 MODBUS协议整理——汇总——如果您还不熟悉modbus,请你花点时间看看吧。



【2】 freemodbus modbus TCP 学习笔记——STM32平台,通过uIP实现modbus TCP从机

【3】 MODBUS学习笔记——modbus tk modbus TCP主机实现——使用modbus tk实现modbus TCP主机。平台为PC,无需修改可移植到树莓派。


【4】 树莓派学习笔记——UART使用——树莓派UART端口使用,本例中将会使用到该文提到的内容。

【5】 树莓派学习笔记——RPi.GPIO 流水灯——GPIO相关操作,本例中将会使用到该文提到的内容。

【6】 STM32 移植FreeModbus 详细过程——个人学习modbus的开始



1.modbus tk安装


详见以下博文


【 MODBUS学习笔记——modbus tk modbus TCP主机实现】



2.简单的例子


【说明】


假设树莓派8个可用GPIO端口分别连接LED,在很多工控领域一个LED可称为控制点,在modbus协议中一个控制点被抽象为线圈寄存器,操作相应的线圈寄存器有05H和15H指令。若使用modbus-tk便不必关心modbus协议的具体内容。下面就通过modbus中协议实现树莓派扩展板上LED的控制。


【代码】


#!/usr/bin/env python
# -*- coding: utf_8 -*-
import sys
import logging
import threading
import modbus_tk
import modbus_tk.defines as cst
import modbus_tk.modbus as modbus
import modbus_tk.modbus_rtu as modbus_rtu
import serial
import time
import RPi.GPIO as GPIO
logger = modbus_tk.utils.create_logger(name="console", record_format="%(message)s")
# 创建server
server = modbus_rtu.RtuServer(serial.Serial("/dev/ttyAMA0", 9600))
slaver = server.add_slave(1)
# BCM GPIO编号
pins = [17,18,27,22,23,24,25,4]
def setup():
    # 采用BCM编号
    GPIO.setmode(GPIO.BCM)
    # 设置所有GPIO为输出状态,且输出低电平
    for pin in pins:
        GPIO.setup(pin, GPIO.OUT)
        GPIO.output(pin, GPIO.LOW)
   
    slaver.add_block("coil", cst.COILS, 0, 16)
    slaver.set_values("coil", 0, 16*[0])
       
def loop():
    logger.info("running...")
    # 启动从机
    server.start()
    while True:
        values = slaver.get_values("coil", 0, 8)
        #print values[0]
        for i in range(0, 8):
            if values[i] == 1:
                GPIO.output(pins[i], GPIO.HIGH)
            else:
                GPIO.output(pins[i], GPIO.LOW)
       
        # 必要的延时
        time.sleep(0.5)
def destory():
    logger.info("destory")
    for pin in pins:
        GPIO.output(pin, GPIO.LOW)
        GPIO.setup(pin, GPIO.IN)
   
    # 停止从机
    server.stop()
       
if __name__ == "__main__":
    setup()
    try:
        loop()
    except KeyboardInterrupt:
        destory()




【分析】


【1】 server = modbus_rtu.RtuServer(serial.Serial("/dev/ttyAMA0", 9600))


创建一个RTU从机,使用串口/dev/ttyAMA0。请注意server和主机并不是一个概念,这里可能胡产生概念的混淆,这里server可理解为一个设备,而这个设备可以具有多个身份(例如具有多个从机ID)
【2】 slaver = server.add_slave(1)


从机编号为1。一个server可以加入多个编号从机。

【3】slaver.add_block("coil", cst.COILS, 0, 16)


创建寄存器,寄存器的别名为coil,寄存器为线圈寄存器(COILS),寄存器起始地址为0,寄存器个数为16.


【4】 slaver.set_values("coil", 0, 16*[0])


线圈寄存器的初始值全部为0


【5】 values = slaver.get_values("coil", 0, 8)


读取线圈寄存器具体值,线圈寄存器地址从0到7,共8个。



3.测试




Modbus RTU python 树莓派 树莓派modbus主机_python



图1 modbus rtu测试



4.总结


使用python,借助python扩展库,利用树莓派,原来觉得难以实现的东西现在做起来特别简单。