C# SerialPort 读写三菱FX系列PLC
1:串口初始化??
com = new SerialPort("COM3", 9600, Parity.Even, 7, StopBits.One);
2:打開關閉串口
if (com.IsOpen)
?{com.Close();}
com.Open();
?
if (com.IsOpen)
{ com.Close();}
3:C# ASCII轉字符及字符轉ASCII
public static string Chr(int asciiCode)
??????? {
??????????? if (asciiCode >= 0 && asciiCode <= 255)
??????????? {
??????????????? System.Text.ASCIIEncoding asciiEncoding = new System.Text.ASCIIEncoding();
??????????????? byte[] byteArray = new byte[] { (byte)asciiCode };
??????????????? string strCharacter = asciiEncoding.GetString(byteArray);
??????????????? return (strCharacter);
??????????? }
??????????? else
??????????? {
??????????????? throw new Exception("ASCII Code is not valid.");
??????????? }
??????? }
?
public static int Asc(string character)
??????? {
??????????? if (character.Length == 1)
??????????? {
??????????????? System.Text.ASCIIEncoding asciiEncoding = new System.Text.ASCIIEncoding();
??????????????? int intAsciiCode = (int)asciiEncoding.GetBytes(character)[0];
??????????????? return (intAsciiCode);
??????????? }
??????????? else
??????????? {
??????????????? throw new Exception("Character is not valid.");
??????????? }
??????? }
?
4:寫入串口的命令字符串的和校驗
?
/// <summary>
??????? /// 和校驗
??????? /// </summary>
??????? /// <param name="data"></param>
??????? /// <returns></returns>
??????? public string SumCheck(string data)
??????? {
??????????? int sum = 0;
??????????? for (int i = 0; i < data.Length; i++)
??????????? {
??????????????? sum += Asc(data.Substring(i, 1));
??????????? }
??????????? string res = sum.ToString("X");
??????????? res = res.Substring(res.Length - 2, 2);
??????????? return res;
??????? }
?
?5:寫入PLC
private void btnWrite_Click(object sender, EventArgs e)
??????? {?
??????????? string[] write = new string[] { "2","2"}; //將準備寫入PLC的值
??????????? //將要寫入的值轉換成16進制數,補齊兩個字節,注意高低字節需要交換
??????????? string sWriteData = "";
??????????? for (int i = 0; i < write.Length; i++)
??????????? {
??????????????? int val = Convert.ToInt32(write[i].Length>0?write[i]:"0");
??????????????? string s = val.ToString("X");
??????????????? while (s.Length<4)
??????????????? {
??????????????????? s = "0" + s;
??????????????? }
??????????????? sWriteData += s.Substring(2,2)+s.Substring(0,2);
??????????? }
??????????? MessageBox.Show(sWriteData);
??????????? //寫入命令,1表示寫入,1194表示D202這個地址的16進制,04表示D202,D203為4個BYTE,1194=(202*2)+4096的16進制數,至于用它表示D202的起始位置,三菱故意要這么麻煩了.
??????????? sWriteData = "1119404" + sWriteData + Chr(3);
??????????? //chr(2)和chr(3)是構成命令的標志字符,然后加上校驗和,命令組織完成
??????????? sWriteData = Chr(2) + sWriteData + SumCheck(sWriteData);
??????????? MessageBox.Show(sWriteData);
??????????? //寫入串口
??????????? com.Write(sWriteData);
??????????? //byte[] data = Encoding.ASCII.GetBytes(sWriteData);?
??????????? //com.Write(data,0,data.Length);
??????? }
?
6:讀PLC
?private void btnRead_Click(object sender, EventArgs e)
??????? {
????????????
??????????? this.txtRead0.Clear();
??????????? string sReadData = "";
??????????? //在讀PLC中的數據之前,需要先發個指令給它,讓它將數據發送到串口,下面的字符串中,chr(2),chr(3)為PLC命令的格式標志,0119404中,0表示讀,1194表示D202的起始地址,04表示讀D202,D203兩個字,共4個字節,66為0119404和chr(3)的校驗和,向串口寫入"讀"命令,其實和向plc地址中寫入數據是一樣的,只是沒有數據,用0表示讀
??????????? string sReadCmd = Chr(2) + "0119404" + Chr(3) + "66";
??????????? com.Write(sReadCmd);
??????????? //等待1秒鐘
??????????? System.Threading.Thread.Sleep(1000);
??????????? // 從串口讀數據
??????????? byte[] data = new byte[1024];
??????????? com.Read(data, 0, 1024);
?????????? //如果首位為2,則表示數據有效.這里有個問題,在第二次讀,第2位才為'2',第三次又是首位為2,需要再測試
??????????? if (data[0]==2)
??????????? {
??????????????? string sReceiveData = System.Text.Encoding.ASCII.GetString(data);
??????????????? //MessageBox.Show(sReceiveData);
?????????????? //解析命令,將讀到的字符解析成數字,注意高低位的轉換
??????????????? for (int i = 1; i < 8; i += 4)
??????????????? {
??????????????????? string sLow = sReceiveData.Substring(i,2);
??????????????????? string sHigh = sReceiveData.Substring(i + 2, 2);
??????????????????? //int res = Convert.ToInt32(sHigh)+ Convert.ToInt32(sLow);
??????????????????? int res = Convert.ToInt32(sHigh,16) + Convert.ToInt32(sLow,16);
??????????????????? this.txtRead0.Text += res.ToString() + ",";
??????????????? }???????????????
?????????????? ?
??????????? }
?
?
分類:?C# 好文要頂?關注我?收藏該文?? 白沙河關注 - 0
粉絲 - 3 +加關注 2 0 (請您對文章做出評價) ??上一篇:無法加載 DLL“sqlceme30.dll”: 找不到指定的模塊。解決
??下一篇:MSComm控件使用詳解
posted on?2008-12-29 09:20?白沙河?閱讀(3929) 評論(8)?編輯?收藏
FeedBack: #1樓 2009-02-25 11:42?|?Ryan.net
博主用的哪一款PLC??
我也在用這東西FX2N(RS232),他給的手冊好像不是這樣說的。。。。?
手冊示例:?
在第5站從X040向X077讀32個點的數據(消息等待時間設為100毫秒)?
應該向PLC發送:?
ENQ 站號 PC號 讀寫指令 響應時間 起始地址 讀取位數 和校驗碼?
ENQ 0 5 F F W R 0 X 0 0 4 0 0 2 4 8?
05H 30H 35H 46H 46H 57H 52H 30H 58H 30H 30H 34H 30H 30H 32H 34H 38H?
我發送?
m_ComPort.COM.Write(ASCIIEncoding.ASCII.GetString(byteTmp) + "FFWR0X004002" + SumChk("FFWR0X004002"));?
可是獲取不到正確的數據 支持(0)反對(0) ?? #2樓[樓主] 2009-02-25 12:01?|?白沙河?
Public Const PLC_X_Group_Base_AddRess = 128
X地址是不是要先加一個128? 支持(0)反對(0) ?? #3樓 2009-02-25 14:23?|?Ryan.net
先謝謝博主回復?
不過沒太看明白?
格式如下(中間用“|”人為分割):?
在第5站從X040向X077讀32個點的數據(消息等待時間設為100毫秒)?
ENQ|站號|PC號|讀寫指令|響應時間|起始地址|讀取位數|和校驗碼?
ENQ|0 5 |F F|W R|0 |X 0 0 4 0| 0 2| 4 8?
05H|30H 35H |46H 46H |57H 52H |30H |58H 30H 30H 34H 30H |30H 32H|34H 38H?
我寫的代碼:?
m_ComPort.COM.Write(Chr(5) + "FFWR0X004002" + SumChk("FFWR0X004002"));?
X地址加一個128??
是不是X0040轉換成ASC之后加128?
支持(0)反對(0) ?? #4樓[樓主] 2009-02-25 15:18?|?白沙河?
以下資料是從網上找的,沒有找到關于X的字或位的說明.但SumChk("FFWR0X004002"))應該不是從0x0040開始吧
//
由于沒有寄存器類型信息,所以地址的計算十分關鍵,如D100和M100分別對應哪個地址呢?下面就是三菱Fx系列PLC地址對應表:
Public Const PLC_D_Base_AddRess = 4096
Public Const PLC_D_Special_Base_AddRess = 3584
Public Const PLC_Y_Group_Base_AddRess = 160
Public Const PLC_PY_Group_Base_AddRess = 672
Public Const PLC_T_Group_Base_AddRess = 192
Public Const PLC_OT_Group_Base_AddRess = 704
Public Const PLC_RT_Group_Base_AddRess = 1216
Public Const PLC_M_SINGLE_Base_AddRess = 2048(命令為7或8時)
Public Const PLC_M_Group_Base_AddRess = 256
Public Const PLC_PM_Group_Base_AddRess = 768
Public Const PLC_S_Group_Base_AddRess = 0
Public Const PLC_X_Group_Base_AddRess = 128
Public Const PLC_C_Group_Base_AddRess = 448
Public Const PLC_OC_Group_Base_AddRess = 960
Public Const PLC_RC_Group_Base_AddRess = 1472
Public Const PLC_TV_Group_Base_AddRess = 2048
Public Const PLC_CV16_Group_Base_AddRess = 2560
Public Const PLC_CV32_Group_Base_AddRess = 3072?
當我們用DEVICE READ命令時,D100地址=100*2+4096;M100地址=100+256;不同的是D類型寄存器存放的是字,M寄存器存放的是位,同樣是讀兩個字節,D100返回的就是PLC中D100地址的值,M類型寄存器返回的是M100到M116的值。所以當我們用FORCE ON 命令時,M100寄存器地址=100+2048;
這也沒有什么復雜的,不是嗎?可是三菱公司好像不甘于如此,FORCE ON/Off命令中地址排列與DEVICE READ/WRITE不同,是低位在前高位在后。如Y20,地址是0510H,代碼中4個字節地址表示為:1005。(注意:Y寄存器為八進制,如Y20 地址=16+1280=0510H)?
其實一點技術含量都沒有,就是拐了幾個彎,偏偏很多時候又不都告訴你,讓人浪費不少時間。 支持(0)反對(0) ?? #5樓 2009-02-25 18:02?|?Ryan.net
謝了,兄弟!?
和廠商通過另外一種模式解決了?
因為時間實在太急,對于這些東西懂得也不多,就沒能繼續研究 支持(0)反對(0) ?? #6樓 2009-06-24 10:28?|?明月伴我行?
你好,請教如何讀D1024后面的值?我現在一直返回零,郁悶。 支持(0)反對(0) ?? #7樓[樓主] 2009-06-26 09:56?|?白沙河?
@明月伴我行
假設讀2個地址,那是不是應該以"0180004"開始,手里沒有PLC,也沒有試過從1024開始,所以也就不確定了. 支持(0)反對(0) ?? #8樓 2009-07-14 17:29?|?明月伴我行?
應該不是 支持(0)反對(0) ?? 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎
總結
以上是生活随笔為你收集整理的C# SerialPort 读写三菱FX系列PLC的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c#-接口
- 下一篇: 遭银行账号诈骗最快最有效自救法