c#调用libmodbus 离线调试方法

准备工具

1. VSPD虚拟串口工具,(7年前用过的工具,现在又用上了,幸好CSDN上传了一份,嘿嘿)

https://download.csdn.net/download/ericwuhk/3753942

2. Modbus Slave调试工具

https://download.csdn.net/download/ericwuhk/10357886

3.libModbus封装库

https://download.csdn.net/download/ericwuhk/10352801

操作步骤:

1.VSPD绑定可以使用的串口号,如COM2与COM3,点击添加端口。


2.Modbus Slave工具点击Connection,选择“serial RTU”模式,COM口选择Port2格式选择如“192000, 8,‘E’,1”,


3.将基于C语言开发的libmodbus类库添加到c#项目工程中,C类库中添加读取ini配置文件的函数,增加需要给C#调用的函数接口

cf_op.h,cf_op.c

#pragma once
#define LineMaxLen 2048  
#define KeyMaxLen 128  
#define MaxFileLength 1024*10

#ifndef CF_OP_H  
#define CF_OP_H  

#ifdef __cplusplus  
extern "C" {
#endif  

	int GetCfItem(const char *pFileName /*in*/, char *pKey /*in*/, char * pValue/*in out*/, int * pValueLen /*out*/);
	int SetCfItem(const char *pFileName /*in*/, char *pKey /*in*/, char *pValue/*in*/);

#ifdef  __cplusplus  
}
#endif  

#if defined(_MSC_VER)
# if defined(DLLBUILD)
/* define DLLBUILD when building the DLL */
#  define MODBUS_API __declspec(dllexport)
# else
#  define MODBUS_API __declspec(dllimport)
# endif
#else
# define MODBUS_API
#endif

static char getValueMsg[KeyMaxLen];
static char setValueMsg[KeyMaxLen];

MODBUS_API char * getValue(char *key);
MODBUS_API char * setValue(char *key, char *value);

MODBUS_API int sum(int a, int b);//only for test

#endif  
char* getValue(char *key)// chane to key[KeyMaxLen] char *key
{
	char *pFileName = "Platform.ini";	
	int len = 0, rv = 0;

	memset(getValueMsg, 0, sizeof(getValueMsg));
	rv = GetCfItem(pFileName, key, getValueMsg, &len);

	if (rv != 0)
	{
		 char *errMsg;
		printf("Get the key value err!");
		switch (rv)
		{
			case -1:
				errMsg = "func GetCfItem paramter err!";
				break;
			case -2:
				errMsg = "fopen file err!";
				break;
			case -3:
				errMsg = "The key has no value!";
				break;
			case -4:
				errMsg = "can't find the key";
				break;
			default:
				break;
		}

		strcpy(getValueMsg, errMsg);
	}

	return getValueMsg;
}

char* setValue(char *key,char *value)
{
	int rv = 0;
	char *pFileName = "Platform.ini";

	memset(setValueMsg, 0, sizeof(setValueMsg));
	memset(value, 0, sizeof(value));*/
				
	rv = SetCfItem(pFileName, key, value);
	if (rv != 0)
	{
		char *errMsg;
		printf("Get the key value err!");
		switch (rv)
		{
			case -1:
				errMsg = "func WriteCfItem paramter err!";
				break;
			case -2:
				errMsg = "fopen file err";
				break;
			case -3:
				errMsg = "file too long unspport";
				break;
			case -4:
				errMsg = "fopen file err";
				break;
			default:
				break;
		}
		strcpy(setValueMsg, errMsg);

		return setValueMsg;
	}
	sprintf(setValueMsg, "key %s=%s set OK", key, value);
	return setValueMsg;
}

int sum(int a, int b)
{
	return a + b;
}

rotControl.h , rotControl.c

/*
* Copyright © <wu_xx2008@hotmail.com>
*
* antoy wu
* 2018-4-16 21:16:30
*/

#ifndef ROTCONTROL_H
#define ROTCONTROL_H

/* Add this for macros that defined unix flavor */
#if (defined(__unix__) || defined(unix)) && !defined(USG)
#include <sys/param.h>
#endif

#ifndef _MSC_VER
#include <stdint.h>
#else
#include "stdint.h"
#endif

#include "modbus-version.h"
#include <stdbool.h>
#include "RotationPlatformDefine.h"

#if defined(_MSC_VER)
# if defined(DLLBUILD)
/* define DLLBUILD when building the DLL */
#  define ROT_API __declspec(dllexport)
# else
#  define ROT_API __declspec(dllimport)
# endif
#else
# define MODBUS_API
#endif

char*       messageStr;
volatile bool b_stop;
bool		  b_isInitial;

modbus_t*	m_ctx;
int				m_rc;
int				m_nb_fail;
int				m_nb_loop;
int				m_addr;
int				m_nb;
uint8_t*		m_tab_rq_bits;
uint8_t*		m_tab_rp_bits;
uint16_t*		m_tab_rq_registers;
uint16_t*		m_tab_rw_rq_registers;
uint16_t*		m_tab_rp_registers;

