毕设做的是掌控小车,因此采用蓝牙通信作为小车和手部通信,前段时间做出实物,对其遇到的问题以及解决的方法做一些总结。一个主控芯片采用STM32F103ZET6,另一个主控芯片采用STM32F103C8T6,原因是本来准备了两个主控C8T6,不小心烧了一个。

1.两个蓝牙的配对

 需要准备的硬件:

2个HC-05主从一体,2个USB转TTL,杜邦线若干,USB拓展口(电脑USB口较少的)

AT指令集(在蓝牙模块进入AT指令模式后,需要在串口助手上发送AT指令):

对于HC-05这款蓝牙模块,其上有一个黑色的小按钮,在通电之前长按,插入电脑USB口后,原本快闪红灯变为慢闪后,即进入AT模式,此时可以在串口助手上发送AT指令。每发送一条AT指令后,串口助手会回馈一个OK或者其他,证明可以正常使用,若不能回复OK,大概有以下问题:

(1)检查连线,是否RXD连接的TXD,是否杜邦线连接正确。

(2)检查波特率是否正确,默认的波特率是38400

以下为两个蓝牙模块配对的过程:

 1.初始化蓝牙模块(需要开启两个串口助手对主从机进行配置,此处A为主机,B为从机)
蓝牙模块A的配置
AT+ORGL        

初始化蓝牙模块(当使用了此条AT指令后,自动退出AT模式,需重新进入AT模式)
AT+PSWD="xxxx"  

设置蓝牙配对密码(其中xxxx代表任意数字,主机从机的密码要一致)
AT+ROLE=1      

设置蓝牙模块A为主机 (1代表主机,0代表从机)


蓝牙模块B的配置
AT+ORGL        

初始化蓝牙模块(当使用了此条AT指令后,自动退出AT模式,需重新进入AT模式)
AT+PSWD="xxxx"  

设置蓝牙配对密码(其中xxxx代表任意数字,主机从机的密码要一致)
AT+ROLE=0      

设置蓝牙模块A为主机 (1代表主机,0代表从机)
2.查询从机地址并绑定
AT+ADDR?      

对从机进行地址查询,获得查询地址,我使用从机获得的的地址0022:12:0205FC
将获得的地址其中的冒号换成逗号即0022,12,0205FC
注意:在AT指令中所有的标点均为英文输入法下的
AT+BIND=0022,12,0205FC

 
在主机的串口助手窗口发送,使主机绑定从机地址
AT+BIND         

查看主机是否成功绑定从机地址
3.设置主机从机的波特率
AT+UART=115200,0,0    

设置主机的波特率为115200
AT+UART?            

查询主机波特率是否为115200
AT+UART=115200,0,0    

设置从机的波特率为115200
AT+UART?            

查询从机波特率是否为115200

配置完成后,拔出再重新通电,此时不用按住黑色小按钮,待两个蓝牙模块的红灯均变为慢闪时,即配对成功,此时在主机的串口助手上发送数字,在从机的串口助手上可以接收到,即实现了两个蓝牙模块的通信。

2.单片机的配置(仅为部分配置代码)

  根据上述两个蓝牙之间的通信,不难推断蓝牙通信就是无线的串口通信,STM32单片机配置时应注意配置两个单片机的串口,要有和蓝牙相同的波特率,同时将蓝牙连接至配置好的单片机所用的串口(RXD,TXD)上

我在小车上的串口配置,使用串口3

#include "usart3.h"
#include "sys.h"
#include "usart.h"
#include "tb6612.h"
#include "timer.h"


uint8_t Serial_RxFlag;
extern int USART3_Flag;
uint16_t R_Data;

void usart3_init(u32 bound)
{ 
	  GPIO_InitTypeDef GPIO_InitStructure;
	  NVIC_InitTypeDef NVIC_InitStructurea;
	  USART_InitTypeDef USART_InitStruct;
	 
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);//
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //
	  USART_DeInit(USART3);//
	
	  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
	  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	  GPIO_Init(GPIOB,&GPIO_InitStructure);    //PB10
	
	  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11;
	  GPIO_Init(GPIOB,&GPIO_InitStructure);  //PB11	 
  
	  NVIC_InitStructurea.NVIC_IRQChannel=USART3_IRQn;
	  NVIC_InitStructurea.NVIC_IRQChannelCmd=ENABLE;
	  NVIC_InitStructurea.NVIC_IRQChannelPreemptionPriority=1;
	  NVIC_InitStructurea.NVIC_IRQChannelSubPriority=1;
	  NVIC_Init(&NVIC_InitStructurea);          //
		
		USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);//
	
	  USART_InitStruct.USART_BaudRate=bound;//
		USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//
		USART_InitStruct.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;//
		USART_InitStruct.USART_Parity=USART_Parity_No;//
		USART_InitStruct.USART_StopBits=USART_StopBits_1;//
		USART_InitStruct.USART_WordLength=USART_WordLength_8b;//
	  USART_Init(USART3,&USART_InitStruct);                 //
		
		USART_Cmd(USART3,ENABLE);//
	

}
void USART3_IRQHandler(void)
{

	if (USART_GetITStatus(USART3, USART_IT_RXNE) == 1)
	{
		R_Data = USART_ReceiveData(USART3);//ÕâÐбíʾÊÕµ½µÄÊý¾Ý
		
		if(R_Data=='A') USART3_Flag=1;
		if(R_Data=='B') USART3_Flag=2;
		if(R_Data=='C') USART3_Flag=3;
		if(R_Data=='D') USART3_Flag=4;
		if(R_Data=='E') USART3_Flag=5;
		USART_ClearITPendingBit(USART3, USART_IT_RXNE);
	}
}


