本文使用SCPI协议与C语言编程,在 Ubuntu 下实现了简单的上位机软件。

需要的工具:

  • 已安装 Ubuntu 20.04 的电脑一台,虚拟机或物理机均可,(现在 NI-VISA 建议使用的版本: Ubuntu 18.04 / 20.04 / 22.04,其它版本请自行测试)
  • 普源示波器 DS1054Z  (本文也适用于其它使用SCPI协议的仪器,不限于普源品牌,不限于示波器)
  • 用来连接电脑与示波器的 USB 数据线

NI-VISA 安装与配置:

1. 下载设备驱动程序安装包:下载NI Linux设备驱动程序 - NI需要注意的,安装包支持的内核版本与你所使用的 Ubuntu 的内核版本必须相同,否则会安装失败,可以在下载页面上点击 “查看自述文件” 查看安装包支持的内核版本,如果内核版本不一致,可以在下载页面上选择其它版本的安装包;

查看 Ubuntu 内核版本:

uname -r

2. 安装 NI-VISA:解压下载的安装包,在解压后的路径下运行下面的命令:

sudo apt install ./ni-ubuntu2004-drivers-2024Q1.deb
sudo apt update
sudo apt install ni-visa

3. 如果你使用的操作系统是 Ubuntu 20.04 / 22.04,请执行下面这些命令,这样做的目的是让普通权限用户也能访问 USB 仪器,Ubuntu 18.04 用户请略过此步。

sudo mkdir -p /etc/udev/agents.d/usb

sudo ln -s /usr/lib/x86_64-linux-gnu/ni-visa/usb/nivisa_usbraw /etc/udev/agents.d/usb/
sudo ln -s /usr/lib/x86_64-linux-gnu/ni-visa/usb/nivisa_usbtmc /etc/udev/agents.d/usb/
sudo ln -s /usr/lib/x86_64-linux-gnu/ni-visa/usb/nivisa_usbtmc.rules /etc/udev/rules.d/

4. 禁用 Ubuntu 系统原生的 usbtmc 模块,因为这个模块会独占仪器的 USB 资源,导致 NI-VISA 无法访问仪器,使用下面的命令禁止 usbtmc 模块加载:

$ sudo su
# echo 'blacklist usbtmc' > /etc/modprobe.d/nousbtmc.conf

5. 收藏或标记本文,然后重启 Ubuntu 

reboot

===== NI-VISA 的安装与配置至此完成 =====

上位机编程:

1. 编译控制仪器源代码 scope.c:

gcc -o scope scope.c -lvisa

 scope.c  源码:

#include <ni-visa/visa.h>
#include <stdio.h>
#include <string.h>
 
#define MAX_SCPI_LEN 4096

void ReadWriteFunc_1(ViSession vi, ViByte* pBuf)
{
	const ViChar szCmd[] = "*IDN?\n";
	ViUInt32 nRwCount;
 
	// 写入命令,并读取命令回应
	if (VI_SUCCESS <= viWrite(vi, szCmd, strlen(szCmd), &nRwCount) && 
		VI_SUCCESS <= viRead(vi, pBuf, MAX_SCPI_LEN - 1, &nRwCount))
	{
		pBuf[nRwCount] = '\0';
		printf("%s\n", pBuf);
	}
}

void ReadWriteFunc_2(ViSession vi, ViByte* pBuf)
{
	// 写入命令,并读取命令回应,pBuf 缓冲区大小必须大于要读取的数据大小 
	// "%t"表示遇到终止符结束读取,默认终止符是'\n',终止符是可设置的
	
	if (VI_SUCCESS <= viPrintf(vi, "%s\n", "*IDN?") &&
		VI_SUCCESS <= viScanf(vi, "%t", pBuf))
	{
		printf("%s\n", pBuf);
	}
}

void ReadWriteFunc_3(ViSession vi, ViByte* pBuf)
{
	// 写入并读取,pBuf 缓冲区大小必须大于要读取的数据大小 
	// "%t"表示遇到终止符结束读取,默认终止符是'\n',终止符是可设置的
	
	if (VI_SUCCESS <= viQueryf(vi, "%s\n", "%t", "*IDN?", pBuf))
	{
		printf("%s\n", pBuf);	
	}
}

int main()
{
	ViStatus nRet;
	ViSession viDef = 0;
	ViSession vi;
 
	char szAddr[VI_FIND_BUFLEN];
	ViUInt32 numInstrs;
	ViFindList findList;
	ViByte btBuf[MAX_SCPI_LEN];
 
	nRet = viOpenDefaultRM(&viDef);
	if (nRet < VI_SUCCESS)
		return -1;
 
	// 查找地址以 USB 开头的仪器资源,并把找到的第一个资源地址放在 szAddr 中
	nRet = viFindRsrc (viDef, "USB?*INSTR", &findList, &numInstrs, szAddr);
	if (nRet < VI_SUCCESS)
	{
		printf("Error code: %X\n", nRet);   
		viClose(viDef);
		return -1;
	}
 
	nRet = viOpen(viDef, szAddr, VI_NULL, VI_NULL, &vi);
	if (nRet < VI_SUCCESS)
	{
		printf("Error code: %X\n", nRet);
		viClose(viDef);
		return -1;
	}
 
 	// 下面 3 个函数功能是相同的,根据实际编程情况选择其一
	ReadWriteFunc_1(vi, btBuf);
	ReadWriteFunc_2(vi, btBuf);
	ReadWriteFunc_3(vi, btBuf);
	
	viClose(vi);
	viClose(viDef);
 
	return 0;
}

2. 用 USB 数据线连接电脑与仪器,运行控制程序,运行之后会在命令行窗口上显示仪器的基本信息。

./scope

3. 如果想要在上位机软件中实现更多功能,可以在仪器生产商官网上下载编程手册(通信协议)。 

Logo

更多推荐