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删掉
在这里插入图片描述
删掉这行代码之后串口接收到的数据就正常了

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

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

相关文章

Mybatis之增删改查

目录 一、引言 二、Mybatis——增 举例&#xff1a;添加用户 三、Mybatis——删 举例&#xff1a;删除用户 四、Mybatis——改 举例&#xff1a;修改用户 五、Mybatis——查 六、注意 END&#xff1a; 一、引言 书接上回&#xff0c;我们在了解完mybatis之后&#xff0c;肯…

ubuntu20 安装缺失的字体

在/usr/share/fonts创建文件夹winfonts sudo mkdir winfonts 下载缺失的字体后&#xff0c;复制命令到对应的文件夹。 刷新字体库 sudo mkfontscale sudo mkfontdir sudo fc-cache

技术分享 | 一文带你了解测试流程的体系

软件测试是软件质量保证的关键步骤。越早发现软件中存在的问题&#xff0c;修复问题的成本就越低&#xff0c;软件质量也就越高&#xff0c;软件发布后的维护费用越低。 为了能更好的保障软件质量&#xff0c;在软件测试的实践中&#xff0c;慢慢形成了一些流程用来达到这一目…

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

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

ceph块存储学习

目录 ceph的组件和功能 ceph的数据读写流程 ceph存储池学习 ceph的组件和功能 Ceph OSD&#xff1a;功能是存储数据&#xff0c;处理数据的复制、恢复、平衡数据分布&#xff0c;并将一些相关数据提供给Ceph Monitor,。 Ceph Monitor: 功能是维护整个集群健康状态&…

C语言之初识C语言

文章目录 前言一、什么是C语言二、第一个C语言程序三、数据类型四、变量&#xff0c;常量1、变量1.1 变量的命名1.2 变量的分类1.3 变量的使用1.4 变量的作用域和生命周期2、变量 五、字符串1. 概念2. 求解字符串的长度【strlen】3. 转义字符【含笔试题】 六、注释七、选择语句…

20 Vue3中使用v-for遍历普通数组

概述 使用v-for遍历普通数组在真实开发中还是比较常见的。 基本用法 我们创建src/components/Demo20.vue&#xff0c;代码如下&#xff1a; <script setup> const tags ["JavaScript", "Vue3", "前端"] </script> <template…

网络安全-API接口安全

本文为作者学习文章&#xff0c;按作者习惯写成&#xff0c;如有错误或需要追加内容请留言&#xff08;不喜勿喷&#xff09; 本文为追加文章&#xff0c;后期慢慢追加 API接口概念 API接口&#xff08;Application Programming Interface&#xff0c;应用程序编程接口&…

亚马逊撸货、撸卡怎么做成功率更高?教你解决亚马逊撸货的底层环境

在当前的跨境电商环境下&#xff0c;许多人都在从事亚马逊的撸货、撸卡业务&#xff0c;但亚马逊的风控系统非常严格&#xff0c;因此很容易被封号或订单被取消。为了提高成功率&#xff0c;我们需要采取一些措施和方法。这篇文章就来分享做亚马逊撸货、撸卡如何提高成功率&…

Leetcode—剑指Offer LCR 025.两数相加II【中等】

2023每日刷题&#xff08;六十七&#xff09; Leetcode—LCR 025.两数相加II 实现代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode…

Centos安装Docker及使用

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

抖店怎么运营?走通流程是关键!

我是电商珠珠 很多新手在入驻抖店的时候&#xff0c;都不知道前期怎么去运营。 运营的技巧很多&#xff0c;牵扯到很多细节&#xff0c;跑通流程是关键。 所以&#xff0c;今天就来给大家讲讲抖店的几个基本流程&#xff0c;只有将流程跑通了才能去更快的抠细节上的东西。 …