Chinaunix首页 | 论坛 | 博客
  • 博客访问: 9463493
  • 博文数量: 1750
  • 博客积分: 12961
  • 博客等级: 上将
  • 技术积分: 20091
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-09 11:25
个人简介

偷得浮生半桶水(半日闲), 好记性不如抄下来(烂笔头). 信息爆炸的时代, 学习是一项持续的工作.

文章分类

全部博文(1750)

文章存档

2024年(26)

2023年(26)

2022年(112)

2021年(217)

2020年(157)

2019年(192)

2018年(81)

2017年(78)

2016年(70)

2015年(52)

2014年(40)

2013年(51)

2012年(85)

2011年(45)

2010年(231)

2009年(287)

分类: 其他平台

2018-05-31 13:59:04

https://blog.csdn.net/u011318735/article/details/17429879

前段时间买了个ATK的HC05蓝牙模块。HC05模块是一款高性能主从一体蓝牙串口模块,可以不用知道太多蓝牙相关知识就可以很好的上手。说白了,只是个蓝牙转串口的设备,你只要知道串口怎么编程使用,就可以了,实现了所谓的透明传输。
ATK-HC05的外观如下图所示:
ATK-HC05蓝牙模块的详细说明 - ziye334 - ziye334的博客

从左到右的引脚分布式是:
1、VCC:当然这个引脚是接电源的正极,电压的范围为3.3v到5.0v,在应用的时候,做好不要直接接电源,而是通过一个PNP三极管,三极管的基极接单片机的引脚,集电极通过一个电阻接地,发射级直接接电源,而VCC引脚则接在集电极上,其实就是个最简单的三极管开关电路,如下图所示:
ATK-HC05蓝牙模块的详细说明 - ziye334 - ziye334的博客

 
2、GND:这个没什么好说的,直接接地就好了
3、TXD:模块串口发送引脚(TTL电平,不能直接接RS232电平),可直接接单片机的RXD引脚
4、RXD:模块串口接收引脚(TTL电平,不能直接接RS232电平),可直接接单片机的TXD引脚
5、KEY:用于进入AT状态:高电平有效(悬空默认为低电平),在应用中,该引脚应该受单片机的引脚控制,当单片机的引脚有上拉电阻式,可以直接接KEY引脚,如果没有,就要像VCC引脚一样,通过一个三极管间接控制:如下图
ATK-HC05蓝牙模块的详细说明 - ziye334 - ziye334的博客

6、LED:这个引脚是用来检测蓝牙模块是否已经连接上了其他蓝牙设备的,连接成功输出高电平,没有连接上输出低电平,可以用单片机的引脚来检测是否连接上,在应用程序中有很重要的作用,当然也可以接一个上拉过的LED灯,这样就可以观察到蓝牙模块是否连接。

模块自带了一个状态指示灯STA,该灯有3种状态,分别为:
1、在模块上电的同时(也可以是之前),将 KEY 设置为高电平(接 VCC),此时 STA慢闪(1秒亮1次),模块进入AT状态,且此时波特率固定为38400.
2、在模块上电的时候,将KEY悬空或接GND,此时STA快闪(1秒2次),表示模块进入可配对状态。如果此时将KEY在拉高,模块也会进入AT状态,但是STA依旧保持快闪。
3模块连接成功,此时STA双闪(1秒2下,2秒1次)

模块的相关资料,大家参考 ,关于模块的一些细节的东西就不说了!!!

接下去主要是结合蓝牙模块的AT指令,讲些应用,很多是手册不会讲的,都是鄙人实验出来的,这里说些重要的AT指令。
1、AT+RESET:该指令顾名思义,是复位HC05蓝牙设备的,蓝牙模块复位后,当然原来连接也就断开了,模块处于INITIALIZED状态,还需要注意的是,如果在用MCU的串口给蓝牙模块发送复位命令,一定要注意发送复位命令1s后才能继续发送其他命令,因为如果你1s内发送其他命令,此时蓝牙模块可能还在复位中,没法响应命令。当然,如果你是用串口工具发送,一般发送两个命令的间隔不会太短。
>AT+RESET\r\n
OK

2、AT+INIT:该指令初始化SPP规范库,所谓的SPP就是蓝牙串口端口协议,总之,没有初始化SPP库就没发扫描周围的蓝牙设备,没有与摸个蓝牙设备连接。,所以,在应用程序中,一定要初始化SPP库,没有初始化SPP库,就发送扫描指令或连接指令,蓝牙模块会返回ERROR:(16)错误,表示没有初始化SPP库。还有个要注意的是,如果发送多次该指令,蓝牙模块会放回ERROR:(17)重复初始化错误。还有,每次断电后再上电或蓝牙模块复位后,都要重新初始化SPP库。
>AT+INIT\r\n
OK         //正确
FALL //失败
ERROR:(17) //重复初始化

