打印
[STM32F1]

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

[复制链接]
1699|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****/









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

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

/* 私有函数原形 --------------------------------------------------------------*/
/* 函数体 --------------------------------------------------------------------*/

/**
  * 函数功能: 初始化HC05 IO
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
static void HC05_GPIO_Config(void)
{       
  GPIO_InitTypeDef GPIO_InitStruct;
  
  HC05_EN_GPIO_CLK();
  
  GPIO_InitStruct.Pin = HC05_EN_GPIO_PIN;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(HC05_EN_GPIO_PORT, &GPIO_InitStruct);  
  
  HAL_GPIO_WritePin(HC05_EN_GPIO_PORT,HC05_EN_GPIO_PIN,GPIO_PIN_RESET);       

}

/**
  * 函数功能: 向HC05模块发送命令并检查OK。只适用于具有OK应答的命令
  * 输入参数: cmd:待发送命令
  *           clean:1:清除接收缓冲区内容
  *                  0:保留接收缓冲区内容
  * 返 回 值: 命令应答状态:1:无OK应答
  *                         0:成功发送并接收到OK应答
  * 说    明:无
  */
uint8_t HC05_Send_CMD(char* cmd,uint8_t clean)
{                          
        uint8_t retry=5;
        uint8_t i;
       
        while(retry--)
        {
                HC05_EN_HIGHT();
                HAL_Delay(10);
                //HAL_UART_Transmit(&husartx_rs485,(uint8_t *)cmd,strlen(cmd),1000);
                        Usart_SendString((uint8_t *)cmd);
    for(i=0;i<20;i++)
    {
      uint16_t len;
      char * redata;
      
      HAL_Delay(10);      
      redata = get_rebuff(&len);
      if(len>0)
      {
        if(redata[0]!=0)
        {
          HC05_DEBUG("send CMD: %s",cmd);
          HC05_DEBUG("receive %s",redata);
        }
        if(strstr(redata,"OK"))                               
        {         
          if(clean==1)
            clean_rebuff();
          return 0;
        }
      }
      else
      {                                       
        HAL_Delay(100);
      }               
    }
    HC05_DEBUG("HC05 send CMD fail %d times",retry);
  }       
        HC05_DEBUG("HC05 send CMD fail ");
        if(clean==1)
                clean_rebuff();
        return 1 ;
}

/**
  * 函数功能: 使用HC05透传字符串数据
  * 输入参数: str,要传输的字符串
  * 返 回 值: 无
  * 说    明:无
  */
void HC05_SendString(char* str)
{
        Usart_SendString((uint8_t *)str);
//HAL_UART_Transmit(&husartx_rs485,(uint8_t *)str,strlen(str),1000);
}

/**
  * 函数功能: 初始化GPIO及检测HC05模块
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
void HC05_Init(void)
{
        uint8_t i;       
        HC05_GPIO_Config();
        HC05_USARTx_Init();       
        for(i=0;i<BLTDEV_MAX_NUM;i++)
        {
                sprintf(bltDevList.unpraseAddr[i]," ");
                sprintf(bltDevList.name[i]," ");
        }       
        bltDevList.num = 0;
}

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

  if (!str)
    return 0;

  while (*str)
  {
    uint8_t value;

    if (*str >= 'a' && *str <= 'f')
      value = (*str - 'a') + 10;
    else if (*str >= 'A' && *str <= 'F')
      value = (*str - 'A') + 10;
    else if (*str >= '0' && *str <= '9')
      value = *str - '0';
    else
      break;

    result = (result * 16) + value;
    ++str;
  }
  return result;
}


/**
  * 函数功能: 在str中,跳过它前面的prefix字符串,
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
char *skipPrefix(char *str, size_t str_length, const char *prefix)
{
  uint16_t prefix_length = strlen(prefix);
  if (!str || str_length == 0 || !prefix)
    return 0;
  if (str_length >= prefix_length && strncmp(str, prefix, prefix_length) == 0)
    return str + prefix_length;
  return 0;
}

/**
  * 函数功能: 从stream中获取一行字符串到line中
  * 输入参数: line,存储获得行的字符串数组
  *           stream,原字符串数据流       max_size,stream的大小   
  * 返 回 值: line的长度,若stream中没有‘\0’,'\r','\n',则返回0
  * 说    明:无
  */
