首页 > 其他分享 >17_I2C通信外设

17_I2C通信外设

时间:2024-03-02 19:44:25浏览次数:22  
标签:17 uint8 MPU6050 外设 InitStruct GPIO I2C I2C2

I2C通信外设

I2C外设简介

image-20240227000723937

固定多主机:固定多个主机和多个从机

可变多主机:没用固定的主机和从机,任何从机都可以变成主机,通信完成后变回从机

10位地址模式:使用第一二个字节当地址,第一个字节是11110开头就是10位地址模式(除了11110之后的2位+第二个字节的8位)

I2C框图

image-20240227141400510

I2C基本结构

image-20240227143113786

复用开漏/推挽输出

image-20240227144827719

主机发送

主机->数据寄存器->移位寄存器->从机

image-20240227144949220

image-20240227145515977

image-20240227150031392

主机接收

当前地址接收

image-20240227151021124

指定地址接收

主机发送+当前地址接收

image-20240302152121611

image-20240302152608084

软件/硬件波形对比

image-20240227151729237

上软件,下硬件

硬件I2C读写MPU6050

image-20240227185357902

代码

MPU6050.c

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

#define MPU6050_ADDRESS		0xD0 //AD0接高电平地址为:0xD2

void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
	uint32_t Timeout;
	while(I2C_CheckEvent(I2Cx,I2C_EVENT)!=SUCCESS)
	{
		Timeout--;
		if(Timeout==0)
		{
			break;
		}
	}
}

void MPU6050_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_OD; //复用开漏模式
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStruct);
	
	I2C_InitTypeDef I2C_InitStruct;
	I2C_InitStruct.I2C_Ack=I2C_Ack_Enable;
	I2C_InitStruct.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;
	I2C_InitStruct.I2C_ClockSpeed=200000;
	I2C_InitStruct.I2C_DutyCycle=I2C_DutyCycle_2;
	I2C_InitStruct.I2C_Mode=I2C_Mode_I2C;
	I2C_InitStruct.I2C_OwnAddress1=0x00;
	I2C_Init(I2C2,&I2C_InitStruct);
	
	I2C_Cmd(I2C2,ENABLE);
	
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01); //解除睡眠模式,使用x轴陀螺仪时钟
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00); //六个轴均不待机
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09); //采样率分频:10分频
	MPU6050_WriteReg(MPU6050_CONFIG,0x06); //配置寄存器
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18); //陀螺仪配置寄存器
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0x18); //加速度计配置寄存器
}

void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data)
{
	//硬件实现不需要接收应答
	I2C_GenerateSTART(I2C2,ENABLE); //START
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT); //EV5
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter); //发送从机地址
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //发送EV6
	I2C_SendData(I2C2,RegAddress); //发送寄存器地址
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING); //EV8
	I2C_SendData(I2C2,Data); //发送数据
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED); //EV8_2
	I2C_GenerateSTOP(I2C2,ENABLE); //STOP
}

uint8_t MPU6050_ReadReg(uint8_t RegAddress) //读一个字节
{
	uint8_t Data;
	I2C_GenerateSTART(I2C2,ENABLE); //START
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT); //EV5
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter); //发送从机地址
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //发送EV6
	I2C_SendData(I2C2,RegAddress); //发送寄存器地址
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED); //EV8_2
	I2C_GenerateSTART(I2C2,ENABLE); //START
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT); //EV5
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Receiver); //接收从机地址
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED); //接收EV6
	I2C_AcknowledgeConfig(I2C2,DISABLE); //设置ACK=0,清除应答
	I2C_GenerateSTOP(I2C2,ENABLE); //STOP
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED); //EV7
	Data=I2C_ReceiveData(I2C2); //接收数据
	I2C_AcknowledgeConfig(I2C2,ENABLE); //恢复应答
	return Data;
}

void MPU6050_GetData(int16_t *AccX,int16_t *AccY,int16_t *AccZ,
					int16_t *GyroX,int16_t *GyroY,int16_t *GyroZ)
{
	uint8_t DataH, DataL;
	DataH=MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H); //加速度X轴寄存器高八位
	DataL=MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L); //加速度X轴寄存器低八位
	*AccX=(DataH<<8)|DataL;
	DataH=MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H); //加速度Y轴寄存器高八位
	DataL=MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L); //加速度Y轴寄存器低八位
	*AccY=(DataH<<8)|DataL;
	DataH=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H); //加速度Z轴寄存器高八位
	DataL=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L); //加速度Z轴寄存器低八位
	*AccZ=(DataH<<8)|DataL;
	DataH=MPU6050_ReadReg(MPU6050_GYRO_XOUT_H); //陀螺仪X轴寄存器高八位
	DataL=MPU6050_ReadReg(MPU6050_GYRO_XOUT_H); //陀螺仪X轴寄存器低八位
	*GyroX=(DataH<<8)|DataL;
	DataH=MPU6050_ReadReg(MPU6050_GYRO_YOUT_H); //陀螺仪Y轴寄存器高八位
	DataL=MPU6050_ReadReg(MPU6050_GYRO_YOUT_H); //陀螺仪Y轴寄存器低八位
	*GyroY=(DataH<<8)|DataL;
	DataH=MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H); //陀螺仪Z轴寄存器高八位
	DataL=MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H); //陀螺仪Z轴寄存器低八位
	*GyroZ=(DataH<<8)|DataL;
}

