C# Winform串口助手

界面设置

在这里插入图片描述

  • 修改控件name属性

  • 了解SerialPort类

  • 实现串口的初始化,开关

创建虚拟串口

在这里插入图片描述

namespace 串口助手
{public partial class Form1 : Form{public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){//在设计页面已经预先添加了COM1 COM2 COM3this.port_cbb.Items.Add("COM4");this.port_cbb.Items.Add("COM5");//给发送框加预设文本this.send_rtb.Text = "我是发送框";//给接收框加预设文本this.recive_rtb.Text = "我是接收框";}private void open_btn_Click(object sender, EventArgs e){try{if (port_cbb.Text != ""){serialPort1.PortName = port_cbb.Text;}serialPort1.Open();if (serialPort1.IsOpen){MessageBox.Show("serialport is open");}}catch (Exception ex){MessageBox.Show(ex.ToString() + serialPort1.PortName.ToString());}}private void send_btn_Click(object sender, EventArgs e){//如果发送的数据不为空,则接收if (this.send_rtb.Text !=""){this.recive_rtb.AppendText(this.send_rtb.Text);}else{MessageBox.Show("请先输入发送数据");}}}
}

详细的Serial参数

  • string PortName 端口号
  • int DataBits 数据位
  • StopBits StopBits 停止位
  • Parity Parity 校验位
  • int BaudRate 波特率
  • bool IsOpen 状态
  • DtrEnable/RtsEnable

波特率

bit 与byte

  • bit就是位,也叫比特位,是计算机中最小的单位
  • byte是字节,也是B
  • 1字节(byte) = 8位(bit)
  • 位只有两种形式0和1,只能表示2种状态,而字节是有8个位组成的。可以表示256个状态。
  • 1byte = 8 bit,1KB = 1024 byte, 1MB = 1024KB,1G = 1024MB,1T = 1024G

波特率:表示每秒传输Bit的位数

校验位

  • 无校验(no parity)
  • 奇校验(odd parity):如果字符数据位中"1"的数目是偶数,校验位为"1",如果"1"的数目是奇数,校验位应为"0"。(校验位调整个数)
  • 偶校验(even parity):如果字符数据位中"1"的数目是偶数,则校验位应为"0",如果是奇数则为"1"。(校验位调整个数)
  • mark parity:校验位始终为1
  • space parity:校验位始终为0

数据位

紧跟在起始位之后,是通信中的真正有效信息。

数据位的位数可以由通信双方共同约定,一般可以是5位、7位或8位,标准ASCII码是0127(7位),扩展的ASCII码是0256(8位)。

传输数据时先传送字符的低位,后传送字符的高位。

停止位

表示单个包的最后一位。典型的值为1,1.5和2位。

由于数据时在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。

适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。

串口操作

开关串口

