天天看點

STM32F103C8T6 MPU6050 原始資料通過序列槽讀取(CubeMx生成 HAL庫)前言一、MPU6050簡介二、CubeMx設定三、MPU6050驅動結果展示

STM32F103C8T6 MPU6050 原始資料通過序列槽讀取(CubeMx生成 HAL庫)

文章目錄

    • STM32F103C8T6 MPU6050 原始資料通過序列槽讀取(CubeMx生成 HAL庫)
  • 前言
  • 一、MPU6050簡介
  • 二、CubeMx設定
  • 三、MPU6050驅動
  • 結果展示

前言

MPU6050作為一個六軸慣性測量單元,經常在各種裝置中被使用,經過一段時間的調試,對其進行小總結,有錯誤還請各位大佬指出。

一、MPU6050簡介

1.基礎介紹

STM32F103C8T6 MPU6050 原始資料通過序列槽讀取(CubeMx生成 HAL庫)前言一、MPU6050簡介二、CubeMx設定三、MPU6050驅動結果展示

MPU6050采用I2C口與單片機進行通信,作為一款六軸運動處理元件,其整合了3軸陀螺儀和三軸加速度傳感器,并且含有第二I2C接口用于連接配接外部磁力傳感器。利用自帶的數字運動處理(DMP: Digital Motion Processor)硬體加速引擎,通過主 IIC 接口,向應用端輸出完整的 9 軸融合演算資料。有了 DMP,我們可以使用 InvenSense 公司提供的運動處理資料庫,非常友善的實作姿态解算,降低了運動處理運算對作業系統的負荷,同時大大降低了開發難度。

​​​​

STM32F103C8T6 MPU6050 原始資料通過序列槽讀取(CubeMx生成 HAL庫)前言一、MPU6050簡介二、CubeMx設定三、MPU6050驅動結果展示

MPU6050的内部框圖入圖所示:

STM32F103C8T6 MPU6050 原始資料通過序列槽讀取(CubeMx生成 HAL庫)前言一、MPU6050簡介二、CubeMx設定三、MPU6050驅動結果展示

​​

SCL和SDA是連接配接在MCU的I2C接口,MCU可以通過這個I2C接口來控制MPU6050,另外的I2C接口用于連接配接外部裝置,若連接配接磁傳感器,就可以組成九![軸傳感器。AD0 是從 IIC 接口(接 MCU)的位址控制引腳,該引腳控制IIC 位址的最低位。如果接 GND,則 MPU6050 的 IIC 位址是:0X68,如果接 VDD,則是0X69,注意:這裡的位址是不包含資料傳輸的最低位的(最低位用來表示讀寫)!!

2.利用STM3F1讀取MPU6050的原始資料步驟。

1)初始化I2C接口

2)複位MPU6050:讓傳感器内部的所有寄存器回複預設值(對電源管理寄存器(0x6B)的bit7寫1實作)。複位後,電源管理寄存器1恢複預設值(0x40)然後設定該寄存器為0x00,喚醒MPU6050。

STM32F103C8T6 MPU6050 原始資料通過序列槽讀取(CubeMx生成 HAL庫)前言一、MPU6050簡介二、CubeMx設定三、MPU6050驅動結果展示
#define MPU_PWR_MGMT1_REG		0X6B	//電源管理寄存器1
MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X80);	//複位MPU6050
MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X00);	//喚醒MPU6050 
           

3)設定角速度傳感器(陀螺儀)和加速度傳感器的滿量程範圍

設定兩個傳感器的滿量程範圍(FSR),分别通過陀螺儀配置寄存器(0X1B)和加速度傳感器配置寄存器(0X1C)設定。一般設定陀螺儀的滿量程範圍為±2000dps,加速度傳感器的滿量程範圍為±2g

STM32F103C8T6 MPU6050 原始資料通過序列槽讀取(CubeMx生成 HAL庫)前言一、MPU6050簡介二、CubeMx設定三、MPU6050驅動結果展示
STM32F103C8T6 MPU6050 原始資料通過序列槽讀取(CubeMx生成 HAL庫)前言一、MPU6050簡介二、CubeMx設定三、MPU6050驅動結果展示
#define MPU_GYRO_CFG_REG		0X1B	//陀螺儀配置寄存器
#define MPU_ACCEL_CFG_REG		0X1C	//加速度計配置寄存器
//fsr:0,±250dps;1,±500dps;2,±1000dps;3,±2000dps
uint8_t MPU_Set_Gyro_Fsr(uint8_t fsr)
{
	return MPU_Write_Byte(MPU_GYRO_CFG_REG,fsr<<3);
}
//設定陀螺儀滿量程範圍  //fsr:0,±2g;1,±4g;2,±8g;3,±16g
uint8_t MPU_Set_Accel_Fsr(uint8_t fsr)
{
	return MPU_Write_Byte(MPU_ACCEL_CFG_REG,fsr<<3);//設定加速度傳感器滿量程範圍  
}
           

