• [C#] 编程控制笔记本蓝牙与外部蓝牙设备通信


    一、蓝牙模块XLBT232‐D01介绍(外部设备蓝牙)

    1.1、蓝牙模块简介

    XLBT232-D0101蓝牙模块采用CSR BlueCore 芯片,配置6-8Mbit 的软件存储空间,
    支持AT 指令,用户可根据需要更改SPP 角色(主、从模式)以及串口波特率、
    设备名称、配对密码等参数,使用灵活。

    1.2、模块功能介绍

    1.2.1、特性

    •  蓝牙协议:Bluetooth Specification V2.1+EDR、V2.0+EDR、V2.1、V2.0 V1.2
    • — 工作频率:2.4GHz ISM band
    • — 调制方式:GFSK(Gaussian Frequency Shift Keying)
    • — 发射 率:≤4dBm, Class 2
    • — 灵 敏 度:≤-84dBm at 0.1% BER
    • — 传输速率:Asynchronous: 2.1Mbps(Max) / 160 kbpsSynchronous: 1Mbps/1Mbps
    • — 安全特性:Authentication and encryption
    • — 支持服务:Bluetooth SPP(主模式& 从模式)
    • — 供电电源:+3.3VDC 50mA
    • — 工作温度:-5 ~ +65 Centigrade
    • — 外观尺寸:26.9mm x 13mm x 2.2 mm

    1.2.2、模块接线原理图

    PS:当然也能用USB转TTL模块进行连接在电脑上调试,毕竟大多数笔记本已经没有串口啦!

    1.3、使用说明

    [图:蓝牙模块]

    >_<" KEY为输入管脚,短按控制,或者输入约100ms 的高电平单次脉冲,可以
    实现以下功能:

    • 模块设置为SPP 主机模式时:

        未连接状态时:清除配对信息(若存在配对设备信息)

        已连接状态时:主动发起断开连接,延时150ms 后重启,重新搜索
      连接从设备; 在断开连接时:重新搜索连接从设备。

    • 模块设置为SPP 从机时:

        在已连接状态时:主动发起断开连接,延时150ms 后重启,重新进入被搜
         索状态,等待主机配对和连接

        在断开连接时:延时150ms 后重启,重新进入被搜索状态,等待主机配对
         和连接。

    >_<" 显示模块当前工作状态:

    • 待机状态慢闪——重复2s 脉冲;
    • 连接状态长亮——高电平。

    1.4、AT指令集

    蓝牙模块出厂默认的串口配置为:波特率9600,无校验,数据位8,停止位1。
    PS:接下来说明以上位机为电脑,模块参数为出厂设置时进行配置说明。
    >_<" 将模块通过USB电平转换板连接到电脑USB口(USB转TTL),使用串口调试助手,按
    照 9600,N,8,1 进行配置,打开串口后,发送 AT(无 ),若返回 OK,说明配置
    成功。
    PS:设置 AT 指令必须在蓝牙模块未连接或断开 SPP 链接时才可以(上电或配对
    后都可以,如果连接 SPP,串口输入的数据将会直接发送到远端蓝牙设备串口)

    1.4.1、测试指令:

    1.4.2、查询设置波特率指令:

    1.4.3、查询设置设备名称指令:

    1.4.4、恢复默认设置指令:

    1.4.5、模块复位重启指令:

    1.4.6、查询设置主从模式:

    1.4.7、查询设置配对密码:

    1.4.8、查询设置是否需要密码鉴权:

    PS:为方便使用,默认为不用密码鉴权连接,搜索到蓝牙串口之后,直接连接
    可。有安全考虑的客户请选择需要密码鉴权。
    PS:此指令只有在从设备时才有效;主设备时不接受此指令,发送此指令没
    有回复,也不执行

    1.4.9、清除主设备配对信息指令:

    PS:此指令只有在主设备时才有效;从设备时不接受此指令,发送此指令
    没有回复,也不执行。

    1.4.10、搜索并连接新的蓝牙串口从设备(*)指令:

    PS:此指令只有在主设备时才有效;从设备时不接受此指令,发送此指令没
    有回复,也不执行。

    1.4.11、连接最后一次连接的蓝牙串口从设备(*)指令:

    PS:此指令只有在主设备时才有效;从设备时不接受此指令,发送此指令没
    有回复,也不执行。

    1.4.12、连接指定蓝牙地址的从设备(*)指令:

    PS:此指令只有在主设备时才有效;从设备时不接受此指令,发送此指令没
    有回复,也不执行。

    1.4.13、查询、设置软件版本指令:

    1.4.14、系统帮助指令:

    1.4.15、查询本机MAC 地址指令:

    >_<: 1:所有参数设置后存储在模块内,下次启动时无需再次设置
             2:AT 指令后标注*号的,表示目前未应用的AT 指令

    二、蓝牙模块配置与笔记本电脑相连

    2.1.1、蓝牙初始化配置:

    将蓝牙模块通过TTL转USB模块连接到笔记本,打开串口助手,通过上述AT指令设置为从设备,波特率为9600,然后重启

    [图:USB转TTL模块]

    [图:串口助手]

    2.1.2、电脑为主设备搜索建立连接:

    点击笔记本蓝牙标志的小图标,添加蓝牙设备:

    然后要等一会,笔记本正在装驱动:

    然后右击蓝牙图标,查看蓝牙设备,可见我们的设备已经被电脑发现并添加:

    查看该设备属性,此时笔记本为该设备提供一个串口,就是笔记本蓝牙和设备蓝牙通信的通道,要记住这个一会编程的时候会用到:

    PS:这个COM15也可以在设备管理器中修改为其他通道

    三、C#编程使笔记本蓝牙和外部设备蓝牙通信:

    其实配对以后,蓝牙就被模拟成了一个端口,我们可以用最简单的端口通讯来收发信息。首先,在每次启动时,需要连接端口:

    [FORM初始化时获取所有的COM口,并加入下拉列表]

     1 public Form1()
     2 {
     3     InitializeComponent();
     4 
     5     //Get all port list for selection
     6     //获得所有的端口列表,并显示在列表内
     7     PortList.Items.Clear();
     8     string[] Ports = SerialPort.GetPortNames();
     9 
    10     for (int i = 0; i < Ports.Length; i++)
    11     {
    12         string s = Ports[i].ToUpper();
    13         Regex reg = new Regex("[^COM\d]", RegexOptions.IgnoreCase | RegexOptions.Multiline);
    14         s = reg.Replace(s, "");
    15 
    16         PortList.Items.Add(s);
    17     }
    18     if (Ports.Length > 1) PortList.SelectedIndex = 1;
    19 }

    [连接按钮事件:选中list中的被选中的COM口进行连接,如果连接成功就在状态栏显示蓝牙连接成功]

     1 private void ConnectButton_Click(object sender, EventArgs e)
     2 {
     3     if (!BluetoothConnection.IsOpen)
     4     {
     5         //Start
     6         Status = "正在连接蓝牙设备";
     7         BluetoothConnection = new SerialPort();
     8         ConnectButton.Enabled = false;
     9         BluetoothConnection.PortName = PortList.SelectedItem.ToString();
    10         BluetoothConnection.Open();
    11         BluetoothConnection.ReadTimeout = 10000;
    12         BluetoothConnection.DataReceived += new SerialDataReceivedEventHandler(BlueToothDataReceived);
    13         Status = "蓝牙连接成功";
    14     }
    15 }

    [蓝牙接收数据事件响应函数,在按钮连接事件中声明的该事件,用于响应蓝牙数据接收]

     1 private void BlueToothDataReceived(object o, SerialDataReceivedEventArgs e)
     2 {
     3     //int length = BluetoothConnection.ReadByte();
     4     Thread.Sleep(1000);
     5     int length = 13;
     6     BlueToothReceivedData = DateTime.Now.ToLongTimeString() + "
    ";
     7     BlueToothReceivedData += "收到字节数:" + length + "
    ";
     8 
     9     byte[] data = new byte[length];
    10     BluetoothConnection.Read(data,0,length);
    11     for (int i = 0; i < length; i++)
    12     {
    13         BlueToothReceivedData += string.Format("data[{0}] = {1}
    ", i, data[i]);
    14     }
    15     //receive close message
    16     if (length == 3 && data[0] == 255 && data[1] == 255 && data[2] == 255)
    17     {
    18         //Stop
    19         Status = "正在断开蓝牙设备";
    20         BluetoothConnection.Close();
    21         BluetoothConnection.Dispose();
    22         BluetoothConnection = null;
    23         ConnectButton.Enabled = true;
    24         Status = "蓝牙断开成功";
    25     }
    26 }
    • 这里第4行让程序休息1是因为延时等待从设备把数据发送完全。
    • 这里为了方便我严格控制让发送数据为13Byte。
    • 从设备发送的13Byte数据送至缓冲区,PC端C#程序通过read()函数将缓冲区数据接收到data中,下面是格式输出一下数据。

    [发送数据函数]

     1 private void BlueToothDataSend(byte[] data)
     2 {
     3     //int length = data.Length;
     4     //byte[] readData = new byte[length + 2];
     5     //readData[0] = (byte)(length % 255);
     6     //readData[1] = (byte)(length / 255);
     7     //for (int i = 0; i < length; i++)
     8     //{
     9     //    readData[i + 2] = data[i];
    10     //}
    11     //BluetoothConnection.Write(readData, 0, length + 2);
    12     BluetoothConnection.Write(data, 0, 1);
    13     //Status = "发送数据字节数:" + length;
    14 }
    • 本来是将data[]数据发送出去,因为我从设备设置为只要有数据发送过来就做出响应发送13Byte数据,所以就直接将data的第一byte发送出去了。

    [定时器函数:用于刷新状态栏,和接收数据显示]

    1 private void MonitorTimer_Tick(object sender, EventArgs e)
    2 {
    3     StatusMessage.Text = Status;
    4     BlueToothMessage.Text = BlueToothReceivedData;
    5 }

    [发送数据按钮:将SendMessage中的数据获得发送出去]

    1 private void SendButton_Click(object sender, EventArgs e)
    2 {
    3     byte n;
    4     byte.TryParse(SendMessage.Text, out n);
    5 
    6     BlueToothDataSend(new byte[] { n });
    7 }

    四、PC和51单片机通过蓝牙连接展示

    4.1.1、51单片机部分程序

    一定要用11.0952Mhz的晶振,我用12Mhz结果出现帧丢失!其实这里采用的是52单片机,在此处区别不是很大~

    将蓝牙模块的RXD连接单片机的RXD(P3.0),TXD连接单片机的TXD(P3.1),然后就像以前操作串口一样操作就行啦~

      1 #include <REG52.H>
      2 #include <INTRINS.H>
      3 typedef unsigned char  uchar;
      4 typedef unsigned short ushort;
      5 typedef unsigned int   uint;
      6     
      7 sbit    SCL=P1^0;            //IIC时钟引脚定义
      8 sbit    SDA=P1^1;            //IIC数据引脚定义
      9 
     10 #define    SlaveAddress    0xD0    //IIC写入时的地址字节数据,+1为读取
     11 //**************************************
     12 //延时5微秒(STC90C52RC@12M)
     13 //不同的工作环境,需要调整此函数
     14 //当改用1T的MCU时,请调整此延时函数
     15 //**************************************
     16 void Delay5us()
     17 {
     18     _nop_();_nop_();_nop_();_nop_();
     19     _nop_();_nop_();_nop_();_nop_();
     20     _nop_();_nop_();_nop_();_nop_();
     21     _nop_();_nop_();_nop_();_nop_();
     22     _nop_();_nop_();_nop_();_nop_();
     23     _nop_();_nop_();_nop_();_nop_();
     24 }
     25 //**************************************
     26 //I2C起始信号
     27 //**************************************
     28 void I2C_Start()
     29 {
     30     SDA = 1;                    //拉高数据线
     31     SCL = 1;                    //拉高时钟线
     32     Delay5us();                 //延时
     33     SDA = 0;                    //产生下降沿
     34     Delay5us();                 //延时
     35     SCL = 0;                    //拉低时钟线
     36 }
     37 //**************************************
     38 //I2C停止信号
     39 //**************************************
     40 void I2C_Stop()
     41 {
     42     SDA = 0;                    //拉低数据线
     43     SCL = 1;                    //拉高时钟线
     44     Delay5us();                 //延时
     45     SDA = 1;                    //产生上升沿
     46     Delay5us();                 //延时
     47 }
     48 //**************************************
     49 //I2C发送应答信号
     50 //入口参数:ack (0:ACK 1:NAK)
     51 //**************************************
     52 void I2C_SendACK(bit ack)
     53 {
     54     SDA = ack;                  //写应答信号
     55     SCL = 1;                    //拉高时钟线
     56     Delay5us();                 //延时
     57     SCL = 0;                    //拉低时钟线
     58     Delay5us();                 //延时
     59 }
     60 //**************************************
     61 //I2C接收应答信号
     62 //**************************************
     63 bit I2C_RecvACK()
     64 {
     65     SCL = 1;                    //拉高时钟线
     66     Delay5us();                 //延时
     67     CY = SDA;                   //读应答信号
     68     SCL = 0;                    //拉低时钟线
     69     Delay5us();                 //延时
     70     return CY;
     71 }
     72 //**************************************
     73 //向I2C总线发送一个字节数据
     74 //**************************************
     75 void I2C_SendByte(uchar dat)
     76 {
     77     uchar i;
     78     for (i=0; i<8; i++)         //8位计数器
     79     {
     80         dat <<= 1;              //移出数据的最高位
     81         SDA = CY;               //送数据口
     82         SCL = 1;                //拉高时钟线
     83         Delay5us();             //延时
     84         SCL = 0;                //拉低时钟线
     85         Delay5us();             //延时
     86     }
     87     I2C_RecvACK();
     88 }
     89 //**************************************
     90 //从I2C总线接收一个字节数据
     91 //**************************************
     92 uchar I2C_RecvByte()
     93 {
     94     uchar i;
     95     uchar dat = 0;
     96     SDA = 1;                    //使能内部上拉,准备读取数据,
     97     for (i=0; i<8; i++)         //8位计数器
     98     {
     99         dat <<= 1;
    100         SCL = 1;                //拉高时钟线
    101         Delay5us();             //延时
    102         dat |= SDA;             //读数据               
    103         SCL = 0;                //拉低时钟线
    104         Delay5us();             //延时
    105     }
    106     return dat;
    107 }
    108 //**************************************
    109 //向I2C设备写入一个字节数据
    110 //**************************************
    111 void Single_WriteI2C(uchar REG_Address,uchar REG_data)
    112 {
    113     I2C_Start();                  //起始信号
    114     I2C_SendByte(SlaveAddress);   //发送设备地址+写信号
    115     I2C_SendByte(REG_Address);    //内部寄存器地址,
    116     I2C_SendByte(REG_data);       //内部寄存器数据,
    117     I2C_Stop();                   //发送停止信号
    118 }
    119 //**************************************
    120 //从I2C设备读取一个字节数据
    121 //**************************************
    122 uchar Single_ReadI2C(uchar REG_Address)
    123 {
    124     uchar REG_data;
    125     I2C_Start();                   //起始信号
    126     I2C_SendByte(SlaveAddress);    //发送设备地址+写信号
    127     I2C_SendByte(REG_Address);     //发送存储单元地址,从0开始    
    128     I2C_Start();                   //起始信号
    129     I2C_SendByte(SlaveAddress+1);  //发送设备地址+读信号
    130     REG_data=I2C_RecvByte();       //读出寄存器数据
    131     I2C_SendACK(1);                //接收应答信号
    132     I2C_Stop();                    //停止信号
    133     return REG_data;
    134 }
    I2C.c
      1 // GY-52 MPU6050 IIC测试程序
      2 // 使用单片机STC89C51 
      3 // 晶振:11.0592M
      4 // 编译环境 Keil uVision2
      5 
      6 #include <REG52.H>    
      7 #include <math.h>    //Keil library  
      8 #include <stdio.h>   //Keil library    
      9 
     10 typedef unsigned char  uchar;
     11 typedef unsigned short ushort;
     12 typedef unsigned int   uint;
     13 
     14 uchar usart_flag,receive_data;//串口中断接收标志和串口接收数据
     15 //****************************************
     16 // 定义MPU6050内部地址
     17 //****************************************
     18 #define    SMPLRT_DIV        0x19    //陀螺仪采样率,典型值:0x07(125Hz)
     19 #define    CONFIG            0x1A    //低通滤波频率,典型值:0x06(5Hz)
     20 #define    GYRO_CONFIG        0x1B    //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
     21 #define    ACCEL_CONFIG    0x1C    //加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)
     22 #define    ACCEL_XOUT_H    0x3B
     23 #define    ACCEL_XOUT_L    0x3C
     24 #define    ACCEL_YOUT_H    0x3D
     25 #define    ACCEL_YOUT_L    0x3E
     26 #define    ACCEL_ZOUT_H    0x3F
     27 #define    ACCEL_ZOUT_L    0x40
     28 #define    TEMP_OUT_H        0x41
     29 #define    TEMP_OUT_L        0x42
     30 #define    GYRO_XOUT_H        0x43
     31 #define    GYRO_XOUT_L        0x44    
     32 #define    GYRO_YOUT_H        0x45
     33 #define    GYRO_YOUT_L        0x46
     34 #define    GYRO_ZOUT_H        0x47
     35 #define    GYRO_ZOUT_L        0x48
     36 #define    PWR_MGMT_1        0x6B    //电源管理,典型值:0x00(正常启用)
     37 #define    WHO_AM_I        0x75    //IIC地址寄存器(默认数值0x68,只读)
     38 
     39 
     40 //****************************************
     41 //函数声明
     42 //****************************************
     43 void  delay(unsigned int k);                                        //延时                        
     44 void  SeriPushSend(uchar send_data);                                  //串口发送函数
     45 void  InitMPU6050();                                                //陀螺仪初始化
     46 int   GetData(uchar REG_Address);                                    //合成数据并发送原数据
     47 void  init_uart();                                                    //串口初始化
     48 void  SeriPushSend(uchar send_data);                                //串口发送函数
     49 
     50 extern uchar Single_ReadI2C(uchar REG_Address);                        //读取I2C数据
     51 extern void  Single_WriteI2C(uchar REG_Address,uchar REG_data);        //向I2C写入数据
     52 
     53 
     54 //****************************************
     55 //延时
     56 //****************************************
     57 void delay(unsigned int k)    
     58 {                        
     59     unsigned int i,j;                
     60     for(i=0;i<k;i++)
     61     {            
     62         for(j=0;j<121;j++);
     63     }                        
     64 }
     65 //**************************************
     66 //初始化MPU6050
     67 //**************************************
     68 void InitMPU6050()
     69 {
     70     Single_WriteI2C(PWR_MGMT_1, 0x00);    //解除休眠状态
     71     Single_WriteI2C(SMPLRT_DIV, 0x07);
     72     Single_WriteI2C(CONFIG, 0x06);
     73     Single_WriteI2C(GYRO_CONFIG, 0x18);
     74     Single_WriteI2C(ACCEL_CONFIG, 0x01);
     75 }
     76 //**************************************
     77 //合成数据并发送原数据
     78 //**************************************
     79 int GetData(uchar REG_Address)
     80 {
     81     uchar H,L;
     82     H=Single_ReadI2C(REG_Address);
     83     L=Single_ReadI2C(REG_Address+1);
     84     SeriPushSend(H);//发送出去
     85     SeriPushSend(L);
     86     return (H<<8)+L;   //合成数据
     87 }
     88 //**************************************
     89 //串口初始化
     90 //**************************************
     91 void init_uart()
     92 {
     93     TMOD=0x20;    //设置T1定时器工作方式2                
     94     TH1=0xfd;     //T1装初值                
     95     TL1=0xfd;        
     96     TR1=1;        //启动T1定时器    
     97     REN=1;        //允许串口中断接收
     98     SM0=0;        //设置串口工作方式
     99     SM1=1;
    100     EA=1;        //开总中断
    101     ES=1;        //开串口中断
    102 }
    103 //****************************************
    104 //串口发送函数
    105 //****************************************
    106 void  SeriPushSend(uchar send_data)
    107 {
    108     SBUF=send_data;  
    109     while(!TI);TI=0;      
    110 }
    111 //****************************************
    112 //串口接收函数
    113 //****************************************
    114 void ser()interrupt 4
    115 {
    116     RI=0;
    117     receive_data=SBUF;
    118     usart_flag=1;
    119 }
    120 //*********************************************************
    121 //主程序
    122 //*********************************************************
    123 void main()
    124 { 
    125     delay(500);                        //上电延时        
    126     init_uart();
    127     InitMPU6050();                    //初始化MPU6050
    128     delay(150);
    129     while(1)
    130     {
    131         if(usart_flag==1)            //有数据传过来
    132         {
    133             ES=0;                    //关闭串口中断
    134             SeriPushSend(0xff);
    135             GetData(ACCEL_XOUT_H);    //发送X轴加速度
    136             GetData(ACCEL_YOUT_H);    //发送Y轴加速度
    137             GetData(ACCEL_ZOUT_H);    //发送Z轴加速度
    138             GetData(GYRO_XOUT_H);    //发送X轴角速度
    139             GetData(GYRO_YOUT_H);    //发送Y轴角速度
    140             GetData(GYRO_ZOUT_H);    //发送Z轴角速度
    141      
    142             ES=1;
    143             usart_flag=0;
    144         }
    145     }
    146 }
    main.c

    因为我还在P1.0和P1.1连接一个陀螺仪MPU6050所以上面的代码有点烦,其实可以参考一下我以前发的51单片机串口通信~

    http://www.cnblogs.com/zjutlitao/p/3788696.htm

    l 

    4.1.2、没有51单片机的情况

    可以将蓝牙模块连接在USB转TTL上,用串口助手和你写的C#程序相互通信。

    4.1.3、运行C#程序进行连接通信

    [选择刚才的那个蓝牙端口点击连接]

    [第一次蓝牙图标会给出一个验证提示:在验证框内输入AT指令配置时的你设置的验证码]

    [然后就可以通信啦,如下:]

    PS:相关代码及资料

    C#蓝牙工程代码:http://pan.baidu.com/s/1hqHwG4W

    51蓝牙工程代码:http://pan.baidu.com/s/1dDqywVZ

    蓝牙模块说明书:http://pan.baidu.com/s/1kT61nx1

    C#蓝牙相关博客链接:http://www.diy-robots.com/?p=410%20%E8%93%9D%E7%89%99

  • 相关阅读:
    MySQL学习——操作表
    MySQL学习——数据类型
    MySQL学习——操作数据库
    MySQL学习——存储引擎
    Linux网络——配置防火墙的相关命令
    查询各分类中最大自增ID
    CentOS7下Rsync+sersync实现数据实时同步
    mysql的join连接查询优化经历
    搭建nginx代理支持前端页面跨域调用接口
    Centos查看系统CPU个数、核心数、线程数
  • 原文地址:https://www.cnblogs.com/zjutlitao/p/3886826.html
Copyright © 2020-2023  润新知