1. 程式人生 > >STC15W4K32S4讀取MPU6050陀螺儀角度加速度串列埠顯示程式程式碼

STC15W4K32S4讀取MPU6050陀螺儀角度加速度串列埠顯示程式程式碼

STC15W4K32S4讀取MPU6050陀螺儀角度加速度串列埠顯示程式程式碼
除錯通過,複製貼上即編譯可使用,無需除錯,晶振:24M,串列埠輸出,波特率:115200
為方便大家除錯,特附該程式的專案檔案,下載開啟即可除錯,下載地址:
http://download.csdn.net/detail/liyu3519/9899708

//*********************************************************************
//STC15系列讀取MPU6505陀螺儀資料
//除錯通過,複製貼上即編譯可使用,無需除錯,晶振:24M,串列埠輸出,波特率:115200
//版本:2.0 日期:2017-07-15 //********************************************************************* #include <STC15W4K32S4.H> //引用STC15系列標頭檔案,百度上搜索下載 #include <INTRINS.H> #include <MATH.H> #define I2C_SCL P14 //時鐘訊號線 #define I2C_SDA P15 //資料訊號線 #define PWR_MGMT_1 0x6B //電源管理,典型值:0x00(正常啟用)
#define WHO_AM_I 0x75 //IIC地址暫存器(預設數值0x68,只讀) #define SlaveAddress 0xD0 //IIC寫入時的地址位元組資料,+1為讀取 #define NOP1() nop_() #define NOP2() NOP1(),NOP1() #define MAIN_Fosc 24000000L //主時鐘,不同的晶振頻率可以直接修改 #define serial_one_read_max 16 //接收快取區長度
#define serial_one_baud_rate 115200L //波特率,波特率可以直接修改 #define Timer1_Reload_Usart (65536UL -(MAIN_Fosc / 4 / serial_one_baud_rate)) //Timer1重灌值,定時器1產生波特率 //**************************************** // 定義MPU6050內部地址 //**************************************** #define SMPLRT_DIV 0x19 //陀螺儀取樣率,典型值:0x07(125Hz) #define CONFIG 0x1A //低通濾波頻率,典型值:0x06(5Hz) #define GYRO_CONFIG 0x1B //陀螺儀自檢及測量範圍,典型值:0x18(不自檢,2000deg/s) #define ACCEL_CONFIG 0x1C //加速計自檢、測量範圍及高通濾波頻率,典型值:0x01(不自檢,2G,5Hz) #define ACCEL_XOUT_H 0x3B #define ACCEL_XOUT_L 0x3C #define ACCEL_YOUT_H 0x3D #define ACCEL_YOUT_L 0x3E #define ACCEL_ZOUT_H 0x3F #define ACCEL_ZOUT_L 0x40 #define TEMP_OUT_H 0x41 #define TEMP_OUT_L 0x42 #define GYRO_XOUT_H 0x43 #define GYRO_XOUT_L 0x44 #define GYRO_YOUT_H 0x45 #define GYRO_YOUT_L 0x46 #define GYRO_ZOUT_H 0x47 #define GYRO_ZOUT_L 0x48 void Delay1000ms() //延時函式1秒 { unsigned char i, j, k; _nop_(); _nop_(); i = 85; j = 12; k = 155; do { do { while (--k); } while (--j); } while (--i); } //======================================================================== // 函式: void I2C_Start() // 描述: I2C起始訊號. // 引數: none. // 返回: none. // 版本: V1.0, 2017-06-23 //======================================================================== void I2C_Start() { I2C_SDA = 1; //拉高資料線 I2C_SCL = 1; //拉高時鐘線 NOP2(); //等待機器反應 I2C_SDA = 0; //產生下降沿 I2C_SCL = 0; //拉低時鐘線 } //======================================================================== // 函式: void I2C_Stop() // 描述: I2C停止訊號. // 引數: none. // 返回: none. // 版本: V1.0, 2017-06-23 //======================================================================== void I2C_Stop() { I2C_SDA = 0; //拉低資料線 I2C_SCL = 1; //拉高時鐘線 NOP2(); //等待機器反應 I2C_SDA = 1; //產生上升沿 NOP1(); //等待機器反應 } //======================================================================== // 函式: void I2C_SendACK(bit ack) // 描述: I2C傳送應答訊號. // 引數: ack (0:ACK 1:NAK). // 返回: none. // 版本: V1.0, 2017-06-23 //======================================================================== void I2C_SendACK(bit ack) { I2C_SDA = ack; //寫應答訊號 I2C_SCL = 1; //拉高時鐘線 NOP2(); //等待機器反應 I2C_SCL = 0; //拉低時鐘線 NOP1(); //等待機器反應 } //======================================================================== // 函式: bit I2C_RecvACK() // 描述: I2C接收應答訊號. // 引數: none. // 返回: 1:成功,0:失敗. // 版本: V1.0, 2017-06-23 //======================================================================== bit I2C_RecvACK() { I2C_SCL = 1; //拉高時鐘線 NOP2(); //等待機器反應 CY = I2C_SDA; //讀應答訊號 I2C_SCL = 0; //拉低時鐘線 return CY; } //======================================================================== // 函式: void I2C_SendByte(u8 dat) // 描述: 向I2C匯流排傳送一個位元組資料. // 引數: dat:要傳送的資料. // 返回: none. // 版本: V1.0, 2017-06-23 //======================================================================== void I2C_SendByte(unsigned char dat) { unsigned char i; for (i=0; i<8; i++) //8位計數器 { dat <<= 1; //移出資料的最高位 I2C_SDA = CY; //送資料口 I2C_SCL = 1; //拉高時鐘線 NOP2(); //等待機器反應 I2C_SCL = 0; //拉低時鐘線 } I2C_RecvACK(); } //======================================================================== // 函式: unsigned char I2C_RecvByte() // 描述: 從I2C匯流排接收一個位元組資料. // 引數: none. // 返回: 接收到的資料. // 版本: V1.0, 2017-06-23 //======================================================================== unsigned char I2C_RecvByte() { unsigned char i; unsigned char dat = 0; I2C_SDA = 1; //使能內部上拉,準備讀取資料, for (i=0; i<8; i++) //8位計數器 { dat <<= 1; I2C_SCL = 1; //拉高時鐘線 NOP2(); //等待機器反應 dat |= I2C_SDA; //讀資料 I2C_SCL = 0; //拉低時鐘線 } return dat; } //======================================================================== // 函式: void Single_WriteI2C(unsigned char REG_Address,unsigned char REG_data) // 描述: 向I2C裝置寫入一個位元組資料. // 引數: REG_Address:地址. // REG_data:要寫入的資料. // 返回: none. // 版本: V1.0, 2017-06-23 //======================================================================== void Single_WriteI2C(unsigned char REG_Address,unsigned char REG_data) { I2C_Start(); //起始訊號 I2C_SendByte(SlaveAddress); //傳送裝置地址+寫訊號 I2C_SendByte(REG_Address); //內部暫存器地址, I2C_SendByte(REG_data); //內部暫存器資料, I2C_Stop(); //傳送停止訊號 } //======================================================================== // 函式: unsigned char Single_ReadI2C(unsigned char REG_Address) // 描述: 從I2C裝置讀取一個位元組資料. // 引數: REG_Address:地址. // 返回: 讀取到的資料. // 版本: V1.0, 2017-06-23 //======================================================================== unsigned char Single_ReadI2C(unsigned char REG_Address) { unsigned char REG_data; I2C_Start(); //起始訊號 I2C_SendByte(SlaveAddress); //傳送裝置地址+寫訊號 I2C_SendByte(REG_Address); //傳送儲存單元地址,從0開始 I2C_Start(); //起始訊號 I2C_SendByte(SlaveAddress+1); //傳送裝置地址+讀訊號 REG_data=I2C_RecvByte(); //讀出暫存器資料 I2C_SendACK(1); //接收應答訊號 I2C_Stop(); //停止訊號 return REG_data; } //======================================================================== // 函式: void MPU6050_init() // 描述: 初始化MPU6050. // 引數: none. // 返回: none. // 版本: V1.0, 2017-06-23 //======================================================================== void MPU6050_Init() { Single_WriteI2C(PWR_MGMT_1, 0x00); //解除休眠狀態 Single_WriteI2C(SMPLRT_DIV, 0x07); Single_WriteI2C(CONFIG, 0x06); Single_WriteI2C(GYRO_CONFIG, 0x18); Single_WriteI2C(ACCEL_CONFIG, 0x01); } //======================================================================== // 函式: int GetData(u8 REG_Address) // 描述: 讀取資料併合成為int型資料. // 引數: REG_Address:地址. // 返回: 讀取到的資料. // 版本: V1.0, 2017-06-23 //======================================================================== int GetData(unsigned char REG_Address) { unsigned char H,L; H = Single_ReadI2C(REG_Address); L = Single_ReadI2C(REG_Address + 1); return (H << 8) + L; //合成數據 } ////======================================================================== //// 函式: int get_x_angle() //// 描述: 獲取三軸角速度,三軸加速度 //// 引數: gyro_id:資料ID,1:x角速度,2:y角速度,3:z角速度,4:x加速度,5:y加速度,6:z加速度. //// 返回: 陀螺儀值. //// 版本: V2.0, 2017-07-15 ////======================================================================== int Get_Gyro_Data(unsigned char gyro_id) { switch(gyro_id) { case 1: return GetData(ACCEL_XOUT_H); break; case 2: return GetData(ACCEL_YOUT_H); break; case 3: return GetData(ACCEL_ZOUT_H); break; case 4: return GetData(GYRO_XOUT_H) ; break; case 5: return GetData(GYRO_YOUT_H) ; break; case 6: return GetData(GYRO_ZOUT_H) ; break; } return 0; } //======================================================================== // 函式: int MPU6050_Get_Angle(float x,float y,float z,u8 dir) // 描述: 轉化成與三個方向的夾角. // 引數: x:x方向資料. // y:y方向資料. // z:z方向資料. // dir:方向ID. // 返回: 夾角角度值(放大10倍). // 版本: V1.0, 2017-06-23 //======================================================================== int MPU6050_Get_Angle(int x,int y,int z,unsigned char dir) { float xdata temp; float xdata res = 0; switch(dir) { case 0://與z軸的夾角 temp = sqrt(((float)x*(float)x+(float)y*(float)y))/(float)z; res = atan(temp); break; case 1://與x軸的夾角 temp = (float)x/sqrt(((float)y*(float)y+(float)z*(float)z)); res = atan(temp); break; case 2://與y軸的夾角 temp = (float)y/sqrt(((float)x*(float)x+(float)z*(float)z)); res = atan(temp); break; } return (int)(res*1800/3.1416);//弧度轉換為角度,擴大10倍 } //======================================================================== // int get_included_angle(unsigned dat) // 描述: 獲取角度或加速度 // 引數: angle_id:方向指示變數(1:X軸角度,2:Y軸角度,3:Z軸角度,4:X軸加速度,5:Y軸加速度,6:Z軸加速度). // 返回: 夾角角度值(放大10倍). // 版本: V1.0, 2017-06-23 //======================================================================== int MPU6050_Get_Data(unsigned angle_id) { switch(angle_id) { case 1:return MPU6050_Get_Angle( Get_Gyro_Data(1), Get_Gyro_Data(2), Get_Gyro_Data(3), 1);break; case 2:return MPU6050_Get_Angle( Get_Gyro_Data(1), Get_Gyro_Data(2), Get_Gyro_Data(3), 2);break; case 3:return MPU6050_Get_Angle( Get_Gyro_Data(1), Get_Gyro_Data(2), Get_Gyro_Data(3), 0);break; case 4:return (int)((float)((float)Get_Gyro_Data(4)/16384)*9.8*100); case 5:return (int)((float)((float)Get_Gyro_Data(5)/16384)*9.8*100); case 6:return (int)((float)((float)Get_Gyro_Data(6)/16384)*9.8*100); } return 0; } //串列埠初始化 void Uart_Init() { SCON |= 0x40; //8位資料 P_SW1 &= ~0xc0; //UART1 使用P30 P31口 預設 TR1 = 0; //關閉定時器1 AUXR &= ~0x01; //串列埠1波特率使用定時器1 TMOD &= ~(1<<6); //Timer1 set As Timer TMOD &= ~0x30; //16位自動重灌 AUXR |= (1<<6); //定時器使用1T模式 TH1 = (unsigned char)(Timer1_Reload_Usart >> 8); TL1 = (unsigned char)Timer1_Reload_Usart; TR1 = 1; //開啟定時器1 PS = 1; //高優先順序中斷 REN = 1; //允許接收 ES = 1; //允許中斷 EA = 1; //允許全域性中斷 } //======================================================================== // 函式: serial_one_send_byte(unsigned char dat) // 描述: 串列埠1傳送一個位元組. // 引數: dat:字元(無符號八位整型資料). // 返回: none. // 版本: V1.0, 2017-06-22 //======================================================================== void serial_one_send_byte(unsigned char dat) { SBUF = dat; while(!TI); TI = 0; } //======================================================================== // 函式: serial_one_send_string(u8 *dat) // 描述: 串列埠1傳送字串. // 引數: dat:字串. // 返回: none. // 版本: V1.0, 2017-06-22 //======================================================================== void serial_one_send_string(unsigned char *dat) { while(*dat) serial_one_send_byte(*dat++); } //======================================================================== // 函式: void serial_one_send_number(long num) // 描述: 串列埠1傳送整型資料. // 引數: num:整型數值. // 返回: none. // 版本: V1.0, 2017-06-22 //======================================================================== void serial_one_send_number(long num) { long dat = 0; unsigned char length = 0; if(num < 0) //當數值為負數時 { serial_one_send_byte('-'); //輸出負號 num = -num; //將數值取相反數 } if(num == 0) //當數值為0時 serial_one_send_byte('0'); //輸出字元0 else //當數值不為0時 { while(num) //將數值倒過來 { dat = dat * 10; dat = dat + num % 10; num = num / 10; length++; } while(length--) //從第一位開始輸出倒過來的數值 { serial_one_send_byte(dat % 10 + '0'); dat = dat / 10; } } } void serial_one_send_float(double float_val, char bit_val) { long xdata value_int = 0; long xdata value_flt = 0; if(float_val < 0) { serial_one_send_byte('-'); float_val = -float_val; } value_int = (long)float_val; float_val = float_val - (double)value_int; for(;bit_val;bit_val--) float_val = float_val * 10; serial_one_send_number(value_int); serial_one_send_byte('.'); serial_one_send_number((long)float_val); } float value = 0; //主函式 void main() { Delay1000ms(); Uart_Init(); //串列埠初始化 MPU6050_Init(); //初始化MPU6505 while(1) { value = MPU6050_Get_Data(1); //獲取與x軸的夾角,角度被放大10倍 serial_one_send_string("模組與x軸的夾角為:"); serial_one_send_float(value / 10,1); //角度除以10,並從串列埠發出,第二個引數為保留一位小數 serial_one_send_string("\r\n"); //換行 value = MPU6050_Get_Data(2); //獲取與y軸的夾角,角度被放大10倍 serial_one_send_string("模組與y軸的夾角為:"); serial_one_send_float(value / 10,1); //角度除以10,並從串列埠發出 serial_one_send_string("\r\n"); //換行 value = MPU6050_Get_Data(3); //獲取與z軸的夾角,角度被放大10倍 serial_one_send_string("模組與z軸的夾角為:"); serial_one_send_float(value / 10,1); //角度除以10,並從串列埠發出 serial_one_send_string("\r\n"); //換行 value = MPU6050_Get_Data(4); //獲取與x軸加速度,數值被放大100倍 serial_one_send_string("x軸加速度為:"); serial_one_send_float(value/100,1); //角度除以100,並從串列埠發出,第二個引數為保留一位小數 serial_one_send_string(" M/S2\r\n"); //換行 value = MPU6050_Get_Data(4); //獲取與y軸加速度,數值被放大100倍 serial_one_send_string("y軸加速度為:"); serial_one_send_float(value / 100,1); //角度除以100,並從串列埠發出 serial_one_send_string(" M/S2\r\n"); //換行 value = MPU6050_Get_Data(4); //獲取與z軸加速度,數值被放大100倍 serial_one_send_string("z軸加速度為:"); serial_one_send_float(value / 100,1); //角度除以100,並從串列埠發出 serial_one_send_string(" M/S2\r\n\r\n"); //換行 Delay1000ms(); Delay1000ms(); } } //串列埠中斷 void Uart1_Int (void) interrupt 4 { if(RI) RI = 0; }