标签 Modbus Master 下的文章

此次移植工作以中国移动 ML302 模组为基础,亿琪软件 YiDTU 设备为原型,开发基于 Modbus Master 应用;
传统模式下,DTU 都是以透传为主要工作,所有的业务需求都是从服务器端发出,而 YiDTU 是作为边缘计算的角色,在工业现场就已经把数据处理做完;

![yigate-yidtu.png][1]

准备工作

硬件设备

  • YiDTU 设备一台
    亿琪软件 YiDTU 设备内置 UART 转 RS485 模块,对外连接 RS485 双线设备,如:YiSensor 模拟量采集模块;对于开发而言,那就是主要针对 UART 串口操作;

  • Micro USB 线一根
    用于操作 YiDTU 设备:AT 串口操作,烧录操作;

  • RS485 设备若干
    可用 USB 转 RS485 转换器代替(需配合 modbus slave 软件使用);有支持 Modbus Slave 设备最好;准备了两个:模拟量 4-20mA 和 开关量各一个;

  • 9~30V 直流电源一个
    支持最大 2A 电流的直流电源一个,用于给 YiDTU 设备供电;

  • 将以上硬件设备连接好

软件 SDK

  • 从中国移动物联网公司获取 ML302 相关 SDK,;
  • 确保 SDK 编译正常;
  • 烧录基本应用成功;

移植过程

Modbus Master 库

  • https://github.com/jiekechoo/ModBus-Master.git 获取源代码,使用 STM32 环境编译成功,确保你的环境没问题;

  • 将 Modbus_Master 目录移植到 ML302 工程中 src/demo/modbus 下,根据需求删除不必要的组件功能;

  • ML302 环境下编译通过,确保没有错误出现;

  • Modbus 枚举值要重新定义

    typedef enum
    {
    // Modbus function codes for bit access
    ku8MBReadCoils = 0x01,          ///< Modbus function 0x01 Read Coils
    ku8MBReadDiscreteInputs = 0x02, ///< Modbus function 0x02 Read Discrete Inputs
    ku8MBWriteSingleCoil = 0x05,    ///< Modbus function 0x05 Write Single Coil
    ku8MBWriteMultipleCoils = 0x0F, ///< Modbus function 0x0F Write Multiple Coils
    
    // Modbus function codes for 16 bit access
    ku8MBReadHoldingRegisters = 0x03,      ///< Modbus function 0x03 Read Holding Registers
    ku8MBReadInputRegisters = 0x04,        ///< Modbus function 0x04 Read Input Registers
    ku8MBWriteSingleRegister = 0x06,       ///< Modbus function 0x06 Write Single Register
    ku8MBWriteMultipleRegisters = 0x10,    ///< Modbus function 0x10 Write Multiple Registers
    ku8MBMaskWriteRegister = 0x16,         ///< Modbus function 0x16 Mask Write Register
    ku8MBReadWriteMultipleRegisters = 0x17 ///< Modbus function 0x17 Read Write Multiple Registers
    } modbusFunc;

串口接收支持

  • 串口接收任务中,将收到的内容复制到全局变量中,目的是把 Modbus Slave 回复的内容获取到,交给 Modbus 组件使用;
    
    extern uint8_t u8ModbusADU[1024];
    extern uint8_t u8ModbusADUSize;

// 接收处理函数中
{
u8ModbusADUSize = uart_buf_len;
memcpy(u8ModbusADU, uart_buf, u8ModbusADUSize);
}


- 接收完成后,创建一个 信号量,通知 Modbus 组件来处理;

{
uart_buf_len = 0;
recv_count = 0;
osSignalSet(OC_Main_TaskHandle, 0x0004);
}


## Modbus 组件
- 将 Modbus 组件中接收处理替换成信号量等待,超时重置接收缓冲区;

// 串口收到数据信号量,2000ms 超时
osEvent osevent = osSignalWait(0x0004, ku16MBResponseTimeout);
if (osevent.status == osEventTimeout)
{
u8MBStatus = ku8MBResponseTimedOut;
memset(u8ModbusADU, 0, sizeof(u8ModbusADU));
u8ModbusADUSize = 0;
}

- Modbus 发送函数重写

uint8_t Modbus_Master_Write(uint8_t buf, uint8_t length)
{
// if(HAL_UART_Transmit(&huart2 ,(uint8_t
)buf,length,0xff))
if (cm_uart_send_no_cache(OPENCPU_MAIN_URAT, (uint8_t *)buf, length, 0xff) == 0)
{
return HAL_ERROR;
}
else
{
return HAL_OK;
}
}

- 如果有 CS 控制口 IO,需要自定义相关函数

if 0

// transmit request RS485接口是需要每次发送前改变接口的模式

if (_preTransmission)
{
_preTransmission();
}

endif

//串口发送数据
Modbus_Master_Write(u8ModbusADU, u8ModbusADUSize);
u8ModbusADUSize = 0;

if 0

// transmit request RS485接口是需要每次发送后改变接口的模式
if (_postTransmission)
{
_postTransmission();
}

endif



> 移植过程比较简单,细节需要一定的嵌入式和 C 语言基础。

# 效果展示
在 YiDTU 业务逻辑中增加相应的功能模块,把数据传输到云平台,这样,就可以及时获取现场的模拟量数据。
![PSX_20210119_151717.jpg][2]


  [1]: https://yiqisoft.cn/blogs/usr/uploads/2021/01/1616746346.png
  [2]: https://yiqisoft.cn/blogs/usr/uploads/2021/01/2439453110.jpg