ProCon说明 快速入门 运动控制 EtherCAT 实时程序 API函数 控件库 硬件说明 问题排查 示例代码 |
安装目录\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();
}));
安装目录\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();
}));
安装目录\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();
}));
安装目录\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);
安装目录\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 |