主要問題
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位就不能滿足要求啦,我的處理方法是將資料分為高位和低位,同時由于串口傳輸無符號資料,負數傳輸會出現錯誤,我的解決辦法是通過判斷是否為負數,然后設定一個標志位,通過置位標志位來判斷是否是負數,
超出范圍以及負數的處理辦法如下
/*用于判斷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 */
為了防止以后忘記怎么弄,來做一個筆記,
同時感謝這位大哥提供的資料處理思路哦
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/295263.html
標籤:其他
