基於STM32的無線飛鼠(二)
在前一篇博客中講了下一些題外話,從本篇開始講講重點的知識,說說無線飛鼠過程用到的模塊
細說MPU6050
- 一、 MPU6050簡介
- 二、 細節問題
- 三、 相關技術
- 四、 操作步驟
- 五、 實現代碼
一、 MPU6050簡介
MPU6050集成了3軸加速度和3軸陀螺儀,是一款不錯的傳感器模塊,可以用在很多方面,比如:四軸飛控、空中鼠標、兩輪平衡車、GPS定位方面、遊戲機、3D遙控器、平板設備等等,此模塊給我們提供了強大的數據供應,由於將加速度和陀螺儀集成到了一起,免去了組合這兩個模塊時之間的軸差問題,減少了包裝問題,這兩年很火,成了DIY製作者的最愛。
二、 細節問題
在淘寶上買MPU6050時,要注意一下幾點:
- 查看賣家給出的介紹信息,是否刻意誇大,結合自己所學的知識進行判斷。比如:當時在某個論壇上看到某位大神將的,tb上說他們的模塊採用高性能的微處理器和先進的動力學解算與卡爾曼動態濾波算法,能夠快速求解出模塊當前的實時運動姿態。細心的你就會發現它的這種處理器根本就不能提供這種需求,也就是會所計算不出來。(STM8是8位的單片機,能做姿態解算和濾波嗎?)呵呵……想了下都有點搞笑.這個論壇上有詳細的解說:http://www.geek-workshop.com/thread-5820-1-1.html
- 不要讓模塊受到碰撞,否則會影響他的性能。
三、相關技術
MPU6050數據是用IIC進行讀取的,So必須學會IIC。類似於USB協議,不過和USB比起來可以說是小巫見大巫。
- IIC技術概述
IIC 即Inter-Integrated Circuit(集成電路總線),這種總線類型是 由飛利浦半導體公司在八十年代初設計出來的兩線式串行總線
特點:接口線少、器件封裝形式小、通信速率較高
IIC總線只有兩根雙向信號線,如下圖所示:
- IIC數據傳輸
數據有效位的定義:
IIC總線在進行數據傳輸時,時鐘信號爲高電平期間,數據線上的數據必須保持穩定,只有在時鐘線上的信號爲低電平期間,數據線的高電平或低電平狀態才允許變化
起始和停止條件:
當SCL線是高電平時,SDA線從高電平向低電平切換,這個情況視爲起始條件。
當SCL線是高電平時,SDA線有低電平向高電平切換,表示停止條件
數據傳輸格式:
IIC總線尋址
IIC總線規定:從機地址有第一個字節的7位組成
(想要插入表格,可是在這裏不會用了,直接從world中截張圖算了)
IIC總線編號
從機的地址有固定部分和可編程部分組成。在一個系統中可能希望接入多個相同的從機,從機地址中科編程部分決定了可接入總線該類期間的最大數目例如:一個從機的7位尋址中有4爲是固定的,3位是可編程的,那個這時僅能尋址8個同類期間。
STM32F103中的IIC
這裏主要看下載STM32中,IIC是怎麼個分佈:
四、操作步驟
- 熟悉MPU6050管腳
上圖是我自己的模塊,由於連上了線,管腳不是很清楚,可以看着一張,管腳和清楚的。
- 管腳功能介紹
這裏已經很詳細的介紹了各個管腳的功能,在心裏就有個大概瞭解,在後面編寫代碼中就會明白好多,更多細節可以查看手冊的!
五、實現代碼
當時開始做這個東西的時候參考了原子、野火的各個例子,再次感謝你們。
代碼塊
MPU初始化:
void MPU_Init()
{
ANBT_I2C_Configuration(); //IIC初始化
delay_ms(30);
AnBT_DMP_MPU6050_Init(); //MPU6050 的DMP初始化
}
下邊是讀取陀螺儀的數據函數:
void Read_Gyro_data(short *rxbuf)
{
unsigned long sensor_timestamp;
unsigned char i = 0;
short gyro[3], accel[3], sensors;//陀螺儀存放數組,加速度存放數組,返回狀態量
unsigned char more;
long quat[4]; //四元數存放數組
dmp_read_fifo(gyro, accel, quat, &sensor_timestamp, &sensors,&more);
if(sensors & INV_WXYZ_QUAT)
{
rxbuf[0] = gyro[0];
rxbuf[1] = gyro[1];
rxbuf[2] = gyro[2];
printf("\r\nRead_Gyro_data gyro:\r\n");
for (i = 0; i < 3; i++)
{
printf(" %d ",gyro[i]);
}
printf("\r\n");
}
}
其實參考了圓點博士的開源代碼的,看了下匿名四軸下位機協議,當初試了下自己獲取的數據是否正確,很不錯的,下面是匿名的協議:
/*
* 函數名:Data_Send_Status
* 描述 :數據發送 傳感器 的狀態
根據匿名四軸最新上位機編寫的顯示姿態的程序
* 輸入 :Pitch:俯仰角
Roll :橫滾角
Yaw :航向角
gyro :陀螺儀
accel:加速度
* 輸出 :
* 調用 :
*/
void Data_Send_Status(float Pitch,float Roll,float Yaw,int16_t *gyro,int16_t *accel)
{
unsigned char i = 0;
unsigned char j = 0;
unsigned char _cnt = 0,sum = 0;
unsigned int _temp;
u8 data_to_send[12] = {0}; //發送數組,初始化爲0
data_to_send[_cnt++] = 0xAA; // 幀頭 170
data_to_send[_cnt++] = 0xAA; // 170
data_to_send[_cnt++] = 0x01; // 功能字 1
data_to_send[_cnt++] = 0; // 長度 0
//橫滾角
_temp = (int)(Roll * 100);
data_to_send[_cnt++] = BYTE1(_temp); // 高 8 位
data_to_send[_cnt++] = BYTE0(_temp); // 低8位
//俯仰角
_temp = 0 - (int)(Pitch * 100);
data_to_send[_cnt++] = BYTE1(_temp);
data_to_send[_cnt++] = BYTE0(_temp);
//航向角
_temp = (int)(Yaw * 100);
data_to_send[_cnt++] = BYTE1(_temp);
data_to_send[_cnt++] = BYTE0(_temp);
data_to_send[3] = _cnt - 4; //數據長度
//和校驗
for(i = 0;i < _cnt;i++)
sum += data_to_send[i];
data_to_send[_cnt++] = sum;
data_to_send[_cnt++] = '\0';
//NRF_Tx_Dat(data_to_send); //發送到NRF緩衝區
//printf("\r\nData_Send_Status:\r\n");
// for (j = 0; j < 12;j++)
// {
// printf(" %d ",data_to_send[j]);
// }
// printf("\r\n");
// //串口發送數據
for(i=0;i<_cnt;i++)
AnBT_Uart1_Send_Char(data_to_send[i]);
}
/*
* 函數名:Send_Data
* 描述 :用於發送傳感器的數據
* 輸入 :Gyro:陀螺儀存放字符指針
Accel:加速度存放指針
* 輸出 :
* 調用 :
*/
void Send_Data(int16_t *Gyro,int16_t *Accel)
{
unsigned char j = 0;
unsigned char i = 0;
unsigned char _cnt = 0;
unsigned char sum = 0;
u8 status;
// unsigned int _temp;
/*
匿名數據協議:
幀頭、功能字、長度(len)、數據、校驗和(Sum) 共32字節
接收端在接收到數據的時候進行對應的解析即可
*/
u8 data_to_send[12];
data_to_send[_cnt++] = 0xAA; //幀頭 AAAA
data_to_send[_cnt++] = 0xAA;
data_to_send[_cnt++] = 0x02; //功能字
data_to_send[_cnt++] = 0; //長度
data_to_send[_cnt++] = BYTE1(Accel[0]);
data_to_send[_cnt++] = BYTE0(Accel[0]);
data_to_send[_cnt++] = BYTE1(Accel[1]);
data_to_send[_cnt++] = BYTE0(Accel[1]);
data_to_send[_cnt++] = BYTE1(Accel[2]);
data_to_send[_cnt++] = BYTE0(Accel[2]);
data_to_send[_cnt++] = BYTE1(Gyro[0]);
data_to_send[_cnt++] = BYTE0(Gyro[0]);
data_to_send[_cnt++] = BYTE1(Gyro[1]);
data_to_send[_cnt++] = BYTE0(Gyro[1]);
data_to_send[_cnt++] = BYTE1(Gyro[2]);
data_to_send[_cnt++] = BYTE0(Gyro[2]);
data_to_send[_cnt++] = 0;
data_to_send[_cnt++] = 0;
data_to_send[_cnt++] = 0;
data_to_send[3] = _cnt - 4;
for(i = 0;i < _cnt;i++)
sum += data_to_send[i];
data_to_send[_cnt++] = sum;
data_to_send[_cnt++] = '\0';
// printf("\r\nSend_Data:\r\n");
// for (j = 0; j < 12;j++)
// {
// printf(" %d ",data_to_send[j]);
// }
// printf("\r\n");
// delay_ms(1000);
// status = NRF_Tx_Dat(data_to_send);
//
// /*判斷髮送狀態*/
// switch(status)
// {
// case MAX_RT:
// printf("\r\n 主機端 沒接收到應答信號,發送次數超過限定值,發送失敗。 \r\n");
// break;
// case ERROR:
// printf("\r\n 未知原因導致發送失敗。 \r\n");
// break;
// case TX_DS:
// printf("\r\n 主機端 接收到 從機端 的應答信號,發送成功! \r\n");
// break;
// }
//
// delay_ms(1000);
// //串口發送數據
for(i = 0;i <_cnt;i++)
AnBT_Uart1_Send_Char(data_to_send[i]);
}
在主函數中調用相應的函數即可獲取相關數據,做一個簡單的測試。
一下是我從串口中獲取的數據:
以及其他數據:
因爲代碼中使用了圓點博士的開源代碼,而且都是現成的,就不往出貼了……
以上只是做了個簡單介紹,以及獲取到了數據,但是並沒有說明怎樣處理數據,這是很關鍵的也是最重要的,本次無線飛鼠的數據不好處理,我做到現在數據也不是很穩定,任然有一定幅度的變化。
歡迎轉載、分享,請註明出處,技術在於交流、分享……
博客地址:http://blog.csdn.net/u013704336\
Email:[email protected]
QQ:936563422