国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

STM32學(xué)習(xí)筆記(十)丨I2C通信(使用I2C實(shí)現(xiàn)MPU6050和STM32之間通信)

這篇具有很好參考價(jià)值的文章主要介紹了STM32學(xué)習(xí)筆記(十)丨I2C通信(使用I2C實(shí)現(xiàn)MPU6050和STM32之間通信)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

???本次課程采用單片機(jī)型號為STM32F103C8T6。(鑒于筆者實(shí)驗(yàn)時(shí)身邊只有STM32F103ZET6,故本次實(shí)驗(yàn)使基于ZET6進(jìn)行的)
???課程鏈接:江協(xié)科技 STM32入門教程


??往期筆記鏈接:
??STM32學(xué)習(xí)筆記(一)丨建立工程丨GPIO 通用輸入輸出
??STM32學(xué)習(xí)筆記(二)丨STM32程序調(diào)試丨OLED的使用
??STM32學(xué)習(xí)筆記(三)丨中斷系統(tǒng)丨EXTI外部中斷
??STM32學(xué)習(xí)筆記(四)丨TIM定時(shí)器及其應(yīng)用(定時(shí)中斷、內(nèi)外時(shí)鐘源選擇)
??STM32學(xué)習(xí)筆記(五)丨TIM定時(shí)器及其應(yīng)用(輸出比較丨PWM驅(qū)動呼吸燈、舵機(jī)、直流電機(jī))
??STM32學(xué)習(xí)筆記(六)丨TIM定時(shí)器及其應(yīng)用(輸入捕獲丨測量PWM波形的頻率和占空比)
??STM32學(xué)習(xí)筆記(七)丨TIM定時(shí)器及其應(yīng)用(編碼器接口丨用定時(shí)器實(shí)現(xiàn)編碼器測速)
??STM32學(xué)習(xí)筆記(八)丨ADC模數(shù)轉(zhuǎn)換器(ADC單、雙通道轉(zhuǎn)換)
??STM32學(xué)習(xí)筆記(九)丨DMA直接存儲器存取(DMA數(shù)據(jù)轉(zhuǎn)運(yùn)、DMA+AD多通道轉(zhuǎn)換)


一、I2C原理簡介

1.1 I2C通信協(xié)議

1.2 STM32的I2C外設(shè)

??STM32內(nèi)部集成了硬件I2C收發(fā)電路,可以由硬件自動執(zhí)行時(shí)鐘生成、起始終止條件生成、應(yīng)答位收發(fā)、數(shù)據(jù)收發(fā)等功能,減輕CPU的負(fù)擔(dān)。

  • 支持多主機(jī)模型(STM32的I2C是基于多主機(jī)模型設(shè)計(jì)的,如果在使用時(shí)不加改變,默認(rèn)上電時(shí)STM32的I2C處于從模式)
  • 支持7位/10位地址模式
  • 支持不同的通訊速度,標(biāo)準(zhǔn)速度(高達(dá)100 kHz),快速(高達(dá)400 kHz)(由于是同步通信方式,I2C通信對時(shí)序的要求并不像串口通信那樣嚴(yán)格)
  • 支持DMA
  • 兼容SMBus協(xié)議

??STM32F103C8T6 硬件I2C資源:I2C1、I2C2。(本次實(shí)驗(yàn)使用STM32F103ZET6)

stm32 i2c mpu6050,STM32 學(xué)習(xí)筆記,stm32,學(xué)習(xí),筆記
stm32 i2c mpu6050,STM32 學(xué)習(xí)筆記,stm32,學(xué)習(xí),筆記
stm32 i2c mpu6050,STM32 學(xué)習(xí)筆記,stm32,學(xué)習(xí),筆記
stm32 i2c mpu6050,STM32 學(xué)習(xí)筆記,stm32,學(xué)習(xí),筆記

二、MPU6050簡介

stm32 i2c mpu6050,STM32 學(xué)習(xí)筆記,stm32,學(xué)習(xí),筆記

??MPU6050是一個6軸姿態(tài)傳感器,可以測量芯片自身X、Y、Z軸的加速度、角速度參數(shù),通過數(shù)據(jù)融合,可進(jìn)一步得到姿態(tài)角,結(jié)合PID算法,常應(yīng)用于小車走直線,平衡車、飛行器等需要檢測自身姿態(tài)的場景。

  • 3軸加速度計(jì)(Accelerometer):測量X、Y、Z軸的加速度。測量出的加速度具有靜態(tài)穩(wěn)定性,不具有動態(tài)穩(wěn)定性。
  • 3軸陀螺儀傳感器(Gyroscope):測量X、Y、Z軸的角速度。測量出的角速度具有動態(tài)穩(wěn)定性,不具有靜態(tài)穩(wěn)定性。

??加速度和角速度都無法單獨(dú)得到當(dāng)前儀器的姿態(tài),如果要得到儀器的姿態(tài)可以將所得數(shù)據(jù)進(jìn)行數(shù)據(jù)解算。MPU6050擁有內(nèi)部的數(shù)字運(yùn)動處理器DMP(Digital Motion Processor),它是MPU6050自帶的硬件姿態(tài)解算算法。可以使用官方的DMP庫方便地實(shí)現(xiàn)姿態(tài)解算得到角度。
??MPU6050可以外擴(kuò)更多的測量計(jì),例如三軸磁力計(jì)來矯正方向,氣壓計(jì)來測量高度。添加更多的測量計(jì)可以使其成為9軸/10軸的姿態(tài)傳感器。

  • 16位ADC采集傳感器的模擬信號,量化范圍:-32768~32767

  • 加速度計(jì)滿量程選擇:±2、±4、±8、±16(g)

  • 陀螺儀滿量程選擇: ±250、±500、±1000、±2000(°/sec)

  • 可配置的數(shù)字低通濾波器

  • 可配置的時(shí)鐘源

  • 可配置的采樣分頻

  • I2C從機(jī)地址:1101000(AD0=0),1101001(AD0=1)