int get_line(char* line, char* stream ,int max_size)  
{  
  char *p;       
  int len = 0;  
  p=stream;
  while( *p != '\0' && len < max_size )
  {  
    line[len++] = *p;  
    p++;
    if('\n' == *p || '\r'==*p)  
        break;  
  }
  if(*p != '\0' && *p != '\n' && *p != '\r')
    return 0;
  line[len] = '\0';  
  return len;  
}

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

  HC05_EN_HIGHT();
  HAL_Delay(10);

  if (arg && arg[0] != 0)
    sprintf(str_buf,"AT+%s%s\r\n",command,arg);
  else if (command && command[0] != 0)
  {
    sprintf(str_buf,"AT+%s\r\n",command);
  }
  else
    sprintf(str_buf,"AT\r\n");
  
  HC05_DEBUG("CMD send:%s",str_buf);
  Usart_SendString((uint8_t *)str_buf);
// HAL_UART_Transmit(&husartx_rs485,(uint8_t *)str_buf,strlen(str_buf),1000);
}


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

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

getNewLine:
                while(getlen < len-2*linenum )
                {       
                        linelen = get_line(linebuff,redata+getlen+2*linenum,len);
                        if(linelen>50 && linelen != 0)
                        {
                                HC05_Send_CMD("AT+INQC\r\n",1);//退出前中断查询
                                return 1;
                        }
                        getlen += linelen;
                        linenum++;                       
                        p = skipPrefix(linebuff,linelen,"+INQ:");
                        if(p!=0)
                        {
                                uint8_t num ;
                                num = bltDev->num;
                                strBLTAddr(bltDev,':');
                                for(i=0;i<=num;i++)
                                {
                                        if(strstr(linebuff,bltDev->unpraseAddr[i]) != NULL)       
                                        {
                                                goto getNewLine;        //!=null时,表示该地址与解码语句的地址相同
                                        }
                                }                                                       
                                /*若蓝牙设备不在列表中,对地址进行解码*/       
                                bltDev->addr[num].NAP = htoul(p);                       
                                p = strchr(p,':');

                                if (p == 0)
                                {
                                        HC05_Send_CMD("AT+INQC\r\n",1);//退出前中断查询
                                        return 1;
                                }
                                bltDev->addr[num].UAP = htoul(++p);
                                p = strchr(p,':');
                                if (p == 0)
                                {
                                        HC05_Send_CMD("AT+INQC\r\n",1);//退出前中断查询
                                        return 1;
                                }
                                bltDev->addr[num].LAP = htoul(++p);
                                /*存储蓝牙地址(字符串形式)*/
                                sprintf(bltDev->unpraseAddr[num],"%X:%X:%X",bltDev->addr[num].NAP,bltDev->addr[num].UAP,bltDev->addr[num].LAP);
                                bltDev->num++;
                        }
                }
                clean_rebuff();
                HC05_Send_CMD("AT+INQC\r\n",1);//退出前中断查询
                return 0;
        }       
        else
        {
                clean_rebuff();
                HC05_Send_CMD("AT+INQC\r\n",1);//退出前中断查询
                return 1;       
        }
}

/**
  * 函数功能: 把蓝牙地址转化成字符串形式
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
void strBLTAddr(BLTDev *bltDev,char delimiter)  
{
        uint8_t i;
       
        if(bltDev->num==0)
        {
                HC05_DEBUG("/*******No other BLT Device********/");
        }
        else
        {
                for(i=0;i<bltDev->num;i++)
                {
                        sprintf(bltDev->unpraseAddr[i],"%X%c%X%c%X",bltDev->addr[i].NAP,delimiter,bltDev->addr[i].UAP,delimiter,bltDev->addr[i].LAP);
                }
        }
}