4)設定其他參數

關閉中斷、關閉 AUX IIC 接口、禁止 FIFO、設定陀螺儀采樣率和設定數字低通濾波器(DLPF)等。

陀螺儀采樣率通過采

樣率分頻寄存器(0X19)控制,這個采樣率我們一般設定為 50 即可。數字低通濾波器(DLPF)則通過配置寄存器(0X1A)設定,一般設定 DLPF 為帶寬的 1/2 即可。

MPU_Set_Rate(50);						//設定采樣率50Hz
	MPU_Write_Byte(MPU_INT_EN_REG,0X00);	//關閉所有中斷
	MPU_Write_Byte(MPU_USER_CTRL_REG,0X00);	//I2C主模式關閉
	MPU_Write_Byte(MPU_FIFO_EN_REG,0X00);	//關閉FIFO
	MPU_Write_Byte(MPU_INTBP_CFG_REG,0X80);	//INT引腳低電平有效
           
//設定MPU6050的數字低通濾波器
//lpf:數字低通濾波頻率(Hz) 
uint8_t MPU_Set_LPF(uint16_t lpf)
{
	u8 data=0;
	if(lpf>=188)data=1;
	else if(lpf>=98)data=2;
	else if(lpf>=42)data=3;
	else if(lpf>=20)data=4;
	else if(lpf>=10)data=5;
	else data=6; 
	return MPU_Write_Byte(MPU_CFG_REG,data);//設定數字低通濾波器  
}
           
//設定MPU6050的采樣率(假定Fs=1KHz)
//rate:4~1000(Hz)
uint8_t MPU_Set_Rate(uint16_t rate)
{
	uint8_t data;
	if(rate>1000)rate=1000;
	if(rate<4)rate=4;
	data=1000/rate-1;
	data=MPU_Write_Byte(MPU_SAMPLE_RATE_REG,data);	//設定數字低通濾波器
 	return MPU_Set_LPF(rate/2);	//自動設定LPF為采樣率的一半
}
           

二、CubeMx設定

1.選擇晶片

STM32F103C8T6 MPU6050 原始資料通過序列槽讀取(CubeMx生成 HAL庫)前言一、MPU6050簡介二、CubeMx設定三、MPU6050驅動結果展示

2.設定I2C(選擇普通I2C即可),設定中斷

STM32F103C8T6 MPU6050 原始資料通過序列槽讀取(CubeMx生成 HAL庫)前言一、MPU6050簡介二、CubeMx設定三、MPU6050驅動結果展示
STM32F103C8T6 MPU6050 原始資料通過序列槽讀取(CubeMx生成 HAL庫)前言一、MPU6050簡介二、CubeMx設定三、MPU6050驅動結果展示

3.設定RCC

STM32F103C8T6 MPU6050 原始資料通過序列槽讀取(CubeMx生成 HAL庫)前言一、MPU6050簡介二、CubeMx設定三、MPU6050驅動結果展示

4.設定SYS

STM32F103C8T6 MPU6050 原始資料通過序列槽讀取(CubeMx生成 HAL庫)前言一、MPU6050簡介二、CubeMx設定三、MPU6050驅動結果展示

5.設定序列槽,DMA打開,中斷勾選

STM32F103C8T6 MPU6050 原始資料通過序列槽讀取(CubeMx生成 HAL庫)前言一、MPU6050簡介二、CubeMx設定三、MPU6050驅動結果展示

6.設定時鐘(c8t6是72Hz)

STM32F103C8T6 MPU6050 原始資料通過序列槽讀取(CubeMx生成 HAL庫)前言一、MPU6050簡介二、CubeMx設定三、MPU6050驅動結果展示

7.設定好後生成MDK代碼

三、MPU6050驅動

生成檔案夾和添加檔案路徑方法見上一篇文章

mpu6050.c

#include "stm32f1xx_hal.h"
#include "mpu6050.h"


