关于两个STM32F103系列单片机的蓝牙通信
毕设做的是掌控小车,因此采用蓝牙通信作为小车和手部通信,前段时间做出实物,对其遇到的问题以及解决的方法做一些总结。在配置好两个单片机的串口之后,其实关于蓝牙通信就已经解决的差不多了,最后剩下的关键只有串口发送函数和串口接收函数的使用,在主机使用串口发送函数,在从机使用串口接收函数,注意串口发送和接收的串口。配置完成后,拔出再重新通电,此时不用按住黑色小按钮,待两个蓝牙模块的红灯均变为慢闪时,即配对
毕设做的是掌控小车,因此采用蓝牙通信作为小车和手部通信,前段时间做出实物,对其遇到的问题以及解决的方法做一些总结。一个主控芯片采用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);
}
}
手部采集部分,使用串口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上发表文章,本人才学疏浅,写下此文也是希望能帮到别人,谢谢。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)