上位机与下位机之间的交互

一、上位机与下位机

(1)、什么是上位机?

               上位机是指可以直接发出操控命令的计算机 这里使用的是winfrom

(2)、什么是下位机?

               下位机是指直接控制设备获取状况的计算机,一般是PLC/ 单片机

(3)、上位机与下位机的通讯

                使用串口(RS232)进行通讯,在winfrom中可以使用seriaPort控件实现通讯对下位机进行操作。在进行通讯前需要连接串口、通过SerialPort.GetPortNames()方法获取串口名称,控件名.Open() 用来打开串口。

            String[] Ports = SerialPort.GetPortNames(); //获得端口名称

			comProt.Items.Add("请选择串口");             //设置第一个选项
			comProt.Items.AddRange(Ports);              //将串口加入到下拉框
			comProt.SelectedIndex = 0;                  //默认显示第一个

二、上位机读取下位机数据进行展示

 (1)、需要连接对应的串口,订阅连接串口的点击事件

		private void button1_Click(object sender, EventArgs e)
		{
			if (comProt.SelectedIndex == 0)
			{
				MessageBox.Show("请先选择正确的串口");
				return;
			}
			//获得串口名称
			if (!serialPort.IsOpen)
				serialPort.PortName = this.Ports[comProt.SelectedIndex - 1];
			//判断串口是否打开 打开默认为true
			if (serialPort.IsOpen)
			{
				try
				{
					serialPort.Close();
					button1.Text = "打开串口";
					button1.BackColor = Color.Green;
				}
				catch
				{
					serialPort.Close();
					MessageBox.Show("端口出错了", "提示");
				}
			}
			else
			{
				//当端口关闭时打开
				try
				{
					serialPort.Open();
					button1.Text = "关闭串口";
					button1.BackColor = Color.Red;
				}
				catch
				{
					serialPort.Close();
					MessageBox.Show("端口出错了", "提示");
				}
			}
		}

(2)、点击获取参数,订阅点击事件

    需要定义一个集合、里面放入操作数:并对数组进行循环

		private void button2_Click(object sender, EventArgs e)
		{
			if (serialPort.IsOpen)
			{
				//设置默认值
				UInt16 _rx_axis_num;
				UInt16 _rx_register_name;
				int rx_tmpDataint;
				float rx_fTemp;
				//对操作命令数组进行循环
				foreach (UInt16 item in cmd_of_info_to_update)
				{
					//对串口进行写入操作
					SerialWriteData(1, 1, item, 0);
					//睡眠30毫秒 确保数据写入完毕
					Thread.Sleep(30);
					//当串口字节数等于8时 说明写入成功
					if (serialPort.BytesToRead == 8)
					{
						//将串口数据写入puff中
						serialPort.Read(puff, 0, 8);
						if (ConvertRxBytesToCmd(puff, out _rx_axis_num, out _rx_register_name, out rx_tmpDataint, out rx_fTemp))
						{
							ProcessReceivedData(_rx_axis_num, _rx_register_name, rx_tmpDataint, rx_fTemp);
						}
					}
				}
			}
			else
			{
				MessageBox.Show("请先打开串口");
				return;
			}
		}