//初始化MPU6050
//傳回值:0,成功
//    其他,錯誤代碼
uint8_t MPU_Init(void)
{
    uint8_t res;

    MPU_IIC_Init();//初始化IIC總線
    MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X80);	//複位MPU6050
    delay_ms(100);
    MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X00);	//喚醒MPU6050
    MPU_Set_Gyro_Fsr(3);					//陀螺儀傳感器,±2000dps
    MPU_Set_Accel_Fsr(0);					//加速度傳感器,±2g
    MPU_Set_Rate(50);						//設定采樣率50Hz
    MPU_Write_Byte(MPU_INT_EN_REG,0X00);	//關閉所有中斷
    MPU_Write_Byte(MPU_USER_CTRL_REG,0X00);	//I2C主模式關閉
    MPU_Write_Byte(MPU_FIFO_EN_REG,0X00);	//關閉FIFO
    MPU_Write_Byte(MPU_INTBP_CFG_REG,0X80);	//INT引腳低電平有效
    res=MPU_Read_Byte(MPU_DEVICE_ID_REG);
    if(res==MPU_ADDR)//器件ID正确
    {
        MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X01);	//設定CLKSEL,PLL X軸為參考
        MPU_Write_Byte(MPU_PWR_MGMT2_REG,0X00);	//加速度與陀螺儀都工作
        MPU_Set_Rate(50);						//設定采樣率為50Hz
    } else return 1;
    return 0;
}
//設定MPU6050陀螺儀傳感器滿量程範圍
//fsr:0,±250dps;1,±500dps;2,±1000dps;3,±2000dps
//傳回值:0,設定成功
//    其他,設定失敗
uint8_t MPU_Set_Gyro_Fsr(uint8_t fsr)
{
    return MPU_Write_Byte(MPU_GYRO_CFG_REG,fsr<<3);//設定陀螺儀滿量程範圍
}
//設定MPU6050加速度傳感器滿量程範圍
//fsr:0,±2g;1,±4g;2,±8g;3,±16g
//傳回值:0,設定成功
//    其他,設定失敗
uint8_t MPU_Set_Accel_Fsr(uint8_t fsr)
{
    return MPU_Write_Byte(MPU_ACCEL_CFG_REG,fsr<<3);//設定加速度傳感器滿量程範圍
}
//設定MPU6050的數字低通濾波器
//lpf:數字低通濾波頻率(Hz)
//傳回值:0,設定成功
//    其他,設定失敗
uint8_t MPU_Set_LPF(uint16_t lpf)
{
    uint8_t data=0;
    if(lpf>=188)data=1;
    else if(lpf>=98)data=2;
    else if(lpf>=42)data=3;
    else if(lpf>=20)data=4;
    else if(lpf>=10)data=5;
    else data=6;
    return MPU_Write_Byte(MPU_CFG_REG,data);//設定數字低通濾波器
}
//設定MPU6050的采樣率(假定Fs=1KHz)
//rate:4~1000(Hz)
//傳回值:0,設定成功
//    其他,設定失敗
uint8_t MPU_Set_Rate(uint16_t rate)
{
    uint8_t data;
    if(rate>1000)rate=1000;
    if(rate<4)rate=4;
    data=1000/rate-1;
    data=MPU_Write_Byte(MPU_SAMPLE_RATE_REG,data);	//設定數字低通濾波器
    return MPU_Set_LPF(rate/2);	//自動設定LPF為采樣率的一半
}

