RS485是工业上常用的串口通讯方式,它可以通过两根线来现实设备间的通讯和数据采集,并且线长可达上千米,具备良好的抗干扰能力,是工业设备必备的通讯接口之一。
Modbus是一种串行通信协议,是Modicon公司(现在的施耐德电气 Schneider Electric)于1979年为使用可编程逻辑控制器(PLC)通信而发表。Modbus已经成为工业领域通信协议的业界标准(De facto),并且现在是工业电子设备之间常用的连接方式。它具有公开发表并且无版权要求、易于部署和维护等多个优点,因此被广泛的使用在工业上。
米尔的板子上带有一个485接口,我们以底板作为服务器主机,去采集下行设备的数据,做一些简单的数据处理和边缘计算。
我这里采用开源的libmodbus库来实现modbus的主机功能,把MYD-Y6ULX-V2作为从机,去采集下行设备的数据,做一个终端汇总处理。
底板上的485接口设备是 /dev/ttymxc3 , 这里我们用电脑端上位机模拟下行设备,来与底板进行通讯,通过usb转485来连接两个设备。
在github上下载libmodbus的源码
git clone https://github.com/stephane/libmodbus.git
按照readme交叉编译成库后就可以开始使用啦。
//从机初始化,设置串口数据等
void ctx_slave_init(ModbusStru_serial *ms)
{
/* 防呆 */
if(ms->baud != 1200 && ms->baud != 2400 && ms->baud != 4800 && ms->baud != 9600 &&
ms->baud != 19200 &&ms->baud != 38400 && ms->baud != 57600 && ms->baud != 115200)
ms->baud = 9600;
if(ms->parity != 'N' && ms->parity != 'O' && ms->parity != 'E')
ms->parity = 'N';
if(ms->data_bit != 5 && ms->data_bit != 6 && ms->data_bit != 7 && ms->data_bit != 8)
ms->data_bit = 8;
if(ms->stop_bit != 1 && ms->stop_bit != 2)
ms->stop_bit = 1;
// printf("%d\n",ms->baud);
/************************ RTU1 Slave*****************************/
ms->ctx_slave = modbus_new_rtu(ms->name, ms->baud, ms->parity, ms->data_bit, ms->stop_bit); //以串口的方式创建libmobus实例,并设置参数
if (ms->ctx_slave == NULL) //
{
fprintf(stderr, "%s ctx_slave:%s Unable to allocate libmodbus contex\n", NOW_TIME, ms->name);
return;
}
modbus_set_debug(ms->ctx_slave, 0); //设置1可看到调试信息
modbus_set_response_timeout(ms->ctx_slave, 0, 1000000);
if (modbus_connect(ms->ctx_slave) == -1) //等待连接设备
{
fprintf(stderr, "%s ctx_slave:%s Connection failed:%s\n", NOW_TIME, ms->name, modbus_strerror(errno));
return;
}
}
不熟悉libmodbus的可以参考它的官网,有很详细的api接口说明。
这里我们把它设置为从机后,就可以开始去采集终端设备的数据。
static void *ctx_slave_send(void *arg)
{
ModbusStru_serial *ms_temp = (ModbusStru_serial *)arg;
while(1)
{
// memset(dest, 0, 0x9999*2);//清理上一次读取的值
for(int i=0;i<ModbusReadArrayMax;i++)
{
if(ms_temp->ctx_slave == NULL || ms_temp->ctx_slave_status == CTX_SLAVE_END)
break;
if(ms_temp->modbus_set_array[i].flag == 0)
continue;
int sum = 0;//偏移量
for(int j=0;j<i;j++)
{
if(ms_temp->modbus_set_array[j].flag == 0)
continue;
sum += ms_temp->modbus_set_array[j].nb;
}
modbus_set_slave(ms_temp->ctx_slave, ms_temp->modbus_set_array[i].addr); //设置slave ID
// printf("%d %d %d %d \n", ms_temp->modbus_set_array[i].flag, ms_temp->modbus_set_array[i].addr, ms_temp->modbus_set_array[i].reg,
// ms_temp->modbus_set_array[i].nb);
int rc = modbus_read_registers(ms_temp->ctx_slave, ms_temp->modbus_set_array[i].reg,
ms_temp->modbus_set_array[i].nb, ms_temp->dest);//从0地址存放
if (rc == -1) //读取保持寄存器的值,可读取多个连续输入保持寄存器
{
fprintf(stderr, "%s ctx_slave: %s %s\n", NOW_TIME, ms_temp->name, modbus_strerror(errno));
}
else
{
modbus_flush(ms_temp->ctx_slave);
// fprintf(stderr, "%s: slave %s, %d read_reegisters ok!\n", NOW_TIME, ms_temp->name, i);
}
usleep(300000);
}
// printf("%d %d\n", ms_temp->ctx_slave, ms_temp->ctx_slave_status);
sleep(1);
}
}
独立的线程来进行数据采集和处理。
程序编译后放到底板上运行,硬件与电脑端连接好,打开上位机软件进行测试,就可以啦。
https://gitee.com/towel-roll/mobuds03-auto-reply.git
这是自己用qt的做的一个上位机,自动应答modbus的03采集数据命令。
更多回帖