对串口进行写入的函数 SerialWriteData

		/// <summary>
		/// 对串口进行写入
		/// </summary>
		/// <param name="_rw">默认为1是读 0是写 固定的两个值</param>
		/// <param name="_axis_num">从站地址 默认为1 默认为1写死的</param>
		/// <param name="_cmd">功能号</param>
		/// <param name="cmdValue">写入的数据 可以是0</param>
		void SerialWriteData(UInt16 _rw, UInt16 _axis_num, UInt16 _cmd, int cmdValue)
		{
			//定义一个缓存串口写入的8个字节数据
			byte[] buffer = new byte[8];
			//也是一个缓存 用来存放数据
			byte[] value = new byte[4];
			//将数据放入value中
			value = BitConverter.GetBytes(cmdValue);

			UInt16 tmpRWcmd = 0x8000;
			tmpRWcmd = (UInt16)(tmpRWcmd | (_rw << 12));   //RW 判断读写
			tmpRWcmd = (UInt16)(tmpRWcmd | (_cmd & 0x0FFF));    //

			buffer[0] = 0;
			buffer[1] = (byte)_axis_num;       //从站地址1
			buffer[2] = (byte)(tmpRWcmd >> 8);//tmpRWcmdByte[1];    //首位读写位
			buffer[3] = (byte)(tmpRWcmd & 0xFF);    //剩余15位 寄存器位
			buffer[4] = value[3];           //数据最高位
			buffer[5] = value[2];
			buffer[6] = value[1];
			buffer[7] = value[0];           //数据最低位

			if (serialPort.IsOpen)
			{
				//将缓存中的数据写入串口中
				serialPort.Write(buffer, 0, 8);
				Thread.Sleep(20);
			}
			else
			{
				MessageBox.Show("串口未打开");
				return;
			}
		}

 处理数据

		/// <summary>
		/// 对数据进行处理
		/// </summary>
		/// <param name="_serialData">要处理的缓存数据</param>
		/// <param name="_axis_num">从站地址1</param>
		/// <param name="_register_name">控件名</param>
		/// <param name="tmpDataint">整型</param>
		/// <param name="fTemp">浮点型</param>
		/// <returns></returns>
		bool ConvertRxBytesToCmd(byte[] _serialData, out UInt16 _axis_num, out UInt16 _register_name, out int tmpDataint, out float fTemp)
		{
			byte[] _tempBytes = new byte[4];
			int _data_err = 0;
			_tempBytes[0] = _serialData[7];
			_tempBytes[1] = _serialData[6];
			_tempBytes[2] = _serialData[5];
			_tempBytes[3] = _serialData[4];
			tmpDataint = 0;
			fTemp = 0.0f;

			try
			{
				tmpDataint = BitConverter.ToInt32(_tempBytes, 0);
			}
			catch { _data_err += 1; }
			try
			{
				fTemp = BitConverter.ToSingle(_tempBytes, 0);
			}
			catch { _data_err += 1; }

			_axis_num = _serialData[1];
			_register_name = (UInt16)(((_serialData[2] << 8) | (_serialData[3])) & 0xFFF);
			return true;
		}

接收数据:

		int axis_to_set = 0;
		// 接收数据
		/// <summary>
		/// 
		/// </summary>
		/// <param name="_axis_num">从站地址为1</param>
		/// <param name="_register_name">下发的指令</param>
		/// <param name="tmpDataint">整型</param>
		/// <param name="fTemp">浮点型</param>
		void ProcessReceivedData(UInt16 _axis_num, UInt16 _register_name, int tmpDataint, float fTemp)
		{
			if (_axis_num == (UInt16)axis_to_set || axis_to_set == 0 || _axis_num == 0
				|| _register_name == 0x11 || _register_name == 0x12)
			{
				//参数、数值反馈等
				if ((_register_name >= 0x101 && _register_name <= 0x10C) ||
					(_register_name >= 0x201 && _register_name <= 0x20C))
				{
					if (true == (GetDataList.ContainsKey(_register_name)))
					{
						this.BeginInvoke(new EventHandler(delegate
						{
							GetDataList[_register_name].Text = fTemp.ToString();
						}));
					}
				}
				else
				{
					if (true == (GetDataList.ContainsKey(_register_name)))
					{
						this.BeginInvoke(new EventHandler(delegate
						{
							if (_register_name == 0x11 || _register_name == 0x12)
							{
								GetDataList[_register_name].Text = tmpDataint.ToString();
							}
							else
							{
								if (_register_name == 0x2F)
								{
									GetDataList[_register_name].Text = fTemp.ToString();
								}
								else if (_register_name == 0x331)
								{
									GetDataList[_register_name].Text = fTemp.ToString();
								}
								else
								{
									GetDataList[_register_name].Text = fTemp.ToString();
								}
							}

						}));
					}
				}
			}
		}

物联沃分享整理
物联沃-IOTWORD物联网 » 上位机与下位机之间的交互

发表评论