淺析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?\r\n"); //發送AT字符串   在此處,這個可變參數是空的,即沒有也可以

    u3_printf("ATKHC05 SendText%d\r\n",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\r\n");    //發送指令
        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\r\n”指令時,返回的是“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\r\n",sendcnt);
                  LCD_ShowString(30+40,160,200,16,16,sendbuf);    //顯示發送數據    
                u3_printf("ALIENTEK HC05 %d\r\n",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++;    
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM