日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

STM32CubeMX教程19 I2C - MPU6050驱动

發布時間:2024/1/21 windows 51 coder
生活随笔 收集整理的這篇文章主要介紹了 STM32CubeMX教程19 I2C - MPU6050驱动 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1、準備材料

正點原子stm32f407探索者開發板V2.4

STM32CubeMX軟件(Version 6.10.0)

野火DAP仿真器

keil μVision5 IDE(MDK-Arm)

ST-LINK/V2驅動

XCOM V2.6串口助手

邏輯分析儀nanoDLA

2、實驗目標

使用STM32CubeMX軟件配置STM32F407開發板的I2C1與MPU6050芯片通信,讀取MPU6050的三軸加速度和陀螺儀數據并通過串口打印出來

3、實驗流程

3.0、前提知識

本實驗重點是理解I2C通信協議,而STM32CubeMX的配置則相對簡單,這里不會過于詳細全面的介紹I2C通信協議,但是會對所有需要知道的知識做介紹

在我們的開發板上有一顆三軸加速度計和陀螺儀傳感器MPU6050,單片機通過I2C1的PB8和PB9兩個引腳與MPU6050進行通信,MPU6050還有一個中斷引腳,這里為3D_INT引腳,但是本實驗僅僅輪詢讀取加速度計和陀螺儀的數據,并沒有用到該引腳中斷功能,我們使用的開發板上的MPU6050芯片硬件原理圖如下圖所示

I2C通信僅需要時鐘線SCLK和數據線SDA兩根線就可以讓主機與掛載在I2C上的從機進行通信和數據交換,一個I2C理論上最多可掛載127個設備(從機地址用7位二進制表示)

為了讓主機準確的與眾多從機中的一個進行通信,每個從機都會有一個地址,I2C通信時會在通信數據中先發送從機地址,然后對應地址的從機才會響應

而且I2C通信使用的時鐘線SCLK和數據線SDA兩根線必須要做上拉設置,因為I2C的兩個引腳被配置為開漏輸出,因此無法輸出高電平,I2C總線連線圖如下圖所示 (注釋1)

MPU6050的從機地址由芯片上的AD0引腳確定,當AD0引腳接地時,從機地址為0X68;

當AD0引腳接VCC時,從機地址為0X69;

根據上面MPU6050芯片硬件原理圖可知此時MPU6050的從機地址為0X68

根據MPU6050 datasheet 9.3 I2C Communications Protocol 小節可知 (注釋2),主機要通過I2C寫入/讀取MPU6050某一個寄存器一字節的數據,其通信步驟序列應該如下圖所示

我們以讀取內部寄存器單個字節數據為例做詳細介紹,首先確定通信的目的為主機Master從從機Slave內部某個寄存器internal register中讀取一個字節數據,以下為詳細通信步驟

  1. 主機時鐘線SCLK和數據線SDA兩根線產生起始信號(當 SCL 線是高電平時 SDA 線從高電平向低電平切換)
  2. 接下來時鐘線SCLK的8個時鐘節拍中,由數據線SDA發送一字節8位的數據,其中高7位為從機的地址,最后一位為0(1表示讀操作,0表示寫操作)
  3. 接下來1個時鐘節拍,從機應該產生應答信號ACK
  4. 接下來8個時鐘節拍,主機發送一字節8位的數據,該數據為要讀取的從機內部寄存器地址
  5. 接下來1個時鐘節拍,從機應該產生應答信號ACK
  6. 主機重新產生一個起始信號
  7. 接下來8個時鐘節拍,重新發送一字節8位的數據,其中高7位為從機的地址,最后一位為1,表示這次要讀
  8. 接下來1個時鐘節拍,從機應該產生應答信號ACK
  9. 接下來8個時鐘節拍,主機讀取一字節8位數據
  10. 接下來1個時鐘節拍,主機應該產生應答信號NACK
  11. 主機時鐘線SCLK和數據線SDA兩根線產生停止信號(當 SCL 線是高電平時 SDA 線由低電平向高電平切換)

接下來我們用邏輯分析儀捕獲下主機使用I2C1讀取MPU6050寄存器WHO_AM_I(0X75)時,時鐘線SCLK和數據線SDA的邏輯電平變化,如下圖所示,從圖上可知I2C讀取讀取MPU6050內部寄存器的時序與上面我們所描述的一致