  • 获取端口号
RegistryKEy keyCom = Registry.LocalMachine.OpenSubKey(@"Harsware\DeviceMap\SerialComm");
  • 初始化配置参数

主要包含:端口号,波特率,数据位,停止位,校验位,编码格式

serialPort.Encoding = Encoding.GetEncoding("Gb2312");
  • 开启关闭操作

通过按钮事件来控制开关

配置参数

namespace 串口助手
{public partial class Form1 : Form{private bool isOpen = false;public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){//初始化串口参数配置//在设计页面已经预先添加了COM1 COM2 COM3this.port_cbb.Items.Add("COM4");this.port_cbb.Items.Add("COM5");this.port_cbb.SelectedIndex = 2;this.baud_cbb.SelectedIndex = 1;this.check_cbb.SelectedIndex = 0;this.databit_cbb.SelectedIndex = 3;this.stopbit_cbb.SelectedIndex = 0;/*//给发送框加预设文本this.send_rtb.Text = "我是发送框";//给接收框加预设文本this.recive_rtb.Text = "我是接收框";*/}private void open_btn_Click(object sender, EventArgs e){try{if (serialPort1.IsOpen == false){serialPort1.PortName = port_cbb.Text;serialPort1.BaudRate = Convert.ToInt32(baud_cbb.Text);serialPort1.DataBits = Convert.ToInt32(databit_cbb.Text);switch(check_cbb.SelectedIndex){case 0:serialPort1.Parity = System.IO.Ports.Parity.None;break;case 1:serialPort1.Parity = System.IO.Ports.Parity.Odd;break;case 2:serialPort1.Parity = System.IO.Ports.Parity.Even;break;case 3:serialPort1.Parity = System.IO.Ports.Parity.None;break;}switch (stopbit_cbb.SelectedIndex){case 0:serialPort1.StopBits = System.IO.Ports.StopBits.One;break;case 1:serialPort1.StopBits = System.IO.Ports.StopBits.OnePointFive;break;case 2:serialPort1.StopBits = System.IO.Ports.StopBits.Two;break;case 3:serialPort1.StopBits = System.IO.Ports.StopBits.One;break;default:serialPort1.StopBits = System.IO.Ports.StopBits.One;break;}serialPort1.Open();isOpen = true;open_btn.Text = "关闭串口";}else{serialPort1.Close();isOpen = false;open_btn.Text = "打开串口";}/*if (port_cbb.Text != ""){serialPort1.PortName = port_cbb.Text;}serialPort1.Open();if (serialPort1.IsOpen){MessageBox.Show("serialport is open");}*/}catch (Exception ex){MessageBox.Show(ex.ToString() + serialPort1.PortName.ToString());}}private void send_btn_Click(object sender, EventArgs e){//如果发送的数据不为空,则接收if (this.send_rtb.Text !=""){this.recive_rtb.AppendText(this.send_rtb.Text);}else{MessageBox.Show("请先输入发送数据");}}}
}

在这里插入图片描述

串口收发

从本地设备列表获取串口

获取端口号:注册列表中获取信息

RegistryKey keyCom = Registry.LocalMachine.OpenSubKey(@"Hardware\DeviceMap\SerialComm");
keyCom.GetValueNames();
keyCom.GetValue(xxx);

或使用**SerialPort.GetPortNames()**方法获取当前计算机的串行端口名的数组。

namespace 串口助手
{public partial class Form1 : Form{private bool isOpen = false;public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){//初始化串口参数配置//在设计页面已经预先添加了COM1 COM2 COM3//this.port_cbb.Items.Add("COM4");//this.port_cbb.Items.Add("COM5");//this.port_cbb.SelectedIndex = 2;//this.baud_cbb.SelectedIndex = 1;//this.check_cbb.SelectedIndex = 0;//this.databit_cbb.SelectedIndex = 3;//this.stopbit_cbb.SelectedIndex = 0;serialLoad();/*//给发送框加预设文本this.send_rtb.Text = "我是发送框";//给接收框加预设文本this.recive_rtb.Text = "我是接收框";*/}private void serialLoad(){//string[] cur_port = SerialPort.GetPortNames();RegistryKey keyCom = Registry.LocalMachine.OpenSubKey(@"Hardware\DeviceMap\SerialComm");string[] sSubKeys = keyCom.GetValueNames();port_cbb.Items.Clear();foreach (var sValue in sSubKeys){string portName =(string) keyCom.GetValue(sValue);port_cbb.Items.Add(portName);}this.port_cbb.SelectedIndex = 0;this.baud_cbb.SelectedIndex = 1;this.check_cbb.SelectedIndex = 0;this.databit_cbb.SelectedIndex = 3;this.stopbit_cbb.SelectedIndex = 0;}private void open_btn_Click(object sender, EventArgs e){try{if (serialPort1.IsOpen == false){serialPort1.PortName = port_cbb.Text;serialPort1.BaudRate = Convert.ToInt32(baud_cbb.Text);serialPort1.DataBits = Convert.ToInt32(databit_cbb.Text);switch(check_cbb.SelectedIndex){case 0:serialPort1.Parity = System.IO.Ports.Parity.None;break;case 1:serialPort1.Parity = System.IO.Ports.Parity.Odd;break;case 2:serialPort1.Parity = System.IO.Ports.Parity.Even;break;case 3:serialPort1.Parity = System.IO.Ports.Parity.None;break;}switch (stopbit_cbb.SelectedIndex){case 0:serialPort1.StopBits = System.IO.Ports.StopBits.One;break;case 1:serialPort1.StopBits = System.IO.Ports.StopBits.OnePointFive;break;case 2:serialPort1.StopBits = System.IO.Ports.StopBits.Two;break;case 3:serialPort1.StopBits = System.IO.Ports.StopBits.One;break;default:serialPort1.StopBits = System.IO.Ports.StopBits.One;break;}serialPort1.Open();isOpen = true;open_btn.Text = "关闭串口";}else{serialPort1.Close();isOpen = false;open_btn.Text = "打开串口";}/*if (port_cbb.Text != ""){serialPort1.PortName = port_cbb.Text;}serialPort1.Open();if (serialPort1.IsOpen){MessageBox.Show("serialport is open");}*/}catch (Exception ex){MessageBox.Show(ex.ToString() + serialPort1.PortName.ToString());}}private void send_btn_Click(object sender, EventArgs e){//如果发送的数据不为空,则接收if (this.send_rtb.Text !=""){this.recive_rtb.AppendText(this.send_rtb.Text);}else{MessageBox.Show("请先输入发送数据");}}}
}

在这里插入图片描述

串口数据的发送

public void Write(byte[] buffer, int offset, int count);
public void Write(strng text);
public void Write(char[] buffer, int offest, int count);
public void WriteLine(string text);

可以在串口控件类中查看到这些方法,并可以尝试使用。

