当前位置: 代码迷 >> 综合 >> STM32HAL库 (cubemx) 两个HC05蓝牙模块相互通信相关问题的解决 数组串口发送与接受的方法
  详细解决方案

STM32HAL库 (cubemx) 两个HC05蓝牙模块相互通信相关问题的解决 数组串口发送与接受的方法

热度:67   发布时间:2023-11-22 08:19:07.0

主要问题

1. 蓝牙模块的连接问题

2. 蓝牙模块的工作模式

3. CUBEMX 配置串口注意事项

4. 两个模块数据传输异常

前言

因为最近都在做基于STM32,MPU6050的手势控制机器人,遇到了无线数据传输的问题,正好手上有几个蓝牙模块,就用蓝牙模块来传输数据,但是并没有想象的那么顺利,最主要的还是两个模块串口传输数据的问题,一直得不到解决,因为简简单单的串口就OK。

首先是实物连接的问题

蓝牙模块与STM32的连接只需要四根线就好,VCC,GND,RX,TX,VCC,提供3.3或者5V,这块基本没有问题

蓝牙模块的工作模式

  1. AT指令
  2. 透传

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位就不能满足要求啦,我的处理方法是将数据分为高位和低位,同时由于串口传输无符号数据,负数传输会出现错误。我的解决办法是通过判断是否为负数,然后设置一个标志位,通过置位标志位来判断是否是负数。
超出范围以及负数的处理办法如下

/*用于判断X的值是否超过255,以及X的正负*/
void Inverse_X (int x)
{
    /*如果X的值大于0不大于255,则高位直接存放X的值,低位不存数据,标志为不置1*/if((x>= 0) && (x < 255)){
    X_H = x;X_L = 0;X_flag = 0;}/*如果超过255,则将数据分为高低两位存储,高位存放255,低位存放剩余的数,标志位不置位*/else if(x>255){
    X_H = 255;X_L = x-255;X_flag = 0;}/*如果数据的值低于-255,则同样分为高低两位,但是这两位存放的是正数,标志位置一,表示为负数*/else if ( x <= -255){
    X_H = 255;X_L = -x-255;X_flag = 1;}/*如果数据的值在0到255之间,则高位存数据的正数,标志位置一*/else {
    X_H = -x;X_L = 0;X_flag = 1;}
}

主函数发送三个数据

ack (300,-6,-200);

发送端的处理基本结束,接下来是接收端

/*三个变量用于存放目标数据,这里时MPU6050的角度*/
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))  //0x2c帧头{
    RxState=1;RxBuffer1[RxCounter1++]=Com_Data;}else if((RxState==1)&&(Com_Data==0xBB))  //0x12帧头{
    RxState=2;RxBuffer1[RxCounter1++]=Com_Data;}/*对数据进行处理*/else if(RxState==2){
    /*接受的数据存放到数组里*/   RxBuffer1[RxCounter1++]=Com_Data;if(RxCounter1>=30||Com_Data == 0xCC)       //RxBuffer1接受满了,接收数据结束{
    RxState=3;/*X,Y,Z都是有高位与低位构成的,这里将高位与低位加到一起即可*/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){
    //RxFlag1 = 0;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;      //将存放数据数组清零}
// printf ("接收异常00\r\n");}
}

上面是一个串口数据的接收函数,具体的接收方式已经在里面哟注释啦!
还有一个函数时对正负数的标志位进行处理的函数,如下

/*符号处理*/
int Inverse(uint8_t x,int X)
{
    /*判断标志为来解决符号问题,标志为为1,说明是负数,对数据进行求相反数*/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);
}

接收端记得在主函数中开启串口接收中断,否则不能进入中断。

 /* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart1,&USART1_RXbuff,1);/* USER CODE END 2 */

为了防止以后忘记怎么弄,来做一个笔记。
同时感谢这位大哥提供的数据处理思路哦

  相关解决方案