用邏輯分析儀捕獲主機使用I2C1向MPU6050寄存器PWR_MGMT_1(0X6B)寫入一字節0X00數據時,時鐘線SCLK和數據線SDA的邏輯電平變化,如下圖所示

為什么上圖中從機地址從0X68變為0XD0了?

HAL庫中的I2C寫入函數HAL_I2C_Mem_Write()和讀取函數HAL_I2C_Mem_Read()對傳入從機地址DevAddress參數做了要求,該地址必須將數據手冊中提到的地址左移才可以調用該接口

0X68(0110 1000)向左移動直到遇到1即為0XD0(1101 0000),在I2C通信中使用上述兩個API,從機地址傳入0XD0表示對從機地址為0X68的從機進行寫操作,傳入0XD1表示對從機地址為0X68的從機進行讀操作

如下圖為HAL庫HAL_I2C_Mem_Read()函數說明

上面提到,當啟用I2C之后,其I2C_SCL和I2C_SDA兩個引腳被配置為了復用功能開漏輸出,而開漏輸出無法輸出高電平,因此I2C_SCL和I2C_SDA兩個引腳需要外部上拉,一般的開發板都會考慮到這一點,在設計原理圖的時候將使用的I2C兩根線給外部上拉到3.3V,如果你使用的是自己設計的板子,請務必記住I2C需要上拉

細心的同學可能又發現了,你上面給出的MPU6050硬件原理圖I2C兩根線并沒有外部上拉呀?

雖然MPU6050硬件原理圖I2C兩根線沒有上拉,但是在開發板的其他I2C通信的芯片上進行了外部上拉,如下圖所示

3.1、CubeMX相關配置

3.1.0、工程基本配置

打開STM32CubeMX軟件,單擊ACCESS TO MCU SELECTOR選擇開發板MCU(選擇你使用開發板的主控MCU型號),選中MCU型號后單擊頁面右上角Start Project開始工程,具體如下圖所示

開始工程之后在配置主頁面System Core/RCC中配置HSE/LSE晶振,在System Core/SYS中配置Debug模式,具體如下圖所示

詳細工程建立內容讀者可以閱讀“STM32CubeMX教程1 工程建立”

3.1.1、時鐘樹配置

系統時鐘使用8MHz外部高速時鐘HSE,HCLK、PCLK1和PCLK2均設置為STM32F407能達到的最高時鐘頻率,具體如下圖所示

3.1.2、外設參數配置

實驗需要通過串口來輸出與MPU6050進行I2C通信讀取的陀螺儀和加速度計數據,因此外設需要初始化USART1和I2C1

單擊Pinout & Configuration頁面左邊Connectivity/USART1選項,然后按照“STM32CubeMX教程9 USART/UART 異步通信”實驗中將USART1配置為異步通信模式,無需開啟中斷,如下圖所示

在Pinout & Configuration頁面右邊芯片引腳預覽Pinout view中找到與開發板上MPU6050芯片連接的I2C的兩個通信引腳PB8和PB9,左邊單擊將其分別配置為I2C1_SCL和I2C1_SDA

然后單擊Connectivity/I2C1選項,在其模式中選擇I2C,在下方Master Features中將 I2C Speed Mode 根據用戶需求選擇快速模式(400kkHz)或者標準模式(100kHz),這兩種模式僅僅影響通信速率,對于本實驗兩個模式均可隨意選擇

其他參數保持默認即可,具體配置如下圖所示

3.1.3、外設中斷配置

本實驗無需啟用中斷,如果需要啟用I2C1的中斷,請單擊System Core/NVIC,然后根據需求勾選I2C1的事件或錯誤中斷,并選擇合適的中斷優先級即可,具體配置如下圖所示

3.2、生成代碼

3.2.0、配置Project Manager頁面

單擊進入Project Manager頁面,在左邊Project分欄中修改工程名稱、工程目錄和工具鏈,然后在Code Generator中勾選“Gnerate peripheral initialization as a pair of 'c/h' files per peripheral”,最后單擊頁面右上角GENERATE CODE生成工程,具體如下圖所示

詳細Project Manager配置內容讀者可以閱讀“STM32CubeMX教程1 工程建立”實驗3.4.3小節

3.2.1、外設初始化調用流程

還是一模一樣的流程,與該系列教程所有的外設初始化一致