stm32 i2c mpu6050,STM32 學(xué)習(xí)筆記,stm32,學(xué)習(xí),筆記
??套件中使用的模塊電路圖如下所示:
stm32 i2c mpu6050,STM32 學(xué)習(xí)筆記,stm32,學(xué)習(xí),筆記

三、代碼實(shí)現(xiàn)

3.1 軟件模擬的I2C通信

3.1.1 I2C軟件模擬通信(協(xié)議)層

  • MyI2C.h
#ifndef __MYI2C_H_
#define __MYI2C_H_

void MyI2C_Init(void);
void MyI2C_Start(void);
void MyI2C_Stop(void);
void MyI2C_SendByte(uint8_t Byte);
uint8_t MyI2C_ReceiveByte(void);
void MyI2C_SendAck(uint8_t AckBit);
uint8_t MyI2C_ReceiveAck(void);

#endif

  • MyI2C.c
#include "stm32f10x.h"                  // Device header

// 更改GPIO和引腳時(shí),只需要更改以下的宏定義即可
// 需要注意:請檢查使用的GPIO是否是APB2總線的外設(shè),如果不是,則需要更改MyI2C_Init函數(shù)中的RCC_APB2PeriphClockCmd函數(shù)名稱
#define SCL_GPIO_Port_CLK	RCC_APB2Periph_GPIOA
#define SDA_GPIO_Port_CLK	RCC_APB2Periph_GPIOA
#define SCL_GPIO_Port		GPIOA
#define SDA_GPIO_Port		GPIOA
#define SCL_Pin				GPIO_Pin_6
#define SDA_Pin				GPIO_Pin_7

/**
  * @brief  軟件I2C的GPIO端口初始化函數(shù)
  * @param  無
  * @retval 無
  */
void MyI2C_Init(void)
{
	// 開啟SCL和SDA對應(yīng)GPIO的時(shí)鐘
	RCC_APB2PeriphClockCmd(SCL_GPIO_Port_CLK, ENABLE);
	RCC_APB2PeriphClockCmd(SDA_GPIO_Port_CLK, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;	
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = SCL_Pin;
 	GPIO_Init(SCL_GPIO_Port, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;	
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = SDA_Pin;
 	GPIO_Init(SDA_GPIO_Port, &GPIO_InitStructure);
	
	GPIO_SetBits(SCL_GPIO_Port, SCL_Pin);
	GPIO_SetBits(SDA_GPIO_Port, SDA_Pin);
}

/**
  * @brief  控制SCL線的下拉與釋放
  * @param  BitValue	其值可以是0或1,0為下拉,1為釋放
  * @retval 
  */
void MyI2C_W_SCL(uint8_t BitValue)
{
	GPIO_WriteBit(SCL_GPIO_Port, SCL_Pin, (BitAction)BitValue);
	// Delay_us(10);
}

/**
  * @brief  控制SDA線的下拉與釋放
  * @param  BitValue	其值可以是0或1,0為下拉,1為釋放
  * @retval 無
  */
void MyI2C_W_SDA(uint8_t BitValue)
{
	GPIO_WriteBit(SDA_GPIO_Port, SDA_Pin, (BitAction)BitValue);
	// Delay_us(10);
}

/**
  * @brief  讀取SDA
  * @param  無
  * @retval 讀取到SDA的高低電平值
  */
uint8_t MyI2C_R_SDA(void)
{
	return GPIO_ReadInputDataBit(SDA_GPIO_Port, SDA_Pin);
	// Delay_us(10);
}

/**
  * @brief  軟件I2C的起始信號
  * @param  無
  * @retval 無
  */
void MyI2C_Start(void)
{
	// 這里先釋放SDA,再釋放SCL的原因是為了使Start信號兼容重復(fù)起始信號RS
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);
}

/**
  * @brief  軟件I2C的結(jié)束信號
  * @param  無
  * @retval 無
  */
void MyI2C_Stop(void)
{
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
}

/**
  * @brief  發(fā)送一個字節(jié)
  * @param  Byte	發(fā)送的字節(jié)數(shù)據(jù)
  * @retval 無
  */
void MyI2C_SendByte(uint8_t Byte)
{
	uint8_t i;
	for (i = 0; i < 8; i ++)
	{
		MyI2C_W_SDA(Byte & (0x80 >> i));
		// SCL產(chǎn)生一個正脈沖,讓從機(jī)讀取數(shù)據(jù)
		MyI2C_W_SCL(1);
		MyI2C_W_SCL(0);
	}
}

/**
  * @brief  接收一個字節(jié)
  * @param  無
  * @retval 接收的字節(jié)數(shù)據(jù)
  */
uint8_t MyI2C_ReceiveByte(void)
{
	uint8_t i, Byte = 0x00;
	MyI2C_W_SDA(1);		// 主機(jī)釋放SDA,交出SDA控制權(quán)
	for (i = 0; i < 8; i ++)
	{
		// 在SCL高電平期間讀取SDA,如果SDA為1,則將Byte對應(yīng)位置1(高位先行)
		MyI2C_W_SCL(1);
		if (MyI2C_R_SDA() == 1)
		{
			Byte |= (0x80 >> i);
		}
		MyI2C_W_SCL(0);
	}
	return Byte;
}

/**
  * @brief  發(fā)送應(yīng)答,以通知從機(jī)數(shù)據(jù)是是否發(fā)送結(jié)束
  * @param  AckBit		0為發(fā)送未結(jié)束,1為發(fā)送已結(jié)束
  * @retval 無
  */
void MyI2C_SendAck(uint8_t AckBit)
{
	MyI2C_W_SDA(AckBit);
	// SCL產(chǎn)生一個正脈沖,讓從機(jī)讀取數(shù)據(jù)
	MyI2C_W_SCL(1);
	MyI2C_W_SCL(0);
}

/**
  * @brief  接受應(yīng)答,主機(jī)讀取該信號以確認(rèn)從機(jī)是否接受到數(shù)據(jù)
  * @param  無
  * @retval 應(yīng)答信號,0為已收到(從機(jī)受到后下拉SDA),1為未收到
  */
uint8_t MyI2C_ReceiveAck(void)
{
	uint8_t AckBit;
	MyI2C_W_SDA(1);		// 主機(jī)釋放SDA,交出SDA控制權(quán)
	// 在SCL高電平期間讀取SDA,如果SDA為1,則將AckBit置1
	MyI2C_W_SCL(1);
	AckBit = MyI2C_R_SDA();
	MyI2C_W_SCL(0);
	
	return AckBit;
}

// I2C地址應(yīng)答測試程序,在main函數(shù)中可以循環(huán)以下過程來遍歷I2C地址,以檢查從機(jī)是否能正常應(yīng)答
	uint8_t ACK;
	MyI2C_Start();
	MyI2C_SendByte(0xD0);	// 0xD0為MPU6050的I2C地址和讀寫操作復(fù)合而成的地址
	ACK = MyI2C_ReceiveAck();
	MyI2C_Stop();

3.1.2 MPU6050設(shè)備操作層

  • MPU6050.h
#ifndef __MPU6050_H_
#define __MPU6050_H_

void MPU6050_Init(void);

void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);
uint8_t MPU6050_ReadID(void);
void MPU6050_ReadData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, 
					  int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ);

