使用freemodbus主机协议栈,调用eMBMasterReqReadHoldingRegister(),寄存器地址设置为0000H时可以正常读取,但设置为0606H后,产生“MB_MRE_EXE_FUN”功能码错误的异常。
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-01-10 zf_19 the first version
*/
#include <rtthread.h>
#include "mb.h"
#include "mb_m.h"
#include "user_mb_app.h"
#ifdef PKG_MODBUS_MASTER_SAMPLE
#define SLAVE_ADDR MB_SAMPLE_TEST_SLAVE_ADDR
#define PORT_NUM MB_MASTER_USING_PORT_NUM
#define PORT_BAUDRATE MB_MASTER_USING_PORT_BAUDRATE
#else
#define SLAVE_ADDR 0x01
#define PORT_NUM 5
#define PORT_BAUDRATE 9600
#endif
#define PORT_PARITY MB_PAR_NONE //无校验位
#define MB_POLL_THREAD_PRIORITY 10
#define MB_SEND_THREAD_PRIORITY RT_THREAD_PRIORITY_MAX - 1
#define MB_SEND_REG_START 3
#define MB_SEND_REG_NUM 3
#define MB_POLL_CYCLE_MS 500 //轮询间隔时间 5个传感器一轮走完需要500ms
/*RS485_RE PI4 对应PI4引脚应填写:132 (I-A=8)*16+4=132 串口使用U5*/
/*各传感器地址配置*/
#define Displacement_sensor01_SLAVE_ADDR 0x01
#define Displacement_sensor02_SLAVE_ADDR 0x02
#define Displacement_sensor03_SLAVE_ADDR 0x03
#define Displacement_sensor04_SLAVE_ADDR 0x04
#define Angle_sensor01_SLAVE_ADDR 0X05
/*寄存器地址配置*/
#define MB_READ_REG_00 0x00 //读当前测量值
#define MB_READ_REG_01 0x01 //仪表类比及当前信息
#define MB_READ_REG_02 0x02 //仪表编号低四位
#define MB_READ_REG_LL_0606 0X0606//L600拉力传感器信息保存寄存器
#define MB_READ_REG_LL_9C04 0X9C04//L600拉力传感器信息保存寄存器
/*寄存器数量---modbus 读数据的长度*/
#define MB_READ_REG_NUM_01 1
#define MB_READ_REG_NUM_02 2
#define MB_READ_REG_NUM_03 3
#define MB_READ_REG_NUM_04 4
static int is_got = 0;
extern USHORT usMRegHoldBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_HOLDING_NREGS];// modbus master 用全局二维数组来记录多个从机的数据
/*进行touchgfx数据更新、电压测量板显示数据格式为signed short -32768~32767*/
int16_t value_FY_DCD_10;
int16_t value_HX_DCD_10;
int16_t value_ZHG_DCD_10;
int16_t value_YHG_DCD_10;
int16_t value_PULL_DLM_20;
/*上传到model俯仰DCD-10传感器信息*/
static int gfxget_FY_DCD_10(void)
{
return value_FY_DCD_10;
}
/*上传到model航向DCD-10传感器信息*/
static int gfxget_HX_DCD_10(void)
{
return value_HX_DCD_10;
}
/*上传到model左横滚DCD-10传感器信息*/
static int gfxget_ZHG_DCD_10(void)
{
return value_ZHG_DCD_10;
}
/*上传到model右横滚DCD-10传感器信息*/
static int gfxget_YHG_DCD_10(void)
{
return value_YHG_DCD_10;
}
static int gfxget_PULL_DLM_20(void)
{
return value_PULL_DLM_20;
}
/*读取各传感器信息线程*/
static void send_thread_entry(void *parameter)
{
eMBMasterReqErrCode error_code = MB_MRE_NO_ERR;
rt_uint16_t error_count = 0;
while (1)
{
/* Test Modbus Master */
/* data[0] = (USHORT)(rt_tick_get() / 10);
data[1] = (USHORT)(rt_tick_get() % 10);*/
/*接收标志位置零*/
is_got = 0;
/*
//往从机多个保持寄存器写入数据
error_code = eMBMasterReqWriteMultipleHoldingRegister(SLAVE_ADDR, //salve address
MB_SEND_REG_START, //register start address
MB_SEND_REG_NUM, //register total number
data, //data to be written
RT_WAITING_FOREVER); //timeout
*/
/* //读位移传感器1多个保持寄存器数据
error_code = eMBMasterReqReadHoldingRegister(Displacement_sensor01_SLAVE_ADDR,
MB_READ_REG_00,
MB_READ_REG_NUM_01,
500);
//读位移传感器2,000H多个保持寄存器数据
error_code = eMBMasterReqReadHoldingRegister(Displacement_sensor02_SLAVE_ADDR,
MB_READ_REG_00, //0000H寄存器
MB_READ_REG_NUM_01, //读取数据数量
500);
//读位移传感器3,0000H多个保持寄存器数据
error_code = eMBMasterReqReadHoldingRegister(Displacement_sensor03_SLAVE_ADDR,
MB_READ_REG_00, //0000H寄存器
MB_READ_REG_NUM_01, //读取数据数量
500);
//读位移传感器4,0000H开始5个保持寄存器数据
error_code = eMBMasterReqReadHoldingRegister(Displacement_sensor04_SLAVE_ADDR,
MB_READ_REG_00, //0000H寄存器
MB_READ_REG_NUM_01, //读取数据数量
500);*/
//读角度传感器5,0000H开始2个保持寄存器数据
error_code = eMBMasterReqReadHoldingRegister(Angle_sensor01_SLAVE_ADDR, //角度传感器地址
MB_READ_REG_LL_0606, //0606H寄存器
MB_READ_REG_NUM_02, //读取数据数量
500);
/* //打印节点1俯仰传感器 保持寄存器的数据
value_FY_DCD_10 = (int16_t)usMRegHoldBuf[0][0];
rt_kprintf("sensor1_detect: %d \t\r\n", (int16_t)usMRegHoldBuf[0][0]);
//打印节点2航向传感器 保持寄存器的数据
value_HX_DCD_10 = (int16_t)usMRegHoldBuf[1][0];
rt_kprintf("sensor2_detect: %d \t\r\n", (int16_t)usMRegHoldBuf[1][0]);
//打印节点3左横滚传感器 保持寄存器的数据
value_ZHG_DCD_10 = (int16_t)usMRegHoldBuf[2][0];
rt_kprintf("sensor3_detect: %d \t\r\n", (int16_t)usMRegHoldBuf[2][0]);
//打印节点4右横滚传感器 保持寄存器的数据
value_YHG_DCD_10 = usMRegHoldBuf[3][0];
rt_kprintf("sensor4_detect: %d \t\r\n", (int16_t)usMRegHoldBuf[3][0]);*/
//打印节点5 拉力传感器 保持寄存器的数据
value_PULL_DLM_20 = usMRegHoldBuf[5][0];
rt_kprintf("sensor5_detect: %d \t\r\n", usMRegHoldBuf[5][0]);
//打印时钟节点
rt_kprintf("tick is %d\r\n",rt_tick_get());
/* Record the number of errors */
if (error_code != MB_MRE_NO_ERR)
{
error_count++;
rt_kprintf("error_count : %d \n",error_count);
rt_kprintf("error_code %d\r\n",error_code);
}
is_got = 1;
rt_thread_delay(100);
}
}
static void mb_msg_get(void *parameter)
{
char mb_get_buf[05][64];
while(1)
{
if (is_got)
{
//置零
//memset(mb_get_buf, 0, 320);
/* //提取数据
sprintf(mb_get_buf[Displacement_sensor01_SLAVE_ADDR - 1],
usMRegHoldBuf[Displacement_sensor01_SLAVE_ADDR - 1][MB_READ_REG_NUM_01]);*/
}
rt_thread_mdelay(5 * RT_TICK_PER_SECOND);
}
}
static void mb_master_poll(void *parameter)
{
//MB初始化 内部已定义停止位,当前为停止位2;
eMBMasterInit(MB_RTU, PORT_NUM, PORT_BAUDRATE, PORT_PARITY);
eMBMasterEnable();
while (1)
{
eMBMasterPoll();
rt_thread_mdelay(MB_POLL_CYCLE_MS);
}
}
static int TDM_TMD_modbus(int argc, char **argv)
{
static rt_uint8_t is_init = 0;
rt_thread_t tid1 = RT_NULL, tid2 = RT_NULL,tid3 = RT_NULL;
if (is_init > 0)
{
rt_kprintf("sample is running\n");
return -RT_ERROR;
}
tid1 = rt_thread_create("md_m_poll", mb_master_poll, RT_NULL, 512, MB_POLL_THREAD_PRIORITY, 10);
if (tid1 != RT_NULL)
{
rt_thread_startup(tid1);
}
else
{
goto __exit;
}
tid2 = rt_thread_create("md_m_send", send_thread_entry, RT_NULL, 512, MB_SEND_THREAD_PRIORITY, 10);
if (tid2 != RT_NULL)
{
rt_thread_startup(tid2);
}
else
{
goto __exit;
}
tid3 = rt_thread_create("mb_msg_get", mb_msg_get, RT_NULL, 2048, 13, 10);
if (tid3 != RT_NULL)
{
rt_thread_startup(tid3);
}
else
{
goto __exit;
}
is_init = 1;
return RT_EOK;
//退出
__exit:
if (tid1)
rt_thread_delete(tid1);
if (tid2)
rt_thread_delete(tid2);
if (tid3)
rt_thread_delete(tid3);
return -RT_ERROR;
}
//导出命令行
MSH_CMD_EXPORT(TDM_TMD_modbus, run a TDM_DTECT sample);
//开机启动
//INIT_APP_EXPORT(TDM_TMD_modbus);
读的是0606H(1542)的数据,设置此处 master holding regs numbers 为2000,仍然报同样错误;设置为4000后可在0606H处正常获取slave数据。
问此处的计算方式是如何?
这个具体看下代码实现吧。如果想随意的读取,可以使用 libmodbus,直接调用API,不必要设置那么大的数组存数据。
推荐 agile_modbus
完整的主从示例
特殊功能码示例
PC 和 MCU 示例