/**
  * 函数功能: 获取远程蓝牙设备的名称
  * 输入参数: bltDev ,蓝牙设备列表指针
  * 返 回 值: 0获取成功,非0不成功
  * 说    明:无
  */
uint8_t getRemoteDeviceName(BLTDev *bltDev)
{
        uint8_t i;
        char *redata;
        uint16_t len;
       
        char linebuff[50];
        uint16_t linelen;
        char *p;
       
        char cmdbuff[100];
       
        strBLTAddr(bltDev,',');

        HC05_DEBUG("device num =%d",bltDev->num);
       
        for(i=0;i<bltDev->num;i++)
        {
                sprintf(cmdbuff,"AT+RNAME?%s\r\n",bltDev->unpraseAddr[i]);
                HC05_Send_CMD(cmdbuff,0);
                redata =get_rebuff(&len);
                if(redata[0] != 0 && strstr(redata, "OK") != 0)
                {
                        linelen = get_line(linebuff,redata,len);
                        if(linelen>50 && linelen !=0 ) linebuff[linelen]='\0';        //超长截断
                                       
                        p = skipPrefix(linebuff,linelen,"+RNAME:");
                        if(p!=0)
                        {
                                strcpy(bltDev->name[i],p);
                        }
                }
                else
                {
                        clean_rebuff();
                        return 1;       
                }
                clean_rebuff();
        }
        return 0;
}

/**
  * 函数功能: 输出蓝牙设备列表
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
void printBLTInfo(BLTDev *bltDev)  
{
        uint8_t i;
        if(bltDev->num==0)
        {
                HC05_DEBUG("/*******No remote BLT Device or in SLAVE mode********/");
        }
        else
        {
                HC05_DEBUG("扫描到 %d 个蓝牙设备",bltDev->num);

                for(i=0;i<bltDev->num;i++)
                {
                        HC05_INFO("/*******Device[%d]********/",i);       
                        HC05_INFO("Device Addr: %s",bltDev->unpraseAddr[i]);
                        HC05_INFO("Device name: %s",bltDev->name[i]);
                }
        }
}

/**
  * 函数功能: 扫描蓝牙设备,并连接名称中含有"HC05"的设备
  * 输入参数: 无
  * 返 回 值: 0获取成功,非0不成功
  * 说    明:无
  */
uint8_t linkHC05(void)
{
        uint8_t i=0;
        char cmdbuff[100];
       
        parseBluetoothAddress(&bltDevList);
        getRemoteDeviceName(&bltDevList);
        printBLTInfo(&bltDevList);
       
        for(i=0;i<=bltDevList.num;i++)
        {
                if(strstr(bltDevList.name[i],"HC05") != NULL) //非NULL表示找到有名称部分为HC05的设备
                {
                        HC05_INFO("搜索到远程HC05模块,即将进行配对连接...");
                        strBLTAddr(&bltDevList,',');               
                        //配对
                        sprintf(cmdbuff,"AT+PAIR=%s,20\r\n",bltDevList.unpraseAddr[i]);
                        HC05_Send_CMD(cmdbuff,0);
                        //连接       
                        sprintf(cmdbuff,"AT+LINK=%s\r\n",bltDevList.unpraseAddr[i]);
                        return HC05_Send_CMD(cmdbuff,0);               
                }
        }
        return 1;
}



沙发
mmuuss586| | 2016-8-7 12:52 | 只看该作者
谢谢分享!

使用特权

评论回复
板凳
gxx-c| | 2016-8-7 13:48 | 只看该作者
谢谢

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

122

主题

216

帖子

48

粉丝