精华内容
下载资源
问答
  • 2018-10-16 15:02:18

    软件:Unity
    所用类:SerialPort
    遇到的问题:
    开启多线程,通过蓝牙连接串口,会遇到蓝牙中断的情况。

    解决方法:判断IsOpen属性为false时,调用close方法,释放端口,然后再调用Open方法。

    注意点:线程开启前,要设置

    thread.IsBackground = true;
    

    不然线程不会关闭,程序会卡死。

    更多相关内容
  • 大体 介绍 :本上位机有普通串口功能和蓝牙 AT 指令直接传送功能 ,还有画图功能, , 3个 图,每个都有最多 图,每个都有最多 8条曲线。 另外 还有 ccd 图像 显示功能,
  • c#串口升级程序

    2018-07-19 10:47:58
    c#程序,每次串口上传,每次上传128字节,按着自己定义的校验,主要目的是自己校验比较快,虽然出错概率会增加,但是校验不会给mcu带来太多压力。程序第一个指令是知道程序在app还是api,然后进入api。
  • C#简单的蓝牙串口调试工具源码
  • C# 虚拟串口通信

    2020-12-19 01:45:32
    将主端口COM8拆分成 COM1和COM2两个...//spSend,spReceive用虚拟串口连接,它们之间可以相互传输数据。spSend发送数据SerialPort spReceive; //spReceive接受数据private delegate void MyDelegate(string indata)...

    将主端口COM8拆分成 COM1和COM2两个虚拟端口

    COM8接收的消息会传递给COM1和COM2

    SerialPort spSend;//spSend,spReceive用虚拟串口连接,它们之间可以相互传输数据。spSend发送数据

    SerialPort spReceive; //spReceive接受数据

    private delegate void MyDelegate(string indata); //委托,处理接收的数据

    private MyDelegate showDelegate = null;

    showDelegate = new MyDelegate(show);

    spReceive = new SerialPort("COM1", 19200, Parity.None, 8, StopBits.One);

    spReceive.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); //虚拟串口监听接收消息监听事件,该事件并不在主线程运行

    spReceive.Open();//打开串口,工作完成时务必关闭串口

    void show(string indata)

    {

    //处理COM1接收的消息

    }

    private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)

    {

    SerialPort sp = (SerialPort)sender;

    this.Invoke(showDelegate, new object[] { sp.ReadExisting() });

    }

    软件:Serial Splitter 4.2

    http://www.pc0359.cn/downinfo/57195.html

    USB虚拟串口通信

    https://blog.csdn.net/errorhai/article/details/85333914

    Linux 虚拟串口及 Qt 串口通信实例

    Linux 虚拟串口及 Qt 串口通信实例 2011-06-22 17:49 佚名 互联网 字号:T | T Linux 虚拟串口及 Qt 串口通信实例是本文所要介绍的内容,在实现过程中,打开了两个伪 ...

    .NET 串口通信

    这段时间做了一个和硬件设备通信的小项目,涉及到扫描头.输送线.称重机.贴标机等硬件.和各设备之间通信使用的是串口或网络(Socket)的方式.扫描头和贴标机使用的网络通信,输送线和称重机使用的是串口通 ...

    .NET 串口通信中断接收,包含0X1A(作为EOF)

    .NET串口通信中将`0X1A`当做EOF处理,.NET接收到EOF会触发一次接收中断,此时事件形参`SerialDataReceivedEventArgs`值为枚举 `Eof`,其他为`Chars` ...

    VS2008基于对话框的MFC上位机串口通信(C++实现)简单例程

    首先,在 vs2008 环境下创建 MFC 运用程序 设置项目名称为 ComTest(这个地方随意命名,根据个人习惯),点击确定后,点击下一步 出现如下界面 选择"基于对话框"模式 ...

    C#串口通信

    通过COM1发送数据,COM2接收数据.当COM2接收完本次发送的数据后,向COM1发送信息通知COM1本次数据已发完,COM1接到通知后,再发下一段数据.这样可以确保每次发送的数据都可以被正确接收. ...

    LabVIEW串口通信

    Instrument I/O 利用LabVIEW内置的驱动程序库和具有工业标准的设备驱动软件,可对 GPIB(通用接口总线).Ethernet(以太网)接口.RS-232(标准串行接口总线)/RS-4 ...

    C#初入串口通信(串行通信)总结

    使用WinFrom来实现: 首先要知道串口通信协议以及原理 原理大概提一下:要自己翻阅看.(http://book.51cto.com/art/200911/162532.htm或者http://hi ...

    在ubuntu下利用minicom实现串口通信

    windos有串口调试助手,linux下也有这样的工具——minicom.不过,minicom和linux下的许多工具都一样,也是命令行模式,没有图形化界面供我们享受.作为一款串口调试工具,虽然难看但 ...

    随机推荐

    Varnish介绍

    “Varnish是一款高性能的开源HTTP加速器,挪威最大的在线报纸 Verdens Gang (http://www.vg.no) 使用3台Varnish代替了原来的12台squid,性能居然比以前 ...

    linux tomcat 用/etc/init.d/tomcat start启动报错

    line 13: [ 0: unary operator expected please use "sudo service tomcat stop|start|restart" ...

    Java遇见HTML——JSP篇之JSP状态管理

    一.http协议的无状态 无状态性是指,当浏览器发送请求给服务器的时候,服务器响应客户端请求.但是当同一个浏览器再次发送请求给服务器的时候,服务器并不知道他就是刚才的那个浏览器.简单的说,就是服务器不 ...

    uva 12526 - Cellphone Typing

    字典树,可惜比赛的时候有两句话写倒了: 害得我调了一个小时: 今天不宜做题 = = 代码: #include #include #define ...

    mysql 常用命令集锦

    Mysql安装目录数据库目录/var/lib/mysql/配置文件/usr/share/mysql(mysql.server命令及配置文件)相关命令/usr/bin(mysqladmin mysqld ...

    win10下vagrant+centos7 rails虚拟开发机配置流程

    此文写于2017.8.21 在写本文前,笔者已经尝试了多种其他的替代方法,例如wmware虚拟机安装kylin.然而发现总是还有各种问题.经大佬指点安装了virtualbox + vagrant.于是 ...

    机器学习基石:13 Hazard of Overfitting

    泛化能力差和过拟合: 引起过拟合的原因: 1)过度VC维(模型复杂度高)------确定性噪声: 2)随机噪声: 3)有限的样本数量N. 具体实验来看模型复杂度Qf/确定性噪声.随机噪声sigma2. ...

    spring cloud 入门系列七:基于Git存储的分布式配置中心

    我们前面接触到的spring cloud组件都是基于Netflix的组件进行实现的,这次我们来看下spring cloud 团队自己创建的一个全新项目:Spring Cloud Config.它用来为 ...

    tolua之wrap文件的原理与使用

    什么是wrap文件 每个wrap文件都是对一个c#类的包装,在lua中,通过对wrap类中的函数调用,间接的对c#实例进行操作. wrap类文件生成和使用的总体流程 生成一个wrap文件的流程 这部分 ...

    oracle的存储过程的作用

    oracle的存储过程的作用 1.存储过程可以使得程序执行效率更高.安全性更好,因为过程建立之后 已经编译并且储存到数据库,直接写sql就需要先分析再执行因此过程效率更高,直接写sql语句会带来安全性 ...

    展开全文
  • c#利用虚拟串口工具进行串口通信数据的发送和接收Posted On 2020年2月7日串口通信串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在...

    c#利用虚拟串口工具进行串口通信数据的发送和接收

    Posted On 2020年2月7日

    串口通信

    串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通信的端口,这些参数必须匹配。

    VSPD虚拟串口工具

    在硬件缺失的情况下,要想测试代码使用的是否正确。就需要使用VSPD虚拟串口工具来虚拟出串口,并在程序中打开串口,并发送接收数据。刚开始真的是啥也不懂(现在也啥也不懂^……),跟着别人贴的代码一步一步写但是就是只能发送数据没有办法接收数据。后来我才知道,他们是有硬件,并且把串口的TXD和RXD短接,这样就能实现自己发的数据,自己接收了。不得不说这个操作太骚了。在VSPD中我们发现串口都是成对出现的,也就是COM1发的数据是COM2接收的。并且只有在COM2打开的情况下才能接收数据。但是我确实很想测试一下程序中代码是否正确怎么办呢?难到我需要再写一个代码去打开另一个串口么?这时候我用到了另一个工具友善串口使用助手。可以在友善串口助手中打开与COM4配对的串口COM5,并向COM4发送数据。示意图如下:

    16ccff2bcbef1dcead227ed005dd6f27.png

    代码

    using System;

    using System.Collections.Generic;

    using System.ComponentModel;

    using System.Data;

    using System.Drawing;

    using System.Linq;

    using System.Text;

    using System.Threading.Tasks;

    using System.Windows.Forms;

    using System.Text.RegularExpressions;

    using System.IO.Ports;

    namespace 串口通信

    {

    public partial class Form1 : Form

    {

    public Form1()

    {

    InitializeComponent();

    }

    private void Form1_Load(object sender, EventArgs e)

    {

    pictureBox1.BackgroundImage = Properties.Resources.red;//将表示状态的图片设为红色,表示端口关闭

    //检测并添加串口

    foreach (string s in System.IO.Ports.SerialPort.GetPortNames())//获取当前计算机的串行端口名的数组

    {

    cbSerial.Items.Add(s);//添加到对应的下拉列表中

    }

    sp.WriteTimeout = 3000;

    sp.ReadTimeout = 3000;

    sp.ReceivedBytesThreshold = 1;

    sp.RtsEnable = true;

    sp.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);//订阅委托

    cbSerial.SelectedIndex = 0; //设置cbSerial的默认选项

    }

    //接收数据事件

    private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)

    {

    int length = sp.BytesToRead;

    byte[] recData = new byte[length];

    sp.Read(recData, 0, length);

    string recText = Encoding.GetEncoding("GB2312").GetString(recData);

    //更新接收区

    txtReceive.Invoke(new EventHandler(delegate {

    txtReceive.AppendText(recText);

    }));

    }

    //将接受到的内容显示出来

    private void AddContent(string content)

    {

    this.BeginInvoke(new MethodInvoker(delegate

    {

    txtReceive.AppendText(content);

    txtReceive.AppendText("\r\n");

    }));

    }

    //打开相应端口

    private void btn_Open_Click(object sender, EventArgs e)

    {

    if (cbSerial.Items.Count == 0)

    {

    MessageBox.Show("没有发现串口,请检查线路!");

    return;

    }

    if (sp.IsOpen == false)//端口未打开,打开端口

    {

    //设置端口属性

    sp.PortName = cbSerial.SelectedItem.ToString();//COM4

    sp.BaudRate = 19200;//设置比特率

    sp.DataBits = 8;//设置数据位长度

    sp.Parity = Parity.None;//获取或设置奇偶校验检查协议

    sp.StopBits = StopBits.One;//设置停止位

    sp2.PortName = cbSerial.SelectedItem.ToString();//COM4

    sp2.BaudRate = 19200;//设置比特率

    sp2.DataBits = 8;//设置数据位长度

    sp2.Parity = Parity.None;//获取或设置奇偶校验检查协议

    sp2.StopBits = StopBits.One;//设置停止位

    try

    {

    sp.Open();//打开串口

    btnSend.Enabled = true;//可发送数据

    MessageBox.Show(sp.PortName + "被打开!");

    }

    catch (Exception ex)

    {

    MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);

    }

    btn_Open.Text = "关闭串口";

    pictureBox1.BackgroundImage = Properties.Resources.green;

    }

    else//串口已经被打开,关闭窗口

    {

    try

    {

    sp.Close();

    btnSend.Enabled = false;//端口已经被关闭不可编辑数据

    MessageBox.Show(sp.PortName + "被打开!");

    }

    catch (Exception ex)

    {

    MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);

    }

    btn_Open.Text = "打开串口";

    pictureBox1.BackgroundImage = Properties.Resources.red;

    }

    }

    //发送数据

    public bool sendData(byte[] date)

    {

    if (sp.IsOpen)

    {

    try

    {

    sp.Write(date, 0, date.Length);

    return true;

    }

    catch (Exception ex)

    {

    MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);

    }

    }

    else

    {

    MessageBox.Show("串口未打开", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);

    }

    return false;

    }

    //点击按钮触发发送事件

    private void btnSend_Click(object sender, EventArgs e)

    {

    byte[] sendData = null;

    if (!sp.IsOpen) //如果没打开

    {

    MessageBox.Show("请先打开串口!", "Error");

    return;

    }

    String strSend = txtSend.Text;

    try

    {

    sendData = Encoding.UTF8.GetBytes(txtSend.Text.Trim());

    sp.Write(sendData, 0, sendData.Length);

    }

    catch (Exception ex)

    {

    MessageBox.Show("Error:" + ex.Message, "Error");

    }

    }

    }

    }

    展开全文
  • 原用途:测量光纤随温度的系数 双模 (蓝牙客户端SPP+串口通信): 蓝牙采用InTheHand.Net.Bluetooth 框架为.Net framework4.6.2
  • Windows 上的蓝牙编程并不方便,由于操作系统并没有提供统一的蓝牙操作接口,通常是由各个蓝牙设备商提供蓝牙栈,所以要想编程...蓝牙虚拟串口是一个较为常见的需求,为了兼容已有使用串口设备的程序,需要将蓝牙...

    Windows 上的蓝牙编程并不方便,由于操作系统并没有提供统一的蓝牙操作接口,通常是由各个蓝牙设备商提供蓝牙栈,所以要想编程兼容这些不同的厂商蓝牙是一个问题。好在有个软件项目 32feet.NET 针对主流蓝牙协议栈提供了支持,包括 Microsfot, Widcomm, BlueSolei 等,同时还支持红外传输协议。

    蓝牙虚拟串口是一个较为常见的需求,为了兼容已有使用串口设备的程序,需要将蓝牙连接转为系统上的虚拟串口,然后提供给其他程序或库使用。32feet.NET 对此也提供了支持。

    32feet.NET 依赖 .NET 3.5 版本以上框架,支持 Windows 桌面版本、Wndows CE 以及 Windows Phone。

    安装

    如果使用 Visual Studio 2015 或者 安装有 NuGet 工具的,可以直接通过 NuGet 安装。在 NuGet 命令行中输入

    1

    Install-Package 32feet.NET

    这样 NuGet 会自动下载安装并添加到当前 .NET 项目中。可以检查项目 References 项,如果存在 InTheHand.Net.Personal 则表明已成功加入到项目中,如果没有,可以手动添加引用,NuGet 下载存放在 SolutionName\packages\32feet.NET.x.x.x.x\ 路径下。

    使用

    下面主要讲解 32feet.NET 的使用,覆盖蓝牙搜索、配对、直接连接以及虚拟串口服务。

    1. 检测系统蓝牙可用性

    如果系统没有蓝牙设备或者蓝牙设备被禁用,那么可以通过以下函数来进行检查:

    123456789101112131415

    /* 定义于类 BTHelper 中 */

    public static bool IsPlatformSupportBT()

    {

    BluetoothClient bc;

    try

    {

    bc = new BluetoothClient();

    }

    catch (PlatformNotSupportedException)

    {

    return false;

    }

    bc.Close();

    return true;

    }

    如果系统不支持蓝牙设备,那么 new BluetoothClient 会抛出 PlatformNotSupportedException 异常,通过捕获这个异常,来检测系统蓝牙设备可用性。

    2. 蓝牙搜索

    BluetoothClient 对象有个方法 DiscoverDevices 用于搜索蓝牙设备,该方法有多个重载版本,最终都是调用如下这个接口:

    1

    public BluetoothDeviceInfo[] DiscoverDevices(int maxDevices, bool authenticated, bool remembered, bool unknown, bool discoverableOnly);

    第一个参数表明搜索的最大设备数,第二个参数表示是否搜索已配对设备,第三个表示是否搜索记住的设备,第四个表示是否搜索未知设备,第五个参数表示是搜索范围内可被发现的设备。

    这里面重要的是第二和第五个参数,第二个代表搜索系统中已配对列表中的设备,即使它们现在并不在线。第五个参数 XP 系统上不支持,表示搜索范围内可被发现的设备。

    如果我们需要获得系统中已配对列表中的蓝牙设备,可以这样调用 DiscoverDevices(255, true, false, false),这里使用了4个参数的重载版本,只将第二个参数置为 true。

    如果我们需要搜索周围环境中可用的蓝牙设备,可以这样调用 DiscoverDevices(255, false, false, false, true),这个调用等同于 DiscoverDevicesInRange()。

    需要注意的是,这个调用是同步阻塞的,在搜索没有结束之前函数不会返回。所以通常我们需要将这个调用放入工作线程中。例外的是,如果只是获取系统中已配对列表中的设备,这个调用会很快完成,不会占用当前线程太多时间。

    库中同时提供了一个异步搜索方法,由类 BluetoothComponent 提供,由事件 DiscoverDevicesProgress 和 事件 DiscoverDevicesComplete 以及方法 DiscoverDevicesAsync 来实现。这个和用 BackgroundWorker 来实现 DiscoverDevices() 异步查找是一样的。

    PS: 可以通过 VS 的 Object Browser 查看 InTheHand.Net.Personal 库中的函数接口说明,说明非常翔实。

    3. 检测蓝牙设备是否在范围内

    当需要检查一个蓝牙设备是否在有效范围内,可以通过查询一个 Fake Service ID 来实现。

    如果蓝牙设备在范围内可访问,那么查询的结果是返回的服务记录为空,表示不支持此服务;如果蓝牙设备不在范围内,那么会抛出套接字异常。

    以下为检测代码:

    12345678910111213141516171819

    /* 定义于类 BTHelper 中 */

    public static bool TestingIfInRange(BluetoothAddress addr)

    {

    bool inRange = false;

    Guid fakeUuid = new Guid("{F13F471D-47CB-41d6-9609-BAD0690BF891}");

    BluetoothDeviceInfo device = new BluetoothDeviceInfo(addr);

    try

    {

    ServiceRecord[] records = device.GetServiceRecords(fakeUuid);

    Debug.Assert(records.Length == 0, "Why are we getting any records? len: " + records.Length);

    inRange = true;

    }

    catch (SocketException)

    {

    inRange = false;

    }

    return inRange;

    }

    需要注意的是,因为蓝牙设备通信需要时间,所以这个调用也需要较长时间才能完成,未完成之前进入阻塞不返回,所以这个方法也需要放入工作线程中执行。

    4. 蓝牙设备配对

    蓝牙配对功能由类 BluetoothSecurity 的静态方法 PairRequest(BluetoothAddress device, string pin) 提供,其中第一个参数是目标设备地址,第二个参数是用于配对的 Pin 码。配对成功返回 true,失败返回 false。

    解除配对是 BluetoothSecurity.RemoveDevice(BluetoothAddress device) 。

    配对操作也需要将长时间完成,所以这个方法也需要放入工作线程中执行。

    5. 蓝牙直接连接

    如果不需要蓝牙虚拟串口而直接读写蓝牙数据,那么可以使用直接连接,这个可以参照官方文档:General Bluetooth Data Connections.

    通过直接连接获取一个可读写的 System.IO.Stream 流对象,就可以直接对蓝牙进行读写数据操作了。以下为官方样例中的代码

    1234567891011

    BluetoothAddress addr = BluetoothAddress.Parse("001122334455");

    Guid serviceClass;

    serviceClass = BluetoothService.SerialPort;

    // - or - etc// serviceClass = MyConsts.MyServiceUuid//var ep = new BluetoothEndPoint(addr, serviceClass);

    var cli = new BluetoothClient();

    cli.Connect(ep);

    Stream peerStream = cli.GetStream();

    // peerStream.Write/Read ...

    6. 蓝牙虚拟串口

    这部分讲解如何实现将蓝牙连接转为系统上的虚拟串口并获取串口名,还可以参阅官方文档: Bluetooth Serial Ports.

    首先需要说明的是,虚拟串口和直接连接数据读写不能同时使用,如果已经使用了其中一个方法进行读写,那么另外的一个方法会失败。

    生成虚拟串口需要将蓝牙设备服务设置为 BluetoothService.SerialPort,官方样例代码如下:

    1234

    BluetoothAddress addr = BluetoothAddress.Parse("123456789012");

    BluetoothDeviceInfo device = new BluetoothDeviceInfo(addr); // Or from discovery etcbool state = true;

    device.SetServiceState(BluetoothService.SerialPort, state, true);

    SetServiceState 的第一个函数表示服务标识,第二个表示要设置的服务状态,true 为启用, false 为禁用,第三个参数表示如果设置失败是否抛出异常。

    但在实际使用中,某些双模蓝牙在设置时,虽然设置成功但是依然会抛出 Win32Exception 异常,所以这里建议调用此函数的重载版本 SetServiceState(System.Guid service, bool state),而想要知道是否设置成功,下面会介绍其他方法来获得。

    这个方法调用并不会告诉我们新生成的串口名,官方文档中的建议是通过设置前后的系统串口列表差异来获取新生成的串口名,而获取系统串口列表则可以调用静态方法 SerialPort.GetPortNames。

    但是不建议用这个方法来获取虚拟串口名,因为这个不可靠而且容易出错,下面介绍另外一个可靠方法,而且这个方法也可以同时告诉我们设置虚拟串口服务是否成功。

    获取蓝牙虚拟串口名

    蓝牙虚拟串口在系统中都有记录,我们可以通过检索这个记录,来找到所设置的设备的虚拟串口名,同时也可以得知我们的蓝牙虚拟串口是否设置成功。

    通过调用 WMI 查询,可以枚举出系统中每个串口的详细信息。这里可以通过 PowerShell 来查询:

    1

    C:\> Get-WmiObject -query "select DeviceID,PNPDeviceID from Win32_SerialPort"

    输出样例(其中 COM66 对应的蓝牙设备地址为 00803A686519):

    1234

    DeviceID : COM66

    PNPDeviceID : BTHENUM\{00001101-0000-1000-8000-00805F9B34FB}\7&1D80ECD3&0&00803A686519_C00000003

    ......

    可以看出蓝牙虚拟串口的 PNPDeviceID 是以 BTHENUM 开头,并且会将蓝牙地址存放其中。

    这个查询也可以通过 C# 代码实现:

    12345678910111213

    using System.Management;

    const string Win32_SerialPort = "Win32_SerialPort";

    SelectQuery q = new SelectQuery(Win32_SerialPort);

    ManagementObjectSearcher s = new ManagementObjectSearcher(q);

    foreach (object cur in s.Get()) {

    ManagementObject mo = (ManagementObject)cur;

    object id = mo.GetPropertyValue("DeviceID");

    object pnpId = mo.GetPropertyValue("PNPDeviceID");

    console.WriteLine("DeviceID: {0} ", id);

    console.WriteLine("PNPDeviceID: {0} ", pnpId);

    console.WriteLine("");

    }//for

    综上,我们可以定义一个函数,这个函数通过 WMI 检索所有串口设备信息,然后返回一个 Hashtable,其中存储的键为蓝牙设备地址,存储的值为串口名。

    函数定义如下:

    123456789101112131415161718192021222324252627282930313233343536373839

    /* 定义于类 BTHelper 中 */

    public static Hashtable QueryBTHPorts()

    {

    const string Win32_SerialPort = "Win32_SerialPort";

    SelectQuery q = new SelectQuery(Win32_SerialPort);

    ManagementObjectSearcher s = new ManagementObjectSearcher(q);

    Hashtable hashResult = new Hashtable();

    foreach (object cur in s.Get())

    {

    ManagementObject mo = (ManagementObject)cur;

    string id = mo.GetPropertyValue("DeviceID").ToString();

    string pnpId = mo.GetPropertyValue("PNPDeviceID").ToString();

    Debug.WriteLine("WMI>>DeviceID: " + id);

    Debug.WriteLine("WMI>>PNPDeviceID: " + pnpId);

    Debug.WriteLine("");

    /* 仅处理蓝牙串口 */

    if (pnpId.StartsWith("BTHENUM"))

    {

    /* 从 PNPDeviceID 中提取出蓝牙地址,策略是逆序字符串 & 后 _ 之前 */

    /* 蓝牙地址为6字节,HEX为12位字符 */

    int rBound = pnpId.LastIndexOf('_');

    int lBound = pnpId.LastIndexOf('&');

    Debug.Assert(rBound - lBound == 13, "Get BT Addr, this will nevery happened.");

    string addr = pnpId.Substring(lBound + 1, 12);

    if (!hashResult.Contains(addr))

    {

    hashResult.Add(addr, id);

    }

    else

    {

    Debug.WriteLine("Get BT Addr, addr" + addr + " has more than 1 ports");

    }

    }

    }

    return hashResult;

    }

    同样,WMI 检索也比较耗时,所以这个函数调用需要放入工作线程中执行。

    有了这个函数,我们可以通过结果中查找我们设置的蓝牙设备地址,就可以得知对应的虚拟串口名,而如果结果中没有我们设置的蓝牙设备地址,那么就可以认定设置虚拟串口服务失败了。

    样例代码

    这里介绍通过配合使用 BackgroundWorker 来实现蓝牙设备的配对、生成虚拟串口的样例代码:

    我们通过传入蓝牙设备地址给 worker,worker 在 DoWork 中帮我们处理所有步骤,过程中报告进度,并最终告诉我们结果。

    worker 的 DoWork 事件代码:

    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495

    /* 进行蓝牙连接操作的后台线程执行函数 */

    /* 传入 蓝牙地址字符串 作为参数 */

    /* 利用 ReportProgress 报告进度 */

    /* 利用 DoWorkEventArgs.Result 报告状态 */

    void bgworkerConnection_DoWork(object sender, DoWorkEventArgs e)

    {

    BackgroundWorker worker = sender as BackgroundWorker;

    string args = e.Argument as string;

    string finalportname = "";

    do

    {

    BluetoothAddress addr = BluetoothAddress.Parse(args);

    BluetoothDeviceInfo deviceinfo = new BluetoothDeviceInfo(addr);

    /* 检测设备是否在服务范围内,有些设备能被发现但不能被配对连接(如果已经被其他终端配对连接) */

    /* 不在范围内则报告错误信息 */

    worker.ReportProgress(10, "Testing if device in range...");

    if (!BTHelper.TestingIfInRange(addr))

    {

    string msg = string.Format("Error: Device {0}({1}) is not reachable!",

    deviceinfo.DeviceName,

    deviceinfo.DeviceAddress.ToString());

    e.Result = msg;

    return;

    }

    worker.ReportProgress(10, "Device is in range.");

    /* 检测设备是否是已配对设备 */

    if (deviceinfo.Authenticated)

    {

    /* 已配对设备枚举系统蓝牙串口,检测是否已绑定虚拟串口 */

    worker.ReportProgress(10, "Querying Bluetooth serialport...");

    Hashtable bthTable1 = BTHelper.QueryBTHPorts();

    if (bthTable1.ContainsKey(addr.ToString()))

    { /* 获取绑定串口 */

    finalportname = bthTable1[addr.ToString()] as string;

    /* !!! 跳出 !!! */

    break;

    }

    /* 此处 else 需考虑枚举结果中没有绑定串口的处理,如果没有绑定串口,那么重新设置串口服务 */

    /* 此处 else 部分会在下面的流程处理,见下方设置串口服务部分 */

    }

    else /* 需要进行配对 */

    {

    worker.ReportProgress(10, "Start pairing...");

    if (!BluetoothSecurity.PairRequest(addr, "1234"))

    { /* 配对失败 */

    string msg = string.Format("Error: Can not pair to Device {0}({1})!",

    deviceinfo.DeviceName,

    deviceinfo.DeviceAddress.ToString());

    e.Result = msg;

    return;

    }

    }

    /* 设置串口服务 */

    /* SLC蓝牙设置串口服务时,如果 SetServiceState */

    /* 第三个参数为 true (允许异常) 那么则一定会抛出异常,即使虚拟串口创建成功 */

    /* 所以这里调用2个参数的重载版本 */

    /* 之后检查串口服务是否设置成功的方法就是 设置后检索蓝牙串口 */

    worker.ReportProgress(10, "Enable serialport service...");

    deviceinfo.SetServiceState(BluetoothService.SerialPort, true);

    /* 枚举系统蓝牙串口,检查对应蓝牙是否有串口绑定 */

    Hashtable bthTable2 = BTHelper.QueryBTHPorts();

    if (bthTable2.ContainsKey(addr.ToString()))

    {

    /* 获取绑定的串口 */

    finalportname = bthTable2[addr.ToString()] as string;

    /* !!! 跳出 !!! */

    break;

    }

    else

    { /* 启用串口服务失败或者无法检测到绑定串口 */

    string msg = string.Format("Error: Failed to set Serialport service for Device {0}({1})!",

    deviceinfo.DeviceName,

    deviceinfo.DeviceAddress.ToString());

    e.Result = msg;

    return;

    }

    } while (false);

    worker.ReportProgress(10, "Open serialport...");

    Debug.WriteLine(string.Format(">>PORT NMAE: {0}", finalportname));

    /* 成功 */

    /* 将串口名放入消息中返回 */

    string okmsg = string.Format("OK: {0}", finalportname);

    e.Result = okmsg;

    }

    代码中通过灵活使用 string 作为 Result 来表明执行结果。

    worker 的 RunCompleted 事件代码:

    123456789101112

    void bgworkerConnection_RunCompleted(object sender, RunWorkerCompletedEventArgs e)

    {

    string msg = e.Result as string;

    if(msg.StartsWidth("OK"))

    { /* OK */

    MessageBox.Show(msg);

    }

    else

    { /* Error */

    MessageBox.Show(msg);

    }

    }

    后续可以通过字符串处理提取出生成的串口名。

    worker 的启动代码:

    1

    bgworkerConnection.RunWorkerAsync(addrstring);

    这样子我们就获取到了绑定的虚拟串口名,但是在使用串口中要注意的是,虚拟串口打开过程中,本质上还是发起了一个蓝牙数据连接,所以打开过程会耗时较长,所以这个虚拟串口打开过程也需要放入工作线程中处理。如果虚拟串口对应的蓝牙设备没有在线或者其他原因造成不可用,那么打开时会抛出异常,需要在代码上进行处理。

    一旦蓝牙设备经过绑定并且设置虚拟串口服务成功,那么对应的串口会一直存在与系统的串口列表中,但这并不代表它是可用的,请在打开这类串口时添加异常处理代码。

    (完)

    展开全文
  • android BluetoothSPP,有兴趣的可以下载研究,不是程序是源码哦,刚下载,还没测试,先分享 android BluetoothSPP,有兴趣的可以下载研究,不是程序是源码哦,刚下载,还没测试,先分享
  • 【实例简介】串口读取发送数据【实例截图】【核心代码】using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System....
  • unity3D串口通信程序,可以实现发送接收。脚本语言是C#编写。基本满足通信要求。
  • 使用C#编写的windows CE蓝牙串口控制蓝牙设备发送接收数据。
  • C#蓝牙通讯 蓝牙模块HC-06

    千次阅读 2022-03-28 14:11:32
    创建C# Form项目 需要在__工具__>>__ NuGet包__下载InTheHand.Net.Bluetooth 目录蓝牙连接部分蓝牙消息发送部分 蓝牙连接部分 program.cs中的代码如下 这部分只负责蓝牙连接 using System; using InTheHand...
  • 蓝牙串口PC版命令行工具(带源代码) 可以用连接Arduino蓝牙串口,或配合虚拟串口进行远程烧录。
  • 而且更强壮(robust),因为使用Winsock的Bluetooth通信可以直接监听到蓝牙设备关闭或者离开通信范围,而Bluetooth Virtual Serial Port只能通过Timeout来检查。 由于支持现有系统(Legacy System),Bluetooth ...
  • C# 串口工具开发

    2021-09-07 17:00:38
    在单片机项目开发中,上位机也是一个很重要的部分,主要用于数据显示(波形、温度等)... 串口蓝牙(HC-06)—— 不多用,暂不介绍;  上位机软软件开发主要包括以下两种:  1、Windows上位机(EXE可执行程序) .
  • private void sp_DataReceived(objectsender, EventArgs e) //sp是串口控件 { int n = sp.BytesToRead; byte[] buf = new byte[n]; sp.Read(buf, 0, n); //1.缓存数据 buffer.AddRange(buf); //2.完整性判断 while ...
  • void ReceiveBack() { int index = 0; //解析每次报文用的标识 byte[] arr1 = new byte[2048]; List<byte> arr3 = new List<byte>(); // 总的报文集合 int totalLen...
  • Android 蓝牙串口通讯

    千次阅读 2021-10-18 18:30:37
    最近在弄蓝牙串口,参考了不少网上的大佬,加上自己早期对C#的学习,写一个给自己的备忘录,如果有大佬看到还请多多指教。 1.简介 Android设备中提供了一整套蓝牙的API,我这边只取了其中需要的部分。 初期权限 1....
  • C#蓝牙链接+传输文件

    2021-11-23 15:42:37
    C#上位机蓝牙收发文件
  • C# 实现蓝牙检测及蓝牙设备信息获取代码 using System; using System.IO; using System.Net.Sockets; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; // 需添加...
  • c# 蓝牙打印

    千次阅读 2011-05-12 14:59:00
     构造方法初始化串口参数   ///     public  Printer()  { // 初始化各个参数  server.BaudRate  =   9600 ; // 波特率  server.Parity  =   0 ; // 校检位  server.DataBits  =   8 ; // 数据位  ...
  • Android应用源码安卓源码包wifi蓝牙串口&Socket通讯窗口抖动Widget小组件等20个合集: android Widget小组件开发.zip Android 开启指定名称和密码的 Wifi热点 demo.zip Android中禁止某软件的安装.zip Android小部件...
  • c#串口通信——自动扫描可用串口

    千次阅读 2020-08-11 14:53:18
    本意是:当界面打开时就能通过依次尝试串口能否打开扫描出来可用串口。后来发现有可能会先打开界面,然后插拔设备导致串口更新变化。未知c#是否有感应串口变化的函数,所以还是多增加一个扫描按键,提高体验。 ...
  • 主要接口GetPortNum 获取虚拟串口所在的COM端口号DeletePort 删除指定的虚拟串口Rescan 重新扫描硬件(在DeletePort之后调用)主要问题1 在做DeletePort的时候,SetupDiCallClassInstaller返回false,使用GetLastError...
  • 我写了一个小程序用于监听串口的数据,第一次点监听,然后暂停,都还正常,但是再点监听的时候就会造成蓝屏死机.我是在虚拟机里面用SerialNull 模拟的串口通信,用别的测试软件通信正常.串口消息是用测试软件发的,监听...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 706
精华内容 282
关键字:

c# 蓝牙串口

c# 订阅