1.窗体搭建
添加time(定时器)
因为需要风速和风向自动刷新
2.进行网口空气检测
①服务器连接按钮
// 连接按钮
private void button1_Click(object sender, EventArgs e)
{
if (button1.Text =="连接")
{
ConnectSocke();// 连接服务器
}
else
{
CloseSocket(); // 关闭服务器
}
}
Socket soc;
// 连接方法
void ConnectSocke()
{
try
{
// 创建socket对象
soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);// 套接字对象
// 连接服务器ip地址,端口号
soc.Connect(this.textBox1.Text, int.Parse(this.textBox2.Text));
button1.Text = "关闭";
textBox1.Enabled = false;
textBox2.Enabled = false;
}
catch (Exception ex)
{
MessageBox.Show("串口服务器连接失败");
}
}
// 关闭方法
void CloseSocket()
{
if (soc!=null && soc.Connected)
{
soc.Close();
}
button1.Text = "连接";
this.textBox1.Enabled = true;
this.textBox2.Enabled = true;
}
// 连接方法
void ConnectSocke()
{
try
{
// 创建socket对象
soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);// 套接字对象
// 连接服务器ip地址,端口号
soc.Connect(this.textBox1.Text, int.Parse(this.textBox2.Text));
button1.Text = "关闭";
textBox1.Enabled = false;
textBox2.Enabled = false;
}
catch (Exception ex)
{
MessageBox.Show("串口服务器连接失败");
}
}
判断button1.text是否为“连接”若是连接则进行ConnectSocke();运行服务器的方法,否则CloseSocket();关闭服务器方法。
连接方法:使用try catch异常处理,创建全局变量Socket soc;创建对象连接ip端口号,讲textbox1.text改成关闭,textBox1.Enabled=false;让输入框无法输,catch异常处理判断try里的代码是否报错,若报错运行catch里代码
断开方法:判断soc是否为空或者soc是否连接如果连接关闭soc.Close();,将button1.text=“连接”,让textbox1和2能Enabled=true;解除
3.连接方法
// 发送按钮
private void button2_Click(object sender, EventArgs e)
{
string sendS = this.textBox3.Text.Trim();// 发送字符串
if (soc == null || !soc.Connected)
{
MessageBox.Show("服务器没连接");
return;
}
if (string.IsNullOrEmpty(sendS))
{
MessageBox.Show("指令不能为空");
return;
}
//1 把字符串转成字符数组
byte[] data = StringToHexByte(sendS);
//2 计算校检码
byte[] b1 = CRCCalc(data);
//3 合并字节数组和校检码数组
data = data.Concat(b1).ToArray();
button2.Enabled = false;
Task.Run(() =>
{
//4 发起请求帧
soc.Send(data);// 发消息 请求 温度请求帧data = []
Thread.Sleep(1000);// 休眠1秒
//5 接受数据 // 接收温度
byte[] rec = new byte[1024]; // rec =
int length = soc.Receive(rec);
// 6 解析数据并且展示数据 把字节数组转成字符串
string s = ByteToString(rec, length);
s += "\r\n";
int temp = (rec[3] * 256 + rec[4]) / 10;// 温度
this.richTextBox1.Invoke((Action)(() =>
{
richTextBox1.AppendText(s);// 响应帧
richTextBox1.AppendText($"当前温度温度为:{temp}摄氏度,时间为:{DateTime.Now.ToString()}r\n");
button2.Enabled = true;
}));
});
}
string ByteToString(byte[] b1,int l)
{
StringBuilder sb = new StringBuilder();// 可变字符串
for (int i = 0; i < l; i++)
{
sb.Append(b1[i].ToString("X2")+" ");
}
return sb.ToString();
}
// 字符串转成字符数组
byte[] StringToHexByte(string s)
{
string[] ss = s.Split(' ');
byte[] result = new byte[ss.Length];// 字节数组
for (int i = 0; i < ss.Length; i++)
{
result[i] = Convert.ToByte(ss[i], 16);//转成16进制字节
}
return result;
}
// 校检方法
public static byte[] CRCCalc(byte[] data)
{
//crc计算赋初始值
int crc = 0xffff;
for (int i = 0; i < data.Length; i++)
{
//XOR
//(1) 0^0=0,0^1=1 0异或任何数=任何数
//(2) 1 ^ 0 = 1,1 ^ 1 = 0 1异或任何数-任何数取反
//(3) 1 ^ 1 = 0,0 ^ 0 = 0 任何数异或自己=把自己置0
//异或操作符是^。异或的特点是相同为false,不同为true。
crc = crc ^ data[i]; //和^表示按位异或运算。
//0x0fff ^ 0x01 Console.WriteLine(result.ToString("X"));
// 输出结果为4094,即十六进制数1001
for (int j = 0; j < 8; j++)
{
int temp;
temp = crc & 1; // & 运算符(与) 1 & 0 为 0 ;0 & 0 为0;1 & 1 为1
//右移 (>>) 将第一个操作数向右移动第二个操作数所指定的位数,空出的位置补0。右移相当于整除. 右移一位相当于除以2;右移两位相当于除以4;右移三位相当于除以8。
//int i = 7;
//int j = 2;
//Console.WriteLine(i >> j); //输出结果为1
crc = crc >> 1;
crc = crc & 0x7fff;
if (temp == 1)
{
crc = crc ^ 0xa001;
}
crc = crc & 0xffff;
}
}
//CRC寄存器的高低位进行互换
byte[] crc16 = new byte[2];
//CRC寄存器的高8位变成低8位,
crc16[1] = (byte)((crc >> 8) & 0xff);
//CRC寄存器的低8位变成高8位
crc16[0] = (byte)(crc & 0xff);
return crc16;
}
3.刷新按钮
// 刷新按钮
private void button3_Click(object sender, EventArgs e)
{
Refresh1();
}
void Refresh1()
{
if (soc == null || !soc.Connected)
{
MessageBox.Show("没连接");
return;
}
Task.Run(() =>
{
// 请求帧的组织
byte[] bs = new byte[] {0x01,0x03,0x00,0x00,0x00,0x02};// 风速和风向请求放在一起
// 数据和校检
bs = bs.Concat(CRCCalc(bs)).ToArray();
soc.Send(bs);// 发送
Thread.Sleep(1000);
// 接受数据表
byte[] rec = new byte[1024];
int length = soc.Receive(rec);
double wind = (rec[3] * 256 + rec[4]) * 0.01;
double dir = (rec[5] * 256 + rec[6]);
this.Invoke((Action)(() =>
{
this.textBox4.Text = wind + "m/s";
this.textBox5.Text = dir + "";
}));
});
}
// 定时器
private void timer1_Tick(object sender, EventArgs e)
{
if (checkBox1.Checked)// 复选框被选中
{
Refresh1();
}
}
}
}