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

主要问题

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 */

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

版权声明:本文为CSDN博主「️零柒️」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_52111026/article/details/119803226

️零柒️

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

串口通信之————IIC(软件驱动)

B站账号:小光学嵌入式 ⏩ 大家好哇!我是小光,嵌入式爱好者,一个想要成为系统架构师的大二学生。⏩最近开始系统性补习STM32基础知识,规划有:串口通信&#xf

STM32串口输出字符串

串口 串口全称为串行接口,采用 全双工、异步通信的通信方式,一次只能传输一帧,一帧中包含 起始位、数据位(一般为 8bit )、校验位、停止位。由于采用异步通信&#xff0