STM32—I2C的基本时序,MU6050的ID读取

目录

前言

一、I2C基本时序的书写

二、I2C基本时序的代码

1.引脚的初始化

2.起始时序

3.停止时序

4.发送一个字节

5.接收一个字节

6.发送一个应答

7.接收一个应答

三.MU6050的应答

1.先验证下应答功能:

2.读取ID

总结



前言

环境:

芯片:STM32F103C8T6

Keil:V5.24.2.0

模块:MU6050模块


一、I2C基本时序的书写

上章对I2C时序进行了简单的讲解.

这章对代码进行书写.

二、I2C基本时序的代码

1.引脚的初始化

引脚的宏定义

#define GPIO_PORT GPIOA

#define SCK_GPIO_PIN GPIO_Pin_10

#define SDA_GPIO_PIN GPIO_Pin_9

大家根据自己的连接需要,更改上面的宏就行.

复制代码
void MyI2C_Init(void)//初始化函数
{
    /*将SCL和SDA引脚初始化为开漏模式*/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Pin = SCK_GPIO_PIN | SDA_GPIO_PIN;
     GPIO_Init(GPIO_PORT, &GPIO_InitStructure);
    
    //需要拉高电平
    GPIO_SetBits(GPIO_PORT,SCK_GPIO_PIN | SDA_GPIO_PIN);
}

2.起始时序

参考上章的内容,起始时序代码如下:

复制代码
void MyI2C_Start(void)
{
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);
}

1,保证SDA和SCL均在高电平

2.先拉低SDA线

3再拉低SCL线

具体书写的代码:补齐了上面的书写代码,参数0就是输出0.

延时10us是怕更高速度的MCU超过了I2C的频率而设置的.

复制代码
void MyI2C_W_SCL(uint8_t BitValue)//SCL书写
{
	GPIO_WriteBit(GPIO_PORT,SCK_GPIO_PIN,(BitAction)BitValue);
	Delay_us(10);
}
void MyI2C_W_SDA(uint8_t BitValue)//SDA书写
{
	GPIO_WriteBit(GPIO_PORT,SDA_GPIO_PIN,(BitAction)BitValue);
	Delay_us(10);
}

3.停止时序

复制代码
void MyI2C_Stop(void)
{
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
}

参考上章内容,时序是:在SCL高电平时拉高SDA

为什么第一句是将SDA拉低呢?因为在读取时可能会因为从机的拉高而不是低电平.所以这里进行一个防呆处理.

4.发送一个字节

复制代码
void MyI2C_SendByte(uint8_t Byte)
{
	uint8_t i;
	for(i = 0;i<8;i++)
	{
		MyI2C_W_SDA(Byte & (0x80 >> i));
		MyI2C_W_SCL(1);
		MyI2C_W_SCL(0);
	}
}

时序说明:

发送一个字节,就是发送一个bit

重复8次

5.接收一个字节

复制代码
uint8_t MyI2C_ReceiveByte(void)
{
	uint8_t i,Byte=0x00;//定义变量
	MyI2C_W_SDA(1);//交出SDA控制权
	for(i = 0;i<8;i++)
	{	
		MyI2C_W_SCL(1);//拉高开始读取数据
		if(MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);}//是1则或上。是0则跳过。
		MyI2C_W_SCL(0);//拉低允许从机放入数据
	}
	return Byte;
}

详情如注释

6.发送一个应答

复制代码
void MyI2C_SendAck(uint8_t AckBit)
{
	MyI2C_W_SDA(AckBit);//写入0或1
	MyI2C_W_SCL(1);
	MyI2C_W_SCL(0);//拉高拉低结束一个字节的发送
}

7.接收一个应答

复制代码
uint8_t MyI2C_ReceiveAck(void)
{
	uint8_t AckBit;
	MyI2C_W_SDA(1);	//交出SDA控制权
	MyI2C_W_SCL(1);//拉高SCL开始读取数据
	AckBit = MyI2C_R_SDA();//读取数据
	MyI2C_W_SCL(0);//接收结束
	return AckBit;
}

以上就是I2C的基本时序.

最后看下.h文件

复制代码
#ifndef  __MYI2C_H__
#define  __MYI2C_H__

void MyI2C_W_SCL(uint8_t BitValue);
void MyI2C_W_SDA(uint8_t BitValue);
uint8_t MyI2C_R_SDA(void);
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