uint16_t		m_tab_reg[32] = { 0 };
uint8_t		        m_rec_reg[32] = { 0 };
uint8_t			m_buf_8[32] = { 0 };
uint16_t		m_buf_16[32] = { 0 };

int32_t			m_cur_pos[3] = { 0 };
int32_t			m_cur_vel[3] = { 0 };
int32_t			m_cur_acc[3] = { 0 };
bool			b_busy;
bool			b_alarm;
bool			b_emgency;

PlatformSetup m_platform_setup;

ROT_API bool rotInit();

#endif  /* ROTCONTROL_H */
void paraInit()
{
	b_stop = false;
	b_isInitial = false;
	m_ctx = NULL;	

	readIni();
}

bool modbusInit()
{	
	const char *device = getValue("Serial");
	//sprintf(device, "COM%s", device);
	if (m_ctx == NULL) {
		m_ctx = modbus_new_rtu(device, Baudrate, Parity, Databit, Stopbit);
	}
	int ret = modbus_set_slave(m_ctx, SLAVE); // set slave adress
	if (ret == -1) {
		return false;
	}
	ret = modbus_connect(m_ctx);
	if (ret == -1) {
		return false;
	}
	b_isInitial = true;

	return b_isInitial;
}

bool rotInit()
{	
	paraInit();//系统参数初始化以及读取配置文件	
	if (modbusInit())
	{
		b_isInitial = true;		
	}
	return b_isInitial;
}

void closeModbus()
{
	if(m_ctx!=NULL)
	{
		modbus_close(m_ctx);
		modbus_free(m_ctx); 
	}
	
}

C#增加一个类库文件RotPlatformControl_CsDll,用于导入modbus.dll中的各个函数。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace RotPlatformControl_CsDll
{
    public class CRotPlatformControl
    {
        [DllImport("modbus.dll", EntryPoint = "sum", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int sum(int a, int b);

        [DllImport("modbus.dll", EntryPoint = "getValue", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr getValue(IntPtr intPtrKey);

        [DllImport("modbus.dll", EntryPoint = "setValue", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr setValue(IntPtr intPtrKey, IntPtr intPtrValue);

        [DllImport("modbus.dll", EntryPoint = "rotInit", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern bool rotInit();
    }
}

UI调试界面增加一些按钮等。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Principal;
using RotPlatformControl_CsDll;

namespace Mirage2B_IMU_Test
{
    public partial class IMUDebugTool : Form
    {
        public IMUDebugTool()
        {
            InitializeComponent();
        }

        private void buttonHome_Click(object sender, EventArgs e)
        {
            log("转台开始回位!");
            bool isRotInit=CRotPlatformControl.rotInit();
            if(isRotInit)
                lblMessage.Text = isRotInit.ToString();
                //string res = Getvalue("Baudrate");
                //lblMessage.Text = res.ToString();
        }

        private void buttonStop_Click(object sender, EventArgs e)
        {
            string strKey = "Hello";
            string strValue = "Kitty";
            string res=setvalue(strKey,strValue);
            lblMessage.Text = res.ToString();
        }

        private string Getvalue(string strKey)
        {           
            IntPtr key = Marshal.StringToHGlobalAnsi(strKey);
            IntPtr temp = CRotPlatformControl.getValue(key);
            string res = Marshal.PtrToStringAnsi(temp).ToString();
            temp = IntPtr.Zero;
            return res;
        }

        private string setvalue(string strKey,string strValue)
        {
            IntPtr key = Marshal.StringToHGlobalAnsi(strKey);
            IntPtr value = Marshal.StringToHGlobalAnsi(strValue);
            IntPtr temp = CRotPlatformControl.setValue(key, value);
            string res = Marshal.PtrToStringAnsi(temp).ToString();
            temp = IntPtr.Zero;
            return res;
        }
        private void log (string strMsg)
        {
            ShowMsg(strMsg, Color.Blue);
        }
        private void error(string strErrMsg)
        {
            ShowMsg(strErrMsg, Color.Red);
        }

        private delegate void ShowMsgHandle(string msgString, Color color);
        private void ShowMsg(string msgString, Color color)
        {
            if (!lblMessage.InvokeRequired)
            {
                lblMessage.Text = msgString;
                lblMessage.ForeColor = color;
                lblMessage.Refresh();
            }
            else
            {
                Invoke(new ShowMsgHandle(ShowMsg), msgString, color);
            }
        }
       
    }
}

最终结果:



几个注意的细节记录如下:

1.C类库中的char*需要对应于c#中的IntPtr,且作为返回值是的char*变量必须为全局变量,否则调用返回为空。

2.为了方便调试,在同一个解决方案下c编译产生的dll文件与c# 类库文件的输出路径最好统一设置在主程序目录下。

3.C#项目属性勾选Debug->Enable Native code debugging,支持本地调试,便于c#调试过程中可以进入到C Dll的源码中进行单步调试。

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值