控件:chart1(图表),cartesianChart1(第三方添加图表),timer(时间)
添加第三方:
效果:图标会根据连接的温度,湿度用timer时间进行改变
Chart1控件样式:Series添加线条,颜色,名称等数据
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//1 安装livecharts第三方; 安装livechartswinform第三方;
timer1.Interval = 1000;
timer1.Start();
//给图表添加系列
//new LineSeries() 添加一个线性的系列
// values 指的是线性系列图表值是 ChartValues类型当中的float类型
cartesianChart1.Series.Add(new LineSeries() { Values = new ChartValues<double>() }); //温度
cartesianChart1.Series.Add(new LineSeries() { Values = new ChartValues<double>() });//湿度
//给x轴加时间
cartesianChart1.AxisX.Add(new LiveCharts.Wpf.Axis() { Labels = times });
//创建客户端对象
tcp = new TcpClient();//创建客户端对象
tcp.Connect("192.168.107.5", 8014);
stream = tcp.GetStream(); //获取网络基础流
}
TcpClient tcp;
NetworkStream stream;
public List<string> times = new List<string>();
Random r = new Random();// 随机数对象
double 温度;
double 湿度;
//实时更新数据
private void timer1_Tick(object sender, EventArgs e)
{
// 模拟数据
//float 温度 = r.Next(-100, 410) / 10F;//模拟请求 请求温度数据
//float 湿度 = r.Next(-100, 410) / 10F; //读取湿度
refresh();
//给chart1 添加数据
// 给系列1添加xy轴 ,x轴是时间,y轴是温度数据
chart1.Series[0].Points.AddXY(DateTime.Now.ToString("HH:mm:ss"), 温度);
chart1.Series[1].Points.AddXY(DateTime.Now.ToString("HH:mm:ss"), 湿度);
//超出一定数值之后 删除一部分图表?
if (chart1.Series[0].Points.Count>=10)
{
chart1.Series[0].Points.RemoveAt(0);
chart1.Series[1].Points.RemoveAt(0);
}
// 给cartesianChart1添加数据
times.Add(DateTime.Now.ToString());
cartesianChart1.Series[0].Values.Add(温度);
cartesianChart1.Series[1].Values.Add(湿度);
}
async void refresh()
{
try
{
//请求帧
byte[] buffer = null;
//响应帧
byte[] res = null;
//设备地址
byte address = Convert.ToByte("1");
//响应数据的个数
int resCount = -1;
//响应帧的crc
byte[] crc;
buffer = new byte[] { address, 0x03, 0x00, 0x02, 0x00, 0x02 };
buffer = buffer.Concat(CRCCalc(buffer)).ToArray();
//异步发请求。发送请求帧
await stream.WriteAsync(buffer, 0, buffer.Length);
//接收数据 响应帧。[地址码 功能码 有效个数,0x00,0x01,0x00,0x01,高位 地位]
res = new byte[9];
resCount = await stream.ReadAsync(res, 0, res.Length);
//数据验证
// 数据验证
if (resCount == 0 || resCount != res.Length)
{
Console.WriteLine("读取湿度、温度时,数据长度不正确");
return;
}
// 验证地址码和功能码
if (res[0] != buffer[0] || res[1] != buffer[1])
{
Console.WriteLine("读取湿度、温度时,设备地址或功能码不匹配");
return;
}
// 验证CRC
crc = CRCCalc(res, 0, res.Length - 2);
if (crc[0] != res[res.Length - 2] || crc[1] != res[res.Length - 1])
{
Console.WriteLine("读取湿度、温度时,CRC验证失败");
return;
}
//数据解析 读取数据
double humidity = (res[3] * 256 + res[4]) * 0.1; //湿度
double wendu = (res[5] * 256 + res[6]) * 0.1;
湿度 = humidity;
温度 = wendu;
}
catch
{
MessageBox.Show("获取数据失败");
}
}
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;
}
public static byte[] CRCCalc(byte[] data, int offset, int length)
{
byte[] Tdata = data.Skip(offset).Take(length).ToArray();
return CRCCalc(Tdata);
}
}