C#电源串口调试

news2025/2/4 18:58:28

目的
记录串口调试的遇到的一些问题以及相应的解决方法
1.串口定义:串口是计算机与其他硬件传输数据的通道,在计算机与外设通信时起到重要作用
2.串口通信的基础知识

  1. C#中的串口通信类
    C#使用串口通信类是SerialPort(),该类使用方法是
    new 一个 SerialPort对象
    为SerialPort对象准备参数
   _serialPort = new SerialPort(portName);
   _serialPort.BaudRate = bauRate;
   _serialPort.Parity = parity;
   _serialPort.DataBits = dataBits;
   _serialPort.StopBits = stopBits;
   _serialPort.Handshake = Handshake.None;
   _serialPort.ReadTimeout = 500;
   _serialPort.WriteTimeout = 500;

接下来就是打开串口并且绑定事件

  try
  {
      ErrorMessage = "";
      _serialPort.Open();

      if (_serialPort.IsOpen)
      {
          _serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
          return true;

      }
      else
      {
          Log.Debug($"Truth_Power.SerialPortHelper.Open().Return [{false.ToString()}]");
          
          return false;
      }

  }
  catch(Exception ex)
  {
      
      ErrorMessage = ex.Message;
      Log.Error($"Truth_Power.SerialPortHelper.Open().Error [{ex.Message}]");
      
      return false;
  }

2.从串口读取数据
串口的性质不同于网络,网络发一个HTTP会返回一个完整的数据。例如请求一个网页,服务端就会返回完整的网页代码。
但是串口不同,串口不一定一次返回完整的数据,可能会分批次返回
例如我已知串口返回来的数据是10个字节但是第一次触发数据接收事件时可能返回5个,第二次再触发事件时返回剩下的5个。这样串口需要一个数据合并的代码,实例代码如下:

    private  void DataReceivedHandler(object sender,SerialDataReceivedEventArgs args)
    {
        //端口缓冲区字节数,本次数据到达的字节数
        int n = _serialPort.BytesToRead;
        //  Console.WriteLine(n);
        //将端口缓冲区数据存入字节数组
        byte[] byteRev = new byte[n];
        _serialPort.Read(byteRev, 0, n);
        //将字节数组存入程序缓冲区
        string data = BitConverter.ToString(byteRev);
       // RecieveBuffer += data;         
        if (IsRead)
        {
            ReadBuffer += "-"+data;   //拼接返回的数据

        }
        //if(ReadBuffer.Length == 20)                            //如果数据长度合格,则可以发出事件   这个事件不应该在回调中发出而是应该在writeRead函数中发出
        //{
        //    ReceivedDataFromPort.Invoke(command, byteRev, n);  //读出完整数据后再发出事件
        //}
       
    }
    public bool WriteAndRead(byte[] sendBytes, out string recieved, int timeOut = 1000, int stepTime = 20)
    {
        IsRead = true;
        ReadBuffer = "";//公共变量
        recieved = "";
        //clearInput();      //清空串口
        if (Write(sendBytes))
        {
            int times = timeOut / stepTime;
            for (int i = 0; i < times; i++)
            {
                recieved = ReadBuffer;         //获取截止到当前串口返回的数据
                Thread.Sleep(stepTime);        //这个延时一定要放在recived = ReadBuffer之后,如果20ms后ReadBuffer被更新,那么received!=ReadBuffer,这时就不会跳出循环
                if (recieved == "")           //如果这次读到是空先跳过,等下次再读
                {
                    continue;
                }
                if (recieved == ReadBuffer)    //当某次达到满数据后可以直接跳出循。跳出后判断i的值,如果i达到times那么说明超时;如果小于times那么没有超时
                {
                    break;
                }
            }

            clearOutput();
            IsRead = false;
            return true;

        }
        IsRead = false;
        Log.Debug($"Truth_Power.SerialPortHelper.WriteAndRead().Return [{false.ToString()}]");
        return false;
    }