//得到溫度值
//傳回值:溫度值(擴大了100倍)
short MPU_Get_Temperature(void)
{
    uint8_t buf[2];
    short raw;
    float temp;
    MPU_Read_Len(MPU_ADDR,MPU_TEMP_OUTH_REG,2,buf);
    raw=((uint16_t)buf[0]<<8)|buf[1];
    temp=36.53+((double)raw)/340;
    return temp*100;;
}
//得到陀螺儀值(原始值)
//gx,gy,gz:陀螺儀x,y,z軸的原始讀數(帶符号)
//傳回值:0,成功
//    其他,錯誤代碼
uint8_t MPU_Get_Gyroscope(short *gx,short *gy,short *gz)
{
    uint8_t buf[6],res;
    res=MPU_Read_Len(MPU_ADDR,MPU_GYRO_XOUTH_REG,6,buf);
    if(res==0)
    {
        *gx=((uint16_t)buf[0]<<8)|buf[1];
        *gy=((uint16_t)buf[2]<<8)|buf[3];
        *gz=((uint16_t)buf[4]<<8)|buf[5];
    }
    return res;;
}
//得到加速度值(原始值)
//gx,gy,gz:陀螺儀x,y,z軸的原始讀數(帶符号)
//傳回值:0,成功
//    其他,錯誤代碼
uint8_t MPU_Get_Accelerometer(short *ax,short *ay,short *az)
{
    uint8_t buf[6],res;
    res=MPU_Read_Len(MPU_ADDR,MPU_ACCEL_XOUTH_REG,6,buf);
    if(res==0)
    {
        *ax=((uint16_t)buf[0]<<8)|buf[1];
        *ay=((uint16_t)buf[2]<<8)|buf[3];
        *az=((uint16_t)buf[4]<<8)|buf[5];
    }
    return res;;
}
//IIC連續寫
//addr:器件位址
//reg:寄存器位址
//len:寫入長度
//buf:資料區
//傳回值:0,正常
//    其他,錯誤代碼
uint8_t MPU_Write_Len(uint8_t addr,uint8_t reg,uint8_t len,uint8_t *buf)
{
    uint8_t i;
    MPU_IIC_Start();
    MPU_IIC_Send_Byte((addr<<1)|0);//發送器件位址+寫指令
    if(MPU_IIC_Wait_Ack())	//等待應答
    {
        MPU_IIC_Stop();
        return 1;
    }
    MPU_IIC_Send_Byte(reg);	//寫寄存器位址
    MPU_IIC_Wait_Ack();		//等待應答
    for(i=0; i<len; i++)
    {
        MPU_IIC_Send_Byte(buf[i]);	//發送資料
        if(MPU_IIC_Wait_Ack())		//等待ACK
        {
            MPU_IIC_Stop();
            return 1;
        }
    }
    MPU_IIC_Stop();
    return 0;
}
//IIC連續讀
//addr:器件位址
//reg:要讀取的寄存器位址
//len:要讀取的長度
//buf:讀取到的資料存儲區
//傳回值:0,正常
//    其他,錯誤代碼
uint8_t MPU_Read_Len(uint8_t addr,uint8_t reg,uint8_t len,uint8_t *buf)
{
    MPU_IIC_Start();
    MPU_IIC_Send_Byte((addr<<1)|0);//發送器件位址+寫指令
    if(MPU_IIC_Wait_Ack())	//等待應答
    {
        MPU_IIC_Stop();
        return 1;
    }
    MPU_IIC_Send_Byte(reg);	//寫寄存器位址
    MPU_IIC_Wait_Ack();		//等待應答
    MPU_IIC_Start();
    MPU_IIC_Send_Byte((addr<<1)|1);//發送器件位址+讀指令
    MPU_IIC_Wait_Ack();		//等待應答
    while(len)
    {
        if(len==1)*buf=MPU_IIC_Read_Byte(0);//讀資料,發送nACK
        else *buf=MPU_IIC_Read_Byte(1);		//讀資料,發送ACK
        len--;
        buf++;
    }
    MPU_IIC_Stop();	//産生一個停止條件
    return 0;
}
//IIC寫一個位元組
//reg:寄存器位址
//data:資料
//傳回值:0,正常
//    其他,錯誤代碼
uint8_t MPU_Write_Byte(uint8_t reg,uint8_t data)
{
    MPU_IIC_Start();
    MPU_IIC_Send_Byte((MPU_ADDR<<1)|0);//發送器件位址+寫指令
    if(MPU_IIC_Wait_Ack())	//等待應答
    {
        MPU_IIC_Stop();
        return 1;
    }
    MPU_IIC_Send_Byte(reg);	//寫寄存器位址
    MPU_IIC_Wait_Ack();		//等待應答
    MPU_IIC_Send_Byte(data);//發送資料
    if(MPU_IIC_Wait_Ack())	//等待ACK
    {
        MPU_IIC_Stop();
        return 1;
    }
    MPU_IIC_Stop();
    return 0;
}
//IIC讀一個位元組
//reg:寄存器位址
//傳回值:讀到的資料
uint8_t MPU_Read_Byte(uint8_t reg)
{
    uint8_t res;
    MPU_IIC_Start();
    MPU_IIC_Send_Byte((MPU_ADDR<<1)|0);//發送器件位址+寫指令
    MPU_IIC_Wait_Ack();		//等待應答
    MPU_IIC_Send_Byte(reg);	//寫寄存器位址
    MPU_IIC_Wait_Ack();		//等待應答
    MPU_IIC_Start();
    MPU_IIC_Send_Byte((MPU_ADDR<<1)|1);//發送器件位址+讀指令
    MPU_IIC_Wait_Ack();		//等待應答
    res=MPU_IIC_Read_Byte(0);//讀取資料,發送nACK
    MPU_IIC_Stop();			//産生一個停止條件
    return res;
}
           

mpu6050.h

#ifndef __MPU6050_H
#define __MPU6050_H
#include "IIC.h"


#define delay_ms				HAL_Delay
#define MPU_IIC_Init			IIC_GPIO_Init
#define MPU_IIC_Start			IIC_Start
#define MPU_IIC_Stop			IIC_Stop
#define MPU_IIC_Send_Byte		IIC_Send_Byte
#define MPU_IIC_Read_Byte		IIC_Read_Byte
#define MPU_IIC_Wait_Ack		IIC_Wait_Ack

