c# 调用研华AD板API例子

本文详细介绍了如何使用C#调用研华PCL816高精度AD转换卡的DLL函数 Adsapi32.dll,特别是解决包含指针类型成员的结构体调用问题。通过示例代码展示了如何正确匹配C++与C#的数据类型,并演示了如何为指针分配内存以避免尝试写入受保护内存的错误。最后,提供了一个完整的C#命令行程序源码,用于读取输入模拟电压。

最近用到研华的一款高精度AD转换卡,PCL816,需要使用C#调用研华库函数中的动态库文件Adsapi32.dll中的函数,参考了网上关于C#调用非托管dll的方法。

其中的难点主要是数据类型的匹配问题。基本的方法在MSDN中关于 c# 调用 C++ 非托管 Dll 的主题有详细的原理说明和例程,我博客上已经转了MSDN这一篇,这里就不赘述了。网上也有很多类型对应关系表,下面是比较好的一个。

 

C#调用C++编写的Win32 DLL文件时参数对应表

Win32 Types
CLR Type

char, INT8, SBYTE, CHAR
System.SByte

short, short int, INT16, SHORT
System.Int16

int, long, long int, INT32, LONG32, BOOL , INT
INT System.Int32

__int64, INT64, LONGLONG
System.Int64

unsigned char, UINT8, UCHAR , BYTE
System.Byte

unsigned short, UINT16, USHORT, WORD, ATOM, WCHAR , __wchar_t
System.UInt16

unsigned, unsigned int, UINT32, ULONG32, DWORD32, ULONG, DWORD, UINT
System.UInt32

unsigned __int64, UINT64, DWORDLONG, ULONGLONG
System.UInt64

float, FLOAT
System.Single

double, long double, DOUBLE
System.Double

 

下面主要说一下调用研华的库函数时遇到的一个新问题。即包含指针类型成员的结构体如何调用的问题。下面是最终成功的源码片段。

        /// <summary>

        /// 获得输入模拟电压,获取指定句柄设备的输入模拟电压结构体

        /// </summary>

        /// <param name="DriverHandle">设备句柄</param>

        /// <param name="lpAIVoltageIn">输入模拟电压</param>

        /// <returns>成功或错误号</returns>

        [DllImport("Adsapi32.dll")]

        public static extern int DRV_AIVoltageIn(int DriverHandle, ref tagPT_AIVoltageIn lpAIVoltageIn);

/// <summary>

        /// 模拟电压结构体

        /// </summary>

        public struct tagPT_AIVoltageIn

        {

            public ushort chan;         //通道

            public ushort gain;         //增益码:参考用户手册中的电压范围

            public ushort TrigMode;     //触发模式:0,内部触发;1,外部触发

            public IntPtr voltage;      //输入模拟电压的指针

        }

在C++函数原型中,tagPT_AIVoltageIn.voltage是一个float* voltage;形式定义的,这里要用C#中特有的指针或句柄类型IntPtr。

调用语句为

dwErrCde = DRV_AIVoltageIn(lDriverHandle, ref ptAIVoltageIn);//读取输入模拟电压

但是这时仍然会提示尝试写入受保护内存。其原因是在调用前没有为指针分配内存。使用下面的初始化语句。

tagPT_AIVoltageIn ptAIVoltageIn = new tagPT_AIVoltageIn(); //电压结构体

ptAIVoltageIn.voltage = Marshal.AllocHGlobal(sizeof(float));//为输入模拟电压指针分配内存,其大小为一个float型变量的大小。

定义一个float型的数组来接收这个指针所指地址的值,代码如下:

float[] fVoltage = new float[1];                            //输入模拟电压

Marshal.Copy(ptAIVoltageIn.voltage, fVoltage, 0, 1);    //从指针地址拷贝到数组中

终于成功接收到数据了!

 

下附我将研华示例代码中的一个C++命令行通用程序改写后的C#命令行程序的源码。

 


using System;

using System.Runtime.InteropServices;

using System.Threading;

 

namespace AD816

{

    class Program

    {

        #region 研华库函数

        /// <summary>

        /// 打开设备,由设备号得到设备句柄

        /// </summary>

        /// <param name="DeviceNum">设备号</param>

        /// <param name="DriverHandle">设备句柄</param>

        /// <returns>成功或错误号</returns>

        [DllImport("Adsapi32.dll")]

     &nbs

### C# 调用 PCI1756 IO 卡 对于在C#调用PCI1756 IO卡的操作,通常需要依赖于厂商提供的动态链接库(DLL),这些DLL封装了底层硬件接口。通过P/Invoke技术可以在托管代码(C#)里调用非托管的API函数。 #### 使用 P/Invoke 技术调用 DLL 函数 为了能够访问到Advantech PCI1756的功能,开发者应当先获取由制造商发布的适用于Windows平台下的驱动包以及对应的SDK文档[^1]。其中包含了用于控制该型号数据采集的各种API说明及其参数定义。接着按照官方指导安装必要的运行环境和支持软件,比如DAQNavi驱动程序[^2]。 下面给出一段简单的示范代码来展示怎样利用P/Invoke机制加载并执行来自外部DLL中的方法: ```csharp using System; using System.Runtime.InteropServices; class Program { // 定义从DLL导入的方法签名 [DllImport("advapi.dll", CallingConvention = CallingConvention.StdCall)] public static extern int Initialize(); [DllImport("advapi.dll", CallingConvention = CallingConvention.StdCall)] public static extern void Cleanup(); [DllImport("advapi.dll", CallingConvention = CallingConvention.StdCall)] public static extern short ReadDI(int port); [DllImport("advapi.dll", CallingConvention = CallingConvention.StdCall)] public static extern bool WriteDO(int port, ushort value); static void Main(string[] args){ try{ Console.WriteLine("Initializing..."); var result = Initialize(); if(result != 0){ throw new Exception($"Initialization failed with error code {result}"); } // 进行读写操作... const int PORT_NUMBER = 0; // 假设我们要操作端口编号为0 // 读取输入状态 short inputStatus = ReadDI(PORT_NUMBER); Console.WriteLine($"Port {PORT_NUMBER} Input Status: {inputStatus}"); // 设置输出值 (这里假设要设置所有位都为高电平) ushort outputValue = 0xFFFF; bool writeResult = WriteDO(PORT_NUMBER,outputValue); if(!writeResult){ Console.WriteLine("Failed to set digital outputs."); }else{ Console.WriteLine($"Successfully wrote {outputValue:X4} to Port {PORT_NUMBER}"); } Cleanup(); }catch(Exception ex){ Console.Error.WriteLine(ex.Message); } } } ``` 这段代码展示了初始化、清理资源的过程,并实现了基本的数据读取和写入命令。需要注意的是`advapi.dll`仅为示意名称,请替换为实际使用的正确文件名;并且具体的函数原型需参照随附的手册进行调整以确保准确性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值