精华内容
下载资源
问答
  • 在调试FreeRTOS系统时,在串口中断中用队列存储数据,然后再定时器中断中用队列接收数据,并通过串口打印出来。在调试代码中编译器报错。 在网上搜索之后,找到了一个解决方法。在usart.c文件中添加以下代码,...

    在调试FreeRTOS系统时,在串口中断中用队列存储数据,然后再定时器中断中用队列接收数据,并通过串口打印出来。在调试代码中编译器报错。
    …\OBJ\LED.axf: Error: L6915E: Library reports error: __use_no_semihosting was requested, but _ttywrch was referenced
    在这里插入图片描述
    在网上搜索之后,找到了一个解决方法。在usart.c文件中添加以下代码,可以解决这个问题。

    //__use_no_semihosting was requested, but _ttywrch was
    _ttywrch(int ch)
    {
        ch = ch;
    }
    

    在这里插入图片描述
    然后通过对比正点原子的代码,发现了另一个解决方法。在usart.c文件中直接屏蔽

    #pragma import(__use_no_semihosting)
    

    这行代码,也可以解决这个问题。
    在这里插入图片描述

    展开全文
  • 基于Unity串口通信解决方案

    万次阅读 多人点赞 2016-11-07 22:24:16
    一、简介1、几个月前我发布过一篇关于Unity的串口通信问题,只是阐述了问题,但是没有什么好的解决方案。经过我几个对串口相关的Unity项目开发,也发现了几种解决方案。开发中遇到的一些问题都详细的描述出来。 2、...

    一、简介

    1、几个月前我发布过一篇关于Unity的串口通信问题,只是阐述了问题,但是没有什么好的解决方案。经过我几个对串口相关的Unity项目开发,也发现了几种解决方案。开发中遇到的一些问题都详细的描述出来。
    2、在上一篇文章我曾提过Unity因为采用的是Mono .NET 2.0。这个版本对COM支持不是很好,所以导致Unity在串口通信方面有些问题。不过最近发布了Mono .NET4.6版本的Unity 5.5测试版,该问题可能会解决掉,不过可能需要等到2017年了。
    3、言归正传,我们首先要知道C#接收串口的主要几种方式:接收字节byte,接收字节数据byte[],接收字符串string。在Unity中往串口中发送数据是为没有问题的,主要是接收数据会存在问题,下面图片我总结了一下,这结果是我经过不下于100次测试而来的,可能每个人的测试结果都不一样或我的测试还有一些局限,如果看到此文章的朋友也有不同的结果,可以加我QQ或者发我邮件(1158078383@qq.com)共同探讨。本人在此感谢。
    这里写图片描述
    还有其他的串口读取方法,但是我就没有测试了,因为我实际项目中就需要这几种,所以其他的我就不好意思说。

    二、Unity与Winform(WPF)串口通信的几种解决方案

    我开发过三个项目采用收发字符串(Unity接收字符串,发送字符串)、收发单个字节(Unity接收单字节,发送字节数组)、收发字节数组。三个项目都是Unity通过串口与Winform程序(或WPF程序)进行串口通信。

    • 项目一
      1、该项目有两种串口接收方式,一种是收发字符串(Unity接收字符串,发送字符串),另一个是收单个字节,然后对每个字节进行组装解析,在发送字节数组。
      2、经过项目的开发和测试,我发现收发字符串是没有问题的,但是在我自己写的测试程序中却出现异常,出现数据错误,数据丢失以及接收不到数据等随机性错误第一篇关于串口文章)。不过经过我发现实际项目中的串口收发格式是有标记位和校验位,但是当我自己写程序去测试时,却发现了异常。针对这个问题我到时候后期会在进行仔细研究下,因为我现在也没找到合适的理由去说服自己以及读者,所以我不会去做详细的介绍只是提醒读者,后期如果解决了我会在博客上写出来。

    • 项目二
      1、该项目是接收字符串数组和发送字符串数组,在实际开发项目中却出现了Unity接收数据错误的问题,针对该问题加上项目时间紧急,不可在此问题耗费我太大心力,所以无意中想到用中间件程序来做Unity与winform程序通信的一个桥梁。
      2、我写一个中间件程序,让Winform程序与我的中间件程序进行串口通信,中间件程序与Unity程序Socket通信
      3、首先启动我的中间件程序,然后中间件程序启动我的Unity程序。中间件程序隐藏起来并与Unity程序互相监听,当Unity程序关闭时,中间件程序也关闭。这样从表面上看起来就只是Unity一个程序在工作,实际上中间还有一个中间件程序在做幕后工作。从而巧妙的完成了所谓的Unity与Winform程序之间的串口通信。但是这终究不是一个很好的解决方案。

    • 项目三
      1、这个项目三就是我们的重头戏了,这也是我最新研究的一种解决方案,而且经过测试和实际项目开发,也是没什么很大问题的,不过有个项目会有一些小问题,但是被我很简单的解决掉了。后面我都会详细的讲解这个解决方案,如果有朋友与我阐述的不符,那么可以参考项目二的解决方案给您一点小思路。
      2、该项目采用的是什么呢,首先Winform程序往Unity中发送字节数组,从Unity中读取字节数组数据。按照正常的逻辑上我们的Unity也应该从串口中读取字节数组和发送字节数组。但是在这一块出现了问题,上面图片我阐述过,Unity从串口接收字节数组时会出现需要两次才能接收完,第一次接收一个字节第二次接收剩下的。数据倒不会出现异常,但是这对我们的数据处理显然是不好的。针对此问题,我下面一大章节来结合实际项目来解释。

    三、Unity解析串口数据,得到完整数据

    结合我实际项目,来讲解!以项目三方式为例。
    在项目三中说过,Unity中接收单个字节,并且进行组装,在解析。
    1、定义存储串口数据变量

    [NonSerialized]
    private List<byte> listReceive = new List<byte>();
    //定义一个泛型,暂时存储接收到的串口数据。这个泛型的特性不用理会。

    2、打开串口

     public bool OpenPort(string portName)
     {
        if (this.port != null && this.port.IsOpen == false)
        {
            try
            {
                this.port = new SerialPort("\\\\?\\" + portName, 9600);
                this.port.ReadTimeout = 500;
                this.port.WriteTimeout = 500;
                this.port.Open();
    
                this.tPort = new Thread(new ThreadStart(PortReceive));
                this.tPort.IsBackground = true;
                this.tPort.Start();
                return true;
            }
            catch (Exception err)
            {
                throw err;
            }
        }
        else
        {
            throw new System.Exception("串口已经打开");
        }
    }
     /*
     代码解释:
     1)在串口号前加"\\\\?\\"是因为我的串口号大于10了,这是因为我采用的是虚拟串口号,为什么要加这个是因为.NET2.0的原因,详细的可看(http://blog.csdn.net/iothua/article/details/51657106)。
     2)代码中有个线程,线程有个方法PortReceive()该方法是读取串口数据的
     */

    3、打印串口数据
    这个打印串口数据是一个方法,就是在Unity中打印接收到的串口数据,怕读者看代码是有点不懂这方法是干嘛的,所以我贴出来。

    void PrintData()
    {
        string str = string.Empty;
        for(int i = 0; i < listReceive.Count; i++) {
            str += listReceive[i].ToString("X2");
        }
        UnityEngine.Debug.Log("协调器打印:" + str+"  字节长度:"+listReceive.Count);
    }

    4、读取串口数据

     private void PortReceive()
    {
        while (this.port!=null && this.port.IsOpen)
        {
            Thread.Sleep(1);
    
            try {
                byte addr = Convert.ToByte(port.ReadByte());
                this.port.DiscardInBuffer();
                listReceive.Add(addr);
    
                PrintData();
                if(this.PropertyChanged_Coordinator != null) {
                    this.PropertyChanged_Coordinator.Invoke(this, new PropertyChangedEventArgs("Receive"));
                    Thread.Sleep(10);
                    this.PropertyChanged_Coordinator.Invoke(this, new PropertyChangedEventArgs("Send"));
                }
                //MessageAddReceive(addr.ToString("X2"));
                if(EventPortRead != null) {
                    EventPortRead(new byte[] { addr });
                }
            }
            catch {
                //listReceive.Clear();
                }
        }
    }
     /*
     解析:
     1)byte addr = Convert.ToByte(port.ReadByte());从串口中接收单个字节,然后转化为byte类型的,默认是int类型的。
     2)this.port.DiscardInBuffer();清除串口缓存数据,不过暂时我没发现这个方法有什么很明显的用户。不过先写着吧。
     3)listReceive.Add(addr);添加到泛型中
     4)PrintData();打印接收到的数据
     5)在这里catch下面的代码最好为空,因为我们是用线程来接收串口数据,当unity没有接收到数据时,就会报异常,所以我们需要在catch下不要写代码,本来是有个属性可以用的,不过在Unity中存在问题,详细的可看我第一篇文章。
     6)其他的就不用理会了,那是我后期的一些处理,跟我们所讲没关系,之所以全部展示出来也是在实际项目中的一些处理。
     */

    从winform程序中发送数据过去
    这里写图片描述
    Unity接收到的数据情况,发送数据经过我们组合后是没有问题的。
    这里写图片描述
    但是当我Unity中发送给上位机数据时,突然unity串口中接收到一个00数据,该测试不是从我写的测试程序测试的,而是从实际项目中测试的,但是我在自己写的测试程序中又没有这个问题。针对此结果加上一些数据规律,我后期自己进行了改动(后面会详细介绍)。
    经过解析数据,然后返回给Winform数据,返回后突然又接到异常数据。
    Unity发送数据给Winform
    Winform接收到的数据
    Winform接收到的数据
    5、解析串口数据

    private void ParseReceive()
    {
        while (true)
        {
            Thread.Sleep(1);
    
             if(listReceive.Count > 0) {
                if(listReceive.Count >= 9) {
    
                    if(listReceive[0] == 0xA5 && listReceive[8] == 0x5A) {
                        //UnityEngine.Debug.Log("****************************");
                        //UnityEngine.Debug.Log("解析接收前******************");
                        //PrintData();//打印当前接收到的数据
                        string temp = string.Empty;
                        for(int i = 0; i < 9; i++) {
                            temp += listReceive[i].ToString("X2");
                        }
                        listReceive.RemoveRange(0, 9);
    
                        //UnityEngine.Debug.Log("解析接收后******************");
                        //PrintData();
                        //UnityEngine.Debug.Log("****************************");
    
                        try {
                            foreach(Sensor.SensorBase sensor in this.ListSensor) {
                            ParameterizedThreadStart pts = new ParameterizedThreadStart(SensorSetData);
                            Thread tSetData = new Thread(pts);
                            object o = new object[] { sensor, temp };
                            tSetData.Start(o);
                            }
                        }
                        catch {
                            listReceive.Clear();
                        }
    
                    }
                    else if(listReceive[0] == 0x00 && listReceive[8] == 0x5A) {
                        listReceive[0] = 0xA5;
                    }
                    else {
                        int count = 0;
                        for(int i = 0; i < listReceive.Count; i++) {
                            //截取到泛型中的第一个5A就好,直接停止循环
                            if(listReceive[i] == 0xA5) {
                                count = i;
                                break;
                            }
                        }
                        listReceive.RemoveRange(0, count);
                    }
    
                }
            }
        }
    }
     /*
     解析:
     1)这是我对首尾标记的检测,从而截取到我想要的数据,这个解析一般是应自身项目需求。
     //if(listReceive[0] == 0xA5 && listReceive[8] == 0x5A)
     2)截取到我想要的数据,从而转化为字符串。并且从泛型中将这些数据移除掉。
     string temp = string.Empty;for(int i = 0; i < 9; i++) {
        temp += listReceive[i].ToString("X2");
        }
        listReceive.RemoveRange(0, 9);
    
    3)然后解析我得到的数据,从而通过串口发送给Winform,这里应自身项目需求,所以可不理会。
    try {
        foreach(Sensor.SensorBase sensor in this.ListSensor) {
        ParameterizedThreadStart pts = new ParameterizedThreadStart(SensorSetData);
        Thread tSetData = new Thread(pts);
        object o = new object[] { sensor, temp };
        tSetData.Start(o);
        }
    }
    catch {
        listReceive.Clear();
    }
    4)之所以做这个处理原因是当我给Winform程序发送数据时,突然会接收到异常数据0x00,但是我的Winform没有回数据,所以这数据怎么来的我也不清楚,后期我会在研究下是我的代码问题还是其他原因,不过这是我的一个处理,所以也不需要理会。
    else if(listReceive[0] == 0x00 && listReceive[8] == 0x5A) {
        listReceive[0] = 0xA5;
    }
    5)、当数据异常时,把异常数据处理掉,保证数据的正常。
    else {
        int count = 0;
        for(int i = 0; i < listReceive.Count; i++) {
            //截取到泛型中的第一个5A就好,直接停止循环
            if(listReceive[i] == 0xA5) {
                count = i;
                break;
            }
        }
        listReceive.RemoveRange(0, count);
    }
    6)从3),4),5)开始都是我对接收到的串口数据一些处理,从而来保证接收数据正常,这也是实际项目中需要干的事情,可能在测试中不需要。
    */

    6、总结
    1、上述可能会让一些读者觉得有比较多的漏洞,我后续如果发现更好的解决方案和问题,也会陆续更新。一方面是记录下曾经问题方便以后,另一方面也是让Unity开发串口这边的开发者一个思路和想法吧。因为我深感此处的坑。
    2、如果有读者看到了,有一些好的解决方案、帮助等都可以联系我,我们共同探讨。我平时不看自己的博客,所以有需要详细的我可以发邮件给我(1158078383@qq.com)。

    展开全文
  • 我用的是串口通信来控制,比如有缺陷,向arduino发送一个字符,arduino收到后判断一下就好,然后给引脚高电平,灯就亮了。 很简单的原理,但我这个小白就在一环上卡住了,就是,理论上程序什么的逻辑都,没有问题...

    最近在学labview,其实去年就有接触,做了一个arduino做下位机,labview做上位机带温湿度传感器的小东西,功能很简单,labview上位机编程很容易,在VI package manager 上下载labview interface for arduino,强烈推荐使用labview2013,我用的就是,各种工具包很全,在官网上都能找到。这个LIFA(labview interface for arduino)里面已经有了读取传感器数据的函数了,在网上搜一下arduino labview简易温度计就行,分别写好上位机也就是labview程序,和arduino程序,串口什么的配置好,就能正常工作了,是一个新手上手非常快,很有成就感的小项目。

    我的重点不在这里,最近做的是一个图像处理和识别的labview程序,想要加一些硬件部分的东西,因此就想到了闲置多年的arduino,我用的是arduino uno 淘宝上小100买的整盒套件,里面的配件和资料都很全,推荐买这样的,方便了不止一丢丢。我要实现的功能很简单,就是有缺陷的时候就亮红灯,没有的就亮绿灯。首先,上位机程序写好,就是判断图像缺陷的部分,结果是一个布尔量。原理很简单,就是通过判断这个布尔量来控制灯亮。我用的是串口通信来控制,比如有缺陷,向arduino发送一个字符,arduino收到后判断一下就好,然后给引脚高电平,灯就亮了。

    很简单的原理,但我这个小白就在一环上卡住了,就是,理论上程序什么的逻辑都,没有问题,但灯就是不亮,搞得我心烦了一天。我有一本参考书感觉特别好,叫《arduino与labview开发实战》,里面有类似这个的一个例程,我把例程做了一遍,完全没有问题。但是回到我这个程序,没有像书上那么复杂的结构,又是case structure又是do-while循环的,就是不能让灯亮。怎么办,调试!!!

    首先,要确保labview真的按照你的约定,发了相应的字符,怎么办?用虚拟串口。我用的创建虚拟串口的软件是configure virtual serial port driver,一创建创建的是一对串口,比如COM1和COM2,这有什么用的,你往串口1发的,串口2能接收到,反之亦然,为什么要这样调试,因为串口是独占设备,你不可能用labview使用一个串口发数据的同时,另一个程序监视串口发了什么。

    所以,我的调试就是往COM1发数据,用串口调试助手查看COM2数据。注意使用串口助手注意选择是ASCII还是hex。

    这没问题之后,我又用arduino的串口调试助手向arduino发数据,发现灯也能正常亮,但是labview和arduino联调,就!是!不!亮!!!!!!

    偶然间,我发现,labview高亮调试的时候,灯可以亮,我以为是因为在灯亮的那个延时,arduino给的延时太短,或者labview延时太短,导致一闪而灭,后来发现,不是这样的。然后,我就上网查,程序高亮正常执行但是普通执行不对,给出的回答是时间的问题。

    后来就是各种尝试了。最后的最后,是因为labview编程,在串口初始化后要加一段时间的延时在发送字符!!切记啊亲们,我试出来的是,至少1600ms才可以,大家也可以自己试试。


    总结:串口初始化后要延时一段时间

                会用局部变量

               复习了子VI的编写和使用

               程序高亮能行 正常执行却不行的解决方法

               ASCII和hex区别,没选好可能会啥都不显示,比如接到0x01要是ASCII模式就啥都不会显示,因为不对应字符

               最后就是,遇到问题不要方啊,方了就不美了


    附上终于调通的程序,很简单,但是作为一只笨鸟,有点挑战性




    展开全文
  • USB转串口驱动下载 win7 64位旗舰版安装pl2303 USB转串口安装成功,但使用时出现“运行时错误8020 读comm设备错误” 程序闪退 解决办法 下载安装USB转串口驱动
  • 为什么C#串口程序在关闭串口时候会死锁_老文章_赛迪网 http://www.ccidnet.com/2010/0524/2067861.shtml 【赛迪网讯】用过微软SerialPort...我想只有一半的人真的解决了。另外一半的人就睁只眼闭只眼阿弥佗佛

    为什么C#串口程序在关闭串口时候会死锁_老文章_赛迪网 http://www.ccidnet.com/2010/0524/2067861.shtml


    【赛迪网讯】用过微软SerialPort类的人,都遇到过这个尴尬,关闭串口的时候会让软件死锁。天哪,我可不是武断,算了。不要太绝对了。99.9%的人吧,都遇到过这个问题。我想只有一半的人真的解决了。另外一半的人就睁只眼闭只眼阿弥佗佛希望不要在客户那里出现这问题了。

    view plaincopy to clipboardprint?
    void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)      
    {      
        //先记录下来,避免某种原因,人为的原因,
        操作几次之间时间长,缓存不一致   
        int n = comm.BytesToRead;   
        //声明一个临时数组存储当前来的串口数据   
        byte[] buf = new byte[n];      
        //增加接收计数   
        received_count += n;    
        //读取缓冲数据     
        comm.Read(buf, 0, n);      
        //清除字符串构造器的内容   
        builder.Clear();      
        //因为要访问ui资源,所以需要使用invoke方式同步ui。      
        this.Invoke((EventHandler)(delegate{...界面更新,略}));      
    }           
    private void buttonOpenClose_Click(object sender, EventArgs e)      
    {      
        //根据当前串口对象,来判断操作      
        if (comm.IsOpen)      
        {      
            //打开时点击,则关闭串口      
            comm.Close();//这里就是可能导致软件死掉的地方   
        }      
        else     
        {...}     
    }  
    void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)   
    {   
        //先记录下来,避免某种原因,人为的原因,
       操作几次之间时间长,缓存不一致
        int n = comm.BytesToRead;
        //声明一个临时数组存储当前来的串口数据
        byte[] buf = new byte[n];   
        //增加接收计数
        received_count += n; 
        //读取缓冲数据  
        comm.Read(buf, 0, n);   
        //清除字符串构造器的内容
        builder.Clear();   
        //因为要访问ui资源,所以需要使用invoke方式同步ui。   
        this.Invoke((EventHandler)(delegate{...界面更新,略}));   
    }     
    private void buttonOpenClose_Click(object sender, EventArgs e)   
    {   
        //根据当前串口对象,来判断操作   
        if (comm.IsOpen)   
        {   
            //打开时点击,则关闭串口   
            comm.Close();//这里就是可能导致软件死掉的地方
        }   
        else  
        {...}  
    }

    为什么会死锁呢,并发冲突。 我们要了解一下SerialPort的实现和串口通讯机制,在你打开串口的时候,SerialPort会创建一个监听线程ListenThread,在这个线程中,等待注册的串口中断,当收到中断后,会调用DataReceived事件。调用完成后,继续进入循环等待,直到串口被关闭退出线程。 我们的UI主线程如何做的呢,首先创建一个窗体,然后执行了Application.Run(窗体实例)。是这样把,这里的Application.Run就是创建了一个消息循环,循环的处理相关的消息。 这里我们就有了2个线程,UI主线程、串口监听线程。那么你在DataReceived处理数据的时候,就需要线程同步,避免并发冲突,什么是并发冲突?并发冲突就是2个或多个并行(至少看上去像)的线程运行的时候,多个线程共同的操作某一线程的资源,在时序上同时或没有按我们的预计顺序操作,这样就可能导致数据混乱无序或是彼此等待完成死锁软件。 而串口程序大多是后者。为什么呢,看看我们的例子中DataReceived做了什么?首先读取数据,然后就是调用this.Invoke方法更新UI了。这里Invoke的时候,监听线程将等待UI线程的标志,等到后,开始操作UI的资源,当操作完成之前,监听线程也就停在DataReceived方法的调用这里,如果这个时候。并发了关闭串口的操作会如何呢?SerialPort的Close方法,会首先尝试等待和监听线程一样的一个互斥体、临界区、或是事件(不确定.net用的哪种)。那这个同步对象什么时候释放呢?每次循环结束就释放,哦。循环为什么不结束呢?因为这一次的循环操作执行到DataReceived之后,执行了Invoke去更新界面了,那Invoke怎么又没有执行完成呢?看上去很简单的几行代码。虽然我没仔细研读过.net的Invoke原理,但我猜测是通过消息的方式来同步的,这也是为什么这么多的类,只有控件(窗体也是控件的一种,.net在概念上,颠覆了微软自己的概念,传统的win32编程,是说所有的控件都是个window,只是父窗体不同,表现形式不同,但都是基于系统消息队列的,.net出于更高的抽象,正好反过来了。呵呵)才有Invoke方法了。(委托自己的Invoke和这个不同) 我猜测控件/窗体的Invoke是SendMessage方式实现的,那么发送消息后就会等待消息循环来处理消息了。如果你直接去关闭串口了。你点击按钮本身也会被转换成消息WM_CLICK,消息循环在处理按钮的WM_CLICK时候,调用你按钮的OnClick方法,进而触发调用你的ButtonClose_Click事件,这都是同步调用的,你的主线程,处理消息的过程,停在了这个Click事件,而你的Click事件又去调用了SerialPort的Close方法,Close方法又因为和串口监听线程的同步信号量关联在一起需要等待一次的while结束,而这个while循环中调用了DataReceived方法,这个方法中调用了Invoke,也就是发送了消息到消息队列等待结果,但消息循环正在处理你的关闭按钮事件等待退出。 实在太复杂了,这个情况下,你想要真的关闭串口成功,就需要while中的DataReceived方法调用结束释放同步信号,就需要执行完Invoke,就需要执行消息循环,幸运的是,我们真的有办法执行消息循环来打破僵局。Application.DoEvents()。还好,不幸中的万幸。可是问题又来了,你能让Invoke结束,但你无法确定是否在你调用消息循环后,你的某一时刻不会再次并发,可能由于单cpu的串行操作模拟并行中,又把时间片先分给了优先级高的串口监听线程呢?是有可能的。所以,我们就需要一点方法来避免再次invoke窗体。优化后不会司机的例子如下,我们修改DataReceived方法,关闭方法,并定义2个标记Listening和Closing。

    view plaincopy to clipboardprint?
    using System;   
    using System.Collections.Generic;   
    using System.ComponentModel;   
    using System.Data;   
    using System.Drawing;   
    using System.Linq;   
    using System.Text;   
    using System.Windows.Forms;   
    using System.IO.Ports;   
    using System.Text.RegularExpressions;     
    namespace SerialportSample   
    {   
        public partial class SerialportSampleForm : Form   
        {   
            private SerialPort comm = new SerialPort();   
            private StringBuilder builder = new StringBuilder();
           //避免在事件处理方法中反复的创建,定义到外面。   
            private long received_count = 0;//接收计数   
            private long send_count = 0;//发送计数   
            private bool Listening = false;
           //是否没有执行完invoke相关操作   
            private bool Closing = false;
          //是否正在关闭串口,执行Application.DoEvents,
          并阻止再次invoke   
      
            public SerialportSampleForm()   
            {   
                InitializeComponent();   
            }     
            //窗体初始化   
            private void Form1_Load(object sender, EventArgs e)   
            {   
                //初始化下拉串口名称列表框   
                string[] ports = SerialPort.GetPortNames();   
                Array.Sort(ports);   
                comboPortName.Items.AddRange(ports);   
                comboPortName.SelectedIndex = 
                comboPortName.Items.Count > 0 ? 0 : -1;   
                comboBaudrate.SelectedIndex = 
                comboBaudrate.Items.IndexOf("9600");   
      
                //初始化SerialPort对象   
                comm.NewLine = "\r\n";   
                comm.RtsEnable = true;//根据实际情况吧。   
      
                //添加事件注册   
                comm.DataReceived += comm_DataReceived;   
            }   
      
            void comm_DataReceived
           (object sender, SerialDataReceivedEventArgs e)   
            {   
                if (Closing) return;
           //如果正在关闭,忽略操作,直接返回,
          尽快的完成串口监听线程的一次循环   
                try  
                {   
                    Listening = true;
                //设置标记,说明我已经开始处理数据,
                一会儿要使用系统UI的。   
                    int n = comm.BytesToRead;
                //先记录下来,避免某种原因,人为的原因,
                操作几次之间时间长,缓存不一致   
                    byte[] buf = new byte[n];
                 //声明一个临时数组存储当前来的串口数据   
                    received_count += n;//增加接收计数   
                    comm.Read(buf, 0, n);//读取缓冲数据   
                    builder.Clear();//清除字符串构造器的内容   
                    //因为要访问ui资源,所以需要使用invoke方式同步ui。   
                    this.Invoke((EventHandler)(delegate  
                    {   
                        //判断是否是显示为16禁止   
                        if (checkBoxHexView.Checked)   
                        {   
                            //依次的拼接出16进制字符串   
                            foreach (byte b in buf)   
                            {   
                                builder.Append(b.ToString("X2") + " ");   
                            }   
                        }   
                        else  
                        {   
                            //直接按ASCII规则转换成字符串   
                            builder.Append(Encoding.ASCII.GetString(buf));   
                        }   
                        //追加的形式添加到文本框末端,并滚动到最后。   
                        this.txGet.AppendText(builder.ToString());   
                        //修改接收计数   
                        labelGetCount.Text = "Get:" + received_count.ToString();   
                    }));   
                }   
                finally  
                {   
                    Listening = false;//我用完了,ui可以关闭串口了。   
                }   
            }   
      
            private void buttonOpenClose_Click(object sender, EventArgs e)   
            {   
                //根据当前串口对象,来判断操作   
                if (comm.IsOpen)   
                {   
                    Closing = true;   
                    while (Listening) Application.DoEvents();   
                    //打开时点击,则关闭串口   
                    comm.Close();   
                }   
                else  
                {   
                    //关闭时点击,则设置好端口,波特率后打开   
                    comm.PortName = comboPortName.Text;   
                    comm.BaudRate = int.Parse(comboBaudrate.Text);   
                    try  
                    {   
                        comm.Open();   
                    }   
                    catch(Exception ex)   
                    {   
                        //捕获到异常信息,创建一个新的comm对象,
                       之前的不能用了。   
                        comm = new SerialPort();   
                        //现实异常信息给客户。   
                        MessageBox.Show(ex.Message);   
                    }   
                }   
                //设置按钮的状态   
                buttonOpenClose.Text = comm.IsOpen ? "Close" : "Open";   
                buttonSend.Enabled = comm.IsOpen;   
            }   
      
            //动态的修改获取文本框是否支持自动换行。   
            private void checkBoxNewlineGet_CheckedChanged
            (object sender, EventArgs e)   
            {   
                txGet.WordWrap = checkBoxNewlineGet.Checked;   
            }   
      
            private void buttonSend_Click(object sender, EventArgs e)   
            {   
                //定义一个变量,记录发送了几个字节   
                int n = 0;   
                //16进制发送   
                if (checkBoxHexSend.Checked)   
                {   
                    //我们不管规则了。如果写错了一些,我们允许的,
                   只用正则得到有效的十六进制数   
                    MatchCollection mc = Regex.Matches(txSend.Text, @"(?i)[\da-f]{2}");   
                    List<byte> buf = new List<byte>();
                      //填充到这个临时列表中   
                    //依次添加到列表中   
                    foreach (Match m in mc)   
                    {   
                        buf.Add(byte.Parse(m.Value));   
                    }   
                    //转换列表为数组后发送   
                    comm.Write(buf.ToArray(), 0, buf.Count);   
                    //记录发送的字节数   
                    n = buf.Count;   
                }   
                else//ascii编码直接发送   
                {   
                    //包含换行符   
                    if (checkBoxNewlineSend.Checked)   
                    {   
                        comm.WriteLine(txSend.Text);   
                        n = txSend.Text.Length + 2;   
                    }   
                    else//不包含换行符   
                    {   
                        comm.Write(txSend.Text);   
                        n = txSend.Text.Length;   
                    }   
                }   
                send_count += n;//累加发送字节数   
                labelSendCount.Text = "Send:" + send_count.ToString();
               //更新界面   
            }   
      
            private void buttonReset_Click(object sender, EventArgs e)   
            {   
                //复位接受和发送的字节数计数器并更新界面。   
                send_count = received_count = 0;   
                labelGetCount.Text = "Get:0";   
                labelSendCount.Text = "Send:0";   
            }   
        }   
    }
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.IO.Ports;
    using System.Text.RegularExpressions;
    
    namespace SerialportSample
    {
        public partial class SerialportSampleForm : Form
        {
            private SerialPort comm = new SerialPort();
            private StringBuilder builder = new StringBuilder();
            //避免在事件处理方法中反复的创建,定义到外面。
            private long received_count = 0;
           //接收计数
            private long send_count = 0;
            //发送计数
            private bool Listening = false;
             //是否没有执行完invoke相关操作
            private bool Closing = false;
           //是否正在关闭串口,执行Application.DoEvents,
          并阻止再次invoke
    
            public SerialportSampleForm()
            {
                InitializeComponent();
            }
    
            //窗体初始化
            private void Form1_Load(object sender, EventArgs e)
            {
                //初始化下拉串口名称列表框
                string[] ports = SerialPort.GetPortNames();
                Array.Sort(ports);
                comboPortName.Items.AddRange(ports);
                comboPortName.SelectedIndex = 
                comboPortName.Items.Count > 0 ? 0 : -1;
                comboBaudrate.SelectedIndex = 
                comboBaudrate.Items.IndexOf("9600");
    
                //初始化SerialPort对象
                comm.NewLine = "\r\n";
                comm.RtsEnable = true;
               //根据实际情况吧。
    
                //添加事件注册
                comm.DataReceived += 
               comm_DataReceived;
            }
    
            void comm_DataReceived
            (object sender, SerialDataReceivedEventArgs e)
            {
                if (Closing) return;
              //如果正在关闭,忽略操作,直接返回,
               尽快的完成串口监听线程的一次循环
                try
                {
                    Listening = true;
                //设置标记,说明我已经开始处理数据,
                  一会儿要使用系统UI的。
                    int n = comm.BytesToRead;
                 //先记录下来,避免某种原因,人为的原因,
                 操作几次之间时间长,缓存不一致
                    byte[] buf = new byte[n];
                   //声明一个临时数组存储当前来的串口数据
                    received_count += n;
                    //增加接收计数
                    comm.Read(buf, 0, n);
                    //读取缓冲数据
                    builder.Clear();
                     //清除字符串构造器的内容
                    //因为要访问ui资源,所以需要使用invoke方式同步ui。
                    this.Invoke((EventHandler)(delegate
                    {
                        //判断是否是显示为16禁止
                        if (checkBoxHexView.Checked)
                        {
                            //依次的拼接出16进制字符串
                            foreach (byte b in buf)
                            {
                                builder.Append(b.ToString("X2") + " ");
                            }
                        }
                        else
                        {
                            //直接按ASCII规则转换成字符串
                            builder.Append(Encoding.ASCII.GetString(buf));
                        }
                        //追加的形式添加到文本框末端,并滚动到最后。
                        this.txGet.AppendText(builder.ToString());
                        //修改接收计数
                        labelGetCount.Text = "Get:" + received_count.ToString();
                    }));
                }
                finally
                {
                    Listening = false;//我用完了,ui可以关闭串口了。
                }
            }
    
            private void buttonOpenClose_Click(object sender, EventArgs e)
            {
                //根据当前串口对象,来判断操作
                if (comm.IsOpen)
                {
                    Closing = true;
                    while (Listening) Application.DoEvents();
                    //打开时点击,则关闭串口
                    comm.Close();
                }
                else
                {
                    //关闭时点击,则设置好端口,波特率后打开
                    comm.PortName = comboPortName.Text;
                    comm.BaudRate = int.Parse(comboBaudrate.Text);
                    try
                    {
                        comm.Open();
                    }
                    catch(Exception ex)
                    {
                        //捕获到异常信息,创建一个新的comm对象,
                      之前的不能用了。
                        comm = new SerialPort();
                        //现实异常信息给客户。
                        MessageBox.Show(ex.Message);
                    }
                }
                //设置按钮的状态
                buttonOpenClose.Text = comm.IsOpen ? "Close" : "Open";
                buttonSend.Enabled = comm.IsOpen;
            }
    
            //动态的修改获取文本框是否支持自动换行。
            private void checkBoxNewlineGet_CheckedChanged
            (object sender, EventArgs e)
            {
                txGet.WordWrap = checkBoxNewlineGet.Checked;
            }
    
            private void buttonSend_Click(object sender, EventArgs e)
            {
                //定义一个变量,记录发送了几个字节
                int n = 0;
                //16进制发送
                if (checkBoxHexSend.Checked)
                {
                    //我们不管规则了。如果写错了一些,
                   //我们允许的,只用正则得到有效的十六进制数
                    MatchCollection mc = 
                   Regex.Matches(txSend.Text, @"(?i)[\da-f]{2}");
                    List<byte> buf = new List<byte>();//填充到这个临时列表中
                    //依次添加到列表中
                    foreach (Match m in mc)
                    {
                        buf.Add(byte.Parse(m.Value));
                    }
                    //转换列表为数组后发送
                    comm.Write(buf.ToArray(), 0, buf.Count);
                    //记录发送的字节数
                    n = buf.Count;
                }
                else//ascii编码直接发送
                {
                    //包含换行符
                    if (checkBoxNewlineSend.Checked)
                    {
                        comm.WriteLine(txSend.Text);
                        n = txSend.Text.Length + 2;
                    }
                    else//不包含换行符
                    {
                        comm.Write(txSend.Text);
                        n = txSend.Text.Length;
                    }
                }
                send_count += n;
              //累加发送字节数
                labelSendCount.Text = "Send:" + send_count.ToString();
             //更新界面
            }
    
            private void buttonReset_Click(object sender, EventArgs e)
            {
                //复位接受和发送的字节数计数器并更新界面。
                send_count = received_count = 0;
                labelGetCount.Text = "Get:0";
                labelSendCount.Text = "Send:0";
            }
        }
    }

    至此,不会再出现关闭死锁问题了。 希望这篇文章能解你的燃眉之急,非常高兴能与读者分享我层遇到,大多数人都遇到的这个问题。如果说的不明白,欢迎讨论。 后续的有关通讯程序底层设计的文章会讲述一个具有丰富扩展性,但有设计简介的万能通讯库,支持网络、蓝牙、串口通讯、并口通讯。但不要指望我都实现出来了,我只是设计出这个框架。


    展开全文
  • ​ ​解决方式一:将Unity串口通信数据模块(接收与发送),用C++来实现,这是最佳最好的解决方式。(最佳) ​解决方式二:用一个中间介程序去实现,Unity串口通信模块通过Socket发送给中介程序,中介程序在通过...
  • 主要介绍了Qt串口通信开发之QSerialPort模块Qt串口通信接收数据不完整的解决方法,需要的朋友可以参考下
  • 打开串口时出现错误: MATLAB:serial:fopen:opfailed 打开失败: Port: COM1 is not available. No ports are available. Use INSTRFIND to determine if other instrument objects are connected to the requested ...
  • //获取当前计算机的串行端口名称数组 ArrayList comList = new ArrayList(); for (int i = 0; i ; i++) { comList.Add(new DictionaryEntry(portlist[i].Substring(3), portlist[i])); } this.Dep_portName....
  • 这个错误说是串口错误吧,有点牵强,因为那段用来串口通讯的源码肯定是没问题的,但是当和SD卡模块的代码组合在一起就产生莫名其妙的问题, 具体的问题主要是如下症状: 本程序中串口部分主要功能是发送一长串的...
  • 使用软件串口,关闭硬件串口,调试与pc串口助手的串口通信4.通信测试:调用wiringPI库函数编写向pc调试助手循环发送数据"hello world"的程序:5.解决4中报错6.写在最后 1.开篇简单介绍 使用设备情况: Raspberry Pi ...
  • USB转串口驱动下载 win7 64位旗舰版安装pl2303 USB转串口安装成功,但使用时出现“运行时错误8020 读comm设备错误” 程序闪退 解决办法 下载安装USB转串口驱动
  • VB与机械手串口通讯,机械手解析字符串经常出现乱码或不正确字符串,哪位大神知道怎么出理?请告知!
  • 本程序主要解决串口接收数据的过程中出现乱码和数据丢失的情况,特别适合于串口通信的初学者.希望能够对大家有所帮助
  • Unity3D 串口通信解决方案

    千次阅读 2017-04-09 21:10:02
    Unity3D与串口通信,同步读取,持续写入,串口参数通过本地文件配置。
  • 软件方面的同学千辛万苦的做好了MFC串口通讯的可执行文件却在做硬件方面同学的PC上运行不 了,即便是他的vs上安装了MFC单个组件运行起来也会遇到这样报错。 其实这个是由于没有安装mscomm.ocx 组件所造成的,只要...
  • Qt串口通信接收数据不完整的解决方法

    万次阅读 多人点赞 2016-03-17 16:38:17
    在使用串口接收数据时,当数据量大的时候会出现...因此串口通信双方在通信前应制定好通信协议,规定好数据的起始和结束标志,串口当读到完整的起始和结束标志之后,才认定读完一条完整的数据。 本例中用串口定时发...
  • Windows上位机软件,测试下位机,完成一个后断电测试下一个,重新上电时不定时出现设置串口参数错误,GetLastErr码为31(连到系统上的设备没有发挥作用),重启软件也不行,拔USB重新插上就可以,USB是485通信转的,是...
  • 在前几天调试openmv时发现同样的代码串口1和串口3的结果却是不一样的,当时着实是把我坑了很久,怎么都找不到原因,用示波器看波形也是没有问题的,在Openedv网站上有位网友指出是我初始化代码的问题,在翻阅参考...
  • 1.串口通信显示未安装驱动。 解决:在NI-VISA官网上下载NI-VISA驱动,下载及安装教程见前文所述。 2.串口调试助手接收到的全是小正方形框框。但是如果调成以16进制显示就没有问题,而labview上收到的数据全是0. 解决...
  • 我是用MSComm控件来收发数据的 if(m_Comm.GetPortOpen()) m_Comm.SetPortOpen(FALSE); /************************************************************************/ ...搜了好多资料都没解决这个问题
  • 【随笔】记一次MPY+W5500网络通信错误解决办法 最近在使用MicroPython的网络通信功能,硬件平台为01Studio的pyBoard,如下图:
  • 串口通信MSComm1输出中遇到小问题MSComm1.Output = a 提示报错, 运行时错误‘380’无效属性值 经过调整后,对发送字节进行数组定义,问题解决,程序如下...
  • 困扰了我老半天啊,也在网上找...话说,我希望做一个用蓝牙来控制Arduino的串口通信设备,来实现Arduino与PC的分离,于是乎我便找学校老师借了块蓝牙模块,问老师型号,老师说就是那最普通的那种。。。嗯最普通的那种,
  • 经典错误1 无法访问已释放的对象。 对象名:“System.Net.Sockets.Socket”;解决方案 经典错误2 "远程主机强迫关闭了一个现有的连接。"解决方案
  • 串口通信

    2021-03-05 16:19:42
    串口通信的基本原理4.S5PV210串行通信接口详解1:串口原理5.S5PV210串行通信接口详解2:串口周边6.S5PV210串行通信接口详解3:串口与中断7.S5PV210串行通信编程实战8.RS232与RS485的区别 前言 S5PV210 1.通信涉及的...
  • 计算机和单片机(如MCS-51)都具有串行通信口,可以设计相应的串口通信程序,完成二者之间的数据通信任务。  实际工作中利用串口完成通信任务的时候非常之多。已有一些文章介绍串口编程的文章在计算机
  • 之前在捣鼓wrtnode板子的时候和同学试图在win10下的系统尝试通过PL2303串口去连接,在网上搜索PL2303的驱动,安装后连接板子时发现总是会报错出现错误代码10。首先在设备管理器下面是这样子的: 而后我下载了最新的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 45,526
精华内容 18,210
关键字:

串口通信错误如何解决