zoukankan      html  css  js  c++  java
  • 串口通讯学习

    //前提需要

    //需要一个 serialPort 工具 可在vs自带的工具栏中获得

    //源代码加串口工具地址:

    //链接:https://pan.baidu.com/s/1YbfvdXEmfsJX87D-Jxljyg   提取码:d32x

    //记录用户打开的串口号 可改为泛型模式

    string serialPortName;

    //一般电脑是没有串口号的,所以要用个软件创建虚拟串口号

    //软件名 - Configure Virtual Serial Port Driver

    波特率设置的值为 1382400,921600,460800,256000,230400,128000,115200,76800,57600,

    43000,38400,19200,14400,9600,4800,1200

    停止位设置的值为:1,1.5,2

    数据位设置的值为:8,7,6,5

    校验位设置的值为:无,奇校验,偶校验

    步骤:

    1.设置串口的基本数据 (串口号,波特率,数据位,停止位,校验位)

    2.使用Open打开串口

    3.使用串口工具的DataReceived()事件进行数据的接收

    4.创建发送数据 Write() ,一般发送的是byte数组

    5.使用Close关闭串口

    界面:

    //一

    //在窗口Load事件中,设置串口基本数据的默认值

    //1.拿到电脑上可以使用的串口号,并赋值给窗口的串口下拉列表中,默认选项索引为0

    string[] prots = System.IO.Ports.SerialPort.GetPortNames();

    this.cbPort.Items.AddRange(prots);

    this.cbPort.SelectedIndex = this.cbPort.Items.Count > 0 ? 0 : -1;

    //2.设置波特率,停止位,数据位,校验位的默认值。

    this.cbBaud.Text = "115200";

    this.cbStopBit.Text = "1";

    this.cbDataBit.Text = "8";

    this.cbComparable.Text = "无";

    //二

    //设置打开串口和关闭串口按钮的单击事件

    //为串口拿到基本数据

    serialPort .PortName = this.cbPort.Text;//串口号

    serialPortName = this.cbPort.Text;//记录用户打开的串口号

    serialPort.BaudRate = int.Parse(this.cbBaud.Text);//波特率

    serialPort.DataBits = int.Parse(this.cbDataBit.Text);//数据位

    //设置停止位

    if (this.cbStopBit.Text == "1") { serialPort.StopBits = StopBits.One; }

    else if (this.cbStopBit.Text == "1.5") { serialPort.StopBits = StopBits.OnePointFive; }

    else if (this.cbStopBit.Text == "2") { serialPort.StopBits = StopBits.Two; }

    //设置奇偶校验

    if (this.cbComparable.Text == "无") { serialPort.Parity = Parity.None; }

    else if (this.cbComparable.Text == "奇校验") { serialPort.Parity = Parity.Odd; }

    else if (this.cbComparable.Text == "偶校验") { serialPort.Parity = Parity.Even; }

    //打开串口 只需要使用Open打开串口

    serialPort1.Open();

    this.btnOpenStat.Text = "关闭串口";

    //如果按钮的Text为 关闭串口的话

    serialPort.Close();//Close() - 关闭串口

    //三 本次串口的简单数据协议 1 - 字符串 bp - 医疗数据 2 - 文件

    //通过串口工具自带的DataReceived事件进行串口的数据接收

    //这次的是自己定义的数据协议,一般都是用公司默认的协议 或者RS232和RS485

    //获取可以读取的字节数 默认最大值是4096 如果想要更改可以直接改变串口的ReadBufferSize属性

    int len = serialPort.BytesToRead;

    if(len == serialPort.ReadBufferSize){

    MessageBox.Show("程序最多只能接受"+serialPort1.ReadBufferSize+"字节的数据!","提示");

    return;

    }

    //拿到数据,Read()

    byte[] buff = new byte[len];

    serialPort.Read(buff,0,len);

    //如果选中了显示时间就赋值,没有就算

    string DateNow = string.Empty;

    //根据协议进行判断

    if(buff[0]==1){

    //拿出原来的数据并去除协议部分 然后放入另一个byte[]数组中

    byte[] result = new byte[len];

    Buffer.BlockCopy(buff,1,result,0,buff.Length-1);

    //将byte数组保存可读string 根据自己的编码格式进行转码

    string str = Encoding.Default.GetString(result);

    //将数据分割为string[] 判断是否为医疗数据

    string[] strPle = str.Split(',');

    if(strPle[0]=="bp"){

    //放入方法中,重新拼装成可用数据

    str = RecHBpData(strPle);

    }

    //由于我们的接收数据的事件是在一个子线程里面的,

    //所以需要Invoke才能给我们主线程创建的控件赋值

    //当然你也可以使用InvokeRequired()来判断是否为主线程创建的控件,我这里就没使用了

    Invoke(new Action(() => {

    //是否显示时间

    if(this.ckDateTime.Checked){

    DateNow = " " + DateTime.Now.ToString();

    }

    //是否为16进制显示

    if(this.checkBox1.Checked){

    this.txtMsg.AppendText(DateNow + " " + byteToHexStr(buff));

    }

    //默认是使用字符串显示

    else{

    this.txtMsg.AppendText(DateNow + " " + str);

    }

    })));

    }

    //如果传送的文件的话

    else if(buff[0]==2){

    ProcessRecieveFile(buff);

    }

    //一般呢,这些方法是放在一个方法类库里面,但是我懒得放就在一个类里面了

    #region 封装的方法

    /// <summary>

    /// 传输的是文件就进行文件的操作

    /// </summary>

    /// <param name="data">数据流</param>

    public void ProcessRecieveFile(byte[] data)

    {

    using (SaveFileDialog dialog = new SaveFileDialog())

    {

    dialog.DefaultExt = "txt";

    dialog.Filter = "文本文件(*.txt)|*.txt|所有文件(*.*)|*.*";

    //由于大部分可能不是主线程,所以我们要加this,不然不会弹出保存框

    if (dialog.ShowDialog(this) != DialogResult.OK)

    {

    return;

    }

    byte[] result = new byte[data.Length - 1];

    Buffer.BlockCopy(data, 1, result, 0, data.Length - 1);

    File.WriteAllBytes(dialog.FileName, result);

    }

    }

    #region 封装 数据定义的协议

    public static string RecHBpData(string[] strPle)

    {

    string str = string.Empty;

    //判断仪器

    str += $"{StaticConstant.DicMedicalnoun[strPle[1]]} ";

    //增加时间

    str += " " + strPle[2] + " " + strPle[3] + " ";

    //增加具体数据

    str += $"{StaticConstant.DicMedicalnoun[strPle[4]]}: {strPle[5].TrimStart('0')} {StaticConstant.DicMedicalnoun[strPle[6]]}: {strPle[7].TrimStart('0')}";

    return str;

    }

    #endregion

    /// <summary>

    /// 字节数组转16进制字符串

    /// </summary>

    /// <param name="bytes">byte数组</param>

    /// <returns>16进制显示形式</returns>

    public static string byteToHexStr(byte[] bytes)

    {

    string retuenStr = "";

    try

    {

    if (bytes != null)

    {

    for (int i = 0; i < bytes.Length; i++)

    {

    retuenStr += bytes[i].ToString("X2") + " ";//变成16进制,两个中间用空格隔开

    }

    }

    return retuenStr;

    }

    catch (Exception ex)

    {

    return retuenStr;

    }

    }

    /// <summary>

    /// 字符串转16进制格式,不够自动前面补0

    /// </summary>

    /// <param name="hexString"></param>

    /// <returns></returns>

    public static byte[] strToHexByte(string hexString)

    {

    int i;

    if ((hexString.Length % 2) != 0)

    {//奇数个

    byte[] returnBytes = new byte[(hexString.Length + 1) / 2];

    try

    {

    for (i = 0; i < hexString.Length - 1; i++)

    {

    returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);

    i = i * 2;

    }

    returnBytes[returnBytes.Length - 1] = Convert.ToByte(hexString.Substring(hexString.Length - 1, 1).PadLeft(2, '0'), 16);

    }

    catch (Exception)

    {

    MessageBox.Show("含有非16进制字符", "提示");

    return null;

    }

    return returnBytes;

    }

    else

    {

    byte[] returnBytes = new byte[(hexString.Length) / 2];

    try

    {

    for (i = 0; i < hexString.Length; i++)

    {

    returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);

    }

    }

    catch (Exception)

    {

    MessageBox.Show("含有非16进制字符", "提示");

    return null;

    }

    return returnBytes;

    }

    }

    #endregion

    //我的医疗数据的封装是放在配置文件中,一般我们都是放在数据库中,不过我就做个小学习工具就 //没做到数据库里面了

    //四 发送数据

    //发送数据,我这边分为发送文件和发送字符串

    //1.发送字符串

    string str = this.txtSendMsg.Text.Trim().Tostring();

    try{

    if(str.Length > 0){

    //16进制发送

    if(this.ckSend.Checked){

    byte[] byt = strToHexBytes(str);

    byte[] result = new byte[byt.Length+1];

    //加上数据协议

    result[0] = 1;

    //数据转移

    Buffer.BlockCopy(byt,0,result,1,byt.Lengt);

    //发送数据,byte形式发送

    serialPort.Write(result,0,result.Length);

    }

    //默认字符串发送

    else{

    //根据自己的编码格式编码

    byte[] dataByte = Encoding.Default.GetBytes(str);

    byte[] result = new byte[dataByte.Length + 1];

    //加上数据协议

    result[0] = 1;

    Buffer.BlockCopy(dataByte ,0,result,1,dataByte .Lengt);

    //发送数据,byte形式发送

    serialPort.Write(result,0,result.Length);

    }

    }

    }catch(Exception ex){}

    //2.发送文件

    try{

    using(OpenFileDialog dialog = new OpenFileDialog()){

    if(dialog.ShowDialog(this) != DialogResult.OK){

    return;

    }

    byte[] data = File.ReadAllBytes(dialog.FileName);

    byte[] result = new byte[data.Length + 1];

    result[0] = 2;

    Buffer.BlockCopy(data,0,result,1,data.Length);

    serialPort.Write(result,0,result.Lenght);

    }

    }catch(Exception ex){

    MessageBox.Show(ex.Message);

    }

  • 相关阅读:
    算法 quick sort
    非常多学ThinkPHP的新手会遇到的问题
    原创jQuery插件之图片自适应
    管理线程之向线程函数传递參数
    [LeetCode]94.Binary Tree Inorder Traversal
    数据库基本概念
    Eclipse4.4 安装java反编译插件Eclipse Class Decompiler
    广义线性模型
    代理模式
    多态之中的一个(继承和虚函数)
  • 原文地址:https://www.cnblogs.com/namelessblog/p/13221303.html
Copyright © 2011-2022 走看看