golang实现仪表控制-visa32.dll方式
Posted cn2719691
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang实现仪表控制-visa32.dll方式相关的知识,希望对你有一定的参考价值。
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))
}
包的下载,目前还没有完善,后续会上传一个共享包和示例程序,着急的也可以留言。
以上是关于golang实现仪表控制-visa32.dll方式的主要内容,如果未能解决你的问题,请参考以下文章