3、AT+ROLE:该指令用于选择HC05蓝牙模块的角色,总共有三种角色:master,slave,loop-slave.
AT+ROLE=0\r\n  将蓝牙模块设置成从角色,只能被动连接
AT+ROLE=1\r\n  将蓝牙模块设置成主角色,可以查询周围SPP蓝牙从设备,并发送连接
AT+ROLE=2\r\n  将蓝牙模块设置成回环角色,被动连接,接收远程蓝牙模块主设备数据并将数据原样返回给远程蓝牙设备
       这几个指令用在不同的场合,当设置蓝牙模块为从设备的时候,可以用手机的相关蓝牙装串口软件连接该设备,进行通讯;当设置成主角色的时候,可以搜索周遭的蓝牙从设备,并连接,这种模式在应用中很常用;回环角色很多时候都是用来做测试用的。
>AT+ROLE=1\r\n
OK

4、AT+PSWD:这个指令时设置蓝牙模块的配对密码,蓝牙模块在做从模块的时候,如果用手机要连接该蓝牙设备,就要键入蓝牙的配对密码才能连接,比如说HC05默认的配对密码是1234,那么就要在手机的输入该配对密码1234才能连接我们的HC05;如果我们的HC05做主模块扫到周围有个蓝牙从设备,这时候想连接该蓝牙从设备该怎么办呢?这个问题也曾经困扰过我很久,因为我一直以为,我用AT+LINK=蓝牙地址  该命令去连接蓝牙从设备,从设备就会发送一些数据叫你键入配对密码,而HC05的AT指令没有发送配对密码的指令,结果搞得我一头雾水,最后都咨询到厂家那里去了,厂家的技术人员终于给了正解。原来你要连接某个蓝牙从设备,就要把自己的蓝牙模块的配对密码设置成蓝牙从设备的配对密码配置成一样。举例说我两块HC05蓝牙模块,蓝牙A设置成主机,蓝牙B设置成从机,原来蓝牙A的配对密码是1234,而蓝牙B的配对密码是2345,此时你就要将蓝牙A的配置密码设置成2345才能连接上蓝牙B.
>AT+PSWD=1234\r\n
OK
 
5、AT_UART:这个指令是设置串口的参数,指令的格式如下:
AT+UART=,,\r\n
Param:波特率,一些常用的波特率都可以设置
Param1:停止位,一般设置成0,表示为1个停止位
Param2:校验位,一帮设置为0,表示不用校验
该指令是设置蓝牙模块与蓝牙模块之间通讯时,蓝牙模块的串口参数。HC05模块在默认的配置下是设置成9600,也就是说,在AT模式下,我们用38400与HC05通讯,而在HC05与某蓝牙模块通讯时,则我们用9600的波特率接收HC05从蓝牙模块的接收到的数据。这里建议将波特率改为38400,这是因为,当用串口调试工具连接HC05时,AT模式是用38400波特率,而连接后默认是9600,这样的不断的切换串口调试工具的波特率,会很麻烦,所以设置成38400后,就方便调试了。
>AT+UART=38400,0,0\r\n
OK

6、AT+INQM:设置或查询访问模式,格式如此:
AT+INQM=,,\r]n
Param:0——inquiry_mode_standard,1——inquiry_mode_rssi,表示标准查询还是带信号强度的查询。
Param1:最多蓝牙设备响应的数量
Param2:最大查询时间(1~48,折合成时间,1,28s~61.44s)
将这个指令是为扫描指令做铺垫,根据自己的实际情况调整。
>AT+INQM=1,1,15
OK

7、AT+INQ:查询蓝牙设备,返回的格式如下:
+INQ:,,....
Param:蓝牙地址
Param1:设备类
Param2:RSSI信号强度
举个例子:+INQ:98D3:31:500DF8,1F00,7FFF,
98D3:31:500DF8表示蓝牙的地址,这里有需要补充下蓝牙的相关知识,蓝牙地址的由NAP(24位地址低端部分):UAP(8为地址高端部分):LAP(16为无意义地址部分),所以该地址:98D3表示LAP,31表示UAP,500DF8表示LAP
>AT+INQ 
+INQ:98D3:31:500DF8,1F00,7FFF //有的话列出 
OK
 
8、AT+RNAME:这个指令获得远端蓝牙设备的名字,我们手机上看到的就是这个名字,而不会直接给出蓝牙设备地址
>AT+RNAME?98D3,31,500DF8   //主要这里是逗号,而不是冒号
+RNAME:EST527
OK

9、AT+LINK:这个命令连接远程设备蓝牙,其实没有什么好说的,连接上后,LED引脚输出高电平,如果该引脚有接上拉LED灯,则会发现LED灭了。
>AT+LINK=98D3,31,500DF8
OK


10、AT+STATE:这个指令用来查询蓝牙模块当前的状态,状态种类如下:
INITIALIZED——初始化状态
READY——准备状态
PAIRABLE——可配对状态
PAIRED——配对状态
INQUIRING——查询状态
CONNECTING——正在连接状态
CONNECTED——连接状态
DISCONNECTED——断开连接
UNKNOW————位置状态

