????????需求:用Labwindows_cvi软件开发整机标校系统。
????????分析:整机标校系统是一个集成控制系统,需程控的硬件主要包含:矢量网络分析仪,扫描架、转台、时序控制器等,通过对这些硬件的控制形成一套标校流程,当前先对这些硬件单独控制,因扫描架、转台、时序控制器是非标仪器,在此不作详细描述。所以该章节主要讲述Labwindows_cvi基于c语言程控矢量网络分析仪。
????????该章节主要有几部分组成:连接仪器、发送仪器命令、接收仪器数据。
1?? Labwindows_cvi中的VISA函数库的使用
????????Labwindows_cvi中提供的VISA函数库就是标准VISA的一个实现,打开VISA函数库的函数面板选择窗口,可以看到包含3个子类。
????????●资源管理;
????????●资源模板;
????????●特定资源的操作。
????????资源管理子类实现了VISA标准中的资源定位和接口通信的生命周期控制;资源模板子类实现了VISA标准中的属性控制、资源锁定服务和事件机制;特定资源的操作子类实现了VISA标准中I/O控制。
1.1资源管理
????????资源管理包括资源定位和通信的生命周期控制。资源定位就是一个函数viOpenDefaultRM,该函数实现机器上所以VISA资源的定位,通过指针返回ViSession类型的资源句柄。对所有特定资源的通信生命周期控制都是通过该句柄实现。通信生命周期控制包括打开资源,查找资源,关闭资源。
1.2资源模板
????????资源模板子类提供了VISA的属性控制、资源锁定服务和事件机制。这一部分内容在本编文章中没有体现,故不作详细说明。
1.3特定资源操作
????????特定资源的操作包含消息基通信函数和寄存器基通信函数。
1.3.1消息基通信函数
????????消息基仪器由独立的处理器来解释接收到的信息,并将信息解释成指令或数据。VISA为消息基通信提供了格式化I/O和基本I/O两类函数。
? ? ? ? (1)格式化I/O函数
????????与标准的C 的格式化函数极为相似,可以发送或接收格式化的数据,包括:viPrintf()、viScanf()、viQueryf()、viFlush()。
? ? ? ? (2)基本I/O函数
????????基本I/O支持同步和异步数据传输两种方式。
????????同步传输的函数在调用过程中终止其他程序的执行,直到数据接收或者发送完成才返回,支持同步传输的函数有viWrite、viRead、viClear、viAssertTrigger和viReadSTB。
????????异步传输函数子啊调用后立即返回,数据传输完成后产生异步读写完成事件(VI_EVENT_IO_COMPLETION),可以通过事件排队或回调函数的方法处理VI_EVENT_IO_COMPLETION事件。
1.3.2寄存器基通信函数
????????在此不做详细阐述。
1.4 VISA常用函数
1.4.1 VISA资源管理器定位——viOpenDefaultRM
????????原型:ViStatus viOpenDefaultRM (ViSession sesn);
????????描述:这个函数用来初始化一个VISA资源管理器,此函数必须要在其他任何VISA函数之前调用。
表1-1 viOpenDefaultRM函数参数
参数 | 描述 | sesn | 返回一个独立的VISA资源管理器ID |
表1-2 viOpenDefaultRM函数返回值
标识符 | 值 | 描述 | VI_SUCCESS | 0 | VISA资源管理器初始化成功。 | VI_ERROR_ALLOC | | 系统资源不足。 | VI_ERROR_INV_SETUP | | 配置文件无效或者不存在。 | VI_ERROR_SYSTEM_ERROR | | VISA系统初始化失败。 |
1.4.2 连接仪器——viOpen
????????原型:ViStatus viOpen (ViSession sesn, ViRsrc name, ViAccessMode mode, ViUInt32 timeout, ViSession vi);
????????描述:连接一个指定的设备,返回一个可用于调用其他功能的连接标识符。
表1-3? viOpen函数参数
参数 | 方向 | 描述 | sesn | IN | VISA资源管理器逻辑标识符 | name | IN | 地址名称 | mode | IN | 连接打开方式,可以是以下值: VI_EXCLUSIVE_LOCK独占方式打开; VI_LOAD_CONFIG根据外部配置文件打开 VI_NULL正常多访问打开 | timeout | IN | 如果是以独占方式打开,该参数是一个绝对时间(单位ms),超时就返回一个错误。其他连接方式忽略此值。 | vi | OUT | 返回打开连接逻辑标识符 |
表1-4? viOpen函数返回值
标识符 | 值 | 描述 | VI_SUCCESS | 0 | 连接成功。 | VI_SUCCESS_DEV_NPRESENT | | 连接成功,但是指定的地址无响应。 | VI_WARN_CONFIG_NLOADED | | 指定的地址不存在或者地址格式不正确。 | VI_ERROR_ALLOC | | 系统资源不足。 | VI_ERROR_INTF_NUM_NCONFIG | | 指定的地址是有效的,但是无法使用。 | VI_ERROR_INV_ACC_MODE | | 非法的存取模式。 | VI_ERROR__INV_RSRC_NAME | | 地址名称语法错误。 | VI_ERROR__INV_SESSION VI_ERROR__INV_OBJECT | | 无效的vi。 | VI_ERROR_LIBRARY_NFOUND | | VISA库加载不完全。 | VI_ERROR_NSUP_OPER | | 资源管理器seen不支持此函数。 | VI_ERROR_RSRC_BUSY | | seen是有效的,但当前无法访问。 | VI_ERROR_RSRC_LOCKED | | seen被独占。 | VI_ERROR_RSRC_NFOUND | | 信息不足或者资源不存在。 | VI_ERROR_TMO | 0Xbfff0015 | 操作超时。 |
1.4.3 发送仪器命令——viPrintf和viWrite
(1)viPrintf
????????原型:ViStatus viPrintf (ViSession vi, ViString writeFmt, ...);
????????描述:格式化字符串并发送格式化后的字符串给设备。(字符串格式化可以参照MFC里CString类中的Format函数。)
????????不能在同一资源上同时使用viWrite和viPrintf函数。
????????部分VISA函数的参数是可变的(如viPrintf,viScanf和viQueryf),导致VB不能调用。用户可以使用与这些函数功能相当的函数代替。
????????writeFmt参数可以包含普通字符、一般格式化字符和特殊字符。普通字符(包含空格)书写方式与平常一样,不用做任何修改。特殊字符则要在该字符前面加一个反斜杠(\);格式化字符由百分号(%)和操作标志组成,操作标志后面介绍。
表1-5 特殊字符
\n | 发送一个ASCII码换行符,并且END标志自动一起发送。 | \r | 发送一个ASCII码回车。 | \t | 发送一个ASCII码制表符。 | \### | 发送一个指定的八进制数。 | \” | 发送一个ASCII码双引号。 | \\ | 发送一个ASCII码反斜杠。 |
表1-6 viPrintf函数参数
参数 | 方向 | 描述 | vi | IN | 对象标识符 | writeFmt | IN | 格式化字符串 |
表1-7 viPrintf函数返回值
标识符 | 值 | 描述 | VI_SUCCESS | 0 | 参数成功格式化。 | VI_ERROR_ALLOC | | 内存不足。 | VI_ERROR_INV_FMT | | writeFmt包含无效格式化说明符。 | VI_ERROR__INV_SESSION VI_ERROR__INV_OBJECT | | vi不能标志正确的连接。 | VI_ERROR_IO | | 位置IO错误。 | VI_ERROR_NSUP_FMT | | writeFmt有不支持的格式说明符。 | VI_ERROR_RSRC_LOCKED | | vi被独占。 | VI_ERROR_TMO | | 操作超时。 |
(2)viWrite
????????原型:ViStatus? viWrite (ViSession vi, ViBuf? buf, ViUInt32 cnt, ViPUInt32 retCnt);
????????描述:同步写入数据。写入的数据存储在buf中。当数据写入完毕函数才返回。任何时间都只能存在一个同步写入。
如果retCnt的值为VI_NULL,将不返回写入数据长度值。
表1-8 viWrite函数参数
参数 | 方向 | 描述 | vi | IN | 对象标识符 | buf | IN | 写入数据存放地址。 | cnt | IN | 指定写入长度。 | retCnt | OUT | 实际写入长度,如果为VI_NULL表示不关心该值。 |
表1-9 viWrite函数返回值
标识符 | 值 | 描述 | VI_SUCCESS | 0 | 成功读取,读取到END指示器结束。 | VI_SUCCESS_MAX_CNT | | 成功读取,已经达到最大长度cnt。 | VI_SUCCESS_TERM_CHAR | | 成功读取,读取到特定终止符。 | VI_ERROR_ASRL_FRAMING | | 格式错误。 | VI_ERROR_ASRL_OVERRUN | | 溢出错误。 | VI_ERROR_ASRL_PARITY | | 同步错误。 | VI_ERROR_BERR | | 总线错误。 | VI_ERROR_CONN_LOST | | 连接丢失。 | VI_ERROR_INV_SESSION VI_ERROR_INV_OBJECT | | vi不能标志正确的连接。 | VI_ERROR_INV_SETUP | | 设置无效,不能执行操作。 | VI_ERROR_IO | | 位置I/O是错误。 | VI_ERROR_NCIC | | 非法控制器。 | VI_ERROR_NLISTENERS | | 没有检测到听者。 | VI_ERROR_NSUP_OPER | | vi不支持此函数。 | VI_ERROR_OUTP_PROT_VIOL | | 设备报告输出协议错误。 | VI_ERROR_RAW_RD_PROT_VIOL | | 传输时读协议被破坏。 | VI_ERROR_RAW_WD_PROT_VIOL | | 传输时写协议被破坏。 | VI_ERROR_RSRC_LOCKED | | vi被独占。 | VI_ERROR_TMO | | 操作超时。 |
1.4.4 接收仪器数据——viScanf或viRead
(1)viScanf????????
????????原型:ViStatus? viScanf (ViSession vi, ViString readFmt,arg1,arg2, ...);
????????描述:这操作从设备读取一个字符串,然后格式化后保存值arg变量中。格式化字符串包含说明符、空格字符和普通字符。
VISA中参数不确定的函数(viPrintf,viScanf,和viQueryf)不能被 VB调用。可以用功能相似的viVPrintf,viVScanf,和viVQueryf代替。
表1-10 viScanf函数参数
参数 | 方向 | 描述 | vi | IN | 对象标识符 | readFmt | IN | 格式化字符串。 |
表1-11 viScanf函数返回值
标识符 | 值 | 描述 | VI_SUCCESS | 0 | 成功读到数据并且格式化到arg参数里。 | VI_ERROR_ALLOC | | 内存不足。 | VI_ERROR_INV_FMT | | readFmt包含无效格式化说明符。 | VI_ERROR__INV_SESSION VI_ERROR__INV_OBJECT | | vi不能标志正确的连接。 | VI_ERROR_IO | | 位置IO错误。 | VI_ERROR_NSUP_FMT | | readFmt有不支持的格式说明符。 | VI_ERROR_RSRC_LOCKED | | vi被独占。 | VI_ERROR_TMO | | 操作超时。 |
(2)viRead
????????原型:ViStatus ?viRead (ViSession vi, ViPBuf buf, ViUInt32 cnt, ViPUInt32 retCnt);
????????描述:同步读取数据。读取的数据存在buf中,当数据读取完毕函数才返回。任何时间都只能存在一个同步读取。遇到以下情况同步读取结束:
????????1)收到END指示器;
????????2)读取到终止符;
????????3)读取的数据大小达到cnt的值。
????????注意:必须设置读取终止符。
表1-12 viRead函数参数
参数 | 方向 | 描述 | vi | IN | 对象标识符 | buf | OUT | 返回数据存取地址。 | cnt | IN | 指定读取长度。 | retCnt | OUT | 实际读取长度,如果为VI_NULL表示不关心该值。 |
表1-13 viRead函数返回值
标识符 | 值 | 描述 | VI_SUCCESS | 0 | 成功读取,读取到END指示器结束。 | VI_SUCCESS_MAX_CNT | | 成功读取,已经达到最大长度cnt。 | VI_SUCCESS_TERM_CHAR | | 成功读取,读取到特定终止符。 | VI_ERROR_ASRL_FRAMING | | 构架错误。 | VI_ERROR_ASRL_OVERRUN | | 溢出错误。 | VI_ERROR_ASRL_PARITY | | 同步错误。 | VI_ERROR_BERR | | 总线错误。 | VI_ERROR_CONN_LOST | | 连接丢失。 | VI_ERROR_INV_SESSION VI_ERROR_INV_OBJECT | | vi不能标志正确的连接。 | VI_ERROR_INV_SETUP | | 设置无效,不能执行操作。 | VI_ERROR_IO | | 位置I/O是错误。 | VI_ERROR_NCIC | | 非法控制器。 | VI_ERROR_NLISTENERS | | 没有检测到听者。 | VI_ERROR_NSUP_OPER | | vi不支持此函数。 | VI_ERROR_OUTP_PROT_VIOL | | 设备记录一个输出协议错误。 | VI_ERROR_RAW_RD_PROT_VIOL | | 传输时读协议被破坏。 | VI_ERROR_RAW_WD_PROT_VIOL | | 传输时写协议被破坏。 | VI_ERROR_RSRC_LOCKED | | vi被独占。 | VI_ERROR_TMO | | 操作超时。 |
1.4.5关闭资源管理器和设备连接——viClose
????????原型:ViStatus? viClose (ViObject vi);
????????描述:关闭一个资源管理器或者设备连接,并释放内存。
表1-14 viClose函数参数
表1-15 viClose函数返回值
标识符 | 值 | 描述 | VI_SUCCESS | 0 | 关闭成功。 | VI_WARN_NULL_OBJECT | | 要关闭的对象时空对象。 | VI_ERROR_CLOSING_FAILED | | vi不能标识正当对话通道。 | VI_ERROR__INV_SESSION VI_ERROR__INV_OBJECT | | 无法释放与该对话通道相关联的内存数据结构。 |
2?? Labwindows_cvi基于c语言编程
????????案例:以3672系列的矢量网络分析仪为例,实现矢网连接,发送命令到矢网,接收矢网数据,关闭矢网连接等功能。?
2.1界面设计
????????界面主要包含矢网连接、发送矢网重置命令、接收矢网数据、断开矢网连接、消息提示框等功能。
图2-1 demo界面
?
2.2实现代码
????????所有功能实现代码如下:
#include <utility.h>
#include <ansi_c.h>
#include <cvirte.h>
#include <userint.h>
#include <visa.h>
#include "PNA_CONECT.h"
static int pnaConect;
ViSession defaultRM ,vi;
unsigned char Data_Mag[5000]; // 幅度测试数据
char c_currentMessage[300]; // 提示消息
void GetDateTime(void);
/*==========VISA资源管理器定位==========*/
int RMConnect(void);
int main (int argc, char *argv[])
{
if (InitCVIRTE (0, argv, 0) == 0)
return -1; /* out of memory */
if ((pnaConect = LoadPanel (0, "PNA_CONECT.uir", PNA_CONECT)) < 0)
return -1;
DisplayPanel (pnaConect);
RunUserInterface ();
DiscardPanel (pnaConect);
return 0;
}
int CVICALLBACK PNA_CONECT_CALLBACK (int panel, int event, void *callbackData,
int eventData1, int eventData2)
{
switch (event)
{
case EVENT_GOT_FOCUS:
break;
case EVENT_LOST_FOCUS:
break;
case EVENT_CLOSE:
QuitUserInterface (0);
break;
}
return 0;
}
/*==========VISA资源管理器定位==========*/
int RMConnect()
{
int error,result;
error= viOpenDefaultRM(&defaultRM);
while(error)
{
result = GenericMessagePopup("Error", "VISA资源管理器定位失败!", "重试", "忽略", "", 0, 0, 0, VAL_GENERIC_POPUP_BTN1, VAL_GENERIC_POPUP_BTN1, VAL_GENERIC_POPUP_NO_CTRL);
if(result==1)
{
error= viOpenDefaultRM(&defaultRM);
}
else
break;
}
return defaultRM;
}
/* 连接矢网 */
int CVICALLBACK ConnectPna_CALLBACK (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
int error, select;
switch (event)
{
case EVENT_COMMIT:
RMConnect();
error = viOpen(defaultRM, "TCPIP0::192.168.1.41::5025::SOCKET", VI_NULL,VI_NULL, &vi); //3672B
if(error==0)
{
GetDateTime() ;
strcat(c_currentMessage," 矢网连接成功!\n");
SetCtrlVal (panel, PNA_CONECT_TEXTBOX, c_currentMessage);
}
while ( error )
{
select= GenericMessagePopup ("Error", "矢网连接错误,请重试或检查连接状态", "重试", "忽略", "", 0, 0, 0, VAL_GENERIC_POPUP_BTN1, VAL_GENERIC_POPUP_BTN1, VAL_GENERIC_POPUP_NO_CTRL);
if ( select == 1 )
{
error = viOpen(defaultRM, "TCPIP0::192.168.1.41::1024::SOCKET", VI_NULL,VI_NULL, &vi);
}
else
{
GetDateTime() ;
strcat(c_currentMessage," 矢网连接错误,请重试或检查连接状态!\n");
SetCtrlVal (panel, PNA_CONECT_TEXTBOX, c_currentMessage);
}
break;
}
}
return vi;
}
//发送矢网命令
int CVICALLBACK SEND_RST_CALLBACK (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event)
{
case EVENT_COMMIT:
// 矢网重置
viPrintf(vi,"*RST\n");
// 删除所有测试设置
viPrintf(vi,"CALC:PAR:DEL:ALL\n");
// 关闭所有窗口
viPrintf(vi,"DISPlay:WIND OFF\n");
// 打开新建窗口
viPrintf(vi,"DISPlay:WIND1 ON\n");
// 定义测试内容
// 定义测试内容
viPrintf(vi,"CALC1:PAR:DEF:EXT 'mytrace','S21'\n");
// 显示测试迹线
viPrintf(vi,"DISPlay:WIND1:TRAC1:FEED 'mytrace'\n");
// 选定测试迹线
viPrintf(vi,"CALC1:PAR:SEL 'mytrace'\n");
// 设置测试类型(对数幅度)
viPrintf(vi,"CALC1:FORM MLOG\n");
// 设置扫描类型为段扫描 */
viPrintf(vi,"SENS1:SWE:TYPE SEGM\n");
// 段扫描开始频率 */
viPrintf(vi,"SENS1:SEGM:FREQ:STAR 12GHz\n");
// 段扫描终止频率 */
viPrintf(vi, "SENS1:SEGM:FREQ:STOP 12GHz\n");
// 段扫描频率点数 */
viPrintf(vi,"SENS1:SEGM:SWE:POIN 1\n");
GetDateTime();
strcat(c_currentMessage," 矢网命令已发送!\n");
SetCtrlVal (panel, PNA_CONECT_TEXTBOX, c_currentMessage);
break;
}
return 0;
}
//接收矢网数据
int CVICALLBACK RECEIVE_DATA_CALLBACK (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
// 频点个数
int length=1;
switch (event)
{
case EVENT_COMMIT:
// 从通道 1 所选测量轨迹中读取格式化数据。
viPrintf(vi,"CALC1:DATA? FDATA\n");
// 读取矢网测试数据 length:频点个数
viRead (vi,Data_Mag ,length*20,VI_NULL);
GetDateTime();
strcat(c_currentMessage," ");
strcat(c_currentMessage,Data_Mag);
//将读取的数据显示
SetCtrlVal (panel, PNA_CONECT_TEXTBOX, c_currentMessage);
GetDateTime();
strcat(c_currentMessage," 数据读取完成!\n");
SetCtrlVal (panel, PNA_CONECT_TEXTBOX, c_currentMessage);
break;
}
return 0;
}
//释放矢网资源
int CVICALLBACK DISCONNECT_CALLBACK (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event)
{
case EVENT_COMMIT:
viClose(vi);
viClose(defaultRM);
GetDateTime();
strcat(c_currentMessage," 已经释放矢网资源并关闭!\n");
SetCtrlVal (panel, PNA_CONECT_TEXTBOX, c_currentMessage);
break;
}
return 0;
}
//获取系统日期时间
void GetDateTime()
{
int i_hour, i_minute , i_second ;
int i_month , i_day , i_year;
char c_hour[9], c_minute[3], c_second[3];
char c_year[10], c_month[3], c_day[3];
char c_diagonal[2]="/", c_colon[2]=":",c_space[2]=" ";
char c_date[19], c_currenttime[9];
//获取系统时间
GetSystemTime(&i_hour,&i_minute , &i_second );
//获取系统日期
GetSystemDate(&i_month,&i_day, &i_year);
//将int类型数据转为字符串数据
sprintf(c_hour,"%d",i_hour);
sprintf(c_minute,"%d",i_minute);
sprintf(c_second,"%d",i_second);
sprintf(c_year,"%d",i_year);
sprintf(c_month,"%d",i_month);
sprintf(c_day,"%d",i_day);
//拼接字符串
strcpy(c_date,strcat(strcat(strcat(strcat(c_year,c_diagonal),c_month),c_diagonal),c_day));
strcpy(c_currenttime,strcat(strcat(strcat(strcat(c_hour,c_colon),c_minute),c_colon),c_second));
strcpy(c_currentMessage,strcat(strcat(c_date,c_space),c_currenttime));
}
2.3功能显示
????????连接的矢量网络分析仪型号时AV3672B矢量网络分析仪,展示功能如下:
图2-2 demo实现效果
?
|