 private void send_btn_Click(object sender, EventArgs e){//判断发送数据是否为空且串口是否打开if (this.send_rtb.Text !="" & serialPort1.IsOpen){//this.recive_rtb.AppendText(this.send_rtb.Text);serialPort1.Write(send_rtb.Text);}else{MessageBox.Show("请先输入发送数据");}}

串口数据的接收

public void Read(byte[] buffer, int offset, int count);
public void Read(char[] buffer, int offset, int count);
public int ReadByte();
public int ReadChar();
public string ReadExisting();
public string ReadLine();
public string ReadTo(string value);
public event SerialDataReceivedEventHandler DataReceived;
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e){string dataReceive = serialPort1.ReadExisting();receive_rtb.AppendText(dataReceive);}

收发数据

异步线程:更新UI

this.Invoke((EventHandler)delegate{});

执行一个异步线程来处理跨线程的数据。

DataReceived是在辅助线程执行,数据要更新到UI的主线程时,这个操作就跨线程了,可以通过异步线程来执行更新。

串口数据:接受字符处理

  • 将数据接受并缓存到数据缓存区(List 优于byte[])
  • 字符的编码格式:“GB2312”,“UTF8” 等等…
EncodingInfo[] encodingInfos = Encoding.GetEncodings();
  • 使用GB2312处理接收的数据
ribreceive.AppendText(Encoding.GetEncoding("gb2312").GetString(data).Replace("\0","\\0"));

在这里插入图片描述

代码:

//接收数据private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e){//显示暂停则不接受数据if (isRxShow == false) return;//1、需要读取有效的数据BytesToReadbyte[] dataTemp = new byte[serialPort1.BytesToRead];serialPort1.Read(dataTemp, 0, dataTemp.Length);receiveBuffer.AddRange(dataTemp);//计数器receiveCount += dataTemp.Length;this.Invoke(new EventHandler(delegate{//显示接收到的数据长度receivecount_tssl.Text = receiveCount.ToString();//判断是否选中十六进制if (!receivehex_chb.Checked){//编码格式选择 国标2312string str = Encoding.GetEncoding("gb2312").GetString(dataTemp);//0x00 -> \0结束,不会显示str = str.Replace("\0", "\\0");receive_rtb.AppendText(str);}else{//十六进制是选中的状态receive_rtb.AppendText(Transform.ToHexString(dataTemp, " "));}}));//string dataReceive = serialPort1.ReadExisting();//receive_rtb.AppendText(dataReceive);}private void stop_btn_Click(object sender, EventArgs e){if (isRxShow == true){isRxShow = false;stop_btn.Text = "取消暂停";}else{isRxShow = true;stop_btn.Text = "暂停";}}private void receivehex_chb_CheckedChanged(object sender, EventArgs e){if (receive_rtb.Text == "") return;if (receivehex_chb.Checked){receive_rtb.Text = Transform.ToHexString(receiveBuffer.ToArray(), " ");}else{receive_rtb.Text = Encoding.GetEncoding("gb2312").GetString(receiveBuffer.ToArray()).Replace("\0", "\\0");}}private void clear_btn_Click(object sender, EventArgs e){receiveBuffer.Clear();receivecount_tssl.Text = "";receive_rtb.Text = "";}private void autoclear_chb_CheckedChanged(object sender, EventArgs e){if (autoclear_chb.Checked){timer1.Start();}else{timer1.Stop();}}private void timer1_Tick(object sender, EventArgs e){if (receive_rtb.Text.Length > 4096){receiveBuffer.Clear();receive_rtb.Text = "";receivecount_tssl.Text = "";}}

串口数据:发送字符处理