#endif

  • MPU6050_Reg.h
#ifndef __MPU6050_REG_H_
#define __MPU6050_REG_H_

#define	MPU6050_SMPLRT_DIV		0x19
#define	MPU6050_CONFIG			0x1A
#define	MPU6050_GYRO_CONFIG		0x1B
#define	MPU6050_ACCEL_CONFIG	0x1C

#define	MPU6050_ACCEL_XOUT_H	0x3B
#define	MPU6050_ACCEL_XOUT_L	0x3C
#define	MPU6050_ACCEL_YOUT_H	0x3D
#define	MPU6050_ACCEL_YOUT_L	0x3E
#define	MPU6050_ACCEL_ZOUT_H	0x3F
#define	MPU6050_ACCEL_ZOUT_L	0x40
#define	MPU6050_TEMP_OUT_H		0x41
#define	MPU6050_TEMP_OUT_L		0x42
#define	MPU6050_GYRO_XOUT_H		0x43
#define	MPU6050_GYRO_XOUT_L		0x44
#define	MPU6050_GYRO_YOUT_H		0x45
#define	MPU6050_GYRO_YOUT_L		0x46
#define	MPU6050_GYRO_ZOUT_H		0x47
#define	MPU6050_GYRO_ZOUT_L		0x48

#define	MPU6050_PWR_MGMT_1		0x6B	//電源管理1
#define	MPU6050_PWR_MGMT_2		0x6C	//電源管理2
#define	MPU6050_WHO_AM_I		0x75	//ID寄存器(默認(rèn)數(shù)值0x68,只讀)

#endif

  • MPU6050.c
#include "stm32f10x.h"                  // Device header
#include "MyI2C.h"
#include "MPU6050_Reg.h"

#define MPU6050_ADDRESS_W			0xD0
#define MPU6050_ADDRESS_R			0xD1

/**
  * @brief  MPU6050 向芯片內(nèi)部的指定地址寫
  * @param  RegAddress	芯片內(nèi)部的寄存器地址
  * @param  Data		要寫入的數(shù)據(jù)
  * @retval 無
  */
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
	MyI2C_Start();
	MyI2C_SendByte(MPU6050_ADDRESS_W);
	MyI2C_ReceiveAck();		// 這里可以對獲取到的回應(yīng)信號進(jìn)行處理
	MyI2C_SendByte(RegAddress);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(Data);
	MyI2C_ReceiveAck();
	MyI2C_Stop();
}

