ProCon说明   快速入门   运动控制   EtherCAT   实时程序   API函数   控件库   硬件说明   问题排查   示例代码  
  

NoTime

共享内存

安装目录\doc\example\Notime\ShareMem,实现共享内存声明、管理及调用。
利用struct封装共享内存:
unsafe public struct MemConfig
{
  // 共享内存成员变量
  public int smTest;
  // 退出命令
  public int exit;
  // 数组
  public fixed int array[256];
}

NoTime端创建共享内存:
int size = Marshal.SizeOf(new MemConfig());
ulong addr = 0;
NoCode code = NoSys.NOS_CreateShareMemory(MEM_NAME, (uint)size, out addr,1);
pConfig = (MemConfig*)addr;
memAddr = addr;

NoTime内存操作逻辑:
//共享内存读写
Byte[] temp = new Byte[4];
//读取array[0]
MemOper.ReadShareMemory(8, temp, 4);
//array[0]写到smTest]
MemOper.WriteShareMemory(0, temp, 4);
//数组访问
MemOper.IncArray(0);

Windows加载Console程序到NoTime:
ProCon.YKM_LoadNotimeAppEx(YKM_NODE.ECAT_A, name)

Windows检查Console程序是否在运行
ProCon.YKM_CheckNotimeApp(YKM_NODE.ECAT_A, Encoding.UTF8.GetBytes("Notime.exe"), out nNotimeStatus);

Windows获取共享内存引用:
ulong addr = 0;
NoCode code = NoSys.NOS_OpenShareMemory(0,MEM_NAME, out addr,1);
pConfig = (MemConfig*)addr;

Windows端显示逻辑:
var smTest = MemOper.GetSmTest();
var array = MemOper.GetArray(0);
textBoxMemRw.Invoke(new Action(() =>
{
  textBoxMemRw.Text = smTest.ToString();
  textBoxArray.Text = array.ToString();
}));

IO翻转

安装目录\doc\example\Notime\DoToggle,在NoTime程序实现IO反转,可借助示波器等仪器抓取IO波形,测试在windows下及NoTime下,IO反转周期的稳定性。
注:将翻转输出引脚短接到翻转输入引脚。
NoTimeIO翻转逻辑:
uint val_set = 1;
uint val_get = uint.MinValue;
while (!mCancel)
{
  //设置输出
  var ret = ProCon.YKM_WriteDigitalOutputBit(0, 4, val_set);
  System.Threading.Thread.Sleep(1);
  ProCon.YKM_ReadDigitalInputBit(0, 3, out val_get);
  val_set = (val_set == 1) ? (uint)0 : 1;
  System.Threading.Thread.Sleep(1);
  if (0 != MemOper.GetExit())
    break;
}

高精度线程

安装目录\doc\example\Notime\SchedulingCycleThread,NoTime下的高精度线程(微秒延时)和Windows下线程,采集任务执行时间,并在windows端显示最大值,当前值。

NoTime端计时器逻辑:
static int loopCount = 0;
//刷新计数统计
static void RefreshTick()
{
  NoSys.NOS_GetUsTick(out mCurTick);
  mDiffCur = mCurTick - mLastTick;
  mDiffMax = mDiffCur > mDiffMax ? mDiffCur : mDiffMax;
  mLastTick = mCurTick;
  loopCount++;
}
//获取高精度tick计数
NoSys.NOS_GetUsTick(out mLastTick);
while (!mCancel)
{
  NoSys.NOS_SleepUs(250);
  if (0 != MemOper.GetExit())
    break;
  RefreshTick();
  //共享内存到NoTimeWin显示
  MemOper.pConfig->times = loopCount;
  MemOper.pConfig->diffCur = mDiffCur;
  MemOper.pConfig->diffMax = mDiffMax;
  //清除最大值
  if(0 != MemOper.pConfig->clrMax)
  {
    mDiffMax = 0;
    MemOper.pConfig->clrMax = 0;
  }
}