  • 发送普通字符串
  • 发送十六进制字符串

在这里插入图片描述


namespace 串口助手
{public partial class Form1 : Form{private bool isOpen = false;private bool isRxShow = true;//接收缓存区private List<byte> receiveBuffer = new List<byte>();//发送缓存区private List<byte> sendBuffer = new List<byte>();//接收计数private int receiveCount = 0;//发送计数private int sendCount = 0;public Form1(){InitializeComponent();Control.CheckForIllegalCrossThreadCalls = false;}private void Form1_Load(object sender, EventArgs e){//初始化串口参数配置//在设计页面已经预先添加了COM1 COM2 COM3//this.port_cbb.Items.Add("COM4");//this.port_cbb.Items.Add("COM5");//this.port_cbb.SelectedIndex = 2;//this.baud_cbb.SelectedIndex = 1;//this.check_cbb.SelectedIndex = 0;//this.databit_cbb.SelectedIndex = 3;//this.stopbit_cbb.SelectedIndex = 0;serialLoad();/*//给发送框加预设文本this.send_rtb.Text = "我是发送框";//给接收框加预设文本this.recive_rtb.Text = "我是接收框";*/}private void serialLoad(){//string[] cur_port = SerialPort.GetPortNames();RegistryKey keyCom = Registry.LocalMachine.OpenSubKey(@"Hardware\DeviceMap\SerialComm");string[] sSubKeys = keyCom.GetValueNames();port_cbb.Items.Clear();foreach (var sValue in sSubKeys){string portName =(string) keyCom.GetValue(sValue);port_cbb.Items.Add(portName);}this.port_cbb.SelectedIndex = 0;this.baud_cbb.SelectedIndex = 1;this.check_cbb.SelectedIndex = 0;this.databit_cbb.SelectedIndex = 3;this.stopbit_cbb.SelectedIndex = 0;}private void open_btn_Click(object sender, EventArgs e){try{if (serialPort1.IsOpen == false){serialPort1.PortName = port_cbb.Text;serialPort1.BaudRate = Convert.ToInt32(baud_cbb.Text);serialPort1.DataBits = Convert.ToInt32(databit_cbb.Text);switch(check_cbb.SelectedIndex){case 0:serialPort1.Parity = System.IO.Ports.Parity.None;break;case 1:serialPort1.Parity = System.IO.Ports.Parity.Odd;break;case 2:serialPort1.Parity = System.IO.Ports.Parity.Even;break;case 3:serialPort1.Parity = System.IO.Ports.Parity.None;break;}switch (stopbit_cbb.SelectedIndex){case 0:serialPort1.StopBits = System.IO.Ports.StopBits.One;break;case 1:serialPort1.StopBits = System.IO.Ports.StopBits.OnePointFive;break;case 2:serialPort1.StopBits = System.IO.Ports.StopBits.Two;break;case 3:serialPort1.StopBits = System.IO.Ports.StopBits.One;break;default:serialPort1.StopBits = System.IO.Ports.StopBits.One;break;}serialPort1.Open();isOpen = true;open_btn.Text = "关闭串口";}else{serialPort1.Close();isOpen = false;open_btn.Text = "打开串口";}/*if (port_cbb.Text != ""){serialPort1.PortName = port_cbb.Text;}serialPort1.Open();if (serialPort1.IsOpen){MessageBox.Show("serialport is open");}*/}catch (Exception ex){MessageBox.Show(ex.ToString() + serialPort1.PortName.ToString());}}private void sendData(){serialPort1.Write(sendBuffer.ToArray(), 0, sendBuffer.Count);sendCount += sendBuffer.Count();sendcount_tssl.Text = sendCount.ToString();}private void send_btn_Click(object sender, EventArgs e){//如果发送的数据不为空,则接收if (this.send_rtb.Text !="" && serialPort1.IsOpen){Console.WriteLine(Transform.ToHexString(sendBuffer.ToArray()));sendData();}else{MessageBox.Show("请先输入发送数据");}}//接收数据private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e){//显示暂停则不接受数据if (isRxShow == false) return;//1、需要读取有效的数据BytesToReadbyte[] dataTemp = new byte[serialPort1.BytesToRead];serialPort1.Read(dataTemp, 0, dataTemp.Length);receiveBuffer.AddRange(dataTemp);//计数器receiveCount += dataTemp.Length;this.Invoke(new EventHandler(delegate{//显示接收到的数据长度receivecount_tssl.Text = receiveCount.ToString();//判断是否选中十六进制if (!receivehex_chb.Checked){//编码格式选择 国标2312string str = Encoding.GetEncoding("gb2312").GetString(dataTemp);//0x00 -> \0结束,不会显示str = str.Replace("\0", "\\0");receive_rtb.AppendText(str);}else{//十六进制是选中的状态receive_rtb.AppendText(Transform.ToHexString(dataTemp, " "));}}));//string dataReceive = serialPort1.ReadExisting();//receive_rtb.AppendText(dataReceive);}private void stop_btn_Click(object sender, EventArgs e){if (isRxShow == true){isRxShow = false;stop_btn.Text = "取消暂停";}else{isRxShow = true;stop_btn.Text = "暂停";}}private void receivehex_chb_CheckedChanged(object sender, EventArgs e){if (receive_rtb.Text == "") return;if (receivehex_chb.Checked){receive_rtb.Text = Transform.ToHexString(receiveBuffer.ToArray(), " ");}else{receive_rtb.Text = Encoding.GetEncoding("gb2312").GetString(receiveBuffer.ToArray()).Replace("\0", "\\0");}}private void clear_btn_Click(object sender, EventArgs e){receiveBuffer.Clear();receivecount_tssl.Text = "";receive_rtb.Text = "";}private void autoclear_chb_CheckedChanged(object sender, EventArgs e){if (autoclear_chb.Checked){timer1.Start();}else{timer1.Stop();}}private void timer1_Tick(object sender, EventArgs e){if (receive_rtb.Text.Length > 4096){receiveBuffer.Clear();receive_rtb.Text = "";receivecount_tssl.Text = "";}}private void send_rtb_Leave(object sender, EventArgs e){if (sendhex_chb.Checked){//判断是否为十六进制字符if (DataEncoding.IsHexString(send_rtb.Text.Replace(" ",""))){sendBuffer.Clear();sendBuffer.AddRange(Transform.ToBytes(send_rtb.Text.Replace(" ", "")));}else{MessageBox.Show("请输入正确的十六进制数据!");send_rtb.Select();}}else{sendBuffer.Clear();sendBuffer.AddRange(Encoding.GetEncoding("gb2312").GetBytes(send_rtb.Text));}}private void send_rtb_TextChanged(object sender, EventArgs e){// 十六进制切换 会出现问题  这问题就是0x00 转换}private void sendhex_chb_CheckedChanged(object sender, EventArgs e){if (send_rtb.Text == "") return;if (sendhex_chb.Checked){send_rtb.Text = Transform.ToHexString(sendBuffer.ToArray(), " ");}else{send_rtb.Text = Encoding.GetEncoding("gb2312").GetString(sendBuffer.ToArray()).Replace("\0", "\\0");}}private void sendclear_btn_Click(object sender, EventArgs e){sendBuffer.Clear();sendcount_tssl.Text = "0";send_rtb.Text = "";sendCount = 0;}}
}

协议解析

数据大小算端

大端模式

指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址
由小向大增加,而数据从高位往低位放;

小端模式

指数据的高字节保存在内存的高地址中, 而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。

数据校验方式:和校验,CRC,LRC等等

