通讯的现场运行效果与代码简单结构介绍可以看下面视屏:前往爱奇异
三菱PLC串口通讯方法源代码与手册
最近有一个简单的项目,是基于三菱FX1N-60MR PLC的,实现IO控制读取的功能。界面如上图。
PLC与工控机或电脑是通过RS232串口连接通讯。
原因之一是这PLC仓库库存大,以后基本用不到了,拿来消耗,二是项目气缸传感器多,IO点数多;
映像三菱PLC编程口 串口通讯协议是不对外开放的,搜了一圈真没找到官方的通讯手册,都是不全的网友分享,测试了也连不上PLC。
只能硬着头皮借鉴百度文库的一篇手册与串口监控工具进行猜测通讯帧的格式。
由于小项目也不急,断断续续搞了5天,终于完工;
这里仅介绍代码编写过程中关键几点,如下:
0.我V信:263946146,本站站长,可提供有偿技术服务;
1.以下协议通过当前源码在三菱PLC FX1N上调试通过;
2.PLC内可无程序或使用目录内的PLC程序进行测试;
3.用到工具:串口监视精灵,可百度下载;
1)使用扩展命令码,手册命令码无效:
读配置 "E00"
写配置 "E10"
读程序 "E01"
写程序 "E11"
2)软元件地址(word长):
X0 0X0240 X(X) = 2*X+0X0240; 如:X30地址为: 2*30+0x0240H = 027C; X70地址为: 02CC
Y0 0X0180 Y(X) = 2*X+0X0180; 如:Y60地址为: 2*60+0x180H = 01F8; Y130地址为:0284
S0 0X0280 S(X) = 2*X+0X0280; 如:S50地址为: 2*50+0x280H = 02E4; S100地址为:0348
M0 0X0000 M(X) = 2*X+0x00H; 如:M100地址为:2*100+0x0000H = 00C8; M800地址为:0640
D0 0X4000 D(X) = 2*X+0X4000H; 如:D200地址为:2*200+0X4000H = 4190;D1000 地址为:47D0
3)数据排序:
以字节为单位,低前高后;
例如:
Y0起16位值:Y17-------Y10(8,4), Y7----------Y0(3,5)
转成帧: /02,E10,35,84, /03
D0起32位值:D0 (1,2,3,4), D1(A,B,C,D)
转成帧: /02,E00, 34,12,CD,AB, /03
当你下载了附件后,根目录后有几个文件夹,如下图:
三菱PLC串口通讯方法源代码与手册
Release目录下有生成的程序,进入打开FXPLCTest_PLCCOMPara.txt 进行串口配置后,可运行FXPLCTest.exe程序,
点击界面上的连接PLC按钮就可控制PLC.
用到的手册与工具 目录下有用到的参考手册,与测试用PLC程序,程序下载到PLC后,可测试D0. D100的读写效果;
代码的使用也非常简单.首先是串串参数的设置:- bool CFXPLC::SetComPara(short nPort,short nDataBits,short nStopBits,short nBaud,short nParity)
- {
- //三菱FX2N PLC 波特率:9600固定,奇偶:偶固定;
- COM_PARA ComPara;
- ComPara.nPortIndex = nPort;
- ComPara.nBaud = nBaud;
- ComPara.nDataBits = nDataBits;
- if(nParity==1)
- ComPara.cParity = 'O';
- else if(nParity==2)
- ComPara.cParity = 'E';
- else
- ComPara.cParity = 'N';
- ComPara.nStopBits = nStopBits;
- ComPara.dwComEvent = EV_RXCHAR | EV_CTS;
- //<>
- CString sValue;
- sValue.Format("%d",nPort);
- WritePrivateProfileString("COM","PORT",sValue,m_sParaPath);
- sValue.Format("%d",nBaud);
- WritePrivateProfileString("COM","BAUD",sValue,m_sParaPath);
- sValue.Format("%d",nDataBits);
- WritePrivateProfileString("COM","DATABITS",sValue,m_sParaPath);
- sValue.Format("%d",nParity);
- WritePrivateProfileString("COM","PARITY",sValue,m_sParaPath);
- sValue.Format("%d",nStopBits);
- WritePrivateProfileString("COM","STOPBITS",sValue,m_sParaPath);
- return ComSetProtocol ( &ComPara );
- }
复制代码 然后就可连接三菱的FX1N PLC,
- bool CFXPLC::ConnectPLC()
- {
- if(m_bPLCConnected)
- return true;
- LoadPara();
- if( !ComOpen() )
- return false;
- Lock();
- AddCommand(Read_X);
- // AddCommand(Write_Y);
- SendCommand();
- PLCCommandExeTimeStart();
- Unlock();
- return true;
- }
复制代码
成功连接了PLC后,就可对PLC进行读写操作了,项目通过封闭的四个函数实现对X,Y,D,D100,进行读写操作:
- bool CFXPLC::ReadX0(long &lInput)
- {
- if(!m_bPLCConnected)
- return false;
- short nIndex=0,nTime=3000;//3S
- m_bReceived[0] = false;
- while(!m_bReceived[0] )
- {
- Sleep(1);
- if(!m_bPLCConnected)
- return false;
- nIndex++;
- if(nIndex>nTime)
- return false;
- }
- lInput = m_dwX0;
- return true;
- }
- bool CFXPLC::WriteY0(long lMask,bool bOutput)
- {
- if(!m_bPLCConnected)
- return false;
- if(bOutput)
- {
- m_dwY0 |= lMask;
- }
- else
- {
- lMask = ~lMask;
- m_dwY0 &= lMask;
- }
- short nIndex=0,nTime=3000;//3S
- m_bReceived[1] = false;//等待串口复位;
- AddCommand(Write_Y);
- while(!m_bReceived[1] )
- {
- Sleep(1);
- if(!m_bPLCConnected)
- return false;
- nIndex++;
- if(nIndex>nTime)
- return false;
- }
- return true;
- }
- bool CFXPLC::ReadD0(long &dwD0)
- {
- if(!m_bPLCConnected)
- return false;
- short nIndex=0,nTime=3000;//3S
- m_bReceived[2] = false;
- AddCommand(Read_D);
- while(!m_bReceived[2] )
- {
- Sleep(1);
- if(!m_bPLCConnected)
- return false;
- nIndex++;
- if(nIndex>nTime)
- return false;
- }
- dwD0 = m_dwD0;
- return true;
- }
- bool CFXPLC::WriteD100(long dwD100)
- {
- if(!m_bPLCConnected)
- return false;
- short nIndex=0,nTime=3000;//3S
- m_bReceived[3] = false;//等待串口复位;
- m_dwD100 = dwD100;
- AddCommand(Write_D);
- while(!m_bReceived[3] )
- {
- Sleep(1);
- if(!m_bPLCConnected)
- return false;
- nIndex++;
- if(nIndex>nTime)
- return false;
- }
- return true;
- }
复制代码 当然PLC提供的串口通讯指令还有很多,可根据自己需求,修改项目内的函数实现:
- void CFXPLC::AddCommand(PLC_COMMAND_TYPE cmd,bool bClearThenAdd)
- {
- /************************************************************************
- 扩展命令码 :;
- 读配置 "E00" ;
- 写配置 "E10" ;
- 读程序 "E01" ;
- 写程序 "E11" ;
- ADDR(word长):
- X0 0X0240 X(X) = 2*X+0X0240; 如:X30地址为: 2*30+0x0240H = 027C; X70地址为: 02CC;
- Y0 0X0180 Y(X) = 2*X+0X0180; 如:Y60地址为: 2*60+0x180H = 01F8; Y130地址为:0284;
- S0 0X0280 S(X) = 2*X+0X0280; 如:S50地址为: 2*50+0x280H = 02E4; S100地址为:0348;
- M0 0X0000 M(X) = 2*X+0x00H; 如:M100地址为:2*100+0x0000H = 00C8; M800地址为:0640;
- D0 0X4000 D(X) = 2*X+0X4000H; 如:D200地址为:2*200+0X4000H = 4190;D1000 地址为:47D0;
- ************************************************************************/
-
- CString sFrame,sData,sBuffer;
- Lock();
- switch(cmd)
- {
- case Read_X:
- sData += "E00"; //0E00 读指令;
- sData += "0240";//X0 起始地址;
- sData += "04"; //读取总字节数;
- break;
- case Read_D:
- sData += "E00"; //0E00 读指令;
- sData += "4000";//D0 起始地址;
- sData += "04"; //读取总字节数;
- break;
- case Write_Y:
- sData += "E10"; //0XE10 写指令;
- sData += "0180"; //Y0起始地址;
- sData += "04"; //读取总字节数;
- sData += itoa_8H(m_dwY0); //数据;
- break;
- case Write_D:
- sData += "E10"; //0XE10 写指令;
- sData += "40C8"; //D100起始地址;
- sData += "04"; //读取总字节数;
- sData += itoa_8H(m_dwD100); //数据;
- break;
- }
- sBuffer.Format("%c",0X02); //0X02 PLC帧头;
- sFrame = sBuffer;
- sBuffer.Format("%c",0X03); //0X03PLC帧尾;
- sData += sBuffer;
- sData += CalcFrameCheck(sData); //lrc检验码;
-
- sFrame += sData;
- if(bClearThenAdd)
- m_CommandList.RemoveAll();
- m_CommandList.AddTail(sFrame);
- Unlock();
- }
复制代码
项目源代码及用到的文档工具下载:
如果您认可,可联系功能定制! 如果您着急,充值会员可直接联系发您资料!
|