后面我们就可以调用基本时序,来进行通讯了.

三.MU6050的应答

现在我们来验证下基本时序的功能正常与否

1.先验证下应答功能:

复制代码
int main(void)
{
	HardWare_Init();//初始化
	Delay_ms(10);
	
	MyI2C_Start();
	MyI2C_SendByte(0xD0);//110 1000,需要左移一位
	uint8_t Ack = MyI2C_ReceiveAck();
	MyI2C_Stop();
	OLED_ShowHexNum(70, 28, Ack, 4, OLED_6X8);//显示应答
	OLED_Update();//显示函数
	
	while (1)
	{

    }
}

此时如果地址正确,则显示0000,如何验证呢?只需要更改下地址,将0xD0更换下再次烧录,则显示0001.说明设备没有应答.

2.读取ID

要写一个读取函数

复制代码
uint8_t MU6050_RegRead(uint8_t RegAddress)
{
	uint8_t Data;
	MyI2C_Start();
	MyI2C_SendByte(MU6050_ADDRESS);//选择设备地址
	MyI2C_ReceiveAck();
	MyI2C_SendByte(RegAddress);//选择寄存器地址
	MyI2C_ReceiveAck();
	
	/*------下面转入正式读程序-------------*/
	MyI2C_Start();
	MyI2C_SendByte(MU6050_ADDRESS | 0x01);//选择设备地址,或上1,表示接下来是从机控制信号
	MyI2C_ReceiveAck();
	Data = MyI2C_ReceiveByte();
	MyI2C_SendAck(1);//不继续读则给1,如果还想继续则给0;
	MyI2C_Stop();
	
	return Data;
}

注意:为什么代码有部分重复了

因为我们需要先选择好设备寄存器的地址后才能进行数据的读取操作

而设备寄存器又是在我们操作完后自动+ 1操作的.所以我们先指定到地址,后面再进行读写,数据不会出错.

验证:

复制代码
int main(void)
{
	HardWare_Init();
	Delay_ms(10);
	
	MyI2C_Start();
	MyI2C_SendByte(0x3D);
	uint8_t Ack = MyI2C_ReceiveAck();
	MyI2C_Stop();
	OLED_ShowHexNum(70, 28, Ack, 4, OLED_6X8);//显示应答
	OLED_Update();//显示函数
	
	uint8_t ID = MU6050_RegRead(0x0f);//0x0F地址参数不正确,需要去查阅下正确的地址
	OLED_ShowHexNum(70, 28, ID, 4, OLED_6X8);
	OLED_Update();
	
	while (1)
	{
    }
}

然后会显示正确的ID号,大家根据手册去验证下读取的是否正确.


总结

通过读取ID号验证了I2C的时序,功能.是否发现I2C也没有想想的那么难了呢?

相关推荐
小柯博客3 小时前
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(十二)
c语言·stm32·单片机·嵌入式硬件·php·嵌入式
SY师弟6 小时前
51单片机基础部分——独立按键检测
单片机·嵌入式硬件·51单片机
Mapleay6 小时前
FMC STM32H7 SDRAM
stm32·单片机·嵌入式硬件
自小吃多6 小时前
STC8H系列 驱动步进电机
笔记·单片机
易知嵌入式小菜鸡7 小时前
STM32CubeMX-H7-19-ESP8266通信(中)--单片机控制ESP8266实现TCP地址通信
stm32·单片机·嵌入式硬件
乄夜7 小时前
嵌入式面试高频(5)!!!C++语言(嵌入式八股文,嵌入式面经)
c语言·c++·单片机·嵌入式硬件·物联网·面试·职场和发展
c7_ln9 小时前
STM32 低功耗设计全攻略:PWR 模块原理 + 睡眠 / 停止 / 待机模式实战(串口 + 红外 + RTC 应用全解析)
stm32·单片机·实时音视频·江协科技
待什么青丝10 小时前
【TMS570LC4357】之相关驱动开发学习记录2
c语言·arm开发·驱动开发·单片机·学习
小柯博客10 小时前
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
c语言·stm32·单片机·嵌入式硬件·物联网
云山工作室11 小时前
一种停车场自动停车导航器的设计(论文+源码)
单片机·嵌入式硬件·毕业设计·毕设