米尔电子
直播中

jf_01801880

2年用户 91经验值
擅长:嵌入式技术
私信 关注

【米尔王牌产品MYD-Y6ULX-V2开发板试用体验】三、 libmodbus使用

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采集数据命令。

更多回帖

发帖
×
20
完善资料,
赚取积分