/**
  * @brief MPU6050 向芯片內(nèi)部的指定地址讀
  * @param  RegAddress	要讀取的寄存器在芯片內(nèi)部的地址
  * @retval 讀取的數(shù)據(jù)
  */
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
	uint8_t Data;
	
	// 向MPU6050發(fā)送將要讀的地址
	MyI2C_Start();
	MyI2C_SendByte(MPU6050_ADDRESS_W);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(RegAddress);
	MyI2C_ReceiveAck();
	
	MyI2C_Start();		// 重復(fù)啟動信號
	MyI2C_SendByte(MPU6050_ADDRESS_R);		// 發(fā)送讀地址,讓出SDA控制權(quán)
	MyI2C_ReceiveAck();
	Data = MyI2C_ReceiveByte();
	MyI2C_SendAck(1);	// 向從機(jī)發(fā)送應(yīng)答信號(不響應(yīng)),從機(jī)終止數(shù)據(jù)發(fā)送
	MyI2C_Stop();
	
	return Data;
}

/**
  * @brief  MPU6050初始化函數(shù)
  * @param  無
  * @retval 無
  */
void MPU6050_Init(void)
{
	MyI2C_Init();
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);		// 不復(fù)位,關(guān)閉睡眠模式,不循環(huán),使能溫度傳感器,選擇X軸陀螺儀的內(nèi)部震蕩電路作為系統(tǒng)時(shí)鐘
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);		// 不需要設(shè)置循環(huán)模式的喚醒頻率, 六個軸都不需要待機(jī)
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);		// 設(shè)置采樣分頻, 這里選擇10分頻
	MPU6050_WriteReg(MPU6050_CONFIG, 0x06);			// 不需要外部同步, 數(shù)字低通濾波設(shè)置為最高(最平滑)
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);	// 角速度計(jì)配置:不自測(高三位為自測使能, 手冊有遺漏), 設(shè)計(jì)為最大量程
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);	// 加速度計(jì)配置:不自測,選擇為最大量程,不使用高通濾波器
}

/**
  * @brief  獲取MPU6050的ID值,可根據(jù)ID值檢查STM32和MPU6050之間是否正常通信
  * @param  無
  * @retval ID值
  */
uint8_t MPU6050_ReadID(void)
{
	return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}

/**
  * @brief  獲取并返回MPU6050六軸傳感器的返回值
  * @param  無
  * @retval 通過參數(shù)指針操作(返回)6個返回值
  */
void MPU6050_ReadData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, 
					  int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)
{
	*AccX = (MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H) << 8)
			| MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
	
	*AccY = (MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H) << 8)
			| MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
	
	*AccZ = (MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H) << 8)
			| MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
	
	*GyroX = (MPU6050_ReadReg(MPU6050_GYRO_XOUT_H) << 8)
			| MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);
	
	*GyroY = (MPU6050_ReadReg(MPU6050_GYRO_YOUT_H) << 8)
			| MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);
	
	*GyroZ = (MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H) << 8)
			| MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);
}

3.1.3 主函數(shù)邏輯層

  • main.c
#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "MPU6050.h"

uint8_t ID;
int16_t AX, AY, AZ, GX, GY, GZ;

int main(void)
{
	OLED_Init();
	MPU6050_Init();
	
	OLED_ShowString(1, 1, "ID:0x");
	ID = MPU6050_ReadID();
	OLED_ShowHexNum(1, 6, ID, 2);
	while (1)
	{
		MPU6050_ReadData(&AX, &AY, &AZ, &GX, &GY, &GZ);
		OLED_ShowSignedNum(2, 1, AX, 5);
		OLED_ShowSignedNum(3, 1, AY, 5);
		OLED_ShowSignedNum(4, 1, AZ, 5);
		OLED_ShowSignedNum(2, 8, GX, 5);
		OLED_ShowSignedNum(3, 8, GY, 5);
		OLED_ShowSignedNum(4, 8, GZ, 5);
	}
}

3.2 使用STM32的I2C外設(shè)實(shí)現(xiàn)I2C通信

3.2.1 常用庫函數(shù)

// I2C外設(shè)缺省配置
void I2C_DeInit(I2C_TypeDef* I2Cx);

// I2C外設(shè)初始化函數(shù)
void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct);

// 初始化結(jié)構(gòu)體的缺省初始化
void I2C_StructInit(I2C_InitTypeDef* I2C_InitStruct);

// I2C外設(shè)的開關(guān)控制函數(shù)
void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState);

// 生成起始信號
void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState);
// 生成結(jié)束信號
void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState);
// 在主機(jī)接收數(shù)據(jù)后是否相應(yīng)從機(jī)配置
void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState);