  • CRC 有多版本:今天使用的是CRC16_ccitt_xmode
  • LRC
  • 和校验
  • 奇偶校验
  • 异或校验

解析数据处理

  • 关键 :queue 队列的先进先出逻辑
  • 关键 :控制协议,决定了数据解析逻辑,不同数据解析方式不同
  • 案例:帧头(0x7F)+数据长度+数据+CRC
  • 数据样本:7f+04+31323334+DE10

在这里插入图片描述

声明

在这里插入图片描述

实例化队列Queue

在这里插入图片描述

//接收数据
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{//显示暂停则不接受数据if (isRxShow == false) return;//1、需要读取有效的数据BytesToReadbyte[] dataTemp = new byte[serialPort1.BytesToRead];serialPort1.Read(dataTemp, 0, dataTemp.Length);receiveBuffer.AddRange(dataTemp);//计数器receiveCount += dataTemp.Length;this.Invoke(new EventHandler(delegate{//显示接收到的数据长度receivecount_tssl.Text = receiveCount.ToString();//判断是否选中"启动数据帧接收"if (!startData_chb.Checked){//判断是否选中十六进制if (!receivehex_chb.Checked){//编码格式选择 国标2312string str = Encoding.GetEncoding("gb2312").GetString(dataTemp);//0x00 -> \0结束,不会显示str = str.Replace("\0", "\\0");receive_rtb.AppendText(str);}else{//十六进制是选中的状态receive_rtb.AppendText(Transform.ToHexString(dataTemp, " "));}}else{//解析数据 queueforeach (byte item in dataTemp){//入列bufferQueue.Enqueue(item);}//解析获取帧头if (!isHeadReceive){//遍历队列获取0x7f位置foreach (byte item in bufferQueue.ToArray()){if (item != 0x7f){//移除数据,保证0x7f在头位置//出列bufferQueue.Dequeue();Console.WriteLine("not 0x7f, Dequeue !");}else{//获取到0x7f,停止遍历//get 0x7f from bufferQueueisHeadReceive = true;Console.WriteLine("0x7f is receive !");break;}}}if (isHeadReceive){//判断数据帧长度if (bufferQueue.Count >= 2){Console.WriteLine(DateTime.Now.ToLongTimeString());//输出缓冲区中的数据,数据以十六进制字符串的形式显示。Console.WriteLine($"show the data in bufferQueue{Transform.ToHexString(bufferQueue.ToArray())}");//使用 X2 格式说明符,表示将值转换为至少两位的大写十六进制数。//如果值的位数少于两位,则在前面补零Console.WriteLine($"frame lenth ={String.Format("{0:X2}", bufferQueue.ToArray()[1])}");frameLenth = bufferQueue.ToArray()[1];// 一帧完整的数据长度判断,不代表数据是正确的if (bufferQueue.Count>=1+1+frameLenth+2){byte[] frameBuffer = new byte[1+1+frameLenth+2];//源数组、源数组的起始索引、目标数组、目标数组的起始索引和要复制的元素数量Array.Copy(bufferQueue.ToArray(), 0, frameBuffer, 0, frameBuffer.Length);if (crc_check(frameBuffer)){Console.WriteLine("frame is check ok,pick it");data_txb.Text = Transform.ToHexString(frameBuffer);data1_txb.Text = String.Format("{0:X2}", frameBuffer[2]);data2_txb.Text = String.Format("{0:X2}", frameBuffer[3]);data3_txb.Text = String.Format("{0:X2}", frameBuffer[4]);data4_txb.Text = String.Format("{0:X2}", frameBuffer[5]);}else{// 无效数据Console.WriteLine("bad frame, drop it");}for (int i = 0; i < 1 + 1 + frameLenth + 2; i++){bufferQueue.Dequeue();}isHeadReceive = false;}}}}}));//string dataReceive = serialPort1.ReadExisting();//receive_rtb.AppendText(dataReceive);}private bool crc_check(byte[] frameBuffer)
{//大小端数据bool ret = false;byte[] temp = new byte[frameBuffer.Length-2];Array.Copy(frameBuffer, 0, temp,0, temp.Length);byte[] crcdata = DataCheck.DataCrc16_Ccitt(temp, DataCheck.BigOrLittle.BigEndian);if (crcdata[0] == frameBuffer[frameBuffer.Length -2] &&crcdata[1] == frameBuffer[frameBuffer.Length-1]){ret = true;}return ret;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/180786.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在Linux上通过NTLM认证连接到AD服务器(未完结)

这篇文章目前还没有实现具体的功能&#xff0c;只实现了明文登录&#xff0c;因为我缺少一些数据&#xff0c;比如通过密码生成hash&#xff0c;以及通过challenge生成response&#xff0c;我不知道怎么实现&#xff0c;因此这篇文章也是一个交流的文章&#xff0c;希望大佬看见…

深入理解网络IO复用并发模型

本文主要介绍服务端对于网络并发模型以及Linux系统下常见的网络IO复用并发模型。文章内容一共分为两个部分。 第一部分主要介绍网络并发中的一些基本概念以及我们Linux下常见的原生IO复用系统调用&#xff08;epoll/select&#xff09;等。第二部分主要介绍并发场景下常见的网…

el-table树状表格末行合计

首先,由于我的表头是动态的,所以就稍微复杂一点 效果图 表头数据格式是这样的 表格的数据格式是这样的 然后用合并的方法,此处就需要递归去计算,根据props去匹配每一列的数据,然后加起来,关键代码 //合计处理getSummaries(param) {const { columns, data } param;const su…

树结构及其算法-二叉排序树

目录 树结构及其算法-二叉排序树 C代码 树结构及其算法-二叉排序树 事实上&#xff0c;二叉树是一种很好的排序应用模式&#xff0c;因为在建立二叉树的同时&#xff0c;数据已经经过初步的比较&#xff0c;并按照二叉树的建立规则来存放数据&#xff0c;规则如下&#xff1…

解决方案中word中分节符的使用

解决方案中必不可少的两个“符号”&#xff0c;分页符&#xff0c;分节符 有了分节符&#xff0c;可以为不同节设置不同的页眉页脚、分栏格式、纸张大小及方向、页边距、不同节间采用不同的页码序号&#xff0c;常用的功能主要是把word下一次的由原来的“竖版”&#xff0c;变…

深入剖析:正则表达式的奥秘

简介 正则表达式&#xff08;Regular Expressions&#xff09;是一种强大的文本处理工具&#xff0c;一种用于匹配文本模式的字符串。它由特定的字符和操作符组成&#xff0c;用于定义一个搜索模式。这些搜索模式可以用于文本搜索、替换、验证和提取数据等多种用途。 以下是一…

canal+es+kibana+springboot

1、环境准备 服务器&#xff1a;Centos7 Jdk版本&#xff1a;1.8 Mysql版本&#xff1a;5.7.44 Canal版本&#xff1a;1.17 Es版本&#xff1a;7.12.1 kibana版本&#xff1a;7.12.1 软件包下载地址&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1jRpCJP0-hr9aI…

【Python语言】序列(列表,元组,字符串)切片操作

目录 序列切片操作 1.1 对list进行切片&#xff0c;从1开始&#xff0c;到5结束&#xff0c;步长为1 [ 1 : 5 ] 1.2 对tuple进行切片&#xff0c;从头开始&#xff0c;到最后结束&#xff0c;步长为1 [ : ] 1.3 对str进行切片&#xff0c;从头开始&#xff0c;到最…

『精』Vue 组件如何模块化抽离Props

『精』Vue 组件如何模块化抽离Props 文章目录 『精』Vue 组件如何模块化抽离Props一、为什么要抽离Props二、选项式API方式抽离三、组合式API方式抽离3.1 TypeScript类型方式3.2 文件分离方式3.3 对文件分离方式优化 参考资料&#x1f498;推荐博文&#x1f357; 一、为什么要抽…

Cordova插件开发二:高精度定位之卫星数据解析

文章目录 1.最终效果预览2.坐标获取方法3.在公共类中封装获取坐标的通用方法4.插件js中封装startGeoLocation方法5.插件主界面封装的方法1.最终效果预览 2.坐标获取方法 let obj = Object.assign({}, this.mapConfig.mapLocationObj)obj.isKeepCallBack = falselet res = await…

探索无限可能:APITable免费开源多维表格与可视化数据库远程访问的魅力

APITable免费开源的多维表格与可视化数据库公网远程访问 文章目录 APITable免费开源的多维表格与可视化数据库公网远程访问前言1. 部署APITable2. cpolar的安装和注册3. 配置APITable公网访问地址4. 固定APITable公网地址 前言 vika维格表作为新一代数据生产力平台&#xff0c…

代码生成器

Easycode Entity ##导入宏定义 $!{define.vm}##保存文件&#xff08;宏定义&#xff09; #save("/entity", ".java")##包路径&#xff08;宏定义&#xff09; #setPackageSuffix("entity")##自动导入包&#xff08;全局变量&#xff09; $!{au…

半导体工厂将应用哪些制造创新技术?

半导体工厂是高科技产业的结晶&#xff0c;汇聚了世界上最新的技术。 在半导体的原料硅晶片上绘制设计图纸&#xff0c;不产生误差&#xff0c;准确切割并包装&#xff0c;然后用芯片生产出我们使用的电脑、智能手机、手表等各种电子产品。绝大多数半导体厂都采用一贯的工艺&a…

android display 杂谈(三)WMS

用来记录学习wms&#xff0c;后续会一点一点更新。。。。。。 代码&#xff1a;android14 WMS是在SystemServer进程中启动的 在SystemServer中的main方法中&#xff0c;调用run方法。 private void run() { // Initialize native services.初始化服务&#xff0c;加载andro…

【PyTorch实战演练】AlexNet网络模型构建并使用Cifar10数据集进行批量训练(附代码)

目录 0. 前言 1. Cifar10数据集 2. AlexNet网络模型 2.1 AlexNet的网络结构 2.2 激活函数ReLu 2.3 Dropout方法 2.4 数据增强 3. 使用GPU加速进行批量训练 4. 网络模型构建 5. 训练过程 6. 完整代码 0. 前言 按照国际惯例&#xff0c;首先声明&#xff1a;本文只是我…

《Pytorch新手入门》第二节-动手搭建神经网络

《Pytorch新手入门》第二节-动手搭建神经网络 一、神经网络介绍二、使用torch.nn搭建神经网络2.1 定义网络2.2 torch.autograd.Variable2.3 损失函数与反向传播2.4 优化器torch.optim 三、实战-实现图像分类(CIFAR-10数据集)3.1 CIFAR-10数据集加载与预处理3.2 定义网络结构3.3…

2.Docker基本架构简介与安装实战

1.认识Docker的基本架构 下面这张图是docker官网上的&#xff0c;介绍了整个Docker的基础架构&#xff0c;我们根据这张图来学习一下docker的涉及到的一些相关概念。 1.1 Docker的架构组成 Docker架构是由Client(客户端)、Docker Host(服务端)、Registry(远程仓库)组成。 …

【Python基础】Python编程入门自学笔记,基础大全,一篇到底!

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…

Dubbo捕获自定义异常

一.问题描述 Dubbo远程服务提供者抛出的自定义异常无法被消费方正常捕获&#xff0c;消费方捕获的自定义异常全部变成RuntimeException&#xff0c;使用起来很不方便。 二.原因分析 相关源码 /** Licensed to the Apache Software Foundation (ASF) under one or more* con…

SpringBoot----自定义Start(自定义依赖)

一&#xff0c;为什么要定义Start 向阿里云OSS如果我们要引入的话很麻烦&#xff0c;所以我们可以自定义一些组件&#xff0c; 然后我们只需要在pom文件中引入对应的坐标就可以 二&#xff0c;怎么定义&#xff08;以阿里云OSS为例&#xff09; 1&#xff0c; 定义两个组件模块…