在生成的工程代碼主函數中新增了MX_I2C1_Init()函數,在該函數中實現了對I2C1的模式及參數配置

在MX_I2C1_Init()函數中調用了HAL_I2C_Init()函數使用配置的參數對I2C1進行了初始化

在HAL_I2C_Init()函數中又調用了HAL_I2C_MspInit()函數對I2C1引腳復用設置,I2C1時鐘使能,如果開啟了中斷該函數中還會有中斷相關設置及使能

如下圖所示為I2C1初始化調用流程

3.2.2、外設中斷調用流程

本實驗無需中斷,因此未啟動任何I2C1的中斷

3.2.3、添加其他必要代碼

需要添加MPU6050的驅動文件,文件中至少應該包括

  1. MPU6050初始化函數
  2. MPU6050獲取三軸加速度計原始數據函數
  3. MPU6050獲取三軸陀螺儀原始數據函數

注意本實驗只使用而不會介紹MPU6050具體驅動文件的原理,具體源代碼如下所示 (注釋3)

mpu6050.c文件

#include "mpu6050.h"
 
/**
* @brief 		MPU6050初始化函數
* @alter		無
* @param		無
* @retval 		成功返回0,失敗返回1
*/
uint8_t MPU6050_Init(I2C_HandleTypeDef *I2Cx)
{
	uint8_t check;
	uint8_t Data;
 
	// check device ID WHO_AM_I
	HAL_I2C_Mem_Read(I2Cx, MPU6050_ADDR, MPU_DEVICE_ID_REG, 1, &check, 1, I2C_TimeOut);
	// 0x68 will be returned by the sensor if everything goes well
	if (check == 104) 
	{
			// power management register 0X6B we should write all 0's to wake the sensor up
			Data = 0;
			HAL_I2C_Mem_Write(I2Cx, MPU6050_ADDR, MPU_PWR_MGMT1_REG, 1, &Data, 1, I2C_TimeOut);
 
			// Set DATA RATE of 1KHz by writing SMPLRT_DIV register
			Data = 0x07;
			HAL_I2C_Mem_Write(I2Cx, MPU6050_ADDR, MPU_SAMPLE_RATE_REG, 1, &Data, 1, I2C_TimeOut);
 
			// Set accelerometer configuration in ACCEL_CONFIG Register
			// XA_ST=0,YA_ST=0,ZA_ST=0, FS_SEL=0 ->   2g
			Data = 0x00;
			HAL_I2C_Mem_Write(I2Cx, MPU6050_ADDR, MPU_ACCEL_CFG_REG, 1, &Data, 1, I2C_TimeOut);
 
			// Set Gyroscopic configuration in GYRO_CONFIG Register
			// XG_ST=0,YG_ST=0,ZG_ST=0, FS_SEL=0 ->   250  /s
			Data = 0x00;
			HAL_I2C_Mem_Write(I2Cx, MPU6050_ADDR, MPU_GYRO_CFG_REG, 1, &Data, 1, I2C_TimeOut);
			return 0;
	}
	return 1;
}
 
 
/**
* @brief 		MPU6050溫度值獲取函數
* @alter		無
* @param		無
* @retval 		溫度值
*/
float MPU_Get_Temperature(void)
{
	uint8_t buf[2]; 
	short raw;
	float temp;
	HAL_I2C_Mem_Read(&MPU6050_I2C, MPU6050_ADDR, MPU_TEMP_OUTH_REG, 1, buf, 2, I2C_TimeOut);
	raw=((int16_t)buf[0]<<8)|buf[1];  
	temp=36.53+((double)raw)/340;  
	return temp;;
}
 
/**
* @brief 		MPU6050陀螺儀值獲取函數(三軸原始值)
* @alter		無
* @param		gx,gy,gz:陀螺儀x,y,z軸的原始讀數(帶符號)
* @retval 		正常:0,錯誤:其他
*/
uint8_t MPU_Get_RAW_Gyroscope(int16_t *gx,int16_t *gy,int16_t *gz)
{
	uint8_t buf[6],res;  
	res = HAL_I2C_Mem_Read(&MPU6050_I2C, MPU6050_ADDR, MPU_GYRO_XOUTH_REG, 1, buf, 6, I2C_TimeOut);
	if(res==0)
	{
		*gx=((int16_t)buf[0]<<8)|buf[1];  
		*gy=((int16_t)buf[2]<<8)|buf[3];  
		*gz=((int16_t)buf[4]<<8)|buf[5];
	} 	
    return res;
}
 