3.C#跨线程访问
C#跨线程访问需要特殊的处理

  private void sendDataThread()
  {
      string fileName = "testdata.txt";
      StreamWriter sr;
      sr = new StreamWriter(fileName);
      
      const  int length = 10; ;//发送与返回的字节长度
      int timeOut = 1000;      //超时时间
      int stepTime = 20;       //时间间隔
      int n = 0;            //当前接收的数据长度

      string hexString;
      //现在的问题就是数据没有写入
      string dataRev;
      

      byte[] dataRecv = new byte[length];
      
      while (true)
      {
          if (killed)                      //如果需要结束线程,那么用break跳出循环
          {
              sr.Close();
              break;
          }
          lock (Lock_Port)
          {

              this.Dispatcher.Invoke(new Action(delegate
              {
                  //你想要做的操作    

                  ControlMode mode = ((MainWindowViewModel)this.DataContext).CurrentSelectedMode;
                  int electric = ((MainWindowViewModel)this.DataContext).Electricity;
                  int magetic = ((MainWindowViewModel)this.DataContext).Magnetic;
                  int voltage = ((MainWindowViewModel)this.DataContext).Voltage;
                  byte[] command;
                  List<byte> data = new List<byte>();
                  switch (mode)
                  {
                      case ControlMode.Voltage:
                          SerialPortCommand.SetVoltage(voltage, Sign.PositiveSign, out command);
                          //这里可能要先清空
                          _serialPortControl.command = command;
                          _serialPortControl.Write(command.ToArray());

                          _serialPortControl.WriteAndRead(command, out dataRev);

                          timestamp = DateTime.Now.ToString();


                          hexString = BitConverter.ToString(command);
                          timestamp = DateTime.Now.ToString();
                          sr.WriteLine("接收时间");
                          sr.WriteLine(timestamp);
                          sr.WriteLine("发送数据");
                          sr.WriteLine(hexString);
                          // hexString = BitConverter.ToString(receive);
                          sr.WriteLine("接收数据");
                          sr.WriteLine(dataRev);
                          sr.WriteLine("接收数据长度");
                          sr.WriteLine(dataRev.Length.ToString());
                          sr.WriteLine("\n");

                          break;
                      case ControlMode.Magnetic:
                          SerialPortCommand.SetMagetic(magetic);
                          break;
                      case ControlMode.Electricity:
                          SerialPortCommand.SetElectric(electric, Sign.PositiveSign, out command);
                          _serialPortControl.command = command;

                          _serialPortControl.WriteAndRead(command, out dataRev);

                          timestamp = DateTime.Now.ToString();


                          hexString = BitConverter.ToString(command);
                          timestamp = DateTime.Now.ToString();
                          sr.WriteLine("接收时间");
                          sr.WriteLine(timestamp);
                          sr.WriteLine("发送数据");
                          sr.WriteLine(hexString);
                          // hexString = BitConverter.ToString(receive);
                          sr.WriteLine("接收数据");
                          sr.WriteLine(dataRev);
                          sr.WriteLine("接收数据长度");
                          sr.WriteLine(dataRev.Length.ToString());
                          sr.WriteLine("\n");
                          break;
                  }
              }));




         
          }

          Thread.Sleep(1000);                                         //延时1秒,保证电源有时间响应
 
      }

4.串口指令生成
写串口实质上是向串口写入数据
数据本质上一串字节型数据,一般有固定的格式。帧头-命令字-数据部分-帧尾,值得关注就是数据部分。
在这里插入图片描述

以这个图片为例,取出32位Int型数据的某八位可以用>>(移位)和&(且)
如果取出高第二个字节

(byte)((dataLength >> 16) & 0xFF)

如果取出Int型数据的低8位

(byte)(dataLength & 0xFF)

5.关于combox selectedChange事件 运行程序立即执行的问题
解决这个bug需要在切换事件中判断串口是否打开,如果未打开则事件立即返回。代码如下:

   //选中的改变之后,根据当前的选中值更新
   //核心获取改变之后的值
   if (!_isOpenForPort)
   {
       MessageBox.Show("串口未打开");
       return;
   }

6.返回重复数据的bug的原因
换成新的WriteAndRead函数后没有把原来的函数Write删掉
在这里插入图片描述
删掉这行代码之后串口接收到的数据就正常了

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【大模型实践】基于文心一言的对话模型设计

文心一言&#xff08;英文名&#xff1a;ERNIE Bot&#xff09;是百度全新一代知识增强大语言模型&#xff0c;文心大模型家族的新成员&#xff0c;能够与人对话互动、回答问题、协助创作&#xff0c;高效便捷地帮助人们获取信息、知识和灵感。文心一言从数万亿数据和数千亿知识…

Git 配置多个 SSH-Key

Git 配置多个 SSH-Key &#xff08;两个都是gitee&#xff09; 先看图&#xff0c;官网固然重要&#xff0c;但是不完全行&#xff08;因为官网示例是一个gitee一个github&#xff09;&#xff0c;现在想是想多个都是gitee在他上面稍微更改即可 一般不对遇到这种问题&#xf…

Kylin基础知识点解析与应用探索

目录 学习目标&#xff1a; 学习内容&#xff1a; 学习时间&#xff1a; 学习产出&#xff1a; Kylin简介 什么是Kylin Kylin的历史和发展 Kylin在大数据领域的地位和作用 Kylin架构 Kylin的组成部分和模块 Kylin的工作原理和流程 Kylin与其他大数据组件的关系和集成 Kylin功能…

ffmpeg 硬件解码零拷贝unity 播放

ffmpeg硬件解码问题 ffmpeg 在硬件解码&#xff0c;一般来说&#xff0c;我们解码使用cuda方式&#xff0c;当然&#xff0c;最好的方式是不要确定一定是cuda&#xff0c;客户的显卡不一定有cuda&#xff0c;windows 下&#xff0c;和linux 下要做一些适配工作&#xff0c;最麻…

Python知识(2/20):Python基本数据类型

1. Python基本数据类型 Python 中基本的数据类型主要有整型&#xff08;int&#xff09;、浮点型&#xff08;float&#xff09;、布尔型&#xff08;bool&#xff09;、 字符串&#xff08;str&#xff09;。 1.1 整型-int 对于整数类型来说&#xff0c;Python 的特殊之处在…

通过navcat的ssh连接 将一个服务器当作跳板连接远程mysql

文章目录 通过ssh连接一个服务器当作跳板连接远程mysql 通过ssh连接一个服务器当作跳板连接远程mysql 简单来说 一共三台机器 windows Linux&#xff08;入口&#xff09; Linux&#xff08;mysql&#xff09; windows 可以通过ssh 私钥连接Linux&#xff08;入口&#xff09;…

数据分析基础之《numpy(4)—ndarry运算》

一、逻辑运算 当我们要操作符合某一条件的数据时&#xff0c;需要用到逻辑运算 1、运算符 满足条件返回true&#xff0c;不满足条件返回false # 重新生成8只股票10个交易日的涨跌幅数据 stock_change np.random.normal(loc0, scale1, size(8, 10))# 获取前5行前5列的数据 s…

小程序隐私保护指引组件wx.getPrivacySetting

问题&#xff1a;项目里使用了获取微信昵称的input标签&#xff0c;发现上线后获取不到微信昵称 解决方案去更新隐私保护协议 然后重新进入小程序就会弹出弹框 2.自己自定义一个隐私保护提示&#xff0c;以下是我的组件 在component里面创建privacyPopup文件夹 privacyPopup.…

裸色打底裤:“光腿神器”怎么就成了“美丽刑具”?

近日&#xff0c;裸色打底裤因其隐形又保暖、拍照显得像真的光腿一般的效果&#xff0c;一直有着“光腿神器”的美誉&#xff0c;在冬天销量十分可观。然而&#xff0c;最近关于“光腿神器的危害有多大”的话题登上热搜&#xff0c;引发了广泛关注。 裸色打底裤作为一种时尚单…

Ubuntu 常用命令之 chown 命令用法介绍

&#x1f4d1;Linux/Ubuntu 常用命令归类整理 chown 命令在 Ubuntu 系统中用于改变文件或目录的所有者和组。这个命令的基本格式是 chown [选项]... [所有者][:[组]] 文件...。 chown 命令的主要参数有 -c 或 --changes&#xff1a;类似 verbose&#xff0c;但只在发生改变时…

【快速解决】python数据可视化时候无法显示中文字符的问题/图表中无法显示中文字符

目录 问题展示 解决方法 运行效果展示 问题展示 解决方法 加入以下代码即可 import matplotlib.pyplot as pltplt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False运行效果展示 成功运行出来 &#x1f30c;点击下方个人名片&#xff0c;交流会…

如何使用 Helm 在 K8s 上集成 Prometheus 和 Grafana|Part 1

本系列将分成三个部分&#xff0c;您将学习如何使用 Helm 在 Kubernetes 上集成 Prometheus 和 Grafana&#xff0c;以及如何在 Grafana 上创建一个简单的控制面板。Prometheus 和 Grafana 是 Kubernetes 最受欢迎的两种开源监控工具。学习如何使用 Helm 集成这两个工具&#x…

15张超级有用的电商模版

电商即电子商务(Electronic Commerce) &#xff0c;是利用计算机技术、网络技术和远程通信技术&#xff0c;实现电子化、数字化和网络化的整个商务过程。本专题包含电商运营策略、电商平台底层逻辑、营销流程设计等模板内容。 如果你是一个电商小白&#xff0c;你需要以下的电…

爬虫实战案例 -- 爬取豆瓣读书网页内容

进入网站检查信息 , 确定请求方式以及相关数据 找到爬取目标位置 开始敲代码 # 链接网站 def url_link(url):res requests.get(url,headers headers)response res.textparse_data(response)# 爬取信息 def parse_data(data):msg <li\sclass"media\sclearfix…

【沁恒蓝牙mesh】CH58x DataFlash 详解

本文主要介绍了 沁恒蓝牙芯片 CH58x 的 DataFlash 分区以及读写操作以及原理 &#x1f4cb; 个人简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是喜欢记录零碎知识点的小菜鸟。&#x1f60e;&#x1f4dd; 个人主页&#xff1a;欢迎访问我的 Ethernet_Comm 博…

恶意软件样本行为分析——Process Monitor和Wireshark

1.1 实验名称 恶意软件样本行为分析 1.2 实验目的 1) 熟悉 Process Monitor 的使用 2) 熟悉抓包工具 Wireshark 的使用 3) VMware 的熟悉和使用 4) 灰鸽子木马的行为分析 1.3 实验步骤及内容 第一阶段&#xff1a;熟悉 Process Monitor 的使用 利用 Process …

