局域网控制系统-上位机-PC机
Posted weifeng727
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了局域网控制系统-上位机-PC机相关的知识,希望对你有一定的参考价值。
C#程序代码:
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 using System.IO.Ports; 10 //using System.Threading; //用于多线程技术 11 12 namespace WindowsFormsApplication1 //C#不再支持控件数组,也就意味不能灵活控制控件 13 { 14 public partial class Form1 : Form 15 { 16 const string deviceID = "03"; //用于串口通信时,定义本地设备ID 17 const string datapackage_headflag = "A"; //用于串口通信时,定义数据包头部的验证标记 18 19 20 //用来请求主线程的委托,利用delegat实现"请求主线程执行指定函数",由于delegate在定义的时候就确定了传递函数的参数,所以在需要传递不同函数给主线程的时候就需要定义多个delegate 21 public delegate void ChangeUI_1(String arg); //子线程不能操作UI,会导致程序崩毁,需要让主线程操作UI 22 public delegate void ChangeUI_2(int[] arg); 23 public delegate void ChangeUI_3(String[] arg); 24 public delegate Boolean ChangeUI_4(); 25 26 //----------定时器控制指令的发送----------// 27 System.Timers.Timer timer_SendCMD = new System.Timers.Timer(1010); //设定定时器计时周期为1000ms 28 29 //不断获取温度传感器值 30 public void GetTemperature(object source, System.Timers.ElapsedEventArgs e) 31 { 32 UART_send(uart_data_temperature_sensor0, 40); //建议获取一次温度值后产生40ms发送间隔 33 } 34 35 //----------固定发送数据包集----------// 36 const String uart_data_light0off = datapackage_headflag + deviceID + "_Ligt00Off_#"; 37 const String uart_data_light0on = datapackage_headflag + deviceID + "_Ligt00On__#"; 38 const String uart_data_light1off = datapackage_headflag + deviceID + "_Ligt01Off_#"; 39 const String uart_data_light1on = datapackage_headflag + deviceID + "_Ligt01On__#"; 40 const String uart_data_light2off = datapackage_headflag + deviceID + "_Ligt02Off_#"; 41 const String uart_data_light2on = datapackage_headflag + deviceID + "_Ligt02On__#"; 42 const String uart_data_temperature_sensor0 = datapackage_headflag + deviceID + "_SenT00____#"; 43 const String uart_data_try = datapackage_headflag + deviceID + "_Try!______#"; 44 //----------通信监测----------// 45 Boolean NeedToCheckUART = false; 46 Boolean heartbeat = false; //心跳包(用来协助监测通信是否断开) 47 System.Timers.Timer timer_UARTMonitor = new System.Timers.Timer(2000); 48 public void CheckUART(object source, System.Timers.ElapsedEventArgs e) 49 { 50 if (NeedToCheckUART) //检查通信状态 51 { 52 NeedToCheckUART = false; 53 if (heartbeat) 54 { 55 heartbeat = false; 56 } 57 else 58 { 59 this.Invoke(new ChangeUI_4(CloseUART)); 60 this.Invoke(new ChangeUI_1(UpdateNotice), "已断开连接!没有接收到心跳包!"); 61 } 62 } 63 else 64 { 65 NeedToCheckUART = true; 66 //请求接收者反馈心跳包,以确认连接是否出现异常 67 UART_send(uart_data_try,25); 68 } 69 } 70 //----------产生发送数据的间隔----------// 71 Boolean SendCMD_WaitFlag = false; 72 void SetSendCMD_Interval(uint Interval) 73 { 74 System.Timers.Timer timer_SetSendCMD_Interval = new System.Timers.Timer(Interval); 75 timer_SetSendCMD_Interval.Elapsed += new System.Timers.ElapsedEventHandler(Erase_SendCMD_WaitFlag); 76 timer_SetSendCMD_Interval.AutoReset = false; 77 timer_SetSendCMD_Interval.Start(); 78 } 79 public void Erase_SendCMD_WaitFlag(object source, System.Timers.ElapsedEventArgs e) 80 { 81 SendCMD_WaitFlag = false; 82 } 83 //----------温度指示----------// 84 int[] TemperatureSensor = new int[4]; 85 int UpLimit_1 = 301, //300=30℃ 86 DownLimit_1 = 100, 87 UpLimit_2 = 300, 88 DownLimit_2 = 100, 89 UpLimit_3 = 300, 90 DownLimit_3 = 100, 91 UpLimit_4 = 300, 92 DownLimit_4 = 100; 93 SolidBrush brush1, 94 brush2; 95 Graphics g1, 96 g2, 97 g3, 98 g4, 99 g5, 100 g6, 101 g7, 102 g8; 103 //------------------------------------// 104 public Form1() 105 { 106 InitializeComponent(); 107 108 } 109 110 private void Form1_Load(object sender, EventArgs e) 111 { 112 /*--------串口通信监测---------*/ 113 timer_UARTMonitor.Elapsed += new System.Timers.ElapsedEventHandler(CheckUART); // 添加定时器计时满一个周期的后要执行的函数; 114 timer_UARTMonitor.AutoReset = true; //设置定时器是否启动自动复位,true意味着定时器一旦启动,如果没有手动关闭,则定时器会不断周期性执行任务,false意味着启动定时器后,到达周期时间值,执行一次任务,然后自动关闭定时器 115 //----------定时器控制指令的发送----------// 116 timer_SendCMD.Elapsed += new System.Timers.ElapsedEventHandler(GetTemperature); 117 timer_SendCMD.AutoReset = true; 118 /*----------串口通信接口设置----------*/ 119 cmb_SerialPort.SelectedIndex = 0; 120 cmb_BaudRate.SelectedIndex = 1; 121 cmb_Parity.SelectedIndex = 0; 122 cmb_DataBit.SelectedIndex = 0; 123 cmb_StopBit.SelectedIndex = 0; 124 btn_Send.Enabled = false; 125 btn_UpdataReceive.Text = "关闭更新串口数据"; 126 127 //温度警报指示 128 brush1 = new SolidBrush(Color.Red); 129 brush2 = new SolidBrush(Color.Green); 130 g1 = this.pictureBox1.CreateGraphics(); 131 g2 = this.pictureBox2.CreateGraphics(); 132 g3 = this.pictureBox3.CreateGraphics(); 133 g4 = this.pictureBox4.CreateGraphics(); 134 g5 = this.pictureBox5.CreateGraphics(); 135 g6 = this.pictureBox6.CreateGraphics(); 136 g7 = this.pictureBox7.CreateGraphics(); 137 g8 = this.pictureBox8.CreateGraphics(); 138 139 //温度上下限文本框初始化 140 textBox1.Text = Convert.ToString((float)(UpLimit_1)/10); 141 textBox2.Text = Convert.ToString((float)(DownLimit_1)/10); 142 textBox4.Text = Convert.ToString((float)(UpLimit_2)/10); 143 textBox3.Text = Convert.ToString((float)(DownLimit_2)/10); 144 textBox6.Text = Convert.ToString((float)(UpLimit_3)/10); 145 textBox5.Text = Convert.ToString((float)(DownLimit_3)/10); 146 textBox8.Text = Convert.ToString((float)(UpLimit_4)/10); 147 textBox7.Text = Convert.ToString((float)(DownLimit_4)/10); 148 149 } 150 151 /*----------串口通信接口设置----------*/ 152 /* 153 客户端数据包格式解释(长度恒为15): 154 例如:A01_fmq_01Off___# 155 A--------数据包的开始标记(可以为A到Z,意味着数据包可以有26种) 156 01-----设备代号 157 fmq_01Off___--------指令(长度恒为10),指令的前4个人字符是指令头部,指令的后6个字符是指令尾部 158 #---------数据包的结束标记 159 160 服务器端数据包格式解释(长度恒为15): 161 例如:A02_SenT010250# 162 A--------数据包的开始标记(可以为A到Z,意味着数据包可以有26种) 163 02-----设备代号 164 SenT010250--------指令(长度恒为10),指令的前4个人字符是指令头部,指令的后6个字符是指令尾部 165 #---------数据包的结束标记 166 */ 167 SerialPort com = new SerialPort("COM2", 9600, Parity.None, 8, StopBits.One); 168 //串口打开与关闭 169 public Boolean CloseUART() 170 { 171 timer_UARTMonitor.Stop(); //停止定时器监测通信状态 172 timer_SendCMD.Stop(); //停止定时器控制指令的定时发送 173 try 174 { 175 com.Close(); //关闭串口 176 btn_OpenSerial.Text = "打开串口"; 177 lab_Status.Text = "未连接!"; 178 btn_Send.Enabled = false; 179 return true; 180 } 181 catch 182 { 183 return false; 184 } 185 } 186 //处理接收数据包函数(成功处理数据包则返回true,否则返回false) 187 public Boolean Deal_UART_RecData(String ReceStr) 188 { 189 if (ReceStr.Length == 15) //数据包长度为15 190 { 191 if ((ReceStr.Substring(0, 1) == datapackage_headflag) && (ReceStr.Substring(14, 1) == "#")) //数据包头尾标记验证 192 { 193 switch (ReceStr.Substring(1, 1)) //识别发送者设备ID的第1位数字 194 { 195 case "0": 196 switch (ReceStr.Substring(2, 1)) //识别发送者设备ID的第2位数字 197 { 198 case "0": 199 200 return false; 201 case "1": 202 203 return false; 204 case "2": 205 //----------指令分析-----------// 206 switch (ReceStr.Substring(4, 4)) //对指令头部进行分析(4个字符) 207 { 208 case "SenT": 209 //对指令尾部进行分析(6个字符) 210 int[] temp = new int[2]; 211 try 212 { 213 temp[0] = int.Parse(ReceStr.Substring(8, 2)); 214 temp[1] = int.Parse(ReceStr.Substring(10, 4)); 215 TemperatureSensor[temp[0]] = temp[1]; 216 this.Invoke(new ChangeUI_2(UpdateSenT), temp); 217 return true; 218 } 219 catch 220 { 221 this.Invoke(new ChangeUI_1(UpdateNotice), "接收的指令:指令尾部异常"); 222 return false; 223 } 224 case "Beat": 225 heartbeat = true; 226 return true; 227 default: 228 this.Invoke(new ChangeUI_1(UpdateNotice), "接收的指令:指令头部异常"); 229 return false; 230 } 231 default: 232 this.Invoke(new ChangeUI_1(UpdateNotice), "接收的数据包:设备ID异常"); 233 return false; 234 } 235 default: 236 this.Invoke(new ChangeUI_1(UpdateNotice), "接收的数据包:设备ID异常"); 237 return false; 238 } 239 } 240 else 241 { 242 this.Invoke(new ChangeUI_1(UpdateNotice), "接收的数据包:头尾部验证异常"); 243 return false; 244 } 245 } 246 else 247 { 248 this.Invoke(new ChangeUI_1(UpdateNotice), "接收的数据包:长度异常"); 249 return false; 250 } 251 } 252 //打开或关闭串口按钮 253 private void btn_OpenSerial_Click(object sender, EventArgs e) 254 { 255 if (btn_OpenSerial.Text == "打开串口") 256 { 257 try 258 { 259 if (!com.IsOpen) 260 { 261 com.PortName = cmb_SerialPort.Text; 262 com.BaudRate = int.Parse(cmb_BaudRate.Text); 263 com.DataBits = int.Parse(cmb_DataBit.Text); 264 switch (cmb_StopBit.SelectedIndex) 265 { 266 case 0: 267 com.StopBits = StopBits.One; break; 268 case 1: 269 com.StopBits = StopBits.Two; break; 270 case 2: 271 com.StopBits = StopBits.OnePointFive; break; 272 case 3: 273 com.StopBits = StopBits.None; break; 274 } 275 switch (cmb_Parity.SelectedIndex) 276 { 277 case 0: com.Parity = Parity.None; break; 278 case 1: com.Parity = Parity.Odd; break; 279 case 2: com.Parity = Parity.Even; break; 280 } 281 com.Open();//打开串口 282 lab_Status.Text = "已连接!"; 283 } 284 btn_OpenSerial.Text = "关闭串口"; 285 btn_Send.Enabled = true; 286 287 //串口连接成功后进行初始化 288 NeedToCheckUART = false; 289 heartbeat = false; 290 timer_SendCMD.Start(); //每隔一段时间获取一次温度值数据 291 timer_UARTMonitor.Start(); //启动定时器监测通信状态 292 293 try 294 { 295 //给串口添加接收中断函数(串口中断函数在没有被执行的时候,也就是串口接收处理空闲的时候,系统会不断监测接收缓冲区是否有数据存在,如果有,则执行中断函数) 296 com.DataReceived += new SerialDataReceivedEventHandler(com_DataReceived); 297 } 298 catch (Exception err) 299 { 300 lab_Status.Text = err.ToString(); 301 } 302 303 } 304 catch 305 { 306 lab_Status.Text = "串口打开错误"; 307 } 308 } 309 else //关闭串口 310 { 311 CloseUART(); 312 } 313 } 314 //串口接收中断函数(注意:不要出现数据包被分割,导致通信异常;数据包之间间隔时间不能太短) 315 private void com_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) 316 { 317 System.Threading.Thread.Sleep(30); //让当前线程睡眠30ms,因为需要保证数据包完整接收到了(在执行中断函数并获取接收缓冲区接收到的字节数时,假如数据包还没有完全被接收完,这时数据包就会出现被“分割”),再去判断接收缓冲区接收到的字节数,才能保证正常通信 318 int count = com.BytesToRead; //获取接收缓冲区接收到的字节数 319 byte[] readBuffer = new byte[count]; 320 com.Read(readBuffer, 0, count); 321 String strReceive = Encoding.Default.GetString(readBuffer); //将ASCLL码 映射成 字符 322 //String strReceive = getStringFromBytes(readBuffer); //将ASCLL码 转换成 字符串 323 this.Invoke(new ChangeUI_1(AddMessage), strReceive); //尝试更新接收数据框 324 //this.Invoke(new ChangeUI_1(UpdateNotice), strReceive.Length.ToString()); //此行代码用于测试数据包是否出现被分割 325 326 //下面对接收到的数据包(strReceive)进行分析,根据情况执行相应事件 327 if (Deal_UART_RecData(strReceive)) 328 { 329 this.Invoke(new ChangeUI_1(UpdateNotice), "处理接收的数据包成功!"); 330 } 331 332 } 333 //子线程请求主线程要执行的子函数,当发生多次请求时,主线程会分时执行函数(之所以要请求主线程是因为涉及到UI操作,子线程不能操作UI,否则导致程序崩毁) 334 public void UpdateSenT(int[] arg) 335 { 336 Int16 graphy_width = 44; 337 Int16 graphy_heigth = 21; 338 switch (arg[0]) 339 { 340 case 0: 341 if (arg[1] == 9999) 342 { 343 label6.Text = "不工作"; 344 return; 345 } 346 if (arg[1] < 0) 347 { 348 label6.Text = (arg[1] / 10).ToString() + "." + ((arg[1] % 10)*(-1)).ToString() + "℃"; 349 } 350 else 351 { 352 label6.Text = "+"+(arg[1] / 10).ToString() + "." + (arg[1] % 10).ToString() + "℃"; 353 } 354 if (TemperatureSensor[arg[0]] > UpLimit_1) 355 { 356 g1.FillRectangle(brush1, 0, 0, graphy_width, graphy_heigth); 357 g2.FillRectangle(brush2, 0, 0, graphy_width, graphy_heigth); 358 } 359 else if (TemperatureSensor[arg[0]] < DownLimit_1) 360 { 361 g2.FillRectangle(brush1, 0, 0, graphy_width, graphy_heigth); 362 g1.FillRectangle(brush2, 0, 0, graphy_width, graphy_heigth); 363 } 364 else 365 { 366 g1.FillRectangle(brush2, 0, 0, graphy_width, graphy_heigth); 367 g2.FillRectangle(brush2, 0, 0, graphy_width, graphy_heigth); 368 } 369 break; 370 case 1: 371 if (arg[1] == 9999) 372 { 373 label7.Text = "不工作"; 374以上是关于局域网控制系统-上位机-PC机的主要内容,如果未能解决你的问题,请参考以下文章