// 主機(jī)發(fā)送數(shù)據(jù)
void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data);
// 主機(jī)接收數(shù)據(jù)
uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx);
// 7位地址模式發(fā)送函數(shù)(該函數(shù)功能也可由數(shù)據(jù)發(fā)送函數(shù)實(shí)現(xiàn))
void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);
  • 關(guān)于I2C狀態(tài)監(jiān)測方案(來自文件stm32f10x_i2c.h
    ??該I2C驅(qū)動程序提供了三種不同的I2C狀態(tài)監(jiān)測方法,根據(jù)應(yīng)用需求和限制而定:
  1. 基本狀態(tài)監(jiān)測(本次實(shí)驗(yàn)采用此方案)
    ??使用I2C_CheckEvent()函數(shù):它將狀態(tài)寄存器(SR1和SR2)的內(nèi)容與給定的事件進(jìn)行比較(可以是一個或多個標(biāo)志的組合)。如果當(dāng)前狀態(tài)包含給定的標(biāo)志,則返回SUCCESS,如果當(dāng)前狀態(tài)中缺少一個或多個標(biāo)志,則返回ERROR。
  • 使用時(shí)機(jī):
    ??對于大多數(shù)應(yīng)用程序以及啟動活動,此函數(shù)是合適的,因?yàn)樵诋a(chǎn)品參考手冊(RM0008)中對事件進(jìn)行了詳細(xì)描述。
    ??對于需要定義自己的事件的用戶也是合適的。
  • 限制:
    ??如果發(fā)生錯誤(即除了被監(jiān)測的標(biāo)志之外,設(shè)置了錯誤標(biāo)志),I2C_CheckEvent()函數(shù)可能會返回SUCCESS,盡管通信暫?;?qū)嶋H狀態(tài)已損壞。在這種情況下,建議使用錯誤中斷來監(jiān)測錯誤事件,并在中斷IRQ處理程序中處理它們。對于錯誤管理,建議使用以下函數(shù):
    ??I2C_ITConfig()用于配置和使能錯誤中斷(I2C_IT_ERR)。
    ??I2Cx_ER_IRQHandler(),在發(fā)生錯誤中斷時(shí)調(diào)用該函數(shù)。其中x是外設(shè)實(shí)例(I2C1、I2C2等)。
    ??在I2Cx_ER_IRQHandler()中調(diào)用I2C_GetFlagStatus()或I2C_GetITStatus(),以確定發(fā)生了哪個錯誤。
    ??調(diào)用I2C_ClearFlag()或I2C_ClearITPendingBit()和/或I2C_SoftwareResetCmd(),和/或I2C_GenerateStop()以清除錯誤標(biāo)志和源,并恢復(fù)正確的通信狀態(tài)。
  1. 高級狀態(tài)監(jiān)測:
    ??使用函數(shù)I2C_GetLastEvent(),它以一個單獨(dú)的字(uint32_t)返回兩個狀態(tài)寄存器的圖像(狀態(tài)寄存器2的值左移16位并連接到狀態(tài)寄存器1)。
  • 使用時(shí)機(jī):
    ??對于上述相同的應(yīng)用程序,該函數(shù)也是合適的,但它允許克服I2C_GetFlagStatus()函數(shù)的限制(見下文)。返回的值可以與庫(stm32f10x_i2c.h)中已定義的事件進(jìn)行比較,或與用戶定義的自定義值進(jìn)行比較。
    ??當(dāng)同時(shí)監(jiān)測多個標(biāo)志時(shí),該函數(shù)是合適的。
  • 限制:
    ??用戶可能需要定義自己的事件。
    ??如果用戶決定僅檢查常規(guī)通信標(biāo)志(并忽略錯誤標(biāo)志),則與該函數(shù)相關(guān)的錯誤管理的相同備注適用。
  1. 基于標(biāo)志的狀態(tài)監(jiān)測:
    ??使用函數(shù)I2C_GetFlagStatus(),它簡單地返回一個單獨(dú)標(biāo)志的狀態(tài)(如I2C_FLAG_RXNE …)。
  • 使用時(shí)機(jī):
    ??該函數(shù)可用于特定應(yīng)用程序或調(diào)試階段。
    ??當(dāng)只需要檢查一個標(biāo)志時(shí),它是合適的(大多數(shù)I2C事件通過多個標(biāo)志進(jìn)行監(jiān)測)。
  • 限制:
    ??調(diào)用該函數(shù)時(shí),將訪問狀態(tài)寄存器。訪問狀態(tài)寄存器時(shí),某些標(biāo)志會被清除。因此,檢查一個標(biāo)志的狀態(tài)可能會清除其他標(biāo)志。
    ??為了監(jiān)測一個單一事件,可能需要調(diào)用該函數(shù)兩次或更多次。

??下面是和狀態(tài)檢測相關(guān)的庫函數(shù):

// 獲取當(dāng)前事件是否發(fā)生
ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT);
// 獲取當(dāng)前狀態(tài)寄存器的值(兩個16位寄存器拼接而成的數(shù)據(jù))
uint32_t I2C_GetLastEvent(I2C_TypeDef* I2Cx);

// 獲取當(dāng)前的狀態(tài)標(biāo)志位
FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG);
// 清除當(dāng)前的狀態(tài)標(biāo)志位
void I2C_ClearFlag(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG);
// 獲取中斷標(biāo)志位
ITStatus I2C_GetITStatus(I2C_TypeDef* I2Cx, uint32_t I2C_IT);
// 清除中斷標(biāo)志位
void I2C_ClearITPendingBit(I2C_TypeDef* I2Cx, uint32_t I2C_IT);

3.2.2 代碼實(shí)現(xiàn)

??軟件和硬件I2C通信在本次實(shí)驗(yàn)中實(shí)驗(yàn)數(shù)據(jù)和現(xiàn)象完全相同,僅在通信層有區(qū)別。在算法實(shí)現(xiàn)時(shí),MPU6050.c模塊不在需要繼承軟件通信協(xié)議MyI2C.h,所以在工程文件中可以直接刪除MyI2C.cMyI2C.h文件。
新的MPU6050.c的代碼如下所示:

  • MPU6050.c
#include "stm32f10x.h"                  // Device header
#include "MPU6050_Reg.h"

#define MPU6050_ADDRESS			0xD0	// 0x68 + 讀寫位,注意這里的定義和軟件模擬I2C有些許區(qū)別

