RS-485和RS-232一样,都是串行通信标准,现在的标准名称是TIA485/EIA-485-A,但是人们会习惯称为RS-485标准,RS-485常用在工业、自动化、汽车和建筑物管理等领域。
RS-485总线弥补了RS-232通信距离短,速率低的缺点,RS-485的速率可高达10Mbit/s,理论通讯距离可达1200米;RS-485和RS-232的单端传输不一样,是差分传输,使用一对双绞线,其中一根线定义为A,另一个定义为B。
Modbus是一种串行通信协议,是Modicon公司(现在的施耐德电气 Schneider Electric)于1979年为使用可编程逻辑控制器PLC)通信而发表。Modbus已经成为工业领域通信协议的业界标准(De facto),并且现在是工业电子设备之间常用的连接方式。它具有公开发表并且无版权要求、易于部署和维护等多个优点,因此被广泛的使用在工业上。
米尔的板子上带有一个485接口,我们以底板作为服务器主机,去采集下行设备的数据,做一些简单的数据处理和边缘计算。
我这里采用开源的libmodbus库来实现modbus的主机功能,把MYC-Y6ULX-V2作为从机,去采集下行设备的数据,做一个终端汇总处理。
底板上的485接口设备是 /dev/ttymxc3 , 这里我们用电脑端上位机模拟下行设备,来与底板进行通讯,通过usb转485来连接两个设备。
/从机初始化,设置串口数据等
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;
}
}
这里我们把它设置为从机后,就可以开始去采集终端设备的数据。
static void *ctx_slave_send(void *arg)
{
ModbusStru_serial *ms_temp = (ModbusStru_serial *)arg;
while(1)
{
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
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);
}
sleep(1);
}
}
我们将程序编译好后,放到底板上面运行,并将硬件USB 转485模块连接好,打开上位机软件进行测试。
全部评论