371 lines
9.2 KiB
C
371 lines
9.2 KiB
C
|
|
/*
|
|||
|
|
* Copyright (c) 2006-2021, RT-Thread Development Team
|
|||
|
|
*
|
|||
|
|
* SPDX-License-Identifier: Apache-2.0
|
|||
|
|
*
|
|||
|
|
* Change Logs:
|
|||
|
|
* Date Author Notes
|
|||
|
|
* 2024-04-23 lijian the first version
|
|||
|
|
*/
|
|||
|
|
#include "modbus_rtu.h"
|
|||
|
|
#include <board.h>
|
|||
|
|
|
|||
|
|
Modbus_RTU_t Modbus_RTU;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 设置modbus从机地址
|
|||
|
|
* @param modbus_addr
|
|||
|
|
*/
|
|||
|
|
void set_Modbus_Addr(rt_uint16_t modbus_addr)
|
|||
|
|
{
|
|||
|
|
Modbus_RTU.modbus_addr = modbus_addr;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 获取Modbus从机地址
|
|||
|
|
* @return rt_uint16
|
|||
|
|
*/
|
|||
|
|
rt_uint16_t get_Modbus_Addr()
|
|||
|
|
{
|
|||
|
|
return Modbus_RTU.modbus_addr;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 设置modbus寄存器地址
|
|||
|
|
* @param modbus_reg_addr
|
|||
|
|
*/
|
|||
|
|
void set_Modbus_Reg_Addr(rt_uint16_t modbus_reg_addr)
|
|||
|
|
{
|
|||
|
|
Modbus_RTU.modbus_reg_addr = modbus_reg_addr;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 获取Modbus读取寄存器起始地址
|
|||
|
|
* @return rt_uint16
|
|||
|
|
*/
|
|||
|
|
rt_uint16_t get_Modbus_Reg_Addr()
|
|||
|
|
{
|
|||
|
|
return Modbus_RTU.modbus_reg_addr;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 设置Modbus读寄存器数量
|
|||
|
|
* @return rt_uint16
|
|||
|
|
*/
|
|||
|
|
void set_Modbus_Reg_Num(rt_uint16_t modbus_reg_num)
|
|||
|
|
{
|
|||
|
|
Modbus_RTU.modbus_reg_num = modbus_reg_num;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 获取Modbus读寄存器数量
|
|||
|
|
* @return rt_uint16
|
|||
|
|
*/
|
|||
|
|
rt_uint16_t get_Modbus_Reg_Num()
|
|||
|
|
{
|
|||
|
|
return Modbus_RTU.modbus_reg_num;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
//功能码01(0x01): 读线圈状态(Read Coils)
|
|||
|
|
//功能码02(0x02): 读离散输入状态(Read Discrete Inputs)
|
|||
|
|
//功能码03(0x03): 读保持寄存器(Read Holding Registers)
|
|||
|
|
//功能码04(0x04): 读输入寄存器(Read Input Registers)
|
|||
|
|
//功能码05(0x05): 写单个线圈(Write Single Coil)
|
|||
|
|
//功能码06(0x06): 写单个保持寄存器(Write Single Holding Register)
|
|||
|
|
//功能码15(0x0F): 写多个线圈(Write Multiple Coils)
|
|||
|
|
//功能码16(0x10): 写多个保持寄存器(Write Multiple Holding Registers)
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* modbus初始化
|
|||
|
|
*/
|
|||
|
|
void Modbus_init()
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
// Modbus_RTU.modbus_addr = (rt_uint16_t)0x01;
|
|||
|
|
// Modbus_RTU.modbus_reg_addr = (rt_uint16_t)0x00;
|
|||
|
|
// Modbus_RTU.modbus_reg_num = (rt_uint16_t)0x02;
|
|||
|
|
|
|||
|
|
rs485_inst_t *hinst = rs485_create(RS485_SAMPLE_MASTER_SERIAL, RS485_SAMPLE_MASTER_BAUDRATE,
|
|||
|
|
RS485_SAMPLE_MASTER_PARITY, RS485_SAMPLE_MASTER_PIN, RS485_SAMPLE_MASTER_LVL);
|
|||
|
|
|
|||
|
|
if (hinst == RT_NULL)
|
|||
|
|
{
|
|||
|
|
rt_kprintf("create rs485 instance fail.\n");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
rs485_set_recv_tmo(hinst, 1000);
|
|||
|
|
if (rs485_connect(hinst) != RT_EOK)
|
|||
|
|
{
|
|||
|
|
rs485_destory(hinst);
|
|||
|
|
rt_kprintf("rs485 connect fail.\n");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
rt_uint8_t ctx_send_buf[AGILE_MODBUS_MAX_ADU_LENGTH];
|
|||
|
|
rt_uint8_t ctx_read_buf[AGILE_MODBUS_MAX_ADU_LENGTH];
|
|||
|
|
|
|||
|
|
|
|||
|
|
agile_modbus_rtu_t ctx_rtu;
|
|||
|
|
agile_modbus_t *ctx = &ctx_rtu._ctx;
|
|||
|
|
agile_modbus_rtu_init(&ctx_rtu, ctx_send_buf, sizeof(ctx_send_buf), ctx_read_buf, sizeof(ctx_read_buf));
|
|||
|
|
agile_modbus_set_slave(ctx, Modbus_RTU.modbus_addr); //地址
|
|||
|
|
rt_kprintf("Modbus Running.\n");
|
|||
|
|
|
|||
|
|
|
|||
|
|
rt_int8_t send_len;
|
|||
|
|
rt_int8_t read_len;
|
|||
|
|
rt_uint8_t i;
|
|||
|
|
rt_int8_t rc;
|
|||
|
|
|
|||
|
|
//
|
|||
|
|
|
|||
|
|
|
|||
|
|
while (1)
|
|||
|
|
{
|
|||
|
|
rt_thread_mdelay(1000);
|
|||
|
|
|
|||
|
|
|
|||
|
|
//if(Modbus_RTU.modbus_func == 3){
|
|||
|
|
send_len = agile_modbus_serialize_read_registers(ctx, Modbus_RTU.modbus_reg_addr, Modbus_RTU.modbus_reg_num);
|
|||
|
|
//
|
|||
|
|
// } else if(Modbus_RTU.modbus_func == 1){
|
|||
|
|
// send_len = agile_modbus_serialize_read_bits(ctx, Modbus_RTU.modbus_reg_addr, Modbus_RTU.modbus_reg_num);
|
|||
|
|
//
|
|||
|
|
// }
|
|||
|
|
|
|||
|
|
// rt_kprintf("rs485 send %d datas : ", send_len);
|
|||
|
|
// for (i = 0; i < send_len; i++) {
|
|||
|
|
// rt_kprintf("%02X ", ctx->send_buf[i]);
|
|||
|
|
// }
|
|||
|
|
|
|||
|
|
// rt_kprintf("\n");
|
|||
|
|
|
|||
|
|
read_len = rs485_send_then_recv(hinst, (void *) ctx->send_buf, send_len, ctx->read_buf, ctx->read_bufsz);
|
|||
|
|
if (read_len < 0)
|
|||
|
|
{
|
|||
|
|
// rt_kprintf("rs485 send datas error.\n");
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (read_len == 0)
|
|||
|
|
{
|
|||
|
|
// rt_kprintf("rs485 recv timeout.\n");
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ctx->read_buf[read_len] = 0;
|
|||
|
|
|
|||
|
|
// Bsp_Rs485_Tx(ctx->send_buf, send_len); //
|
|||
|
|
// int read_len = Bsp_Rs485_Rx(ctx->read_buf, ctx->read_bufsz); //
|
|||
|
|
|
|||
|
|
if (read_len == 0)
|
|||
|
|
{
|
|||
|
|
// rt_kprintf("Receive timeout.\n");
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
rc = agile_modbus_deserialize_read_registers(ctx, read_len, Modbus_RTU.hold_register);
|
|||
|
|
if (rc < 0)
|
|||
|
|
{
|
|||
|
|
Modbus_RTU.modbus_rec = 0;
|
|||
|
|
|
|||
|
|
rt_kprintf("Receive failed.\n");
|
|||
|
|
if (rc != -1)
|
|||
|
|
rt_kprintf("Error code:%d\n", -128 - rc);
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Modbus_RTU.modbus_rec = 1;
|
|||
|
|
|
|||
|
|
if (Modbus_RTU.log) {
|
|||
|
|
rt_kprintf("Hold Registers:");
|
|||
|
|
for (i = 0; i < 10; i++)
|
|||
|
|
rt_kprintf("Register [%d]: 0x%04X\n", i, Modbus_RTU.hold_register[i]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (Modbus_RTU.modbus_rec) {
|
|||
|
|
//get_modbus_rec();
|
|||
|
|
// MQTT_Send_Modbus(get_modbus_rec());
|
|||
|
|
}
|
|||
|
|
rt_kprintf("\r\n\r\n\r\n");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void set_modbus_log(rt_uint8_t log){
|
|||
|
|
Modbus_RTU.log = log;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取modbus读取数据的转换后返回值
|
|||
|
|
* @return
|
|||
|
|
*/
|
|||
|
|
rt_uint16_t get_modbus_rec(){
|
|||
|
|
if (Modbus_RTU.modbus_rec) {
|
|||
|
|
|
|||
|
|
rt_uint8_t high_d=0;
|
|||
|
|
rt_uint8_t low_d=0;
|
|||
|
|
|
|||
|
|
if (Modbus_RTU.modbus_reg_num == 2) {
|
|||
|
|
high_d = Modbus_RTU.hold_register[0];
|
|||
|
|
low_d = Modbus_RTU.hold_register[1];
|
|||
|
|
rt_uint16_t rec = (high_d << 8) | low_d;
|
|||
|
|
return rec;
|
|||
|
|
}
|
|||
|
|
Modbus_RTU.modbus_rec =0;
|
|||
|
|
}
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//void Bsp_Rs485_Tx(){
|
|||
|
|
//
|
|||
|
|
//}
|
|||
|
|
//
|
|||
|
|
//void Bsp_Rs485_Rx(){
|
|||
|
|
//
|
|||
|
|
//}
|
|||
|
|
//
|
|||
|
|
//static void rs485_sample_master(void *args)
|
|||
|
|
//{
|
|||
|
|
// const char read_cmd[] = "read datas test\r\n";
|
|||
|
|
// static rt_uint8_t buf[256];
|
|||
|
|
// rs485_inst_t *hinst = rs485_create(RS485_SAMPLE_MASTER_SERIAL, RS485_SAMPLE_MASTER_BAUDRATE,
|
|||
|
|
// RS485_SAMPLE_MASTER_PARITY, RS485_SAMPLE_MASTER_PIN, RS485_SAMPLE_MASTER_LVL);
|
|||
|
|
//
|
|||
|
|
// if (hinst == RT_NULL)
|
|||
|
|
// {
|
|||
|
|
// LOG_E("create rs485 instance fail.");
|
|||
|
|
// return;
|
|||
|
|
// }
|
|||
|
|
//
|
|||
|
|
// rs485_set_recv_tmo(hinst, 1000);
|
|||
|
|
// if (rs485_connect(hinst) != RT_EOK)
|
|||
|
|
// {
|
|||
|
|
// rs485_destory(hinst);
|
|||
|
|
// LOG_E("rs485 connect fail.");
|
|||
|
|
// return;
|
|||
|
|
// }
|
|||
|
|
//
|
|||
|
|
// while (1)
|
|||
|
|
// {
|
|||
|
|
// int len = strlen(read_cmd);
|
|||
|
|
// len = rs485_send_then_recv(hinst, (void *) read_cmd, len, buf, sizeof(buf));
|
|||
|
|
// if (len < 0)
|
|||
|
|
// {
|
|||
|
|
// LOG_E("rs485 send datas error.");
|
|||
|
|
// break;
|
|||
|
|
// }
|
|||
|
|
//
|
|||
|
|
// if (len == 0)
|
|||
|
|
// {
|
|||
|
|
// LOG_D("rs485 recv timeout.");
|
|||
|
|
// continue;
|
|||
|
|
// }
|
|||
|
|
//
|
|||
|
|
// buf[len] = 0;
|
|||
|
|
// LOG_D("rs485 recv %d datas : %s", len, buf);
|
|||
|
|
// }
|
|||
|
|
//
|
|||
|
|
//}
|
|||
|
|
|
|||
|
|
//
|
|||
|
|
//#define PORT_NUM MB_MASTER_USING_PORT_NUM
|
|||
|
|
//#define PORT_BAUDRATE MB_MASTER_USING_PORT_BAUDRATE
|
|||
|
|
//
|
|||
|
|
//#define PORT_PARITY MB_PAR_EVEN
|
|||
|
|
//
|
|||
|
|
//#define MB_POLL_CYCLE_MS 500
|
|||
|
|
//
|
|||
|
|
//#define func_Coil 1
|
|||
|
|
//#define func_Holding 3
|
|||
|
|
//
|
|||
|
|
//#define MODBUS_REG_NUM 30
|
|||
|
|
|
|||
|
|
//rt_uint16_t buffer[MODBUS_REG_NUM];
|
|||
|
|
//
|
|||
|
|
///*
|
|||
|
|
// *
|
|||
|
|
|
|||
|
|
// *
|
|||
|
|
// */
|
|||
|
|
//
|
|||
|
|
//void Copy_Holding(rt_uint16_t * Holding, rt_uint16_t reg_num){
|
|||
|
|
// rt_uint16_t * a = get_modbus_03();
|
|||
|
|
// for (rt_uint8_t var = 0; var < reg_num; var++) {
|
|||
|
|
// Holding[var] = a[var];
|
|||
|
|
// }
|
|||
|
|
//}
|
|||
|
|
//
|
|||
|
|
//void Copy_Coil(rt_uint16_t * Coil, rt_uint16_t reg_num){
|
|||
|
|
// unsigned char * a = get_modbus_01();
|
|||
|
|
// for (rt_uint8_t var = 0; var < reg_num; var++) {
|
|||
|
|
// Coil[var] = a[var];
|
|||
|
|
// }
|
|||
|
|
//}
|
|||
|
|
//
|
|||
|
|
//
|
|||
|
|
//
|
|||
|
|
//void Modbus_Read_Holding_Registers(rt_uint16_t addr, rt_uint16_t reg_addr, rt_uint16_t reg_num, rt_uint16_t * Holding){
|
|||
|
|
//
|
|||
|
|
// while(1){
|
|||
|
|
// eMBMasterPoll();
|
|||
|
|
//
|
|||
|
|
// /*
|
|||
|
|
// * ucSndAddr 请求的从机地址,0代表广播。
|
|||
|
|
// usRegAddr 读寄存器的地址
|
|||
|
|
// usRegData 读寄存器的数量
|
|||
|
|
// lTimeOut 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。
|
|||
|
|
// */
|
|||
|
|
// eMBMasterReqReadHoldingRegister(addr, reg_addr, reg_num, 1000);
|
|||
|
|
//
|
|||
|
|
// rt_thread_mdelay(MB_POLL_CYCLE_MS);
|
|||
|
|
//
|
|||
|
|
// if (get_Holding_flag()) {
|
|||
|
|
// Copy_Holding(Holding, reg_num);
|
|||
|
|
// Modbus_RTU.modbus_rec =1;
|
|||
|
|
// get_modbus_rec();
|
|||
|
|
// }
|
|||
|
|
//
|
|||
|
|
// }
|
|||
|
|
//}
|
|||
|
|
//
|
|||
|
|
//void Modbus_Read_Coils(rt_uint16_t addr, rt_uint16_t reg_addr, rt_uint16_t reg_num, rt_uint16_t * Coil){
|
|||
|
|
//
|
|||
|
|
// while(1){
|
|||
|
|
// eMBMasterPoll();
|
|||
|
|
//
|
|||
|
|
// /*
|
|||
|
|
// * ucSndAddr 请求的从机地址,0代表广播。
|
|||
|
|
// usCoilAddr 读线圈的地址
|
|||
|
|
// usNCoils 读线圈的数量
|
|||
|
|
// lTimeOut 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可
|
|||
|
|
// */
|
|||
|
|
// eMBMasterReqReadCoils(addr, reg_addr, reg_num, 1000);
|
|||
|
|
//
|
|||
|
|
// rt_thread_mdelay(MB_POLL_CYCLE_MS);
|
|||
|
|
// if (get_Coil_flag()) {
|
|||
|
|
// Copy_Coil(Coil , reg_num);
|
|||
|
|
// Modbus_RTU.modbus_rec =1;
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
//}
|
|||
|
|
//
|
|||
|
|
//
|
|||
|
|
//void Modbus_config(void){
|
|||
|
|
//
|
|||
|
|
// eMBMasterInit(MB_RTU, PORT_NUM, PORT_BAUDRATE, PORT_PARITY);
|
|||
|
|
// eMBMasterEnable();
|
|||
|
|
//
|
|||
|
|
//// if(Modbus_RTU.modbus_func == func_Holding){
|
|||
|
|
// Modbus_Read_Holding_Registers(Modbus_RTU.modbus_addr, Modbus_RTU.modbus_reg_addr, Modbus_RTU.modbus_reg_num ,buffer);
|
|||
|
|
//// } else if(Modbus_RTU.modbus_func == func_Coil){
|
|||
|
|
//// Modbus_Read_Coils(Modbus_RTU.modbus_addr, Modbus_RTU.modbus_reg_addr, Modbus_RTU.modbus_reg_num , buffer);
|
|||
|
|
//// }
|
|||
|
|
//
|
|||
|
|
//}
|
|||
|
|
//
|
|||
|
|
|
|||
|
|
|