// 用宏定義在一定程度上實(shí)現(xiàn)解耦
// 重定義GPIO端口,需要注意使用的GPIO如果不是APB2的外設(shè)需要更改MPU6050_Init函數(shù)
#define GPIO_Periph_CLK			RCC_APB2Periph_GPIOB
#define GPIO_Periph				GPIOB
#define GPIO_Pin_SCL			GPIO_Pin_6
#define GPIO_Pin_SDA			GPIO_Pin_7
// 重定義I2C外設(shè)端口,這里同樣需要檢查使用的I2C外設(shè)是否是APB1的外設(shè)
#define I2C_Periph_CLK			RCC_APB1Periph_I2C1
#define I2C_Periph				I2C1

/**
  * @brief  I2C硬件讀寫的事件等待發(fā)生函數(shù),即等待某事件發(fā)生
  * @param  I2Cx		操作的I2Cx外設(shè)
  * @param  I2C_EVENT	要等待的事件,該參數(shù)的可取值在stm32f10x_i2c.c文件中
  * @retval 無
  */
void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
	uint32_t TimeOut = 10000;	// 等待的時(shí)間值,可以由多次實(shí)驗(yàn)調(diào)試確定
	while (I2C_CheckEvent(I2Cx, I2C_EVENT) != SUCCESS)
	{
		TimeOut --;
		if (TimeOut == 0)
		{
			/* 可在此進(jìn)行錯誤和故障處理 */
			break;
		}
	}
}

/**
  * @brief  MPU6050 向芯片內(nèi)部的指定地址寫
  * @param  RegAddress	芯片內(nèi)部的寄存器地址
  * @param  Data		要寫入的數(shù)據(jù)
  * @retval 無
  */
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
	I2C_GenerateSTART(I2C_Periph, ENABLE);
	MPU6050_WaitEvent(I2C_Periph, I2C_EVENT_MASTER_MODE_SELECT);		// EV5, 等待起始條件已發(fā)送,事件發(fā)生(主模式已選擇)
	
	I2C_Send7bitAddress(I2C_Periph, MPU6050_ADDRESS, I2C_Direction_Transmitter);
	/* 在庫函數(shù)中,發(fā)送函數(shù)都自帶接收應(yīng)答的過程,接收函數(shù)都自帶發(fā)送應(yīng)答的過程 */
	MPU6050_WaitEvent(I2C_Periph, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);	// EV6, I2C地址和寫命令已發(fā)送
	
	I2C_SendData(I2C_Periph, RegAddress);		// 發(fā)送寄存器地址
	MPU6050_WaitEvent(I2C_Periph, I2C_EVENT_MASTER_BYTE_TRANSMITTING);	// EV8, 數(shù)據(jù)正在發(fā)送(DR非空)
	I2C_SendData(I2C_Periph, Data);			// 發(fā)送寄存器數(shù)據(jù)
	MPU6050_WaitEvent(I2C_Periph, I2C_EVENT_MASTER_BYTE_TRANSMITTED);		// EV8_2, 數(shù)據(jù)發(fā)送已完成
	
	I2C_GenerateSTOP(I2C_Periph, ENABLE);
}

/**
  * @brief MPU6050 向芯片內(nèi)部的指定地址讀
  * @param  RegAddress	要讀取的寄存器在芯片內(nèi)部的地址
  * @retval 讀取的數(shù)據(jù)
  */
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
	uint8_t Data;
	
	I2C_GenerateSTART(I2C_Periph, ENABLE);
	MPU6050_WaitEvent(I2C_Periph, I2C_EVENT_MASTER_MODE_SELECT);	// EV5, 起始條件已發(fā)送(主模式已選擇)
	
	I2C_Send7bitAddress(I2C_Periph, MPU6050_ADDRESS, I2C_Direction_Transmitter);
	MPU6050_WaitEvent(I2C_Periph, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);	// EV6, I2C地址和寫命令已發(fā)送
	
	I2C_SendData(I2C_Periph, RegAddress);
	MPU6050_WaitEvent(I2C_Periph, I2C_EVENT_MASTER_BYTE_TRANSMITTED);		// EV8_2, 等待數(shù)據(jù)(寄存器地址)發(fā)送已完成
	
	I2C_GenerateSTART(I2C_Periph, ENABLE);		// 重復(fù)起始條件
	MPU6050_WaitEvent(I2C_Periph, I2C_EVENT_MASTER_MODE_SELECT);	// EV5, 起始條件已發(fā)送(主模式已選擇)
	
	I2C_Send7bitAddress(I2C_Periph, MPU6050_ADDRESS, I2C_Direction_Receiver);
	MPU6050_WaitEvent(I2C_Periph, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);	// EV6, I2C地址和讀命令已發(fā)送
	
	// 如果要讀取的數(shù)據(jù)使最后一個數(shù)據(jù), 則在執(zhí)行讀命令之前, 就將ACK置0(不響應(yīng)), STOP置1(結(jié)束條件)
	I2C_AcknowledgeConfig(I2C_Periph, DISABLE);
	I2C_GenerateSTOP(I2C_Periph, ENABLE);
	
	MPU6050_WaitEvent(I2C_Periph, I2C_EVENT_MASTER_BYTE_RECEIVED);	// EV7, RxNE = 1, 已收到一個字節(jié)
	Data = I2C_ReceiveData(I2C_Periph);	// 取走DR的值, 并存放在Data變量中

	return Data;
}

/**
  * @brief  MPU6050初始化函數(shù)
  * @param  無
  * @retval 無
  */