//#define MPU_ACCEL_OFFS_REG		0X06	//accel_offs寄存器,可讀取版本号,寄存器手冊未提到
//#define MPU_PROD_ID_REG			0X0C	//prod id寄存器,在寄存器手冊未提到
#define MPU_SELF_TESTX_REG		0X0D	//自檢寄存器X
#define MPU_SELF_TESTY_REG		0X0E	//自檢寄存器Y
#define MPU_SELF_TESTZ_REG		0X0F	//自檢寄存器Z
#define MPU_SELF_TESTA_REG		0X10	//自檢寄存器A
#define MPU_SAMPLE_RATE_REG		0X19	//采樣頻率分頻器
#define MPU_CFG_REG				0X1A	//配置寄存器
#define MPU_GYRO_CFG_REG			0X1B	//陀螺儀配置寄存器
#define MPU_ACCEL_CFG_REG			0X1C	//加速度計配置寄存器
#define MPU_MOTION_DET_REG		0X1F	//運動檢測閥值設定寄存器
#define MPU_FIFO_EN_REG			0X23	//FIFO使能寄存器
#define MPU_I2CMST_CTRL_REG		0X24	//IIC主機控制寄存器
#define MPU_I2CSLV0_ADDR_REG		0X25	//IIC從機0器件位址寄存器
#define MPU_I2CSLV0_REG			0X26	//IIC從機0資料位址寄存器
#define MPU_I2CSLV0_CTRL_REG		0X27	//IIC從機0控制寄存器
#define MPU_I2CSLV1_ADDR_REG		0X28	//IIC從機1器件位址寄存器
#define MPU_I2CSLV1_REG			0X29	//IIC從機1資料位址寄存器
#define MPU_I2CSLV1_CTRL_REG		0X2A	//IIC從機1控制寄存器
#define MPU_I2CSLV2_ADDR_REG		0X2B	//IIC從機2器件位址寄存器
#define MPU_I2CSLV2_REG			0X2C	//IIC從機2資料位址寄存器
#define MPU_I2CSLV2_CTRL_REG		0X2D	//IIC從機2控制寄存器
#define MPU_I2CSLV3_ADDR_REG		0X2E	//IIC從機3器件位址寄存器
#define MPU_I2CSLV3_REG			0X2F	//IIC從機3資料位址寄存器
#define MPU_I2CSLV3_CTRL_REG		0X30	//IIC從機3控制寄存器
#define MPU_I2CSLV4_ADDR_REG		0X31	//IIC從機4器件位址寄存器
#define MPU_I2CSLV4_REG			0X32	//IIC從機4資料位址寄存器
#define MPU_I2CSLV4_DO_REG		0X33	//IIC從機4寫資料寄存器
#define MPU_I2CSLV4_CTRL_REG		0X34	//IIC從機4控制寄存器
#define MPU_I2CSLV4_DI_REG		0X35	//IIC從機4讀資料寄存器

#define MPU_I2CMST_STA_REG		0X36	//IIC主機狀态寄存器
#define MPU_INTBP_CFG_REG			0X37	//中斷/旁路設定寄存器
#define MPU_INT_EN_REG			0X38	//中斷使能寄存器
#define MPU_INT_STA_REG			0X3A	//中斷狀态寄存器

#define MPU_ACCEL_XOUTH_REG		0X3B	//加速度值,X軸高8位寄存器
#define MPU_ACCEL_XOUTL_REG		0X3C	//加速度值,X軸低8位寄存器
#define MPU_ACCEL_YOUTH_REG		0X3D	//加速度值,Y軸高8位寄存器
#define MPU_ACCEL_YOUTL_REG		0X3E	//加速度值,Y軸低8位寄存器
#define MPU_ACCEL_ZOUTH_REG		0X3F	//加速度值,Z軸高8位寄存器
#define MPU_ACCEL_ZOUTL_REG		0X40	//加速度值,Z軸低8位寄存器

#define MPU_TEMP_OUTH_REG			0X41	//溫度值高八位寄存器
#define MPU_TEMP_OUTL_REG			0X42	//溫度值低8位寄存器

#define MPU_GYRO_XOUTH_REG		0X43	//陀螺儀值,X軸高8位寄存器
#define MPU_GYRO_XOUTL_REG		0X44	//陀螺儀值,X軸低8位寄存器
#define MPU_GYRO_YOUTH_REG		0X45	//陀螺儀值,Y軸高8位寄存器
#define MPU_GYRO_YOUTL_REG		0X46	//陀螺儀值,Y軸低8位寄存器
#define MPU_GYRO_ZOUTH_REG		0X47	//陀螺儀值,Z軸高8位寄存器
#define MPU_GYRO_ZOUTL_REG		0X48	//陀螺儀值,Z軸低8位寄存器

#define MPU_I2CSLV0_DO_REG		0X63	//IIC從機0資料寄存器
#define MPU_I2CSLV1_DO_REG		0X64	//IIC從機1資料寄存器
#define MPU_I2CSLV2_DO_REG		0X65	//IIC從機2資料寄存器
#define MPU_I2CSLV3_DO_REG		0X66	//IIC從機3資料寄存器

