• 浅析STM32F1芯片蓝牙HC05模块


      1.前期准备

      今天,笔者将在STM32F1开发板上,使用一块HC05模块与手机的BlueToothSerial(即蓝牙调试助手)连接,通过发送字符给开发板,开发板通过strcmp函数进行对比,无误则执行对应操作,本实验将只点亮或者熄灭LED1灯。

      准备条件: 软件:MDK5(电脑端)、BlueToothSerial(手机端,可通过华为应用商店进行下载)

            硬件:STM32正点原子(F1系列)精英开发板、ST-Link烧录器、HC05模块一块、带蓝牙功能耳机一部

      硬件连接情况:

      

      

      其中,需要连接的端子主要是:

      KEY   HC05芯片的命令数据控制端(推挽输出),当要发送命令时要置高,当要传输数据时,置低

      LED  HC05芯片的连接状态指示端(上拉输入),当其输入为1表示已连接,反之未连接

      TXD  HC05芯片的发送数据线(PB10     复用推挽输出)

      RXD HC05芯片的接收数据线(PB11   浮空输入) 

      VCC   连接3.3V

      GND  接地

    2.程序设计

      本实验的数据传输 挺有意思的,通过定时器7定时可以限制接受时间(一到定时时间就通过置高传输状态标志USART3_RX_STA|=(1<<15)),强制把接收完成,而不是像以前的串口实验那样,通过回车键来判断本次数据已经结束。

    USART3.c

    void USART3_IRQHandler(void)                                        //串口1中断服务程序
    {
        u8 Res;
        if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)  //接收中断
        {
            Res =USART_ReceiveData(USART3);                                            //读取接收到的数据
            if((USART3_RX_STA&(1<<15))==0)                                            //代表上次的已经接收完成,可以开始本次
            {
                if(USART3_RX_STA<USART3_RX_LEN)                                        //当接收的个数少于规定数量USART3_RX_LEN
                {
                    TIM_SetCounter(TIM7,0);                                                    //先把定时器清零
                    TIM_Cmd(TIM7,ENABLE);                                                        //使能定时器,使其开始计数
                    USART3_RX_BUF[USART3_RX_STA++]=Res;                            //把数据赋给已经定义好的接收数组
                                                                                  //这里为啥不把USART3_RX_STA清零,而是在main函数中呢?
                                                                       //为了可以在mian函数中读取本次传输数据的长度,方便数据的显示操作及其他操作                                                            
        }else
                {
                    USART3_RX_STA|=(1<<15);                //接收完成
                }
            
            }
        }
    } 

    在串口3里面还有一个发送数据函数比较有趣,他的构造是void u3_printf(char* fmt,...)  

    对的,你没看错,char *fmt,后面接的是“...”三个点,这三个点表示可以是任意类型的数据,他怎么实现的呢?

    举个例子,说明一下 u3_printf中的参数“...”三个点可以是任意类型的参数

        u3_printf("AT+NAME? "); //发送AT字符串   在此处,这个可变参数是空的,即没有也可以

        u3_printf("ATKHC05 SendText%d ",sendcnt);   //在此处,这个可变参数是整数类型,此时va_start(ap,fmt),是把fmt中的可变参数地址赋给ap指针,使其指向那个可变参数

    我们通过这个函数代码来分析

    void u3_Printf(char *fmt,...) //...表示可变参数(多个可变参数组成一个列表,后面有专门的指针指向他),不限定个数和类型,     
    {         
    va_list ap;//初始化指向可变参数列表的指针         
    char string[256];         
    va_start(ap,fmt);//将第一个可变参数的地址付给ap,即ap指向可变参数列表的开始         
    vsprintf(string,fmt,ap);//将参数fmt、ap指向的可变参数一起转换成格式化字符串,放string数组中,其作用同sprintf(),只是参数类型不同         
    Uart_SendString(string); //把格式化字符串从开发板串口送出去         
    va_end(ap);    //ap付值为0,没什么实际用处,主要是为程序健壮性 

    这个可变参数是什么?怎么功能这么强大!!!

    依靠的是va_list、va_start、va_end等一组宏指令进行申明一个可变参数

    通过va_list ap;=====>首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针;

    va_start(ap,fmt)=======>然后用VA_START宏初始化变量刚定义的VA_LIST变量,即把ap指针指向fmt中的可变参数

    va_end(ap)========>把ap指针清空

    本质上,ap就是一个指向fmt里面的可变参数的指针,可以是int,float,char等类型

    里面的vsprintf函数的用法同sprintf,都是把格式化字符串送到指定数组中

    函数名: vsprintf

    功 能: 送格式化输出串到指定数组中,第三个参数是可变参数(类型)

    用 法: int vsprintf(char *string, char *format, va_list param);

    HC05.c

    /*
    函数名:HC05_Init
    功能: 检测HC05模块是否存在
    参数:void
    返回:(u8)代表程序运行是否成功标志
    
    */
    
    
    u8 HC05_Init(void)
    {
        int i,retry=10;
        u16 temp;
        u8 res=1;
        
        GPIO_InitTypeDef GPIO_InitType;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);    
        
        GPIO_InitType.GPIO_Pin=GPIO_Pin_4;        //KEY  PA4  推挽输出
        GPIO_InitType.GPIO_Mode=GPIO_Mode_Out_PP;//HC05芯片的命令数据控制端(推挽输出),当要发送命令时要置高,当要传输数据时,置低
        GPIO_InitType.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitType);
        
        GPIO_InitType.GPIO_Pin=GPIO_Pin_15;        //LED   PA15  上拉输出
        GPIO_InitType.GPIO_Mode=GPIO_Mode_IPU;//HC05芯片的连接状态指示端(上拉输入),当其输入为1表示已连接,反之未连接
        GPIO_Init(GPIOA,&GPIO_InitType);
        GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
        HC05_KEY=1;
        HC05_LED=1;
        
        uart3_init(9600);
        
        while(retry--)
        {
            HC05_KEY=1;                    //KEY置高,进入AT模式
            delay_ms(10);                //只有在AT模式,才可发送指令
            u3_printf("AT
    ");    //发送指令
            HC05_KEY=0;                        //退出AT模式,可发送数据
            
            
            for(i=0;i<10;i++)                                        //在50ms内等待接收
            {
                delay_ms(5);
                if(USART3_RX_STA&0x8000) break;
            }
            
            if(USART3_RX_STA&0x8000)                        //接受到数据的话
            {
                temp=USART3_RX_STA&0x7FFF;                //取数据长度
                USART3_RX_STA=0;                                    //把接收数据标志位清零,方便下一次接收的开始
                if(temp==4&&(USART3_RX_BUF[0]=='O')&&(USART3_RX_BUF[1]=='K'))
                {
                    res=0;                                                    //当发送“AT
    ”指令时,返回的是“OK”
                    break;
                }
            }
        
        }
        if(retry==0) res=0xFF;                //当循环次数达到retry时,返回参数将是报错标志0xFF,正常返回的是0
        return res;
        
    }

    其他指令:如查询主从角色、查询版本号、查询蓝牙名字、更改波特率等,都大致相同,就不一一累赘。

    3.主函数调用

    实现功能:

      1)通过按键KEY0按下,开始一直发送一个数组“ATKHC05 SendText%d”(%d是0~99)

      2)通过按键KEY1按下,发送指令“AT+ROLE=0”或者“AT+ROLE=1”更改主从角色

      3)一直通过if语句对接收标志进行判断,时刻准备对手机发送过来的信号进行处理,

    当是"+LED1 ON"指令,strcmp(USART3_RX_BUF,"+LED1 ON"),返回是0,即一样时进行亮LED1灯操作,

    反之,则灭LED1灯。

    while(HC05_Init())         //初始化ATK-HC05模块  
        {
            LCD_ShowString(30,90,200,16,16,"ATK-HC05 Error!"); 
            delay_ms(500);
            LCD_ShowString(30,90,200,16,16,"Please Check!!!"); 
            delay_ms(100);
        }                                                       
        LCD_ShowString(30,90,210,16,16,"KEY1:ROLE KEY0:SEND/STOP");  
        LCD_ShowString(30,110,200,16,16,"ATK-HC05 Standby!");  
          LCD_ShowString(30,160,200,16,16,"Send:");    
        LCD_ShowString(30,180,200,16,16,"Receive:"); 
        POINT_COLOR=BLUE;
        HC05_Role_Show();
        delay_ms(100);
        USART3_RX_STA=0;
         while(1) 
        {        
            key=KEY_Scan(0);
            if(key==KEY1_PRES)                        //切换模块主从设置
            {
                   key=HC05_Get_Role();
                if(key!=0XFF)
                {
                    key=!key;                      //状态取反       
                    if(key==0)HC05_Set_Cmd("AT+ROLE=0");
                    else HC05_Set_Cmd("AT+ROLE=1");
                    HC05_Role_Show();
                    HC05_Set_Cmd("AT+RESET");    //复位ATK-HC05模块
                    delay_ms(200);
                }
            }else if(key==KEY0_PRES)
            {
                sendmask=!sendmask;                //发送/停止发送       
                if(sendmask==0)LCD_Fill(30+40,160,240,160+16,WHITE);//清除显示
            }else delay_ms(10);       
            if(t==50)
            {
                if(sendmask)                    //定时发送
                {
                    sprintf((char*)sendbuf,"ALIENTEK HC05 %d
    ",sendcnt);
                      LCD_ShowString(30+40,160,200,16,16,sendbuf);    //显示发送数据    
                    u3_printf("ALIENTEK HC05 %d
    ",sendcnt);        //发送到蓝牙模块
                    sendcnt++;
                    if(sendcnt>99)sendcnt=0;
                }
                HC05_Sta_Show();        
                t=0;
                LED0=!LED0;          
            }      
            if(USART3_RX_STA&0X8000)            //接收到一次数据了
            {
                LCD_Fill(30,200,240,320,WHITE);    //清除显示
                 reclen=USART3_RX_STA&0X7FFF;    //得到数据长度
                  USART3_RX_BUF[reclen]=0;         //加入结束符
                if(reclen==9||reclen==8)         //控制DS1检测
                {
                    if(strcmp((const char*)USART3_RX_BUF,"+LED1 ON")==0)LED1=0;    //打开LED1
                    if(strcmp((const char*)USART3_RX_BUF,"+LED1 OFF")==0)LED1=1;//关闭LED1
                }
                 LCD_ShowString(30,200,209,119,16,USART3_RX_BUF);//显示接收到的数据
                 USART3_RX_STA=0;     
            }                                                                                         
            t++;    
        }
  • 相关阅读:
    QML Image Element
    QML基本可视化元素--Text
    联想笔记本电脑的F1至F12键盘问题。怎么设置才能不按FN就使用F1
    Qt Creator 黑色主题配置
    虚拟机配置
    虚拟机下安装ubuntu后root密码设置
    联想(Lenovo)小新310经典版进bios方法
    带有对话框的父窗口
    添加菜单的窗口
    添加组件的窗口
  • 原文地址:https://www.cnblogs.com/18689400042qaz/p/13373757.html
Copyright © 2020-2023  润新知