CANoe9.0用CAPL控制数控电源

1.前言

本文提供一种基于CAPL控制数控电源的方法,其实现原理是CAPL中调用RS232,发送SCPI指令与数控电源通信。

理论上,本文适用于串口通信的数控电源或其他串口设备。

2.开发环境

2.1硬件环境

数控电源KORAD KA3005P,CANcaseXL

2.2软件环境

CANoe 9.0,串口调试助手

3.参考资料

KA系列标准通信协议_百度文库  https://wenku.baidu.com/view/6adf09f1294ac850ad02de80d4d8d15abe230039.html

CANoe DEMO:File-Sample Configurations-IO HIL-RS232,这里是个使用RS232的DEMO

4.测试SCPI指令

将数控电源连上PC,注意,虽然是USB接口,但是数控电源内部虚拟了串口,可以在设备管理器中发现。

用串口助手打开电源的串口,设置波特率为9600(这里测试任何一个波特率都可以,不知为什么)。

然后以ASCII的方式发送指令。

这里测试的目的主要是为了验证通信。

具体的指令可以根据文档描述测试一下,这里就不细说了。

5.建立CANoe工程

创建个合适的工程,建立CAPL NODE,DBC,以及PANEL

6.编辑CAPL代码

以下代码参考了Demo

/*@!Encoding:936*/
includes
{
  
}

variables
{
  // GLOBAL
  const int kBUFFER_SIZE = 1000;
  const int kINFO        = 1;
  const int kWARN        = 2;
  const int kERROR       = 3;
  
  const int kHANDSHAKE_DISABLED = 0;
  const int kHANDSHAKE_RTSCTS   = 33;
  
  // define for dp serial port com9
  const dword port = 9;
  const dword baudrate = 9600;
  const dword dataBits = 8;
  const dword stopBits = 1;
  const dword parity = 0;//0:none 1:even 0:odd
   
  // data is copied from callback buffer to gReceiverBuffer (collects data)
  byte gReceiverCallbackBuffer[kBUFFER_SIZE];
  
  byte gReceivedBuffer[kBUFFER_SIZE];
  dword gReceivedIndex= 0;
  
  // state variable
  byte gSending = 0;
  
  byte gGetValueSt = 0;
  byte gSetValueSt = 0;
  
  msTimer t100ms;
  msTimer t20ms;
}

on preStart
{
  InitSerialPort();  
}

on start
{
  setTimer(t100ms,100);
}
//RS232 Init
InitSerialPort()
{
  // close serial port (port may have changed, former port shall not remain open)
  if(Rs232Close(port)!=1)
    writeLineEx(0,kERROR,"An error occurred during closing of the serial port %d.", port);    

  // set state (close aborts all open requests)
  gSending = 0;

  // open the serial port (comes up with Windows defaults)
  if(Rs232Open(port)==1)
    writeLineEx(0,kINFO, "Serial port %d successfully opened.", port);    
  else
    writeLineEx(0,kERROR,"An error occurred during opening of the serial port %d.", port);    

  // configure the serial port
  // - just take the panel content
  if(Rs232Configure(port,baudrate,dataBits,stopBits,parity)==1)
    writeLineEx(0,kINFO, "Serial port %d successfully initialized.", port);    
  else
    writeLineEx(0,kERROR,"An error occurred during initialization of the serial port %d.", port);    
  
  // port, handshake, xonLim, xoffLim, xonChar, xoffChar, writeTimeout
  // without last timeout parameter: use default timeout
  // for transmission of small amounts of data one may not need to use handshake ! 
  // e.g. 33 for RTS/CTS as second parameter for large volumes of data, 0 for small volumes
  if(Rs232SetHandshake(port, kHANDSHAKE_DISABLED, 0, 0, 0, 0))
    writeLineEx(0,kINFO, "Handshake parameters for serial port %d successfully configured.", port);    
  else
    writeLineEx(0,kERROR,"An error occurred during the serial port %d configuration of handshake parameters.", port);

  // set buffer for reception (otherwise callback would not work)
  if(Rs232Receive(port, gReceiverCallbackBuffer, kBUFFER_SIZE))
    writeLineEx(0,kINFO, "Receiver buffer for serial port %d successfully set.", port);    
  else
    writeLineEx(0,kERROR,"An error occurred during setting the receiver buffer for serial port %d.", port);
}
//RS232 Call back
RS232OnReceive( dword port, byte buffer[], dword number )
{
  dword i;
  for(i=0;i<number;i++)
  {  
    gReceivedBuffer[gReceivedIndex++]=buffer[i];
    if(gReceivedIndex>=5)
    {
      DP_DataRecevied(gReceivedBuffer,gReceivedIndex);
      gReceivedIndex=0;
    }
  }
}
//RS232 Call back
RS232OnSend( dword port, byte buffer[], dword number )
{
  // set state
  gSending = 0;

  //writeLineEx(0,kINFO,"Transmission of %d bytes from port %d completed !", number, port);
}
//RS232 Call back
RS232OnError( dword port, dword errorFlags )
{
  // set state
  gSending = 0;

  writeLineEx(0,kERROR,"Error handler called with error code %d !", errorFlags);

  if ( errorFlags & 1 )
    writeLineEx(0,1,"%d informs of send error",errorFlags);
  if ( errorFlags & 2 )
    writeLineEx(0,1,"%d informs of receive error",errorFlags);
  if ( errorFlags & 4 )
    writeLineEx(0,1,"%d informs of frame error",errorFlags);
  if ( errorFlags & 8 )
    writeLineEx(0,1,"%d informs of parity error",errorFlags);
  if ( errorFlags & 16 )
    writeLineEx(0,1,"%d informs of overrun error",errorFlags);
  if ( errorFlags & 32 )
    writeLineEx(0,1,"%d informs of receiver overrun error",errorFlags);
  if ( errorFlags & 64 )
    writeLineEx(0,1,"%d informs of break state",errorFlags);
  if ( errorFlags & 128 )
    writeLineEx(0,1,"%d informs of send timeout error",errorFlags);
}