#define MPU_I2CMST_DELAY_REG		0X67	//IIC主機延時管理寄存器
#define MPU_SIGPATH_RST_REG		0X68	//信号通道複位寄存器
#define MPU_MDETECT_CTRL_REG		0X69	//運動檢測控制寄存器
#define MPU_USER_CTRL_REG			0X6A	//使用者控制寄存器
#define MPU_PWR_MGMT1_REG			0X6B	//電源管理寄存器1
#define MPU_PWR_MGMT2_REG			0X6C	//電源管理寄存器2 
#define MPU_FIFO_CNTH_REG			0X72	//FIFO計數寄存器高八位
#define MPU_FIFO_CNTL_REG			0X73	//FIFO計數寄存器低八位
#define MPU_FIFO_RW_REG			0X74	//FIFO讀寫寄存器
#define MPU_DEVICE_ID_REG			0X75	//器件ID寄存器

//如果AD0腳(9腳)接地,IIC位址為0X68(不包含最低位).
//如果接V3.3,則IIC位址為0X69(不包含最低位).
#define MPU_ADDR					0X68


因為子產品AD0預設接GND,是以轉為讀寫位址後,為0XD1和0XD0(如果接VCC,則為0XD3和0XD2)
//#define MPU_READ    0XD1
//#define MPU_WRITE   0XD0

uint8_t MPU_Init(void); 								//初始化MPU6050
uint8_t MPU_Write_Len(uint8_t addr,uint8_t reg,uint8_t len,uint8_t *buf);//IIC連續寫
uint8_t MPU_Read_Len(uint8_t addr,uint8_t reg,uint8_t len,uint8_t *buf); //IIC連續讀
uint8_t MPU_Write_Byte(uint8_t reg,uint8_t data);				//IIC寫一個位元組
uint8_t MPU_Read_Byte(uint8_t reg);						//IIC讀一個位元組

uint8_t MPU_Set_Gyro_Fsr(uint8_t fsr);
uint8_t MPU_Set_Accel_Fsr(uint8_t fsr);
uint8_t MPU_Set_LPF(uint16_t lpf);
uint8_t MPU_Set_Rate(uint16_t rate);
uint8_t MPU_Set_Fifo(uint8_t sens);


short MPU_Get_Temperature(void);
uint8_t MPU_Get_Gyroscope(short *gx,short *gy,short *gz);
uint8_t MPU_Get_Accelerometer(short *ax,short *ay,short *az);

#endif

           

IIC.c

#include "stm32f1xx_hal.h"
#include "IIC.h"

/* 定義IIC總線連接配接的GPIO端口, 使用者隻需要修改下面4行代碼即可任意改變SCL和SDA的引腳 */
#define GPIO_PORT_IIC     GPIOB                       /* GPIO端口 */
#define RCC_IIC_ENABLE    __HAL_RCC_GPIOB_CLK_ENABLE()       /* GPIO端口時鐘 */
#define IIC_SCL_PIN       GPIO_PIN_6                 /* 連接配接到SCL時鐘線的GPIO */
#define IIC_SDA_PIN       GPIO_PIN_7                 /* 連接配接到SDA資料線的GPIO */

/* 定義讀寫SCL和SDA的宏,已增加代碼的可移植性和可閱讀性 */
#if 1	/* 條件編譯: 1 選擇GPIO的庫函數實作IO讀寫 */
#define IIC_SCL_1()  HAL_GPIO_WritePin(GPIO_PORT_IIC, IIC_SCL_PIN, GPIO_PIN_SET)		/* SCL = 1 */
#define IIC_SCL_0()  HAL_GPIO_WritePin(GPIO_PORT_IIC, IIC_SCL_PIN, GPIO_PIN_RESET)		/* SCL = 0 */

#define IIC_SDA_1()  HAL_GPIO_WritePin(GPIO_PORT_IIC, IIC_SDA_PIN, GPIO_PIN_SET)		/* SDA = 1 */
#define IIC_SDA_0()  HAL_GPIO_WritePin(GPIO_PORT_IIC, IIC_SDA_PIN, GPIO_PIN_RESET)		/* SDA = 0 */

#define IIC_SDA_READ()  HAL_GPIO_ReadPin(GPIO_PORT_IIC, IIC_SDA_PIN)	/* 讀SDA口線狀态 */
#else	/* 這個分支選擇直接寄存器操作實作IO讀寫 */
/* 注意:如下寫法,在IAR最進階别優化時,會被編譯器錯誤優化 */
#define IIC_SCL_1()  GPIO_PORT_IIC->BSRR = IIC_SCL_PIN				/* SCL = 1 */
#define IIC_SCL_0()  GPIO_PORT_IIC->BRR = IIC_SCL_PIN				/* SCL = 0 */

#define IIC_SDA_1()  GPIO_PORT_IIC->BSRR = IIC_SDA_PIN				/* SDA = 1 */
#define IIC_SDA_0()  GPIO_PORT_IIC->BRR = IIC_SDA_PIN				/* SDA = 0 */

#define IIC_SDA_READ()  ((GPIO_PORT_IIC->IDR & IIC_SDA_PIN) != 0)	/* 讀SDA口線狀态 */
#endif

void IIC_GPIO_Init(void);