ElasticSearch 数据分片

一、ElasticSearch 分片 ElasticSearch集群中有许多个节点(Node)&#xff0c;每一个节点实例就是一个实例&#xff1b;数据分布在分片之间。集群的容量和性能主要取决于分片如何在节点上如何分配。将数据分片是为了提高可处理的容量和易于进行水平扩展&#xff0c;为分片做副本…

Centos安装Docker及使用

文章目录 配置要求Centos安装Docker卸载docker&#xff08;可选&#xff09;安装docker首先需要大家虚拟机联网&#xff0c;安装yum工具然后更新本地镜像源&#xff1a;然后输入安装docker命令&#xff1a;查看docker的版本 启动docker关闭防火墙接着通过命令启动docker 配置镜…

Maven将Jar包打入本地仓库

Maven将Jar包打入本地仓库 Maven将Jar包打入本地仓库嘚吧嘚下载Maven配置Maven新建MAVEN_HOME编辑Path验证Maven配置 Jar包打入Maven仓库 Maven将Jar包打入本地仓库 嘚吧嘚 最近项目用到一个Jar包&#xff0c;不能从远程仓库拉取&#xff0c;只有一个Jar包&#xff0c;所以需…

java设计模式学习之【命令模式】

文章目录 引言命令模式简介定义与用途实现方式 使用场景优势与劣势在Spring框架中的应用股票示例代码地址 引言 想象一下&#xff0c;你在一个忙碌的厨房里&#xff0c;厨师们正忙于准备各种菜肴。每当服务员带来一个新订单时&#xff0c;他们不会直接对厨师说需要做什么菜。相…