void MPU6050_Init(void)
{
	RCC_APB1PeriphClockCmd(I2C_Periph_CLK, ENABLE);
	RCC_APB2PeriphClockCmd(GPIO_Periph_CLK, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;		// 復(fù)用開漏模式, 將GPIO端口的控制權(quán)交給片上外設(shè)
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_SCL | GPIO_Pin_SDA;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIO_Periph, &GPIO_InitStructure);
	
	I2C_InitTypeDef I2C_InitStructure;
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;	
	I2C_InitStructure.I2C_ClockSpeed = 100000;			// 標(biāo)準(zhǔn)模式,時(shí)鐘頻率為100kHz(該參數(shù)最大不能超過400kHz)
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;	// 快速模式下的時(shí)鐘占空比, 在標(biāo)準(zhǔn)模式下該參數(shù)沒有作用
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;			// 主機(jī)接收一個數(shù)據(jù)后是否響應(yīng)從機(jī), 該參數(shù)也可以由獨(dú)立的函數(shù)進(jìn)行配置
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;		// 地址的位數(shù)
	I2C_InitStructure.I2C_OwnAddress1 = 0x00;			// STM32從模式下的自身地址, 主模式下沒有作用
	I2C_Init(I2C_Periph, &I2C_InitStructure);
	
	I2C_Cmd(I2C_Periph, ENABLE);
	
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);		// 不復(fù)位,關(guān)閉睡眠模式,不循環(huán),使能溫度傳感器,選擇X軸陀螺儀的內(nèi)部震蕩電路作為系統(tǒng)時(shí)鐘
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);		// 不需要設(shè)置循環(huán)模式的喚醒頻率, 六個軸都不需要待機(jī)
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);		// 設(shè)置采樣分頻, 這里選擇10分頻
	MPU6050_WriteReg(MPU6050_CONFIG, 0x06);			// 不需要外部同步, 數(shù)字低通濾波設(shè)置為最高(最平滑)
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);	// 角速度計(jì)配置:不自測(高三位為自測使能, 手冊有遺漏), 設(shè)計(jì)為最大量程
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);	// 加速度計(jì)配置:不自測,選擇為最大量程,不使用高通濾波器
}

/**
  * @brief  獲取MPU6050的ID值,可根據(jù)ID值檢查STM32和MPU6050之間是否正常通信
  * @param  無
  * @retval ID值
  */
uint8_t MPU6050_ReadID(void)
{
	return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}

/**
  * @brief  獲取并返回MPU6050六軸傳感器的返回值
  * @param  無
  * @retval 通過參數(shù)指針操作(返回)6個返回值
  */
void MPU6050_ReadData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, 
					  int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)
{
	*AccX = (MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H) << 8)
			| MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
	
	*AccY = (MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H) << 8)
			| MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
	
	*AccZ = (MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H) << 8)
			| MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
	
	*GyroX = (MPU6050_ReadReg(MPU6050_GYRO_XOUT_H) << 8)
			| MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);
	
	*GyroY = (MPU6050_ReadReg(MPU6050_GYRO_YOUT_H) << 8)
			| MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);
	
	*GyroZ = (MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H) << 8)
			| MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);
}


???課程鏈接:江協(xié)科技 STM32入門教程,歡迎大家一起交流學(xué)習(xí)。
??持續(xù)更新完善中……


??原創(chuàng)筆記,碼字不易,歡迎點(diǎn)贊,收藏~ 如有謬誤敬請?jiān)谠u論區(qū)不吝告知,感激不盡!博主將持續(xù)更新有關(guān)嵌入式開發(fā)、機(jī)器學(xué)習(xí)方面的學(xué)習(xí)筆記~文章來源地址http://www.zghlxwxcb.cn/news/detail-803082.html

