一、中断、多线程、多任务
中断是一种使CPU中止正在执行的程序而转去处理特殊事件的操作。在运行一个程序的过程中,断续地以“插入”方式执行一些完成特定处理功能的程序段。
硬件多线程是指多核的CPU,例如英特尔的入门级CPU i3 10100为4核八线程、AMD的Ryzen 3 3300X为4核八线程。
软件多线程则是通过快速的在不同线程之间进行切换,由于时间间隔很短从而给人造成一种多个线程同时运行的假象。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
多任务,任务是指独立的应用程序,“多任务”类似于手机或者电脑的应用程序的“两开”、“多开”。abb有一个选项包623-1 multitasking 可以实现最多同时运行14个RAPID程序,用于监控外部设备或先进计算。
二、中断触发socket发送实时位置给上位机,0.1s周期,精确到小数点后2位
abb提供了永久变量改变时中断、模拟量信号到达指定范围时中断、数字量及组输入组输出信号为1时或改变时中断、定时触发中断等。
那么,咱们做个例子,plc或上位机点击按钮实现实时位置上传功能。首先想到的实现方法是为abb添加623-1 multitasking选项包,不过现在咱们了解了中断,用两个中断也可实现这个功能。
先用永久变量改变时中断触发一个中断程序,再在这个中断程序中添加此永久变量为1时,启动定时中断,触发最小间隔为0.1s的、发送当前实时位置的程序。
http://mpvideo.qpic.cn/0b78haaaiaaapuaby5kp2bqfaogdaq4aabaa.f10002.mp4?dis_k=693b3fa58a6891774e9aa4b2763f4b2b&dis_t=1653188450&vid=wxv_1781807822230323208&format_id=10002&support_redirect=0&mmversion=false
代码:
LOCAL VAR num server_port:=4002;
LOCAL VAR socketdev server_socket;
LOCAL VAR socketdev client_socket;
PERS num Sync_var_robot;
LOCAL VAR intnum intr_var;
LOCAL VAR intnum intr_send_robstatus;
LOCAL CONST num send_cycletime:=0.1;
VAR string receiveStr;
VAR num receiveDataNumb;
VAR bool OK;
VAR robtarget CurrentPos;
VAR num CurrentX;
VAR num CurrentY;
VAR num CurrentZ;
VAR num CurrentA;
VAR num CurrentB;
VAR num CurrentC;
VAR string sendStr;
PROC main()
Init_socket server_socket,server_port;
Wait_for_client server_socket,client_socket;
init_var_interrupt;
WHILE TRUE DO
IF (SocketGetStatus(client_socket)=SOCKET_CONNECTED) THEN
SocketReceive client_socket, \str:=receiveStr\NoRecBytes:=receiveDataNumb;
ELSE
ExitCycle;
ENDIF
OK:=StrToVal(receiveStr,Sync_var_robot);
ENDWHILE
ENDPROC
PROC Init_socket(VAR socketdev server_socket,num port)
IF (SocketGetStatus(client_socket)<>SOCKET_CLOSED) SocketClose client_socket;
IF (SocketGetStatus(server_socket)<>SOCKET_CLOSED) SocketClose server_socket;
IF (SocketGetStatus(server_socket)=SOCKET_CLOSED) SocketCreate server_socket;
! GetSysInfo(\LanIp) return "VC" in vitual controler
!IF (SocketGetStatus(server_socket) = SOCKET_CREATED) SocketBind server_socket, GetSysInfo(\LanIp), port;
IF (SocketGetStatus(server_socket)=SOCKET_CREATED) SocketBind server_socket,"127.0.0.1",port;
IF (SocketGetStatus(server_socket)=SOCKET_BOUND) SocketListen server_socket;
ERROR
! raise errors to calling code
RAISE ;
ENDPROC
PROC Wait_for_client(VAR socketdev server_socket,VAR socketdev client_socket,\num wait_time)
VAR string client_ip;
VAR num time_val:=WAIT_MAX;
! default to wait-forever
IF Present(wait_time) time_val:=wait_time;
! close client_socket for this port
IF (SocketGetStatus(client_socket)<>SOCKET_CLOSED) SocketClose client_socket;
WaitUntil(SocketGetStatus(client_socket)=SOCKET_CLOSED);
! waiting for the connection
TPWrite "waiting for connection.";
SocketAccept server_socket,client_socket,\ClientAddress:=client_ip,\Time:=time_val;
TPWrite "Client at "+client_ip+" connected.";
ERROR
RAISE ;
ENDPROC
LOCAL PROC init_var_interrupt()
IDelete intr_var;
CONNECT intr_var WITH var_handler;
IPers Sync_var_robot,intr_var;
ERROR
RAISE;
ENDPROC
LOCAL TRAP var_handler
IDelete intr_send_robstatus;
IF (Sync_var_robot=1) THEN
! Sync_var_robot = 1 means send robstatus
init_send_robstatus_interrupt;
ENDIF
ENDTRAP
LOCAL PROC init_send_robstatus_interrupt()
IDelete intr_send_robstatus;
CONNECT intr_send_robstatus WITH send_robstatus;
ITimer send_cycletime,intr_send_robstatus;
ERROR
RAISE;
ENDPROC
LOCAL TRAP send_robstatus
CurrentPos :=CRobT();
CurrentX:=CurrentPos.trans.x;
CurrentY:=CurrentPos.trans.y;
CurrentZ:=CurrentPos.trans.z;
CurrentC:=EulerZYX(\x,CurrentPos.rot);
CurrentB:=EulerZYX(\y,CurrentPos.rot);
CurrentA:=EulerZYX(\z,CurrentPos.rot);
sendStr:=NumToStr(CurrentX,2)+";"+NumToStr(CurrentY,2)+";"+NumToStr(CurrentZ,2)+";"+NumToStr(CurrentA,2)+";"+NumToStr(CurrentB,2)+";"+NumToStr(CurrentC,2);
SocketSend client_socket\str:=sendStr;
ENDTRAP