/**
* @brief 		MPU6050加速度值獲取函數(三軸原始值)
* @alter		無
* @param		ax,ay,az:加速度計x,y,z軸的原始讀數(帶符號)
* @retval 		正常:0,錯誤:其他
*/
uint8_t MPU_Get_RAW_Accelerometer(int16_t *ax,int16_t *ay,int16_t *az)
{
	uint8_t buf[6],res;  
	res = HAL_I2C_Mem_Read(&MPU6050_I2C, MPU6050_ADDR, MPU_ACCEL_XOUTH_REG, 1, buf, 6, I2C_TimeOut);
	if(res==0)
	{
		*ax=((int16_t)buf[0]<<8)|buf[1];  
		*ay=((int16_t)buf[2]<<8)|buf[3];  
		*az=((int16_t)buf[4]<<8)|buf[5];
	} 	
    return res;
}

mpu6050.h文件

#ifndef __MPU6050_H
#define __MPU6050_H
#include "main.h"
#include "i2c.h"
#endif
 
 
#define MPU6050_I2C      		hi2c1
#define MPU6050_ADDR     		0xD0   
#define I2C_TimeOut  			100
 
/*MPU6050內部寄存器地址*/
#define MPU_SAMPLE_RATE_REG		0X19	//采樣頻率分頻器
#define MPU_GYRO_CFG_REG		0X1B	//陀螺儀配置寄存器
#define MPU_ACCEL_CFG_REG		0X1C	//加速度計配置寄存器
#define MPU_ACCEL_XOUTH_REG		0X3B	//加速度值,X軸高8位寄存器
#define MPU_TEMP_OUTH_REG		0X41	//溫度值高八位寄存器
#define MPU_GYRO_XOUTH_REG		0X43	//陀螺儀值,X軸高8位寄存器
#define MPU_PWR_MGMT1_REG		0X6B	//電源管理寄存器1
#define MPU_DEVICE_ID_REG		0X75	//器件ID寄存器
 
uint8_t MPU6050_Init(I2C_HandleTypeDef *I2Cx);
float MPU_Get_Temperature(void);
uint8_t MPU_Get_RAW_Gyroscope(int16_t *gx,int16_t *gy,int16_t *gz);
uint8_t MPU_Get_RAW_Accelerometer(int16_t *ax,int16_t *ay,int16_t *az);
 
/*
MPU6050內部所有寄存器地址
#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寄存器
*/

在keil中添加.c/.h文件步驟如下圖所示

然后將源代碼復制到新建的.c/.h文件中,最后將.c文件添加到工程即可,如下圖所示

在主函數中初始化MPU6050,主循環中獲取原始的三軸加速度數據和三軸陀螺儀數據,并通過串口打印信息

源代碼如下

/*main.c中定義的變量*/
int16_t ax,ay,az,gx,gy,gz;
 
/*初始化代碼*/
while(MPU6050_Init(&hi2c1) != HAL_OK){HAL_Delay(1);}
 
/*主循環中代碼*/
MPU_Get_RAW_Gyroscope(&ax,&ay,&az);
MPU_Get_RAW_Accelerometer(&gx,&gy,&gz);
printf("ax:%d,ay:%d,az:%d,",ax,ay,az);
printf("gx:%d,gy:%d,gz:%d\r\n",gx,gy,gz);
HAL_Delay(100);

4、常用函數

/*I2C讀函數*/
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)
 
/*I2C寫函數*/
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)

5、燒錄驗證

燒錄程序,上電后開啟串口,可以看到源源不斷的輸出當前MPU6050三軸加速度數據和三軸陀螺儀數據,移動開發板會發現數據有規律改變,如下圖所示為串口輸出的數據

6、注釋詳解

注釋1:圖片來源 I2C通信協議介紹 - 知乎

注釋2:MPU6050 Datasheet https://invensense.tdk.com/wp-content/uploads/2015/02/MPU-6000-Datasheet1.pdf

注釋3:MPU6050驅動庫參考 https://github.com/leech001/MPU6050

更多內容請瀏覽 STM32CubeMX+STM32F4系列教程文章匯總貼

總結

以上是生活随笔為你收集整理的STM32CubeMX教程19 I2C - MPU6050驱动的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。