/*
*********************************************************************************************************
*	函 數 名: IIC_Delay
*	功能說明: IIC總線位延遲,最快400KHz
*	形    參:無
*	返 回 值: 無
*********************************************************************************************************
*/
static void IIC_Delay(void)
{
    uint8_t i;

    /* 
     	下面的時間是通過安富萊AX-Pro邏輯分析儀測試得到的。
    	CPU主頻72MHz時,在内部Flash運作, MDK工程不優化
    	循環次數為10時,SCL頻率 = 205KHz
    	循環次數為7時,SCL頻率 = 347KHz, SCL高電平時間1.5us,SCL低電平時間2.87us
     	循環次數為5時,SCL頻率 = 421KHz, SCL高電平時間1.25us,SCL低電平時間2.375us

    IAR工程編譯效率高,不能設定為7
    */
    for (i = 0; i < 10; i++);
}

/*
*********************************************************************************************************
*	函 數 名: IIC_Start
*	功能說明: CPU發起IIC總線啟動信号
*	形    參:無
*	返 回 值: 無
*********************************************************************************************************
*/
void IIC_Start(void)
{
    /* 當SCL高電平時,SDA出現一個下跳沿表示IIC總線啟動信号 */
    IIC_SDA_1();
    IIC_SCL_1();
    IIC_Delay();
    IIC_SDA_0();
    IIC_Delay();
    IIC_SCL_0();
    IIC_Delay();
}

/*
*********************************************************************************************************
*	函 數 名: IIC_Start
*	功能說明: CPU發起IIC總線停止信号
*	形    參:無
*	返 回 值: 無
*********************************************************************************************************
*/
void IIC_Stop(void)
{
    /* 當SCL高電平時,SDA出現一個上跳沿表示IIC總線停止信号 */
    IIC_SDA_0();
    IIC_SCL_1();
    IIC_Delay();
    IIC_SDA_1();
}

/*
*********************************************************************************************************
*	函 數 名: IIC_SendByte
*	功能說明: CPU向IIC總線裝置發送8bit資料
*	形    參:_ucByte : 等待發送的位元組
*	返 回 值: 無
*********************************************************************************************************
*/
void IIC_Send_Byte(uint8_t _ucByte)
{
    uint8_t i;

    /* 先發送位元組的高位bit7 */
    for (i = 0; i < 8; i++)
    {
        if (_ucByte & 0x80)
        {
            IIC_SDA_1();
        }
        else
        {
            IIC_SDA_0();
        }
        IIC_Delay();
        IIC_SCL_1();
        IIC_Delay();
        IIC_SCL_0();
        if (i == 7)
        {
            IIC_SDA_1(); // 釋放總線
        }
        _ucByte <<= 1;	/* 左移一個bit */
        IIC_Delay();
    }
}

/*
*********************************************************************************************************
*	函 數 名: IIC_ReadByte
*	功能說明: CPU從IIC總線裝置讀取8bit資料
*	形    參:無
*	返 回 值: 讀到的資料
*********************************************************************************************************
*/
uint8_t IIC_Read_Byte(uint8_t ack)
{
    uint8_t i;
    uint8_t value;

    /* 讀到第1個bit為資料的bit7 */
    value = 0;
    for (i = 0; i < 8; i++)
    {
        value <<= 1;
        IIC_SCL_1();
        IIC_Delay();
        if (IIC_SDA_READ())
        {
            value++;
        }
        IIC_SCL_0();
        IIC_Delay();
    }
    if(ack==0)
        IIC_NAck();
    else
        IIC_Ack();
    return value;
}

/*
*********************************************************************************************************
*	函 數 名: IIC_WaitAck
*	功能說明: CPU産生一個時鐘,并讀取器件的ACK應答信号
*	形    參:無
*	返 回 值: 傳回0表示正确應答,1表示無器件響應
*********************************************************************************************************
*/
uint8_t IIC_Wait_Ack(void)
{
    uint8_t re;

    IIC_SDA_1();	/* CPU釋放SDA總線 */
    IIC_Delay();
    IIC_SCL_1();	/* CPU驅動SCL = 1, 此時器件會傳回ACK應答 */
    IIC_Delay();
    if (IIC_SDA_READ())	/* CPU讀取SDA口線狀态 */
    {
        re = 1;
    }
    else
    {
        re = 0;
    }
    IIC_SCL_0();
    IIC_Delay();
    return re;
}

/*
*********************************************************************************************************
*	函 數 名: IIC_Ack
*	功能說明: CPU産生一個ACK信号
*	形    參:無
*	返 回 值: 無
*********************************************************************************************************
*/
void IIC_Ack(void)
{
    IIC_SDA_0();	/* CPU驅動SDA = 0 */
    IIC_Delay();
    IIC_SCL_1();	/* CPU産生1個時鐘 */
    IIC_Delay();
    IIC_SCL_0();
    IIC_Delay();
    IIC_SDA_1();	/* CPU釋放SDA總線 */
}