MPU6050.h

#ifndef __MPU6050_H__
#define __MPU6050_H__

void MPU6050_Init(void);
void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data);
void MPU6050_WriteMulReg(uint8_t RegAddress,uint8_t *Data);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);
void MPU6050_ReadMulReg(uint8_t RegAddress, uint8_t* result);
void MPU6050_GetData(int16_t *AccX,int16_t *AccY,int16_t *AccZ,
					int16_t *GyroX,int16_t *GyroY,int16_t *GyroZ);

#endif

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MPU6050.h"

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

int main(void)
{
	OLED_Init();
	MPU6050_Init();
	while(1)
	{
		MPU6050_GetData(&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);
	}
}

标签:17,uint8,MPU6050,外设,InitStruct,GPIO,I2C,I2C2
From: https://www.cnblogs.com/mzx233/p/18049125

相关文章

  • P3671 [USACO17OPEN] Where's Bessie? S 题解
    我们先枚举所有子矩阵,验证其在不考虑重叠的情况下是否为PCL矩阵(dfs求一遍联通块即可)。然后将所有满足条件的矩阵存下来,最后朴素判断每个矩阵是否被其他矩阵包括,若没有矩阵包括它,则其对于答案的贡献为\(1\),累加所有贡献即为最终结果。时间复杂度是\(O(n^6)\)的。思路很简......
  • CF17C
    传送门定义一个字符串\(S\)的缩字符串\(S':\)把\(S\)中所有连续的相同字符变成\(1\)个。发现通过复制操作,若\(A\)能变成\(B\),则\(B'\)一定是\(A'\)的子序列;反之,如果\(B'\)是\(A'\)的子序列,\(A\)能复制成\(B\)。因此我们考虑求出\(A'\),然后选出\(B\),同时......
  • [AH2017HNOI2017] 礼物(fft)
    [AH2017/HNOI2017]礼物(fft)题目描述我的室友最近喜欢上了一个可爱的小女生。马上就要到她的生日了,他决定买一对情侣手环,一个留给自己,一个送给她。每个手环上各有\(n\)个装饰物,并且每个装饰物都有一定的亮度。但是在她生日的前一天,我的室友突然发现他好像拿错了一个手环,而且......
  • [ABC217F] Make Pair 题解
    [ABC217F]MakePair题解思路解析通过\(n\le200\)和“选出的两个学生离开队列,空出来的位置左右合拢”这两个细节可以想到能用区间dp做,\(f_{i,j}\)表示将\(i\toj\)这个区间全部选完的方案数,然后常规区间dp,加一个判断如果当前区间\([l,r]\)中\(l,r\)是朋友,就可......
  • 打卡17
    GitHub使用教程(十) 你的改动现在已经在本地仓库的HEAD中了。执行如下命令以将这些改动提交到远端仓库:gitpush-uoriginmaster可以把master换成你想要推送的任何分支。如果你还没有克隆现有仓库,并欲将你的仓库连接到某个远程服务器,你可以使用如下命令添加:gitremot......
  • P8647 [蓝桥杯 2017 省 AB] 分巧克力
    题目链接:小巧克力的边长一定在\(1\sim10^5\)之间。答案为在\(1\sim10^5\)之间找一个最大的数,使得所有\(h[i]/a*w[i]/a\)的和\(\geqslantk\)即可。#include<cstdio>#include<algorithm>constintN=1e5+10;intn,k,h[N],w[N];boolcheck(inta)......
  • 17
    在activity_main.xml里编写主界面布局根据预览图,主界面需要一个ListView和一个ImageButton,还要给ImageButton添加一个Onclick事件,将按钮的UI图片tianjia.png放入drawable文件夹<?xmlversion="1.0"encoding="utf-8"?><RelativeLayoutxmlns:android="http://schemas.android.com......
  • ARC171C
    题面给定一棵\(n\)个节点的树,每个点有个权值\(a_i\),初始时\(a_i=i\)。你可以执行任意操作:选择一条边\((u,v)\),交换\(a_u\)和\(a_v\),并将这条边删掉。问通过上述操作,最后\((a_1,a_2,\cdots,a_n)\)有多少种不同的排列方式,答案对\(998244353\)取模。数据范围:\(n\le3......
  • 题解 CF1709 XOR
    *2400*dsuontree一道很好的题目思路很巧妙传送门题目大意给出一棵树,\(n\)个节点,每个节点有权值\(v\),定义一次操作为修改任意一个节点的值为任意正整数,要求最后的树不存在任意简单路径使得路径异或和为\(0\)Solution一个很常用的套路,先钦定根节点为\(1\)定义\(w......
  • MySQL-17.触发器
    C-17.触发器在实际开发中,经常会遇到这样的情况,有两个或者多个相互关联的表,如商品信息和库存信息分别存放在2个不同的数据表中,我们在添加一条新商品记录的时候,为了保证数据的完整性,必须同时在库存表中添加一条库存记录。这样一来,我们就必须把这两个关联的操作步骤写在程序里面,而......