一、上位机与下位机
(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();
}
}
}));
}
}
}
}