[STM32F1] 【HAL库每天一例】第086例:HC-05蓝牙模块_手机APP控制开发板

[复制链接]
2121|2
 楼主| 亼亽 发表于 2016-8-7 11:33 | 显示全部楼层 |阅读模式
【HAL库每天一例】系列例程从今天开始持续更新。。。。。
我们将**每天至少发布一个基于YS-F1Pro开发板的HAL库例程,
该系列例程将带领大家从零开始使用HAL库,后面会持续添加模块应用例程。
同样的,我们还程序发布基于HAL库的指导文档和视频教程,欢迎持续关注,并提出改进意见。

例程下载:
资料包括程序、相关说明资料以及软件使用截图

百度云盘:https://pan.baidu.com/s/1slN8rIt 密码:u6m1
360云盘:https://yunpan.cn/OcPiRp3wEcA92u密码 cfb6
(硬石YS-F1Pro开发板HAL库例程持续更新\2. 软件设计之高级裸机例程(HAL库版本)\YSF1_HAL-119. HC-05蓝牙模块_手机APP控制开发板
/**
  ******************************************************************************
  *                           硬石YS-F1Pro开发板例程功能说明
  *
  *  例程名称: YSF1_HAL-119. HC-05蓝牙模块_手机APP控制开发板
  *   
  ******************************************************************************
  * 说明:
  * 本例程配套硬石stm32开发板YS-F1Pro使用。
  *
  * 淘宝:
  * 论坛:http://www.ing10bbs.com
  * 版权归硬石嵌入式开发团队所有,请勿商用。
  ******************************************************************************
  */

【1】例程简介
  HC05是一款高性能主从一体蓝牙串口模块,可以同各种带蓝牙功能的电脑、蓝牙主机、手机等智能
终端配置,默认比特率为38400,模块兼容5V或3.3V单片机系统,可以很方便的和自己的终端相连接
  
【2】跳线帽情况
******* 为保证例程正常运行,必须插入以下跳线帽 **********
丝印编号     IO端口      目标功能引脚        出厂默认设置
  JP1        PA10        TXD(CH340G)          已接入
  JP2        PA9         RXD(CH340G)          已接入
  CN10       PA2         RX(HC05)             已接入
  CN10       PA3         TX(HCO5)             已接入
【3】操作及现象
    使用开发板配套的MINI USB线连接到开发板标示“调试串口”字样的MIMI USB接口(需要安
装驱动),在电脑端打开串口调试助手工具,设置参数为115200 8-N-1,下载程序,按下模块上
的按键。打开手机APP,搜索连接蓝牙模块,默认密码为:1234,连接后即可发送指令控制开发板

/******************* (C) COPYRIGHT 2015-2020 硬石嵌入式开发团队 *****END OF FILE****/

CubeMX_1.jpg
CubeMX_2.jpg
CubeMX_3.jpg
CubeMX_4.jpg
CubeMX_5.jpg
CubeMX_6.jpg


bsp_hc05.c
  1. /**
  2.   ******************************************************************************
  3.   * 文件名程: bsp_usartx.c
  4.   * 作    者: 硬石嵌入式开发团队
  5.   * 版    本: V1.0
  6.   * 编写日期: 2015-10-04
  7.   * 功    能: 串口底层驱动程序
  8.   ******************************************************************************
  9.   * 说明:
  10.   * 本例程配套硬石stm32开发板YS-F1Pro使用。
  11.   *
  12.   * 淘宝:
  13.   * 论坛:http://www.ing10bbs.com
  14.   * 版权归硬石嵌入式开发团队所有,请勿商用。
  15.   ******************************************************************************
  16.   */
  17. /* 包含头文件 ----------------------------------------------------------------*/
  18. #include "hc05/bsp_hc05.h"
  19. #include "usart/bsp_usartx.h"
  20. #include <string.h>
  21. #include <stdio.h>

  22. /* 私有类型定义 --------------------------------------------------------------*/
  23. /* 私有宏定义 ----------------------------------------------------------------*/
  24. /* 私有变量 ------------------------------------------------------------------*/
  25. /* 扩展变量 ------------------------------------------------------------------*/
  26. extern  BLTDev bltDevList;   //蓝牙设备列表,在main文件中定义

  27. /* 私有函数原形 --------------------------------------------------------------*/
  28. /* 函数体 --------------------------------------------------------------------*/

  29. /**
  30.   * 函数功能: 初始化HC05 IO
  31.   * 输入参数: 无
  32.   * 返 回 值: 无
  33.   * 说    明:无
  34.   */
  35. static void HC05_GPIO_Config(void)
  36. {       
  37.   GPIO_InitTypeDef GPIO_InitStruct;
  38.   
  39.   HC05_EN_GPIO_CLK();
  40.   
  41.   GPIO_InitStruct.Pin = HC05_EN_GPIO_PIN;
  42.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  43.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  44.   HAL_GPIO_Init(HC05_EN_GPIO_PORT, &GPIO_InitStruct);  
  45.   
  46.   HAL_GPIO_WritePin(HC05_EN_GPIO_PORT,HC05_EN_GPIO_PIN,GPIO_PIN_RESET);       

  47. }

  48. /**
  49.   * 函数功能: 向HC05模块发送命令并检查OK。只适用于具有OK应答的命令
  50.   * 输入参数: cmd:待发送命令
  51.   *           clean:1:清除接收缓冲区内容
  52.   *                  0:保留接收缓冲区内容
  53.   * 返 回 值: 命令应答状态:1:无OK应答
  54.   *                         0:成功发送并接收到OK应答
  55.   * 说    明:无
  56.   */
  57. uint8_t HC05_Send_CMD(char* cmd,uint8_t clean)
  58. {                          
  59.         uint8_t retry=5;
  60.         uint8_t i;
  61.        
  62.         while(retry--)
  63.         {
  64.                 HC05_EN_HIGHT();
  65.                 HAL_Delay(10);
  66.                 //HAL_UART_Transmit(&husartx_rs485,(uint8_t *)cmd,strlen(cmd),1000);
  67.                         Usart_SendString((uint8_t *)cmd);
  68.     for(i=0;i<20;i++)
  69.     {
  70.       uint16_t len;
  71.       char * redata;
  72.       
  73.       HAL_Delay(10);      
  74.       redata = get_rebuff(&len);
  75.       if(len>0)
  76.       {
  77.         if(redata[0]!=0)
  78.         {
  79.           HC05_DEBUG("send CMD: %s",cmd);
  80.           HC05_DEBUG("receive %s",redata);
  81.         }
  82.         if(strstr(redata,"OK"))                               
  83.         {         
  84.           if(clean==1)
  85.             clean_rebuff();
  86.           return 0;
  87.         }
  88.       }
  89.       else
  90.       {                                       
  91.         HAL_Delay(100);
  92.       }               
  93.     }
  94.     HC05_DEBUG("HC05 send CMD fail %d times",retry);
  95.   }       
  96.         HC05_DEBUG("HC05 send CMD fail ");
  97.         if(clean==1)
  98.                 clean_rebuff();
  99.         return 1 ;
  100. }

  101. /**
  102.   * 函数功能: 使用HC05透传字符串数据
  103.   * 输入参数: str,要传输的字符串
  104.   * 返 回 值: 无
  105.   * 说    明:无
  106.   */
  107. void HC05_SendString(char* str)
  108. {
  109.         Usart_SendString((uint8_t *)str);
  110. //HAL_UART_Transmit(&husartx_rs485,(uint8_t *)str,strlen(str),1000);
  111. }

  112. /**
  113.   * 函数功能: 初始化GPIO及检测HC05模块
  114.   * 输入参数: 无
  115.   * 返 回 值: 无
  116.   * 说    明:无
  117.   */
  118. void HC05_Init(void)
  119. {
  120.         uint8_t i;       
  121.         HC05_GPIO_Config();
  122.         HC05_USARTx_Init();       
  123.         for(i=0;i<BLTDEV_MAX_NUM;i++)
  124.         {
  125.                 sprintf(bltDevList.unpraseAddr[i]," ");
  126.                 sprintf(bltDevList.name[i]," ");
  127.         }       
  128.         bltDevList.num = 0;
  129. }

  130. /**
  131.   * 函数功能: 把接收到的字符串转化成16进制形式的数字变量(主要用于转化蓝牙地址)
  132.   * 输入参数: str:待转换字符串
  133.   * 返 回 值: 无
  134.   * 说    明:无
  135.   */
  136. unsigned long htoul(const char *str)
  137. {
  138.   long result = 0;

  139.   if (!str)
  140.     return 0;

  141.   while (*str)
  142.   {
  143.     uint8_t value;

  144.     if (*str >= 'a' && *str <= 'f')
  145.       value = (*str - 'a') + 10;
  146.     else if (*str >= 'A' && *str <= 'F')
  147.       value = (*str - 'A') + 10;
  148.     else if (*str >= '0' && *str <= '9')
  149.       value = *str - '0';
  150.     else
  151.       break;

  152.     result = (result * 16) + value;
  153.     ++str;
  154.   }
  155.   return result;
  156. }


  157. /**
  158.   * 函数功能: 在str中,跳过它前面的prefix字符串,
  159.   * 输入参数: 无
  160.   * 返 回 值: 无
  161.   * 说    明:无
  162.   */
  163. char *skipPrefix(char *str, size_t str_length, const char *prefix)
  164. {
  165.   uint16_t prefix_length = strlen(prefix);
  166.   if (!str || str_length == 0 || !prefix)
  167.     return 0;
  168.   if (str_length >= prefix_length && strncmp(str, prefix, prefix_length) == 0)
  169.     return str + prefix_length;
  170.   return 0;
  171. }

  172. /**
  173.   * 函数功能: 从stream中获取一行字符串到line中
  174.   * 输入参数: line,存储获得行的字符串数组
  175.   *           stream,原字符串数据流       max_size,stream的大小   
  176.   * 返 回 值: line的长度,若stream中没有‘\0’,'\r','\n',则返回0
  177.   * 说    明:无
  178.   */
  179. int get_line(char* line, char* stream ,int max_size)  
  180. {  
  181.   char *p;       
  182.   int len = 0;  
  183.   p=stream;
  184.   while( *p != '\0' && len < max_size )
  185.   {  
  186.     line[len++] = *p;  
  187.     p++;
  188.     if('\n' == *p || '\r'==*p)  
  189.         break;  
  190.   }
  191.   if(*p != '\0' && *p != '\n' && *p != '\r')
  192.     return 0;
  193.   line[len] = '\0';  
  194.   return len;  
  195. }

  196. /**
  197.   * 函数功能: 向HC05写入命令,不检查模块的响应
  198.   * 输入参数: arg,命令参数,为0时不带参数,若command也为0时,发送"AT"命令
  199.   * 返 回 值: 无
  200.   * 说    明:无
  201.   */
  202. void writeCommand(const char *command, const char *arg)
  203. {
  204.   char str_buf[50];

  205.   HC05_EN_HIGHT();
  206.   HAL_Delay(10);

  207.   if (arg && arg[0] != 0)
  208.     sprintf(str_buf,"AT+%s%s\r\n",command,arg);
  209.   else if (command && command[0] != 0)
  210.   {
  211.     sprintf(str_buf,"AT+%s\r\n",command);
  212.   }
  213.   else
  214.     sprintf(str_buf,"AT\r\n");
  215.   
  216.   HC05_DEBUG("CMD send:%s",str_buf);
  217.   Usart_SendString((uint8_t *)str_buf);
  218. // HAL_UART_Transmit(&husartx_rs485,(uint8_t *)str_buf,strlen(str_buf),1000);
  219. }


  220. /**
  221.   * 函数功能: 扫描周边的蓝牙设备,并存储到设备列表中
  222.   * 输入参数: 无
  223.   * 返 回 值: 无
  224.   * 说    明:无
  225.   */
  226. uint8_t parseBluetoothAddress(BLTDev *bltDev)
  227. {
  228.   /* Address should look like "+ADDR:<NAP>:<UAP>:<LAP>",
  229.    * where actual address will look like "1234:56:abcdef".
  230.    */
  231.         char* redata;
  232.         uint16_t len;
  233.         char linebuff[50];
  234.         uint16_t linelen;
  235.         uint16_t getlen=0;
  236.         uint8_t linenum=0;       
  237.         uint8_t i;
  238.         char *p;

  239.         HC05_Send_CMD("AT+INQ\r\n",0);
  240.         redata =get_rebuff(&len);
  241.         if(redata[0] != 0 && strstr(redata, "+INQ:") != 0)
  242.         {
  243.                 HC05_DEBUG("rebuf =%s",redata);

  244. getNewLine:
  245.                 while(getlen < len-2*linenum )
  246.                 {       
  247.                         linelen = get_line(linebuff,redata+getlen+2*linenum,len);
  248.                         if(linelen>50 && linelen != 0)
  249.                         {
  250.                                 HC05_Send_CMD("AT+INQC\r\n",1);//退出前中断查询
  251.                                 return 1;
  252.                         }
  253.                         getlen += linelen;
  254.                         linenum++;                       
  255.                         p = skipPrefix(linebuff,linelen,"+INQ:");
  256.                         if(p!=0)
  257.                         {
  258.                                 uint8_t num ;
  259.                                 num = bltDev->num;
  260.                                 strBLTAddr(bltDev,':');
  261.                                 for(i=0;i<=num;i++)
  262.                                 {
  263.                                         if(strstr(linebuff,bltDev->unpraseAddr[i]) != NULL)       
  264.                                         {
  265.                                                 goto getNewLine;        //!=null时,表示该地址与解码语句的地址相同
  266.                                         }
  267.                                 }                                                       
  268.                                 /*若蓝牙设备不在列表中,对地址进行解码*/       
  269.                                 bltDev->addr[num].NAP = htoul(p);                       
  270.                                 p = strchr(p,':');

  271.                                 if (p == 0)
  272.                                 {
  273.                                         HC05_Send_CMD("AT+INQC\r\n",1);//退出前中断查询
  274.                                         return 1;
  275.                                 }
  276.                                 bltDev->addr[num].UAP = htoul(++p);
  277.                                 p = strchr(p,':');
  278.                                 if (p == 0)
  279.                                 {
  280.                                         HC05_Send_CMD("AT+INQC\r\n",1);//退出前中断查询
  281.                                         return 1;
  282.                                 }
  283.                                 bltDev->addr[num].LAP = htoul(++p);
  284.                                 /*存储蓝牙地址(字符串形式)*/
  285.                                 sprintf(bltDev->unpraseAddr[num],"%X:%X:%X",bltDev->addr[num].NAP,bltDev->addr[num].UAP,bltDev->addr[num].LAP);
  286.                                 bltDev->num++;
  287.                         }
  288.                 }
  289.                 clean_rebuff();
  290.                 HC05_Send_CMD("AT+INQC\r\n",1);//退出前中断查询
  291.                 return 0;
  292.         }       
  293.         else
  294.         {
  295.                 clean_rebuff();
  296.                 HC05_Send_CMD("AT+INQC\r\n",1);//退出前中断查询
  297.                 return 1;       
  298.         }
  299. }

  300. /**
  301.   * 函数功能: 把蓝牙地址转化成字符串形式
  302.   * 输入参数: 无
  303.   * 返 回 值: 无
  304.   * 说    明:无
  305.   */
  306. void strBLTAddr(BLTDev *bltDev,char delimiter)  
  307. {
  308.         uint8_t i;
  309.        
  310.         if(bltDev->num==0)
  311.         {
  312.                 HC05_DEBUG("/*******No other BLT Device********/");
  313.         }
  314.         else
  315.         {
  316.                 for(i=0;i<bltDev->num;i++)
  317.                 {
  318.                         sprintf(bltDev->unpraseAddr[i],"%X%c%X%c%X",bltDev->addr[i].NAP,delimiter,bltDev->addr[i].UAP,delimiter,bltDev->addr[i].LAP);
  319.                 }
  320.         }
  321. }

  322. /**
  323.   * 函数功能: 获取远程蓝牙设备的名称
  324.   * 输入参数: bltDev ,蓝牙设备列表指针
  325.   * 返 回 值: 0获取成功,非0不成功
  326.   * 说    明:无
  327.   */
  328. uint8_t getRemoteDeviceName(BLTDev *bltDev)
  329. {
  330.         uint8_t i;
  331.         char *redata;
  332.         uint16_t len;
  333.        
  334.         char linebuff[50];
  335.         uint16_t linelen;
  336.         char *p;
  337.        
  338.         char cmdbuff[100];
  339.        
  340.         strBLTAddr(bltDev,',');

  341.         HC05_DEBUG("device num =%d",bltDev->num);
  342.        
  343.         for(i=0;i<bltDev->num;i++)
  344.         {
  345.                 sprintf(cmdbuff,"AT+RNAME?%s\r\n",bltDev->unpraseAddr[i]);
  346.                 HC05_Send_CMD(cmdbuff,0);
  347.                 redata =get_rebuff(&len);
  348.                 if(redata[0] != 0 && strstr(redata, "OK") != 0)
  349.                 {
  350.                         linelen = get_line(linebuff,redata,len);
  351.                         if(linelen>50 && linelen !=0 ) linebuff[linelen]='\0';        //超长截断
  352.                                        
  353.                         p = skipPrefix(linebuff,linelen,"+RNAME:");
  354.                         if(p!=0)
  355.                         {
  356.                                 strcpy(bltDev->name[i],p);
  357.                         }
  358.                 }
  359.                 else
  360.                 {
  361.                         clean_rebuff();
  362.                         return 1;       
  363.                 }
  364.                 clean_rebuff();
  365.         }
  366.         return 0;
  367. }

  368. /**
  369.   * 函数功能: 输出蓝牙设备列表
  370.   * 输入参数: 无
  371.   * 返 回 值: 无
  372.   * 说    明:无
  373.   */
  374. void printBLTInfo(BLTDev *bltDev)  
  375. {
  376.         uint8_t i;
  377.         if(bltDev->num==0)
  378.         {
  379.                 HC05_DEBUG("/*******No remote BLT Device or in SLAVE mode********/");
  380.         }
  381.         else
  382.         {
  383.                 HC05_DEBUG("扫描到 %d 个蓝牙设备",bltDev->num);

  384.                 for(i=0;i<bltDev->num;i++)
  385.                 {
  386.                         HC05_INFO("/*******Device[%d]********/",i);       
  387.                         HC05_INFO("Device Addr: %s",bltDev->unpraseAddr[i]);
  388.                         HC05_INFO("Device name: %s",bltDev->name[i]);
  389.                 }
  390.         }
  391. }

  392. /**
  393.   * 函数功能: 扫描蓝牙设备,并连接名称中含有"HC05"的设备
  394.   * 输入参数: 无
  395.   * 返 回 值: 0获取成功,非0不成功
  396.   * 说    明:无
  397.   */
  398. uint8_t linkHC05(void)
  399. {
  400.         uint8_t i=0;
  401.         char cmdbuff[100];
  402.        
  403.         parseBluetoothAddress(&bltDevList);
  404.         getRemoteDeviceName(&bltDevList);
  405.         printBLTInfo(&bltDevList);
  406.        
  407.         for(i=0;i<=bltDevList.num;i++)
  408.         {
  409.                 if(strstr(bltDevList.name[i],"HC05") != NULL) //非NULL表示找到有名称部分为HC05的设备
  410.                 {
  411.                         HC05_INFO("搜索到远程HC05模块,即将进行配对连接...");
  412.                         strBLTAddr(&bltDevList,',');               
  413.                         //配对
  414.                         sprintf(cmdbuff,"AT+PAIR=%s,20\r\n",bltDevList.unpraseAddr[i]);
  415.                         HC05_Send_CMD(cmdbuff,0);
  416.                         //连接       
  417.                         sprintf(cmdbuff,"AT+LINK=%s\r\n",bltDevList.unpraseAddr[i]);
  418.                         return HC05_Send_CMD(cmdbuff,0);               
  419.                 }
  420.         }
  421.         return 1;
  422. }

串口调试助手截图.jpg

mmuuss586 发表于 2016-8-7 12:52 | 显示全部楼层
谢谢分享!
gxx-c 发表于 2016-8-7 13:48 | 显示全部楼层
您需要登录后才可以回帖 登录 | 注册

本版积分规则

122

主题

216

帖子

48

粉丝
快速回复 在线客服 返回列表 返回顶部