毕设做的是掌控小车,因此采用蓝牙通信作为小车和手部通信,前段时间做出实物,对其遇到的问题以及解决的方法做一些总结。一个主控芯片采用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); //PB10GPIO_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.2GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //¸´ÓÃÍÆÍìÊä³öGPIO_Init(GPIOA, &GPIO_InitStructure);//³õʼ»¯GPIOA.2GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3GPIO_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 ;//ÇÀÕ¼ÓÅÏȼ¶3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //×ÓÓÅÏȼ¶3NVIC_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); //³õʼ»¯´®¿Ú2USART_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上发表文章,本人才学疏浅,写下此文也是希望能帮到别人,谢谢。