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也没有想想的那么难了呢?

相关推荐
HQB202612 小时前
EG1198|屹晶微电子 120V 内置 MOS 异步降压 DC‑DC(高性价比)
嵌入式硬件·硬件工程
果壳science13 小时前
张祥前实验如何获取正电荷
笔记·科技·嵌入式硬件·硬件工程·制造
南山电子nscn13 小时前
中科芯CETC汽车电池管理系统BMS进口芯片国产型号替代指南
单片机·汽车·bms
沉淀的.晴天14 小时前
can总线
stm32
桀人14 小时前
认识AT24C02
stm32·单片机·嵌入式硬件
国科安芯15 小时前
星间激光通信终端CANFD控制网络的时延确定性与辐射可靠性
网络·嵌入式硬件·信息与通信·canfd·低轨卫星·商业航天·抗辐射
一直C16 小时前
嵌入式 Linux 驱动开发学习笔记:内核定时器、platform 总线与 I²C 驱动
linux·驱动开发·嵌入式硬件·学习·imx6ull
传感器与混合集成电路16 小时前
150MHz主频、8路DAC与6路PWM:JLH221360伺服控制SIP解析
嵌入式硬件
comyccccc16 小时前
STM32PID控制板设计全解析学习笔记
单片机·嵌入式硬件
碧海银沙音频科技研究院17 小时前
实现炬芯ATS308X的usb cdc 串口IAP 固件升级功能实现
人工智能·嵌入式硬件·深度学习·算法