>AT+STATE
+STATE:INITIALIZED
OK

+STATE:PAIRED
OK

11、AT+CMODE:这个指令其实很重要。
AT+CMODE=0\r\n  指定蓝牙地址连接模式(指定蓝牙地址呦绑定指令设置)
AT+CMODE=1\r\n  任意蓝牙地址连接模式(不受绑定指令的设置地址约束)
AT+CMODE=2\r\n  回环角色
        为0时,该指令设置模块为指定地址配对,如果先设置模块为任意地址,然后配对,接下去使用该指令,则模块会记忆最后一次配对的地址,下次上电会一直搜索该地址的模块,直到搜索到为止。
为1时,该指令设置模块可以对任意地址的蓝牙模块进行配对,只要有模块的配对秘钥跟自己的一样的就能自动连上。
AT+CMODE=1\r\n
OK


最后想讲讲关于这些蓝牙装串口模块或WIFI转串口模块的编程。
准备好工程,已经设置好了串口配置,最好能有两个串口,串口1用来发送AT指令,串口2则用来打印一些调试信息信息,还有配置一个定时器。
串口1的波特率设置成38400,1个停止位,没有校验位,编写发送函数,比如我以stm32为例:

void USART1SendStr(char *str) { while(*str!='\0') { USART_SendData(USART1,*str); while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);/*等待发送完成*/ str++; } }

最好在某个头文件里定义下  #define ATSendCmd(x) USART1SendStr(x)  用ATSendCmd()来发送AT指令
        串口2最为调试用,连接上标准库,然后使用printf函数发送调试信息!

	

/*----------------------跟编译器相关,连接标准C库----------------------*/ #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif



/******************************************************** 函数:PUTCHAR_PROTOTYPE 描述:连接标准C库的printf函数 参数:无 返回:无 ********************************************************/ PUTCHAR_PROTOTYPE { USART_SendData(USART2, (uint8_t) ch); while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET){} return ch; }

如上,这样就能使用printf函数了,要学会在编程时候常使用printf函数,显示函数的情况与进程,当发生错误时,这样就能很精准的定位错误位置了。最好还要定义一个宏定义 #define DEBUG     在写printf时最好如下写法:

	

#ifdef DEBUG

printf("xxxxxxxxxxxxx");

#endif

这样的写法,就起了一个宏开关的作用,只要屏蔽#define DEBUG 就能关闭调试信息了。

因为像蓝牙装串口模块这样的独立模块,我们单片机发送配置指令时,必须收到配置成功相关回应是,才能接下去发送命令,但是如果我们单片机发送命令,结果蓝牙模块没有回应,我们程序就废了,要么无限等待,要么继续发送可能没有响应的指令。所以,我们必须设置一个重传机制,和一个超时机制。重传机制用在,我们给蓝牙模块发送命令,结果蓝牙有响应,但是回来的响应错误,这是就要重传指令;而超时机制则是,我们单片机给蓝牙模块发送命令,而蓝牙模块没有响应,我们等超时时间到了之后,再重新发送命令,如果连续好几次失败,则需要程序复位下了!!!
所以我们还需要一个定时器,定时时间这里设置为1s,要写个设置超时时间的函数:

	

u16 timeCnt=0; extern u8 timeOut;


/******************************************************** 函数:SetTimeOut() 描述:设置超时时间 参数:无 返回:无 ********************************************************/ void SetTimeOut(u16 timeout) { timeCnt=timeout; timeOut=0; TIM_Cmd(TIM2,ENABLE); }

还要写个定时器中断服务函数:

	

void TIM2_IRQHandler(void) { if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//检测是否发生溢出更新事件 { //清除TIM2的中断待处理位  TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update); LED1_Toggle(); if(timeCnt!=0) { timeOut=0; printf("."); timeCnt--; } else { timeOut=1; printf("\r\n定时时间到!\r\n"); TIM_Cmd(TIM2,DISABLE); } } }

在中断服务程序中,一旦超时时间到了,就要关闭定时器,等待下一次设置超时时间再打开。
接下去就是指令的发送函数了,我以发送reset命令为例:

	

/******************************************************** 函数:HC05_Reset 描述:复位蓝牙模块 参数:无 返回:无 ********************************************************/ void HC05_Reset(void) { ATSendCmd("AT+RESET\r\n"); curStat=CRESET; //当前状态设置为CRESET SetTimeOut(6); //设置定时时间为4s while(curStat!=NOCMD) //等待蓝牙模块响应 { if(tryAgain ||timeOut)//重新发送命令 { printf("蓝牙模块复位失败,重试中!\r\n"); tryAgain=0; ATSendCmd("AT+RESET\r\n"); SetTimeOut(6); //重新设置定时时间为4s } } CloseTimer(); //关闭定时器 Delay_ms(1000); printf("蓝牙模块复位成功!\r\n"); }

 这里的curStat的状态是在串口接收程序程序里改变的,如果接收正确curStat=NOCMD,如果接收失败,则tryAgain置1,。
阅读(3450) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~