Windows端计时器逻辑:
static int loopCount = 0;
//刷新计数统计
static void RefreshTick()
{
  NoSys.NOS_GetUsTick(out mCurTick);
  mDiffCur = mCurTick - mLastTick;
  mDiffMax = mDiffCur > mDiffMax ? mDiffCur : mDiffMax;
  mLastTick = mCurTick;
  loopCount++;
}
//获取高精度tick计数
NoSys.NOS_GetUsTick(out mLastTick);
while (!mCancel)
{
  System.Threading.Thread.Sleep(1);
  if (0 != MemOper.GetExit())
    break;
  RefreshTick();

Windows端显示计时统计:
var ticks = MemOper.GetTimes();
var diffCur = MemOper.GetDiffCur();
var diffMax = MemOper.GetDiffMax();
txtTime.Invoke(new Action(() =>
{
  this.txtTime.Text = ticks.ToString();
  this.txtDiffCur.Text = diffCur.ToString();
  this.txtDiffMax.Text = diffMax.ToString();
  this.txtTimeWin.Text = Worker.loopCount.ToString();
  this.txtDiffCurWin.Text = Worker.mDiffCur.ToString();
  this.txtDiffMaxWin.Text = Worker.mDiffMax.ToString();
}));

高精度线程VB.net

安装目录\doc\example\Notime\SchedulingCycleThreadVB,NoTime下的VB.net实现高精度线程和Windows下线程,采集任务执行时间,并在windows端显示最大值,当前值。

NoTime端计时器逻辑:
Shared loopCount As Integer
//刷新计数统计
Public Shared Sub RefreshTick()
  NoSys.NOS_GetUsTick(mCurTick)
  mDiffCur = mCurTick - mLastTick
  mDiffMax = IIf(mDiffCur > mDiffMax, mDiffCur, mDiffMax)
  mLastTick = mCurTick
  loopCount += 1
End Sub
//获取高精度tick计数
While Not mCancel
  System.Threading.Thread.Sleep(1)
  If MemOper.GetExit() <> 0 Then
    Exit While
  End If
  RefreshTick()
  //共享内存到NoTimeWin显示
  MemOper.SetDiffCur(mDiffCur)
  MemOper.SetDiffMax(mDiffMax)
  MemOper.SetTimes(loopCount)
  //清除最大值
  If 0 <> MemOper.GetClearMax() Then
    mDiffMax = 0
    MemOper.SetClearMax(0)
  End If
  End While
End Sub

Windows端计时器逻辑:
static int loopCount = 0;
//刷新计数统计
static void RefreshTick()
{
  NoSys.NOS_GetUsTick(out mCurTick);
  mDiffCur = mCurTick - mLastTick;
  mDiffMax = mDiffCur > mDiffMax ? mDiffCur : mDiffMax;
  mLastTick = mCurTick;
  loopCount++;
}
//获取高精度tick计数
NoSys.NOS_GetUsTick(out mLastTick);
while (!mCancel)
{
  System.Threading.Thread.Sleep(1);
  if (0 != MemOper.GetExit())
    break;
  RefreshTick();

Windows端显示计时统计:
var ticks = MemOper.GetTimes();
var diffCur = MemOper.GetDiffCur();
var diffMax = MemOper.GetDiffMax();
txtTime.Invoke(new Action(() =>
{
  this.txtTime.Text = ticks.ToString();
  this.txtDiffCur.Text = diffCur.ToString();
  this.txtDiffMax.Text = diffMax.ToString();
  this.txtTimeWin.Text = Worker.loopCount.ToString();
  this.txtDiffCurWin.Text = Worker.mDiffCur.ToString();
  this.txtDiffMaxWin.Text = Worker.mDiffMax.ToString();
}));

Socket客户端

安装目录\doc\example\Notime\SocketClient,NoTime下实现的Socket客户端。

1、实时系统下网卡配置
物理网卡导入参考快速入门-实时系统-网卡导入章节。

2、实时系统下IP设置
鼠标右击"INtime"图标,选择"INtime Configuration"进入设置面板。

双击"Node Management"打开节点配置,选择"AutoLoad"选项卡,将Network设置为"Enabled"。

选择"Network"选项卡,将Start automatically设置为"Yes",点击"NIC List"进入编辑界面

选择"NIC List"进入编辑界面

选择"Add"进入IP设置

序号 注释
1 选择对应驱动的网卡类型"Type"
2 虚拟网卡可以不用选择跳过此步。物理网卡需要选择网卡的instance编号,如果存在instance编号为0的网卡正被使用在EtherCAT通讯中,那么用于Socket通讯的网卡选instance编号为1的网卡。
如果必须要使用instance编号为0的网卡进行Socket通讯,那么用于进行EtherCAT通讯的网卡会自动分配为instance编号为1的网卡,所以请将用于EtherCAT通讯的网线插入对应instance编号为1的网卡口中。
如何知晓网卡的instance编号请参考INtime中的多网卡导入:INtime多网卡导入
3 如果配置的是虚拟网口勾选Use interrupt,如果配置的是实际物理网口,勾选Poll the NIC every
4 配置本机INtime系统中用于Socket通讯的ip地址

第四步中,选择OK确认后,单击Save并单击Exit退出,弹框提示是否重启kernels

选择"是"。重启成功后,链路正常,如果配置的是虚拟网卡,则Windows下网络连接中"TenAsys Virtual Ethernet Adapter"连接显示已连接状态,如下图所示。适配器中的该虚拟网卡是Windows系统中用于进行Socket通讯的虚拟网卡,所以也需要给该网卡设置相应的ip地址。注意:Windows系统下设置的ip和INtime系统下设置的ip需在同一个子网中。


3、ping命令使用

注意:INtime端与Windows端的ip地址需处在同一个子网下面。

Windows下ping,键盘按Win图标+R,输入cmd,按Enter进入命令行,输入ping 192.168.211.2(目标地址为INtime端配置IP,根据用户设置更改),出现如下图所示,无错误,则链路正常。

Intime端ping,键盘按Win图标+R,输入cmd,按Enter进入命令行,输入C:\Program Files (x86)\INtime\bin并按Enther,切换到Intime目录。输入piperta.exe ping 192.168.10.3,可诊断链路情况,如下图所示,为链路正常。
注意Windows端防火墙需关闭。

4、编程

注意:NoTime里写的Socket和Windows里是一样的,但是目前不能使用事件的形式接受消息,推荐用buffer非阻塞轮询读取消息,然后校验一下数据完整性,再处理。

不支持拼包操作,如果接收大的数据包,会分多次接收。

NoTime客户端:
//创建客户端套接字
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
byte[] szIP = new byte[128];
//共享内存接收Windows端设置的服务端IP
MemOper.GetIP(szIP);
string strIP = Encoding.Default.GetString(szIP,0,szIP.Length).TrimEnd('\0');
Console.WriteLine("IP:"+ strIP);
IPAddress ip = IPAddress.Parse(strIP);
int nPort = MemOper.GetPort();
Console.WriteLine("IP:"+ nPort);
IPEndPoint iPEndPoint = new IPEndPoint(ip, nPort);
socket.Blocking = false;
//连接服务器
socket.Connect(iPEndPoint);
Console.WriteLine("连接:"+socket.Connected);
//循环接收消息
while (!mCancel)
{
  if (0 != MemOper.GetExit())
  break;
  string strRtn = "";
  if ((socket?.Connected).Value)
  {
    byte[] buffer = new byte[1024 * 2];
    try
    {
      int ret = socket.Receive(buffer);
      if (ret != 0)
      {
        strRtn = Encoding.Default.GetString(buffer, 0, ret);
        Console.WriteLine(strRtn);
        socket.Send(buffer);
      }
    }
    catch (Exception)
    {
    }
  }
  System.Threading.Thread.Sleep(1);
}
socket?.Close();

Windows服务器:
//创建服务器套接字
_socketService = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress address = IPAddress.Parse(txt_ServiceIP.Text);
IPEndPoint endPoint = new IPEndPoint(address, nPort);
//绑定监听IP及端口
_socketService.Bind(endPoint);
_socketService.Listen(int.MaxValue);
//异步监听客户端连接,并保存连接对象
System.Threading.Tasks.Task task = new System.Threading.Tasks.Task(()=>{
  _socketClient = _socketService.Accept();
  _socketClient.Blocking = false;
});
task.Start();
//通过共享内存设置NoTime客户端服务器IP及端口
MemOper.SetIP(Encoding.UTF8.GetBytes(txt_ServiceIP.Text));
MemOper.SetPort(nPort);
System.Threading.Thread.Sleep(100);
//启动客户端
MemOper.SetStartClient(1);

Socket服务器

安装目录\doc\example\Notime\SocketService,NoTime下实现的Socket服务器。网卡及IP配置,参见Socket客户端。

NoTime服务器:
//创建服务器套接字
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
byte[] szIP = new byte[128];
//共享内存接收Windows端设置的服务端IP
MemOper.GetIP(szIP);
string strIP = Encoding.Default.GetString(szIP,0,szIP.Length).TrimEnd('\0');
Console.WriteLine("IP:"+ strIP);
IPAddress ip = IPAddress.Parse(strIP);
int nPort = MemOper.GetPort();
Console.WriteLine("IP:"+ nPort);
IPEndPoint iPEndPoint = new IPEndPoint(ip, nPort);
//绑定监听IP及端口
socket.Bind(iPEndPoint);
socket.Listen(3);
Socket socketClient = socket.Accept();
Console.WriteLine("连接:"+ socketClient.Connected);
//循环接收消息
while (!mCancel)
{
  if (0 != MemOper.GetExit())
  break;
  string strRtn = "";
  if ((socketClient?.Connected).Value)
  {
    byte[] buffer = new byte[1024 * 2];
    try
    {
      int ret = socketClient.Receive(buffer);
      if (ret != 0)
      {
        strRtn = Encoding.Default.GetString(buffer, 0, ret);
        Console.WriteLine(strRtn);
        socketClient.Send(buffer);
      }
    }
    catch (Exception)
    {
    }
  }
  System.Threading.Thread.Sleep(1);
}
socketClient?.Close();
socket?.Close();

Windows客户端:
//通过共享内存设置NoTime服务器IP及端口
MemOper.SetIP(Encoding.UTF8.GetBytes(txt_ServiceIP.Text));
MemOper.SetPort(nPort);
System.Threading.Thread.Sleep(100);
//启动服务器
MemOper.SetStartSocket(1);
System.Threading.Thread.Sleep(100);
//创建客户端套接字
_socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress address = IPAddress.Parse(txt_ServiceIP.Text);
IPEndPoint endPoint = new IPEndPoint(address, nPort);
//连接服务器
_socketClient.Connect(endPoint);

串口

安装目录\doc\example\Notime\SerialPort,NoTime下实现串口通信。

1、串口导入
鼠标右击"INtime"图标,选择"INtime Configuration"进入设置面板。

双击"INtime Device Manager",打开设备管理器页面。

展开①"端口",右击选择对应串口,选择②"Pass to INtime using polling",点击③感叹号保存配置。

2、串口驱动配置
进入"Node Management"节点管理

选择①"Auto Load"选项卡,单击②"Add",进入驱动加载设置

设置串口描述①"Application Title",注意非实际串口名,选择串口驱动路径②"Full Path"。
串口驱动选择参照下表

设置成功后选择重启kernel。

3、编程

NoTime端:
//共享内存接收串口配置并配置
byte[] szCOM = new byte[128];
MemOper.GetCOM(szCOM);
string strCOM = Encoding.Default.GetString(szCOM,0,szCOM.Length).TrimEnd('\0');
Console.WriteLine("COM:"+ strCOM);
int nBaudRate = MemOper.GetBaudRate();
Console.WriteLine("Baud:"+ nBaudRate);
//SerialPort 类不可使用无参构造函数SerialPort(),会引发寻找Windows注册表错误。
SerialPort serialPort = new SerialPort(strCOM, nBaudRate);
//打开串口
serialPort.Open();
Console.WriteLine("连接:"+ serialPort.IsOpen);
serialPort.ReadTimeout = 100;
//循环接收消息
while (!mCancel)
{
  if (0 != MemOper.GetExit())
  break;
  string strRtn = "";
  if ((serialPort?.IsOpen).Value)
  {
    try
    {
      strRtn = serialPort.ReadLine();
      if (strRtn?.Length >0)
      {
        Console.WriteLine(strRtn);
        serialPort.WriteLine(strRtn);
      }
    }
    catch (Exception)
    {
    }
  }
  System.Threading.Thread.Sleep(1);
}
serialPort?.Close();

Windows端:
//初始化并打开串口
_serialPort = new SerialPort(strCOMWin);
_serialPort.Open();
if (_serialPort.IsOpen)
{
//通过共享内存设置NoTime串口信息
  MemOper.SetCOM(Encoding.UTF8.GetBytes(strCOMNotime));
  MemOper.SetBaudRate(nBaudRate);
  System.Threading.Thread.Sleep(100);
//启动NoTime串口
  MemOper.SetStartCOM(1);
  return;
}
else
{
  MessageBox.Show("串口打开失败");
  return;
}

事件

安装目录\doc\example\Notime\Event,NoTime下事件实现及订阅。
//事件发布器
class EventTest
{
  public delegate void SecondEvent();
  public static event SecondEvent SecondChange;
  public static void DoEvent()
    {
    if (SecondChange != null)
    {
      SecondChange();
    }
  }
}
//订阅事件
EventTest.SecondChange += SecondFunTimes;
EventTest.SecondChange += SeconFunYKCat;
//在线程中周期触发事件
EventTest.DoEvent();
//共享内存操作
unsafe public static void SecondFunTimes()
{
  MemOper.pConfig->times = sTimes++;
}
//YKCat2调用
unsafe public static void SeconFunYKCat()
{
  YKM_BusInfo yKM_BusInfo = new YKM_BusInfo();
  ProCon.YKM_GetBusInfo(out yKM_BusInfo);
  MemOper.pConfig->cur_payload = yKM_BusInfo.cur_payload;
}

 

  
Copyright © 2015 深圳市优易控软件有限公司 www.proutech.com