原文:
[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 的高电平单次脉冲可以
实现以下功能
未连接状态时清除配对信息(若存在配对设备信息)
已连接状态时主动发起断开连接延时150ms 后重启重新搜索
连接从设备 在断开连接时重新搜索连接从设备。
在已连接状态时主动发起断开连接延时150ms 后重启重新进入被搜
索状态等待主机配对和连接
在断开连接时延时150ms 后重启重新进入被搜索状态等待主机配对
和连接。
>_<" 显示模块当前工作状态
- 待机状态慢闪——重复2s 脉冲
- 连接状态长亮——高电平。
1.4、AT指令集
蓝牙模块出厂默认的串口配置为波特率9600无校验数据位8停止位1。
PS:接下来说明以上位机为电脑模块参数为出厂设置时进行配置说明。
>_<" 将模块通过USB电平转换板连接到电脑USB口(USB转TTL)使用串口调试助手按
照 9600,N,8,1 进行配置打开串口后发送 AT(无\r\n)若返回 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所有参数设置后存储在模块内下次启动时无需再次设置
2AT 指令后标注*号的表示目前未应用的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() + "\r\n";
7 BlueToothReceivedData += "收到字节数" + length + "\r\n";
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}\r\n", 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(不自检2G5Hz)
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