主要问题
1. 蓝牙模块的连接问题
2. 蓝牙模块的工作模式
3. CUBEMX 配置串口注意事项
4. 两个模块数据传输异常
前言
因为最近都在做基于STM32,MPU6050的手势控制机器人,遇到了无线数据传输的问题,正好手上有几个蓝牙模块,就用蓝牙模块来传输数据,但是并没有想象的那么顺利,最主要的还是两个模块串口传输数据的问题,一直得不到解决,因为简简单单的串口就OK。
首先是实物连接的问题
蓝牙模块与STM32的连接只需要四根线就好,VCC,GND,RX,TX,VCC,提供3.3或者5V,这块基本没有问题
蓝牙模块的工作模式
- AT指令
- 透传
AT
按住蓝牙模块的按钮,然后上电,之后在松开就可以进入AT指令模式,这是时候可以对模块进行必要的设置,比如波特率等,也可以查询模块的相关信息,AT指令要以\R\N结尾,而且此时的波特率固定为38400,常用的AT指令在下面啦!! 透传 正常上电,模块上的灯闪得比较快,这个时候就是透传,当使用两个模块相互通信的时候要先进入AT模式,将其中一个设置为主机,另外一个设置为从机,这样上电之后主机会自动连接从机。
cubemx 的配置
这个很简单,就是正常的配置串口,但是切记波特率要与蓝牙模块的波特率一致,透传模式下默认是9600,可以在AT指令中自行修改 如果是指定一边发送,另外一边接受的话,接受的一段 需要开启中断,发送的一段可以不开启,就是普通的阻塞模式。
今天最主要的不是上面的内容,这些都很简单,主要是两个模块的数据发送与接受的处理方式,这个是今天笔记的主要对象
首先来看发送端的
发送端的数据我放到了一个数组里,通过发送数组将数据发送出去 由于串口HAL库本身没有数组的发送函数,所以需要自己写一个数组发送的函数,原理是通过反复的调用串口发送函数来实现的,那么问题来了,
为什么不能使用printf函数来实现呢?
如果使用printf函数来实现的话,也可以传输十六进制的数据,但是,你传输出去之后,到接受端就会变成十进制,这可能是我自己软件的问题,但是网上大佬也是这么说的,所以最好使用HAL库自带的函数来实现,这里会有一个问题,就是串口调试助手可能会显示异常,但是不影响,因为你需要的是接收端能够正常的显示,发送端主要能正确的把数据发送就好。 发送端串口偶尔异常,还没探究具体的原因。
void ack(int x,int y,int z)
{
Inverse_X (x);
Inverse_Y (y);
Inverse_Z (z);
uint8_t str[12]= {0};
str[0] = 0xAA;
str[1] = 0xBB;
str[2] = X_H ;
str[3] = X_L ;
str[4] = Y_H ;
str[5] = Y_L ;
str[6] = Z_H ;
str[7] = Z_L ;
str[8] = X_flag ;
str[9] = Y_flag ;
str[10] =Z_flag ;
str[11] = 0xCC;
UART_SendStr (str,12);
}
这块代码是重点,因为串口发送的数据是8位的,也就是只能传输0-255,这样的256个数字,超过范围的就不能正常的显示,但是MPU6050的角度纵不能只到255度吧。得到300度甚至更多,所以有时候8位就不能满足要求啦,我的处理方法是将数据分为高位和低位,同时由于串口传输无符号数据,负数传输会出现错误。我的解决办法是通过判断是否为负数,然后设置一个标志位,通过置位标志位来判断是否是负数。 超出范围以及负数的处理办法如下
void Inverse_X (int x)
{
if((x>= 0) && (x < 255))
{
X_H = x;
X_L = 0;
X_flag = 0;
}
else if(x>255)
{
X_H = 255;
X_L = x-255;
X_flag = 0;
}
else if ( x <= -255)
{
X_H = 255;
X_L = -x-255;
X_flag = 1;
}
else
{
X_H = -x;
X_L = 0;
X_flag = 1;
}
}
主函数发送三个数据
ack (300,-6,-200);
发送端的处理基本结束,接下来是接收端
static int X=0,Y=0,Z=0;
void Openmv_Receive_Data(uint16_t Com_Data)
{
uint8_t i;
static uint8_t RxCounter1=0;
static uint16_t RxBuffer1[50]={0};
static uint8_t RxState = 0;
if((RxState==0)&&(Com_Data==0xAA))
{
RxState=1;
RxBuffer1[RxCounter1++]=Com_Data;
}
else if((RxState==1)&&(Com_Data==0xBB))
{
RxState=2;
RxBuffer1[RxCounter1++]=Com_Data;
}
else if(RxState==2)
{
RxBuffer1[RxCounter1++]=Com_Data;
if(RxCounter1>=30||Com_Data == 0xCC)
{
RxState=3;
X = RxBuffer1[2]+RxBuffer1[3];
Y = RxBuffer1[4]+RxBuffer1[5];
Z = RxBuffer1[6]+RxBuffer1[7];
X = Inverse (RxBuffer1 [8],X);
Y = Inverse (RxBuffer1 [9],Y);
Z = Inverse (RxBuffer1 [10],Z);
printf("X = %d\r\n",X);
printf("Y = %d\r\n",Y);
printf("Z = %d\r\n",Z);
}
}
else if(RxState==3)
{
if(RxBuffer1[RxCounter1-1] == 0xCC)
{
RxCounter1 = 0;
RxState = 0;
}
else
{
printf ("erro");
RxState = 0;
RxCounter1=0;
for(i=0;i<10;i++)
{
RxBuffer1[i]=0x00;
}
}
}
else
{
RxState = 0;
RxCounter1=0;
for(i=0;i<10;i++)
{
RxBuffer1[i]=0x00;
}
}
}
上面是一个串口数据的接收函数,具体的接收方式已经在里面哟注释啦! 还有一个函数时对正负数的标志位进行处理的函数,如下
int Inverse(uint8_t x,int X)
{
if(x==0)
X = X;
else
X = -X;
printf("******%d\r\n",X);
return X ;
}
最后是串口中断的回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
uint16_t tempt
if(huart->Instance==USART1)
{
tempt=USART1_RXbuff;
Openmv_Receive_Data(tempt);
}
HAL_UART_Receive_IT(&huart1,&USART1_RXbuff,1);
}
接收端记得在主函数中开启串口接收中断,否则不能进入中断。
HAL_UART_Receive_IT(&huart1,&USART1_RXbuff,1);
为了防止以后忘记怎么弄,来做一个笔记。 同时感谢这位大哥提供的数据处理思路哦
|