可以参考一个老哥的https://blog.csdn.net/hbzdsXCV/article/details/129278918?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168240123616800186542106%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=168240123616800186542106&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-5-129278918-null-null.142^v86^wechat,239^v2^insert_chatgpt&utm_term=%E4%B8%A4%E4%B8%AA%E5%8D%95%E7%89%87%E6%9C%BA%E7%9A%84%E8%93%9D%E7%89%99%E9%80%9A%E4%BF%A1&spm=1018.2226.3001.4187

手部采集部分,使用串口2

#include "usart2.h"


u8  USART2_RX_BUF[USART2_REC_LEN]; //½ÓÊÕ»º³å,×î´óUSART_REC_LEN¸ö×Ö½Ú.Ä©×Ö½ÚΪ»»Ðзû 
u16 USART2_RX_STA;         		//½ÓÊÕ״̬±ê¼Ç	

void uart2_Init(u32 baudrate)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//ʹÄÜUSART2£¬GPIOAʱÖÓ

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//¸´ÓÃÍÆÍìÊä³ö
    GPIO_Init(GPIOA, &GPIO_InitStructure);//³õʼ»¯GPIOA.2

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//¸¡¿ÕÊäÈë
    GPIO_Init(GPIOA, &GPIO_InitStructure);//³õʼ»¯GPIOA.3  

    //Usart1 NVIC ÅäÖÃ
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//ÇÀÕ¼ÓÅÏȼ¶3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;		//×ÓÓÅÏȼ¶3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQͨµÀʹÄÜ
    NVIC_Init(&NVIC_InitStructure);	//¸ù¾ÝÖ¸¶¨µÄ²ÎÊý³õʼ»¯VIC¼Ä´æÆ÷

    //USART ³õʼ»¯ÉèÖÃ

    USART_InitStructure.USART_BaudRate = baudrate;//´®¿Ú²¨ÌØÂÊ
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//×Ö³¤Îª8λÊý¾Ý¸ñʽ
    USART_InitStructure.USART_StopBits = USART_StopBits_1;//Ò»¸öֹͣλ
    USART_InitStructure.USART_Parity = USART_Parity_No;//ÎÞÆæżУÑéλ
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//ÎÞÓ²¼þÊý¾ÝÁ÷¿ØÖÆ
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//ÊÕ·¢Ä£Ê½

    USART_Init(USART2, &USART_InitStructure); //³õʼ»¯´®¿Ú2
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//¿ªÆô´®¿Ú½ÓÊÜÖжÏ
    USART_Cmd(USART2, ENABLE);                    //ʹÄÜ´®¿Ú2
}

void USART2_IRQHandler(void)                	//´®¿Ú2ÖжϷþÎñ³ÌÐò
{
	u8 Res;

    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //½ÓÊÕÖжÏ(½ÓÊÕµ½µÄÊý¾Ý±ØÐëÊÇ0x0d 0x0a½áβ)
    {
        Res =USART_ReceiveData(USART2);	//¶ÁÈ¡½ÓÊÕµ½µÄÊý¾Ý

        if((USART2_RX_STA&0x8000)==0)//½ÓÊÕδÍê³É
        {
            if(USART2_RX_STA&0x4000)//½ÓÊÕµ½ÁË0x0d
            {
                if(Res!=0x0a)USART2_RX_STA=0;//½ÓÊÕ´íÎó,ÖØпªÊ¼
                else USART2_RX_STA|=0x8000;	//½ÓÊÕÍê³ÉÁË 
            }
            else //»¹Ã»ÊÕµ½0X0D
            {	
                if(Res==0x0d)USART2_RX_STA|=0x4000;
                else
                {
                    USART2_RX_BUF[USART2_RX_STA&0X3FFF]=Res ;
                    USART2_RX_STA++;
                    if(USART2_RX_STA>(USART2_REC_LEN-1))USART2_RX_STA=0;//½ÓÊÕÊý¾Ý´íÎó,ÖØпªÊ¼½ÓÊÕ	  
                }		 
            }
        }   		 
    } 

} 
static u8 USART2_TX_BUF[200];

void u2_printf(char* fmt,...)  
{     
	u16 i,j; 
	va_list ap; 
	va_start(ap,fmt);
	vsprintf((char*)USART2_TX_BUF,fmt,ap);
	va_end(ap);
	i=strlen((const char*)USART2_TX_BUF);		//´Ë´Î·¢ËÍÊý¾ÝµÄ³¤¶È
	for(j=0;j<i;j++)							//Ñ­»··¢ËÍÊý¾Ý
	{
		while((USART2->SR&0X40)==0);			//Ñ­»··¢ËÍ,Ö±µ½·¢ËÍÍê±Ï   
		USART2->DR=USART2_TX_BUF[j];  
	} 
}

3.实现两个蓝牙的通信

在配置好两个单片机的串口之后,其实关于蓝牙通信就已经解决的差不多了,最后剩下的关键只有串口发送函数和串口接收函数的使用,在主机使用串口发送函数,在从机使用串口接收函数,注意串口发送和接收的串口。

4.遇到的问题及解决方案

开始由于好久没捣鼓过32了,而且我这个电脑ST-LINK一直没有调过来,因此后来改成用串口烧录,对于c8t6的串口烧录(使用TTL转USB烧录),烧录时应用跳线帽将BOOT0置1,待烧录完成后将BOOT0置0,才可正常工作,而期间BOOT1一直置0。

5.完整版代码

链接:https://pan.baidu.com/s/1Nar8uLibDYbWvmrfeW7pBg?pwd=rx1l 
提取码:rx1l

这是本人第一次在CSDN上发表文章,本人才学疏浅,写下此文也是希望能帮到别人,谢谢。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