/*
*********************************************************************************************************
*	函 數 名: IIC_NAck
*	功能說明: CPU産生1個NACK信号
*	形    參:無
*	返 回 值: 無
*********************************************************************************************************
*/
void IIC_NAck(void)
{
    IIC_SDA_1();	/* CPU驅動SDA = 1 */
    IIC_Delay();
    IIC_SCL_1();	/* CPU産生1個時鐘 */
    IIC_Delay();
    IIC_SCL_0();
    IIC_Delay();
}

/*
*********************************************************************************************************
*	函 數 名: IIC_GPIO_Config
*	功能說明: 配置IIC總線的GPIO,采用模拟IO的方式實作
*	形    參:無
*	返 回 值: 無
*********************************************************************************************************
*/
void IIC_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_IIC_ENABLE;	/* 打開GPIO時鐘 */

    GPIO_InitStructure.Pin = IIC_SCL_PIN | IIC_SDA_PIN;
    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD;  	/* 開漏輸出 */
    HAL_GPIO_Init(GPIO_PORT_IIC, &GPIO_InitStructure);

    /* 給一個停止信号, 複位IIC總線上的所有裝置到待機模式 */
    IIC_Stop();
}

/*
*********************************************************************************************************
*	函 數 名: IIC_CheckDevice
*	功能說明: 檢測IIC總線裝置,CPU向發送裝置位址,然後讀取裝置應答來判斷該裝置是否存在
*	形    參:_Address:裝置的IIC總線位址
*	返 回 值: 傳回值 0 表示正确, 傳回1表示未探測到
*********************************************************************************************************
*/
uint8_t IIC_CheckDevice(uint8_t _Address)
{
    uint8_t ucAck;

    IIC_GPIO_Init();		/* 配置GPIO */

    IIC_Start();		/* 發送啟動信号 */

    /* 發送裝置位址+讀寫控制bit(0 = w, 1 = r) bit7 先傳 */
    IIC_Send_Byte(_Address|IIC_WR);
    ucAck = IIC_Wait_Ack();	/* 檢測裝置的ACK應答 */

    IIC_Stop();			/* 發送停止信号 */

    return ucAck;
}

           

IIC.h

#ifndef _IIC_H
#define _IIC_H

#include <inttypes.h>

#define IIC_WR	0		/* 寫控制bit */
#define IIC_RD	1		/* 讀控制bit */

void IIC_Start(void);
void IIC_Stop(void);
void IIC_Send_Byte(uint8_t _ucByte);
uint8_t IIC_Read_Byte(uint8_t ack);
uint8_t IIC_Wait_Ack(void);
void IIC_Ack(void);
void IIC_NAck(void);
uint8_t IIC_CheckDevice(uint8_t _Address);
void IIC_GPIO_Init(void);

#endif

           

完成所有驅動檔案的添加之後記得将User檔案夾添加到c/c++路徑中編譯,編譯成功後就可以開始編寫主函數。

首先添加頭檔案

STM32F103C8T6 MPU6050 原始資料通過序列槽讀取(CubeMx生成 HAL庫)前言一、MPU6050簡介二、CubeMx設定三、MPU6050驅動結果展示

為了序列槽列印友善,加入printf函數

STM32F103C8T6 MPU6050 原始資料通過序列槽讀取(CubeMx生成 HAL庫)前言一、MPU6050簡介二、CubeMx設定三、MPU6050驅動結果展示
int main(void)
{
  /* USER CODE BEGIN 1 */
  short aacx,aacy,aacz;			//加速度傳感器原始資料
  short gyrox,gyroy,gyroz;		//陀螺儀原始資料
  short temp;					//溫度
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_I2C1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
MPU_Init();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
			HAL_Delay(500);
	  MPU_Get_Accelerometer(&aacx,&aacy,&aacz);
		MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);
		temp=MPU_Get_Temperature();
		printf("AAC_X:%5d AAC_Y:%5d AAC_Z:%5d\r\nGYRO_X:%5d GYRO_Y:%5d GYRO_Z:%5d\r\n",
	aacx,aacy,aacz,gyrox,gyroy,gyroz);
  }
  /* USER CODE END 3 */
}
           

結果展示

STM32F103C8T6 MPU6050 原始資料讀取(CubeMx生成 HAL庫)

STM32F103C8T6 MPU6050 原始資料通過序列槽讀取(CubeMx生成 HAL庫)前言一、MPU6050簡介二、CubeMx設定三、MPU6050驅動結果展示

原始資料的讀取對于MPU6050的使用而言隻是第一步,要想取得俯仰角(pitch),橫滾角(roll),航偏角(yaw)的資料,還需要使用官方給出的DMP庫或者卡爾曼濾波。

繼續閱讀