CopyBuffer( byte destBuffer[], dword destOffset, byte srcBuffer[], dword srcNumber )
{
  dword i;

  for (i=0; i<srcNumber; i++)
  {
    destBuffer[destOffset+i] = srcBuffer[i];
  }
}

/* Panel */
on envVar Env_KeyOnOff
{
  if(getValue(this)==1)
  {
    if(getValue(Env_OnOff)==1)
    {
      putValue(Env_OnOff,0);
      putValue(Env_StrOnOff,"OFF");
    }  
    else
    {
      putValue(Env_OnOff,1);
      putValue(Env_StrOnOff,"ON");
    }
  }
}

on envVar Env_Send
{
  if(getValue(this)==1)
  {
    gSetValueSt = 0;
    setTimer(t20ms, 30);
    
    cancelTimer(t100ms);
  }
}

on timer t100ms
{
  if(gGetValueSt == 0)
  {
    DP_Send("VOUT1?",6);
  }
  else
  {
    DP_Send("IOUT1?",6);
  }
  setTimer(t100ms, 100);
}

on timer t20ms
{
  switch(gSetValueSt)
  {
    case 0:
      DP_SetVoltage(getValue(Env_SetVoltage));
      setTimer(t20ms, 40);//20ms seems too short chg to 40ms
      break;
    case 1:
      DP_SetCurrent(getValue(Env_SetCurrent));
      setTimer(t20ms, 40);//20ms seems too short chg to 40ms
      break;
    case 2:
      if(getValue(Env_OnOff)==1)
        DP_Send("OUT1",4);
      else
        DP_Send("OUT0",4);
      setTimer(t100ms, 100);
      break;
    default:
      break;
  }
  gSetValueSt++;
}

DP_Send(char str[],byte len)
{
  byte buffer[100];
  byte i;
  if ( gSending )
  {
    writeLineEx(0,kWARN,"Ongoing transmission, please wait for completion of previous one !");
    return;
  }
  
  for(i=0; i<len; i++)
  {
    buffer[i] = (byte)(str[i]);
  }
  
  if(0==Rs232Send(port, buffer, len))
  {
    writeLineEx(0,kERROR,"An error occurred during write of block of data to the serial port %d.", port);
    return;
  } 
  // set state
  gSending = 1;
}

DP_SetVoltage(float data)
{
  char str[7]="VSET1:";
  char buf[100];
  word vol=0;
  byte i;
  
  for(i=0; i<6; i++)
  {
    buf[i]=str[i];
  }
  
  vol = (word)(data*100);
  
  if(vol>3000)
    writeLineEx(0,kERROR,"Voltage too high! ");
  else
  {
    buf[i++]=(byte)(vol/1000)+0x30;
    vol%=1000;
    buf[i++]=(byte)(vol/100)+0x30;
    vol%=100;
    buf[i++]='.';
    buf[i++]=(byte)(vol/10)+0x30;
    buf[i++]=(byte)(vol%10)+0x30;
    
    DP_Send(buf, i);
  }
}

DP_SetCurrent(float data)
{
  char str[7]="ISET1:";
  char buf[100];
  word vol=0;
  byte i;
  
  for(i=0; i<6; i++)
  {
    buf[i]=str[i];
  }
  
  vol = (word)(data*1000);
  
  if(vol>5000)
    writeLineEx(0,kERROR,"Current too high! ");
  else
  {
    buf[i++]=(byte)(vol/1000)+0x30;
    vol%=1000;
    buf[i++]='.';
    buf[i++]=(byte)(vol/100)+0x30;
    vol%=100;
    buf[i++]=(byte)(vol/10)+0x30;
    buf[i++]=(byte)(vol%10)+0x30;
    
    DP_Send(buf, i);
  }
}

DP_DataRecevied(byte buffer[], dword len)
{
  switch(gGetValueSt)
  {
    case 0:
      putValue(Env_GetVoltage,AtoF(buffer,len));
      gGetValueSt=1;
      break;
    case 1:
      putValue(Env_GetCurrent,AtoF(buffer,len));
      gGetValueSt=0;
      break;
    default:
      break;
  }
}

float AtoF(byte buffer[], dword len)
{
  double getData;
  dword i;
  byte flag;
  dword per;
  
  getData = 0;//static
  per=1;//static
  flag=0;//static
  
  for(i=0; i<len; i++)
  {
    if('0'<=buffer[i] && buffer[i]<='9')
    {
      getData*=10;
      getData+=(buffer[i]-'0');
      
      if(flag)
      {
        per*=10;
      }
    }
    else if(buffer[i]=='.')
    {
      flag=1;
    }   
  }
  
  getData/=per;

  return getData;
}

 

7.测试

8.总结

(1)CANoe十分强大,可以干很多事情,本文中的方法也只是众多控制数控电源方式中的一种,本人未开发过基于CANoe的自动化测试设备,也并不清楚并不清楚商业上是如何实现的。

(2)DEMO很有参考价值,不会的可以找DEMO参考

(3)他节点可以通过调用dbc中定义的环境变量,来获取或者设置电源的电压电流

(4)win10微软拼音在360浏览器编辑此贴,打字会抽风

 

  • 25
    点赞
  • 177
    收藏
    觉得还不错? 一键收藏
  • 23
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值