C#电源串口调试

目的
记录串口调试的遇到的一些问题以及相应的解决方法
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删掉
在这里插入图片描述
删掉这行代码之后串口接收到的数据就正常了

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Prometheus-JVM

一. JVM监控 通过 jmx_exporter 启动端口来实现JVM的监控 Github Kubernetes Deployment Java 服务&#xff0c;修改 wget https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.19.0/jmx_prometheus_javaagent-0.19.0.jar# 编写配置文件&#xff0…

JAVA判断两个时间之间的差

1.首先引入jar包 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.3.7</version> </dependency>2.计算差值 public static DateFormat getDateTimeFormat(){DateFormat dtf new Sim…

即将来临的2024年,汽车战场再起波澜?

我们来简要概况一下11月主流车企的销量表现&#xff1a; 根据数据显示&#xff0c;11月吉利集团总销量29.32万辆&#xff0c;同比增长28%。这在当月国内主流车企中综合实力凌厉&#xff0c;可谓表现得体。而与吉利直接竞争的比亚迪&#xff0c;尽管数据未公布&#xff0c;但我们…

华为二层交换机与防火墙配置实例

二层交换机与防火墙对接上网配置示例 组网图形 图1 二层交换机与防火墙对接上网组网图 二层交换机简介配置注意事项组网需求配置思路操作步骤配置文件相关信息 二层交换机简介 二层交换机指的是仅能够进行二层转发&#xff0c;不能进行三层转发的交换机。也就是说仅支持二层…

Flink系列之:Savepoints

Flink系列之&#xff1a;Savepoints 一、Savepoints二、分配算子ID三、Savepoint 状态四、算子五、触发Savepoint六、Savepoint 格式七、触发 Savepoint八、使用 YARN 触发 Savepoint九、使用 Savepoint 停止作业十、从 Savepoint 恢复十一、跳过无法映射的状态恢复十二、Resto…

22 3GPP在SHF频段基于中继的5G高速列车场景中的标准化

文章目录 信道模型实验μ参考信号初始接入方法波形比较 RRH&#xff1a;remote radio head 远程无线头 HTS&#xff1a;high speed train 高速移动列车 信道模型 考虑搭配RRH和车载中继站之间的LOS路径以及各种环境&#xff08;开放或峡谷&#xff09;&#xff0c;在本次实验场…

Postgresql源码(118)elog/ereport报错跳转功能分析

1 日志接口 elog.c完成PG中日志的生产、记录工作&#xff0c;对外常用接口如下&#xff1a; 1.1 最常用的ereport和elog ereport(ERROR,(errcode(ERRCODE_UNDEFINED_TABLE),errmsg("relation \"%s\" does not exist",relation->relname)));elog(ERRO…

如何粗暴地下载huggingface_hub指定数据文件

参考这里&#xff1a; https://huggingface.co/docs/huggingface_hub/guides/download 可见下载单个文件&#xff0c;下载整个仓库文件都是可行的。 这是使用snapshot_download下载的一个例子&#xff1a; https://qq742971636.blog.csdn.net/article/details/135150482 sn…

轻松管理TXT文本,高效批量内容调整,打造高效工作流程!

在数字时代&#xff0c;文本文件已经成为我们生活和工作中不可或缺的一部分。无论是简单的笔记、待办事项&#xff0c;还是复杂的项目报告、小说草稿&#xff0c;TXT文本都能为我们提供灵活的存储和编辑方式。但是&#xff0c;随着文本文件的增多&#xff0c;如何轻松管理、高效…

Java 并发编程中的线程池

7 并发编程中的线程池 自定义线程池 package com.rainsun.d7_thread_pool;import lombok.extern.slf4j.Slf4j;import java.util.ArrayDeque; import java.util.Deque; import java.util.HashSet; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Co…

vue3引入使用高德地图,不显示地图问题

将全局引入的mockjs去除&#xff0c;就可以了。

基于ChatGLM搭建专业领域问答机器人的思路

如果我们对ChatGLM进一步提出涉及专业领域的问题&#xff0c;而此方面知识是ChatGLM未经数据训练的&#xff0c;那么ChatGLM的回答效果如何呢&#xff1f;本节将考察ChatGLM在专业领域的问答水平&#xff0c;并尝试解决此方面的问题。 在使用ChatGLM制作专业领域问答机器人之前…

如何利用烛龙和谷歌插件优化CLS(累积布局偏移) | 京东云技术团队

简介 CLS 衡量的是页面的整个生命周期内发生的每次意外布局偏移的最大突发性_布局偏移分数_。布局变化的发生是因为浏览器倾向于异步加载页面元素。更重要的是&#xff0c;您的页面上可能存在一些初始尺寸未知的媒体元素。这种组合意味着浏览器在加载完成之前无法确定单个元素…

anconda常用命令

一、基础指令说明 1、查看anconda版本号 conda --version 2、查看当前已有虚拟环境 conda env list 3、创建新环境 conda create -n classify python3.9 创建一个叫做classify的虚拟环境&#xff0c;其中python等于3.9 4、进入虚拟环境 activate classify 5、安装包 接下来…

【Skynet 入门实战练习】事件模块 | 批处理模块 | GM 指令 | 模糊搜索

文章目录 前言事件模块批处理模块GM 指令模块模糊搜索最后 前言 本节完善了项目&#xff0c;实现了事件、批处理、模糊搜索模块、GM 指令模块。 事件模块 什么是事件模块&#xff1f;事件模块是用来在各系统之间传递事件消息的。 为什么需要事件模块&#xff1f;主要目的是…

由浅入深走进Python异步编程【多进程】(含代码实例讲解 || multiprocessing、异步进程池、进程通信)

写在前面 从底层到第三方库&#xff0c;全面讲解python的异步编程。这节讲述的是python的多线程实现&#xff0c;纯干货&#xff0c;无概念&#xff0c;代码实例讲解。 本系列有6章左右&#xff0c;点击头像或者专栏查看更多内容&#xff0c;陆续更新&#xff0c;欢迎关注。 …

群多多社群人脉H5-2.1.4多开插件+小程序独立前端+搭建教程

功能介绍&#xff1a; 1、群多多社群大全&#xff0c;是一个集发布、展示社群信息、人脉推广的裂变工具/平台。 2、通过人脉广场&#xff0c;将商家信息通过名片进行展示&#xff0c;让资源对接、人脉推广更加便捷高效。 3、行业群、兴趣群、知识付费群、交友群、商家活动推…

DMA实验3-外设到内存搬运

实验要求 使用 DMA 的方式将串口接收缓存寄存器的值搬运到内存中&#xff0c;同时闪烁 LED1 。 CubeMX 配置 DMA 配置&#xff1a; 串口中断配置 代码实现 如何判断串口接收是否完成&#xff1f;如何知道串口收到数据的长度&#xff1f; 使用串口空闲中断&#xff08;IDL…

十一、W5100S/W5500+RP2040之MicroPython开发<MQTT阿里云示例>

文章目录 1. 前言2. 平台操作流程3. WIZnet以太网芯片4. 示例讲解以及使用4.1 程序流程图4.2 测试准备4.3 连接方式4.4 相关代码4.5 烧录验证 5. 注意事项6. 相关链接 1. 前言 在这个智能硬件和物联网时代&#xff0c;MicroPython和树莓派PICO正以其独特的优势引领着嵌入式开发…

谷歌 | Duet AI 让洞察、聚类模型和可视化变得简单

迷失在数据的海洋 我们都经历过这样的情况&#xff1a;淹没在数据的海洋中&#xff0c;努力驾驭复杂的管道&#xff0c;感觉数据令人头晕。管理大量充满不同工具和 Google 搜索的选项卡以及花费大量时间筛选数据和代码以创建满足您需求的模型所带来的挫败感&#xff0c;真的会…