I2C
I2C有两条总线线路,分别是SCL(时钟线)和SDA(数据线)。
I2C的时序非常重要:读数据和写数据的时序有点不一样,在写程序的时候就体现得到。
I2C的SCL高电平时有效,SDA高电平为1,低电平为0。
I2C的驱动:
I2C.h
#ifndef __I2c__H
#define __I2c__H
#include "stm32f4xx.h"
#define MPU_ADDRESS 0xd0
#define I2C_SCL_CLK RCC_AHB1Periph_GPIOB
#define I2C_SDA_CLK RCC_AHB1Periph_GPIOB
#define MPU_I2C_CLK RCC_APB1Periph_I2C1
#define I2C_SCL_PORT GPIOB
#define I2C_SDA_PORT GPIOB
#define MPU_I2C_PORT I2C1
#define I2C_SCL_PIN GPIO_Pin_6
#define I2C_SDA_PIN GPIO_Pin_7
#define I2C_SCL_SOURCE_PIN GPIO_PinSource6
#define I2C_SDA_SOURCE_PIN GPIO_PinSource7
#define SCL_I2C_AF GPIO_AF_I2C1
#define SDA_I2C_AF GPIO_AF_I2C1
void I2C_GPIO_config(void);
void MPU_I2c_config(void);
void MPU6050_I2C_Init(void);
uint8_t MPU6050_WriteByte(uint8_t addr,uint8_t data);
uint8_t MPU6050_ReadByte(uint8_t addr);
uint16_t MPU6050_Readbuffer(uint8_t addr,short*buffer,uint8_t num);
#endif
1.初始化I2C的引脚,开启复用功能
I2C需要配置成开漏输出
void I2C_GPIO_config(void)
{
RCC_AHB1PeriphClockCmd(I2C_SCL_CLK|
I2C_SDA_CLK,
ENABLE);
GPIO_PinAFConfig(I2C_SCL_PORT,I2C_SCL_SOURCE_PIN,SCL_I2C_AF);
GPIO_PinAFConfig(I2C_SDA_PORT,I2C_SDA_SOURCE_PIN,SDA_I2C_AF);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType=GPIO_OType_OD;
GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_100MHz;
GPIO_InitStruct.GPIO_Pin=I2C_SCL_PIN;
GPIO_Init(I2C_SCL_PORT, & GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin=I2C_SDA_PIN;
GPIO_Init(I2C_SDA_PORT, & GPIO_InitStruct);
}
2.初始化I2C
I2C_OwnAddress1(MCU的设备地址,只要和I2C上挂载的设备地址不一样即可)
记得使能I2C
void MPU_I2c_config(void)
{
RCC_APB1PeriphClockCmd(MPU_I2C_CLK,ENABLE);
//I2C_DeInit(MPU_I2C_PORT);
I2C_InitTypeDef I2C_InitStruct;
I2C_InitStruct.I2C_Mode=I2C_Mode_I2C;
I2C_InitStruct.I2C_ClockSpeed=100000;
I2C_InitStruct.I2C_DutyCycle=I2C_DutyCycle_2 ;
I2C_InitStruct.I2C_OwnAddress1=0x0a;
I2C_InitStruct.I2C_Ack=I2C_Ack_Enable;
I2C_InitStruct.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;
I2C_Init(MPU_I2C_PORT,&I2C_InitStruct);
I2C_Cmd(MPU_I2C_PORT,ENABLE);
}
3.编写I2C写一个字节的函数
体现I2C读数据的时序
注意应答事件,这里很容易写错,有两个EV6,分别是作为发送端和接收端
uint8_t MPU6050_WriteByte(uint8_t addr,uint8_t data)
{
while(I2C_GetFlagStatus(MPU_I2C_PORT,I2C_FLAG_BUSY));//检查总线是否在忙
I2C_GenerateSTART(MPU_I2C_PORT ,ENABLE);//发送起始信号
while(I2C_CheckEvent(MPU_I2C_PORT,I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS);//应答
I2C_Send7bitAddress(MPU_I2C_PORT,MPU_ADDRESS,I2C_Direction_Transmitter);//发送挂在在I2C上设备的地址
while(I2C_CheckEvent(MPU_I2C_PORT,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)!=SUCCESS);//应答
I2C_SendData(MPU_I2C_PORT,addr);//发送写入设备的内部地址
while(I2C_CheckEvent(MPU_I2C_PORT,I2C_EVENT_MASTER_BYTE_TRANSMITTED)!=SUCCESS);//应答
I2C_SendData(MPU_I2C_PORT,data);//发送写入的数据
while(I2C_CheckEvent(MPU_I2C_PORT,I2C_EVENT_MASTER_BYTE_TRANSMITTED)!=SUCCESS);//应答
I2C_GenerateSTOP(MPU_I2C_PORT ,ENABLE);//发送停止信号
return 0;
}
4.编写I2C读入一个字节的函数
在读数据过程中,需要发送两次的起始信号,第一次发送起始信号是要告诉I2C上挂载的设备要操作它的内部地址,第二次发送起始信号告诉设备现在要读它
uint8_t MPU6050_ReadByte(uint8_t addr)
{
uint8_t readdata=0;
I2C_GenerateSTART(MPU_I2C_PORT ,ENABLE);//发送起始信号
while(I2C_CheckEvent(MPU_I2C_PORT,I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS);//应答
I2C_Send7bitAddress(MPU_I2C_PORT,MPU_ADDRESS,I2C_Direction_Transmitter);//发送设备地址
while(I2C_CheckEvent(MPU_I2C_PORT,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)!=SUCCESS);//应答
I2C_Cmd(MPU_I2C_PORT,ENABLE);//清除事件EV6
I2C_SendData(MPU_I2C_PORT,addr);//发送要读取设备的内部地址
while(I2C_CheckEvent(MPU_I2C_PORT,I2C_EVENT_MASTER_BYTE_TRANSMITTING)!=SUCCESS);//应答
I2C_GenerateSTART(MPU_I2C_PORT ,ENABLE);发送第二次起始信号
while(I2C_CheckEvent(MPU_I2C_PORT,I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS);//应答
I2C_Send7bitAddress(MPU_I2C_PORT,MPU_ADDRESS,I2C_Direction_Receiver);//发送设备地址
while(I2C_CheckEvent(MPU_I2C_PORT,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)!=SUCCESS);//应答
I2C_AcknowledgeConfig(MPU_I2C_PORT ,DISABLE);//失能应答
readdata=I2C_ReceiveData(MPU_I2C_PORT);//读取数据
while(I2C_CheckEvent(MPU_I2C_PORT,I2C_EVENT_MASTER_BYTE_RECEIVED)!=SUCCESS);//应答
I2C_GenerateSTOP(MPU_I2C_PORT ,ENABLE);//发送停止信号
I2C_AcknowledgeConfig(MPU_I2C_PORT ,ENABLE);//使能应答
return readdata;返回读取数据
}
5.编写I2C连续读取函数
和读取一个字节函数区别不大
uint16_t MPU6050_Readbuffer(uint8_t addr,short *buffer,uint8_t num)
{
while(I2C_GetFlagStatus(MPU_I2C_PORT,I2C_FLAG_BUSY));
I2C_GenerateSTART(MPU_I2C_PORT ,ENABLE);
while(I2C_CheckEvent(MPU_I2C_PORT, I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS);
I2C_Send7bitAddress(MPU_I2C_PORT, MPU_ADDRESS,I2C_Direction_Transmitter);
while(I2C_CheckEvent(MPU_I2C_PORT, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)!=SUCCESS);
I2C_Cmd(MPU_I2C_PORT,ENABLE);
I2C_SendData(MPU_I2C_PORT,addr);
while(I2C_CheckEvent(MPU_I2C_PORT, I2C_EVENT_MASTER_BYTE_TRANSMITTED)!=SUCCESS);
I2C_GenerateSTART(MPU_I2C_PORT ,ENABLE);
while(I2C_CheckEvent(MPU_I2C_PORT, I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS);
I2C_Send7bitAddress(MPU_I2C_PORT, MPU_ADDRESS,I2C_Direction_Receiver);
while(I2C_CheckEvent(MPU_I2C_PORT, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)!=SUCCESS);
while(num)
{
if(num==1)
{
I2C_AcknowledgeConfig(MPU_I2C_PORT, DISABLE);
I2C_GenerateSTOP(MPU_I2C_PORT, ENABLE);
}
while(I2C_CheckEvent(MPU_I2C_PORT, I2C_EVENT_MASTER_BYTE_RECEIVED)!=SUCCESS);
{
*buffer=I2C_ReceiveData(MPU_I2C_PORT);
buffer++;
num--;
}//这个中括号表示连续读取
}
I2C_AcknowledgeConfig(MPU_I2C_PORT,ENABLE);
return 1;
}
MPU6050的驱动
MPU6050.h
#ifndef __MPU6050__H
#define __MPU6050__H
#include "stm32f4xx.h"
#include "I2c.h"
#include "USART.h"
#include "stdio.h"
#include "Delay.h"
#define MPU6050_RA_WHO_AM_I 0x75
#define MPU6050_RA_PWR_MGMI 0x6B
#define MPU6050_RA_SAP_RT_DIV 0x19
#define MPU6050_RA_CONFIG 0x1A
#define MPU6050_RA_ACCEL_CONFIG 0x1C
#define MPU6050_RA_GYRO_CONFIG 0x1B
#define MPU6050_RA_FIFO_ENABLE 0X23
#define MPU6050_RA_ACCEL0_MESUME 0X3B
#define MPU6050_RA_GRYO0_MESUME 0X43
uint8_t MPU6050_ReadID(void);
void MPU6050_Init(void);
void MPU6050_Write(uint8_t addr,uint8_t data);
uint8_t MPU6050_Read(uint8_t addr);
void MPU6050_ReadACCEL(uint8_t addr,short *acc_data,uint8_t num);
void MPU6050_ReadGYRO(uint8_t addr,short *gyro_data,uint8_t num);
#endif
1.MPU6050读字节函数 写字节函数
void MPU6050_Write(uint8_t addr,uint8_t data)
{
MPU6050_WriteByte(addr,data);
}
uint8_t MPU6050_Read(uint8_t addr)
{
uint8_t readdata=0;
readdata=MPU6050_ReadByte(addr);
return readdata;
}
uint16_t MPU6050_Readdata(uint8_t addr,short *buffer,uint8_t num)
{
MPU6050_Readbuffer(addr,buffer,num);
return 0;
}
2.初始化MPU6050
初始化MPU6050思路:
1.MPU6050上电后处于休眠状态,所以要解除休眠状态,“POWER MANAGEMENT 1”寄存器中sleep位置0,就解除休眠状态
2.SAMPLE RATE DIVIDER 频率采样分频器
3.配置外部引脚采样,初始化不需要你用到什么,选择不做任何配置
4.陀螺仪配置(开启自检,选择量程)
5.加速度计(开启自检,选择量程)
void MPU6050_Init(void)
{//MPU6050上电要预热
delay (500);
MPU6050_Write(MPU6050_RA_PWR_MGMI,0x00);
MPU6050_Write(MPU6050_RA_SAP_RT_DIV,0x07);
MPU6050_Write(MPU6050_RA_CONFIG,0x06);
MPU6050_Write(MPU6050_RA_ACCEL_CONFIG,0xF8);
MPU6050_Write(MPU6050_RA_GYRO_CONFIG,0xF8);
}
3.读取MPU6050 ID的函数
根据手册 ID在设备地址的基础上右移一位
uint8_t MPU6050_ReadID(void)
{
uint8_t ID=0;
ID=MPU6050_Read(MPU6050_RA_WHO_AM_I);
ID = ID>>1;
if(ID!=0x68)
{
printf("检测不到MPU6050n");
printf("error ID=0x%x",ID);
return 0;
}
else
{
printf("检测到MPU6050n");
return 1;
}
}
4.编写读取加速度计和陀螺仪的函数
void MPU6050_ReadACCEL(uint8_t addr,short*acc_data,uint8_t num)
{
short buf[6];
MPU6050_Readdata(addr,buf,num);
acc_data[0]=((buf[0]<<8)|(buf[1]));
acc_data[1]=((buf[2]<<8)|(buf[3]));
acc_data[2]=((buf[4]<<8)|(buf[5]));
}
void MPU6050_ReadGYRO(uint8_t addr,short *gyro_data,uint8_t num)
上一篇:STM32 高级定时器 输出PWM (用DHT11测得的温度去调节RGB灯的亮度)
下一篇:RCC 使用HSE/HSI配置系统时钟
推荐阅读最新更新时间:2024-11-16 23:45
推荐帖子
- ADS1298的常见问题
- 本帖最后由dontium于2015-1-2311:21编辑ADS1298的常见问题1、问:我想使用不带MMB0的ADS1298ECGFEEVM,这是否可能?答:是的,完全没问题!不过应首先考虑到以下几个方面:-电路板电源ADS1298ECGFE板的电源来自10引脚双排插座J4。通过MMB0连接头J5,可将+5V、+3.3V以及+1.8V交付给ADS1298板。+5V供电电压通过稳压器,可为ADS1298芯片提供模拟电压
- 模拟IC 模拟与混合信号
- 高分辨率ADC的板布线
- 本文描述的是系统设计方面的一些关键性问题,特别关注印制电路板(PCB)地和电源平面布线技术。现代化的ADC需要现代化的板设计。没有精确的时钟源或仔细设计的板布线,则高性能变换器将达不到其性能指标。 单IF外差接收机结构和高级的功率nobrid=nobr74style=CURSOR:pointer;COLOR:#cb4bfc;BORDER-BOTTOM:rgb(102,0,255)1pxdotted;BACKGROUND-COLOR:transparent;TEX
- kandy2059 RF/无线
- 运算放大器、比较器设计指南 第十四版
- 本帖最后由paulhyde于2014-9-1504:25编辑介绍的比较详细!!!!!!!!运算放大器、比较器设计指南第十四版本帖最后由paulhyde于2014-9-1504:25编辑本帖最后由paulhyde于2014-9-1504:25编辑真是好人认真负责真是好人认真负责本帖最后由paulhyde于2014-9-1504:25编辑很好,复习复习模电,哈哈回复楼主kmopty
- kmopty 电子竞赛
- 基于ARM 和Qt/E的车载HMI终端设计
- 车载HMI是人与车辆之间的关键设备,使人能够对车辆的运行实现控制;设计了一种触摸控制与数字显示合理结合的车载HMI终端,采用ARM作为处理器,通过移植Qt/E对系统加以实现;该终端通过在Polo车CAN总线试验台测试,实现了对基本设备的触摸控制和车辆状态信息的实时显示,表明所设计的终端能够满足车载HMI的基本要求。 0引言 改善HMI(HumanMachineInterface)终端性能可降低车辆控制系统操作的复杂性,也可提高驾驶员对自己车辆的控制力。车载HMI通过
- fish001 微控制器 MCU
- 功率放大器知识
- 功率放大电路的原理及其知识........功率放大器知识这个资料4个芯币,楼主不厚道啊....呵呵,楼主的价格有点贵,,,不要发大财哦哈哈虽仍是菜鸟,但毕竟已非今日才入门,不想拾人牙慧,故现在我会先跟帖再下档案,实际上,我不太喜欢下人家的东西(虽然有币),而我发布的,都是图(不需登录也可见)。楼主太不厚道了,要5个币,下载完了才发现上当了,不就华成英的讲义么,人家全套模拟电路的下载也没有要币的。
- Jackiedzc 模拟电子
- 【2024 DigiKey创意大赛】+基于大语言模型的智能家居平台+最终提交贴
- 基于大语言模型的智能家居平台作者:SeasonMay一、作品简介本作品以乐鑫的ESP32-S3-LCD-EV-BOARD为家居平台的核心主控,搭配以DFROBOT的TCS3200颜色传感器(SEN0101)以及Adafruit的15x7矩阵灯板作为家居平台的主要演示场景平台,并以Adafruit的FeatherTFTESP32-S3作为协控中心,处理器件与上位机等的通信服务等任务。全家福如下:1.ESP32-S3-LCD-EV-Board是一款基于
- SeasonMay DigiKey得捷技术专区
设计资源 培训 开发板 精华推荐
- Microchip 喊你快来打造你的理想型单片机,智能门铃、百元京东卡等【80份】好礼等你赢!
- 直播已结束【安森美和安富利物联网创新设计大赛颁奖典礼】
- 泰克 MSO6B 探索营:设计资源集锦
- nanoPower技术:延长电池寿命,提升传感器性能 2021年1月20日 上午10:00在线研讨会
- 2009EEWORLD年度人物大评选活动
- 领跑2021,你准备好了么?领取下载积分,点燃学习小宇宙!
- 英飞凌开发板618大促:爆款清单揭秘,有好礼!
- 阅读并了解是德科技汽车电子、物联网(IOT) 精彩专题,答题赢好礼!
- 月度原创精选评选2018年7月(总第6期)
- 报名观看TI嵌入式主题月直播,场场精彩,好运连连