golang实现仪表控制-visa32.dll方式

golang实现仪表控制-visa32.dll方式,第1张

golang,go语言实现仪表控制可以采用2种方式,一种是使用CGO编程,使用驱动自带的VISA.H文件进行开发,但是感觉怪怪的,感觉这样还不如直接使用C进行开发,还有现成的版本可用。因此本文使用的是调用dll的方式来进行。

常用函数

viOpenDefaultRM:打开设备管理器,初始化。

func OpenRM() uintptr {

    VISA32 := syscall.NewLazyDLL("visa32.dll")

    viOpenDefaultRM := VISA32.NewProc("viOpenDefaultRM")

    ret, _, _ := viOpenDefaultRM.Call(uintptr(unsafe.Pointer(&resourceManager)))

    fmt.Println("硬件信息为:", resourceManager)

    return ret

}

viFindRsrc:查询仪表清单。

func FindRsrc() bool {

    VISA32 := syscall.NewLazyDLL("visa32.dll")

    viFindRsrc := VISA32.NewProc("viFindRsrc")

    var list int = 0

    instrDor := getMyString("?*")

    var data [180]byte

    retcnt := 0

    ret, _, _ := viFindRsrc.Call(uintptr(resourceManager), uintptr(unsafe.Pointer(instrDor.Str)), uintptr(unsafe.Pointer(&list)), uintptr(unsafe.Pointer(&retcnt)), uintptr(unsafe.Pointer(&data)))

    if ret != 0 {

        fmt.Println("查询代码:", ret)

        return false

    }

    fmt.Println("查询成功->")

    viFindNext := VISA32.NewProc("viFindNext")

    viFindNext.Call(uintptr(list), uintptr(unsafe.Pointer(&data)))

    s := string(Bytes2string(data))

    viClose := VISA32.NewProc("viClose")

    viClose.Call(uintptr(list))

    fmt.Println(s)

    return true

}

viOpen:使用地址打开仪表。

    instrDor := getMyString(addr)

    VISA32 := syscall.NewLazyDLL("visa32.dll")

    viOpen := VISA32.NewProc("viOpen")

    var instr int = 0

    ret, _, _ := viOpen.Call(uintptr(resourceManager), uintptr(unsafe.Pointer(instrDor.Str)), uintptr(0), uintptr(0), uintptr(unsafe.Pointer(&instr)))

    if instr == 0 {

        return "打开仪器失败,错误代码为:" + fmt.Sprint(ret)

    }

viClose:关闭设备管理器,关闭仪器清单,关闭打开的仪表(可以理解为释放内存)上面的3个函数都要。

viPrintf/viScanf:发送和接收仪表的数据

// 发送信息给仪表

// addr为仪器地址,m为需要发送的信息,如GPIB0::15::INSTR,send:DISP TX

func SendMsg(addr, m string) string {

    instrDor := getMyString(addr)

    VISA32 := syscall.NewLazyDLL("visa32.dll")

    viOpen := VISA32.NewProc("viOpen")

    var instr int = 0

    ret, _, _ := viOpen.Call(uintptr(resourceManager), uintptr(unsafe.Pointer(instrDor.Str)), uintptr(0), uintptr(0), uintptr(unsafe.Pointer(&instr)))

    if instr == 0 {

        return "打开仪器失败,错误代码为:" + fmt.Sprint(ret)

    }

    m = m + "\n"

    msg := getMyString(m)

    viPrintf := VISA32.NewProc("viPrintf")

    ret2, _, _ := viPrintf.Call(uintptr(instr), uintptr(unsafe.Pointer(msg.Str)))

    viClose := VISA32.NewProc("viClose")

    viClose.Call(uintptr(instr))

    if ret2 == 0 {

        return "信息发送成功!---" + m

    }

    return "发送失败,代码为:" + fmt.Sprint(ret2)

}



// 发送信息给仪表,并等待仪表返回数据。

func ReadData(addr, m string) string {

    instrDor := getMyString(addr)

    VISA32 := syscall.NewLazyDLL("visa32.dll")

    viOpen := VISA32.NewProc("viOpen")

    var instr int = 0

    ret, _, _ := viOpen.Call(uintptr(resourceManager), uintptr(unsafe.Pointer(instrDor.Str)), uintptr(0), uintptr(0), uintptr(unsafe.Pointer(&instr)))

    if instr == 0 {

        return "打开仪器失败,错误代码为:" + fmt.Sprint(ret)

    }

    m = m + "\n"

    msg := getMyString(m)

    viPrintf := VISA32.NewProc("viPrintf")

    viPrintf.Call(uintptr(instr), uintptr(unsafe.Pointer(msg.Str)))

    readFmt := getMyString("%t")

    viScanf := VISA32.NewProc("viScanf")

    var data [180]byte

    viScanf.Call(uintptr(instr), uintptr(unsafe.Pointer(readFmt.Str)), uintptr(unsafe.Pointer(&data)))

    s := string(Bytes2string(data))

    viClose := VISA32.NewProc("viClose")

    viClose.Call(uintptr(instr))

    return s

}

// 返回的数据后面有很多个0,截断处理会更好些。
func Bytes2string(data [180]byte) string {
	for i := 0; i < len(data); i++ {
		if data[i] == 10 || data[i] == 0 {
			return string(data[:i])
		}
	}
	return string(data[:])
}
常见的坑

go语言的string与C的string是有所区别的,gostring的结构是首字符的指针+长度,而Cstring的结构只有首字符指针,然后读取时顺序读到字符0为止。因此在传递中要进行转换,比如:

使用CGO使用C.CString进行转换,但这个方式会导致内存不能释放。

文中采用了另一种方式,改造结构体的方式,因此采用了另一种结构体MyString。

// 新建类型,代替C.CString

// C.CString使用会产生拷贝,并不会自动释放,需要进行free。

type MyString struct {

    Str unsafe.Pointer

    Len int

}

//类型转换

// \x00是必须的,go的string是由首字符指针+长度组成。而C的string只有首字符指针,长度由字节0来确定,即顺序读,直到读到0。\x00即代表字符0

func getMyString(s string) *MyString {

    s = s + "\x00"

    return (*MyString)(unsafe.Pointer(&s))

}
包的下载,目前还没有完善,后续会上传一个共享包和示例程序,着急的也可以留言。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/995288.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存