到了這里,關(guān)于STM32學(xué)習(xí)筆記(十)丨I2C通信(使用I2C實(shí)現(xiàn)MPU6050和STM32之間通信)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【STM32】STM32學(xué)習(xí)筆記-I2C通信外設(shè)(34)

    【STM32】STM32學(xué)習(xí)筆記-I2C通信外設(shè)(34)

    I2C(Inter-Integrated Circuit)總線 是一種由NXP(原PHILIPS)公司開發(fā)的兩線式串行總線,用于連接微控制器及其外圍設(shè)備。多用于主控制器和從器件間的主從通信,在小數(shù)據(jù)量場合使用,傳輸距離短,任意時(shí)刻只能有一個主機(jī)等特性。 串行的 8 位雙向數(shù)據(jù)傳輸位速率在標(biāo)準(zhǔn)模式下可

    2024年01月17日
    瀏覽(21)
  • 【STM32學(xué)習(xí)】——STM32-I2C外設(shè)&硬件讀寫MPU6050&軟硬件讀寫波形對比

    目錄 前言 一、I2C外設(shè) 二、硬件I2C操作流程 1.主機(jī)發(fā)送時(shí)序 3.其他時(shí)序

    2024年02月10日
    瀏覽(30)
  • STM32F407硬件I2C實(shí)現(xiàn)MPU6050通訊(CUBEIDE)

    STM32F407硬件I2C實(shí)現(xiàn)MPU6050通訊(CUBEIDE)

    工程代碼 https://download.csdn.net/download/weixin_52849254/87886714 I2C1通道可選擇三種不同的通訊協(xié)議:I2C、SMBus-Alert-mode、SMBus-two-wire-Interface。 SMBus (System Management Bus,系統(tǒng)管理總線), 為系統(tǒng)和電源管理這樣的任務(wù)提供了一條控制總線,SMBus與I2C總線之間在時(shí)序特性上存在一些差別 修改

    2024年02月09日
    瀏覽(18)
  • STM32軟件I2C驅(qū)動MPU6050

    STM32軟件I2C驅(qū)動MPU6050

    這里沒有什么復(fù)雜的地方,采用MPU6050的現(xiàn)成模塊.模塊的SCL接B10,SDA接B11,這里連接了一個OLED顯示屏,用于顯示獲取到的數(shù)據(jù). 注意:這里使用的模塊自帶上拉電阻 首先在工程目錄里創(chuàng)建: \\\"MyI2C.h\\\"和\\\"MyI2C.c\\\"文件,用于軟件驅(qū)動I2C. \\\"MPU6050.h\\\",\\\"MPU6050.c\\\"和\\\"MPU6050Reg.h\\\"文件,用于MPU6050的驅(qū)動. 在

    2024年02月15日
    瀏覽(22)
  • 【stm32】軟件I2C讀寫MPU6050

    【stm32】軟件I2C讀寫MPU6050

    概況 首先建立通信層的.c和.h模塊 在通信層里寫好I2C底層的GPIO初始化 以及6個時(shí)序基本單元 起始、終值、發(fā)送一個字節(jié)、接收一個字節(jié)、發(fā)送應(yīng)答、接收應(yīng)答 寫好I2C通信層之后,再建立MPU6050的.c和.h模塊 基于I2C通信的模塊,來實(shí)現(xiàn)指定地址讀、指定地址寫 再實(shí)現(xiàn)寫寄存器對

    2024年04月26日
    瀏覽(19)
  • STM32--MPU6050與I2C外設(shè)

    STM32--MPU6050與I2C外設(shè)

    在51單片機(jī)專欄中,用過I2C通信來進(jìn)行實(shí)現(xiàn)AT24C02的數(shù)據(jù)存儲; 里面介紹的是 利用程序的編程來實(shí)現(xiàn)I2C的時(shí)序 ,進(jìn)而實(shí)現(xiàn)AT24C02與單片機(jī)之間的關(guān)系連接; 本章將介紹使用I2C的硬件外設(shè)來實(shí)現(xiàn)I2C通信,和介紹MPU6050,利用I2C通信實(shí)現(xiàn)STM32對MPU6050的控制. I2C通信軟件實(shí)現(xiàn)程序鏈接

    2024年02月11日
    瀏覽(28)
  • STM32 I2C通訊+MPU6050通訊演示

    STM32 I2C通訊+MPU6050通訊演示

    1.I2C通訊簡介 I2C(Inter IC Bus)是由Philips公司開發(fā)的一種通用數(shù)據(jù)總線; 兩根通信線:SCL(Serial Clock)、SDA(Serial Data); 同步,半雙工,帶數(shù)據(jù)應(yīng)答; 支持總線掛載多設(shè)備(一主多從、多主多從) 2.硬件電路 所有I2C設(shè)備的SCL連在一起,SDA連在一起; 設(shè)備的SCL和SDA均要配置

    2024年01月21日
    瀏覽(23)
  • 01_STM32軟件+硬件I2C讀取MPU6050(HAL庫)

    01_STM32軟件+硬件I2C讀取MPU6050(HAL庫)

    目錄 1、I2C簡介 2、I2C時(shí)序單元 2.1 起始條件 2.2 終止條件 2.3 發(fā)送一個字節(jié) 2.4 接收一個字節(jié) 2.5 發(fā)送應(yīng)答 2.6 接收應(yīng)答 3、I2C完整時(shí)序 3.1 指定地址寫一個字節(jié) 3.2 當(dāng)前地址讀一個字節(jié) 3.2?指定地址讀一個字節(jié) 4、簡單軟件I2C代碼(HAL) 4.1 軟件I2C 4.2 軟件I2C讀MPU6050寄存器 5、ST

    2024年04月17日
    瀏覽(29)
  • 【STM32】I2C練習(xí),HAL庫讀取MPU6050角度陀螺儀

    【STM32】I2C練習(xí),HAL庫讀取MPU6050角度陀螺儀

    MPU-6000(6050)為全球首例整合性6軸運(yùn)動處理組件,相較于多組件方案,免除了組合陀螺儀與加速器時(shí)間軸之差的問題,減少了大量的封裝空間。當(dāng)連接到三軸磁強(qiáng)計(jì)時(shí),MPU-60X0提供完整的9軸運(yùn)動融合輸出到其主I2C或SPI端口(SPI僅在MPU-6000上可用)。 寄存器地址 寄存器內(nèi)容 0X3B

    2024年02月16日
    瀏覽(28)
  • STM32——I2C通信

    STM32——I2C通信

    ????????I2C(Inter IC Bus)是由Philips公司開發(fā)的一種通用數(shù)據(jù)總線,它是兩線式串行總線,它具有兩根通信線: SCL(Serial Clock)、SDA(Serial Data) ,多用于主控制器和從器件間的主從通信,在小數(shù)據(jù)量場合使用,傳輸距離短,任意時(shí)刻只能有一個主機(jī)等特性。I2C是同步半雙

    2024年01月25日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包