STM32——I2C通信

这篇具有很好参考价值的文章主要介绍了STM32——I2C通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、什么是I2C通信

1、I2C 简介      

        I2C(Inter IC Bus)是由Philips公司开发的一种通用数据总线,它是两线式串行总线,它具有两根通信线:SCL(Serial Clock)、SDA(Serial Data),多用于主控制器和从器件间的主从通信,在小数据量场合使用,传输距离短,任意时刻只能有一个主机等特性。I2C是同步半双工的工作模式。

2、I2C硬件电路

        所有I2C设备的SCL连在一起,SDA连在一起,设备的SCL和SDA均要配置成开漏输出模式 SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右

STM32——I2C通信,stm32f1,stm32,嵌入式硬件,单片机

上图的CPU是该通信的主机

I2C硬件电路的特点:

(1)主机对SCL时钟总线具有绝对的控制权,并且再空闲状态下,主机可以发起对SDA的控制,只有在从机发送数据和从机应答的时候主机才会转交SDA的控制权给从机;

(2)所以设备都设置开漏输出模式(只会产生浮空和强下拉电路,为了防止电路处于浮空状态,所以加了上拉电阻,产生弱上拉)原因这样是为了防止两个设备同时处于输出状态且一个输出高电平一个输出低电平造成短路。这样会产生一个线与的状态,也就是只要有一个设备属于低电平,总线就处于低电平。

3、I2C时序基本单元

 (1)起始条件

        SCL高电平期间,SDA从高电平切换到低电平

STM32——I2C通信,stm32f1,stm32,嵌入式硬件,单片机

(2)终止条件

        SCL高电平期间,SDA从低电平切换到高电平

STM32——I2C通信,stm32f1,stm32,嵌入式硬件,单片机

(3)发送一个字节

        主机发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节

STM32——I2C通信,stm32f1,stm32,嵌入式硬件,单片机

(4)接收一个字节

主机接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)

STM32——I2C通信,stm32f1,stm32,嵌入式硬件,单片机

(5)发送应答(主机希望你继续发送)

       主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答

STM32——I2C通信,stm32f1,stm32,嵌入式硬件,单片机

(6)接收应答(主机判断从机是否响应)

主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)

STM32——I2C通信,stm32f1,stm32,嵌入式硬件,单片机

二、I2C基本时序

1、指定地址写

对于指定设备(Slave Address),在指定地址(Reg Address)下,写入指定数据(Data)

起始条件——从机地址+读/写位(为0)——应答信号——要写入的寄存器地址——应答信号——写入的数据——终止条件

STM32——I2C通信,stm32f1,stm32,嵌入式硬件,单片机

2、当前地址读

对于指定设备(Slave Address),在当前地址指针指示的地址下,读取从机数据(Data)

起始条件——从机地址+读/写位(为1)——应答信号——读取数据——应答信号——终止条件

STM32——I2C通信,stm32f1,stm32,嵌入式硬件,单片机

3、指定地址读

对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据(Data),先进性写操作使寄存器指针指向要读的寄存器地址,在进行当前地址读操作

起始条件——从机地址+读/写位(为0)——应答信号——要写入的寄存器地址——应答信号——重复起始条件——从机地址+读/写位(为1)——应答信号——读取数据——应答信号——终止条件

STM32——I2C通信,stm32f1,stm32,嵌入式硬件,单片机

三、STM32F1软件I2C通信

协议层代码

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

void MyI2C_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);
}

void MyI2C_W_SCL(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);
	Delay_us(10);
}

void MyI2C_W_SDA(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);
	Delay_us(10);
}

uint8_t MyI2C_R_SDA(void)
{
	uint8_t BitValue;
	BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
	Delay_us(10);
	return BitValue;
}

void MyI2C_Start(void)
{
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);
}

void MyI2C_Stop(void)
{
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
}

void MyI2C_SendByte(uint8_t Byte)//发送一个字节
{
	uint8_t i;
	for (i = 0; i < 8; i ++)
	{
		MyI2C_W_SDA(Byte & (0x80 >> i));//取Byte各个位再发送,高位先行
		MyI2C_W_SCL(1);
		MyI2C_W_SCL(0);
	}
}

uint8_t MyI2C_ReceiveByte(void)//接收一个字节
{
	uint8_t i, Byte = 0x00;
	MyI2C_W_SDA(1);
	for (i = 0; i < 8; i ++)
	{
		MyI2C_W_SCL(1);
		if (MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);}
		MyI2C_W_SCL(0);
	}
	return Byte;
}

void MyI2C_SendAck(uint8_t AckBit)//发送应答
{
	MyI2C_W_SDA(AckBit);
	MyI2C_W_SCL(1);
	MyI2C_W_SCL(0);
}

uint8_t MyI2C_ReceiveAck(void)//接收应答
{
	uint8_t AckBit;
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	AckBit = MyI2C_R_SDA();
	MyI2C_W_SCL(0);
	return AckBit;
}





















MPU6050调用软件I2C代码使用

#include "stm32f10x.h"                  // Device header
#include "MyI2C.h"
#include "MPU6050Reg.h"

#define MPU6050_ADDRESS 0xD0

void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data)//指定地址写一个字节
{
	MyI2C_Start();
	MyI2C_SendByte(MPU6050_ADDRESS);//指定从机地址
	MyI2C_ReceiveAck();
	MyI2C_SendByte(RegAddress);//指定读写寄存器
	MyI2C_ReceiveAck();
	MyI2C_SendByte(Data);//写入内容
	MyI2C_ReceiveAck();
	MyI2C_Stop();
}

uint8_t MPU6050_ReadReg(uint8_t RegAddress)//指定地址读一个字节
{
	uint8_t Data;
	
	MyI2C_Start();
	MyI2C_SendByte(MPU6050_ADDRESS);//指定从机地址
	MyI2C_ReceiveAck();
	MyI2C_SendByte(RegAddress);//指定读写寄存器
	MyI2C_ReceiveAck();
	
	MyI2C_Start();//重复起始位
	MyI2C_SendByte(MPU6050_ADDRESS | 0x01);//指定从机地址 读写位变为1 为读
	MyI2C_ReceiveAck();//此时接收应答后,sda控制权就交给从机了,开始发送一个字节
	
	Data = MyI2C_ReceiveByte();//读取从机发送的数据
	
	MyI2C_SendAck(1);//返回給从机应答位
	MyI2C_Stop();
	
	return Data;
	
}

四、STM32F1硬件I2C通信

1、STM32——I2C简介

        STM32内部集成了硬件I2C收发电路,可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能,减轻CPU的负担,STM32F103C8T6 硬件I2C资源:I2C1、I2C2。

        支持多主机模型,支持7位/10位地址模式,支持不同的通讯速度,标准速度(高达100 kHz),快速(高达400 kHz) ,支持DMA ,兼容SMBus协议

2、STM32——内部I2C框图

STM32——I2C通信,stm32f1,stm32,嵌入式硬件,单片机

3、主机发送及接收时序图(附代码)

主机发送

STM32——I2C通信,stm32f1,stm32,嵌入式硬件,单片机

主机接收

STM32——I2C通信,stm32f1,stm32,嵌入式硬件,单片机

代码部分文章来源地址https://www.toymoban.com/news/detail-824090.html

#include "stm32f10x.h"                  // Device header
#include "MPU6050Reg.h"

#define MPU6050_ADDRESS 0xD0

void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data)//指定地址写一个字节
{
	uint32_t Timeout;
	Timeout = 10000;
	I2C_GenerateSTART(I2C2,ENABLE);
	while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)	//超时退出
	{
		Timeout--;
		if(Timeout)
		{
			break;
		}
	}
	
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);	//Transmitter地址最低位致0,为发送模式
	while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);
	
	I2C_SendData(I2C2,RegAddress);
	while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING) != SUCCESS);//指定从机地址
	
	I2C_SendData(I2C2,Data);
	while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS);//发送数据后不再继续发送
	
	I2C_GenerateSTOP(I2C2,ENABLE);
	
}

uint8_t MPU6050_ReadReg(uint8_t RegAddress)//指定地址读一个字节
{
	uint8_t Data;

	I2C_GenerateSTART(I2C2,ENABLE);
	while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);
	
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);	//Transmitter地址最低位致0,为发送模式
	while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);
	
	I2C_SendData(I2C2,RegAddress);
	while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS);//指定从机地址,注意标志位
	
	I2C_GenerateSTART(I2C2,ENABLE);
	while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);
	
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Receiver);	//Receiver最低位致1,为接收模式
	while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS);
	
	I2C_AcknowledgeConfig(I2C2,DISABLE);
	I2C_GenerateSTOP(I2C2,ENABLE);//在接收单个字节时,我们要在EV6之后EV6_1之前将应答位置0,再设置停止位,在连续时就是EV7之后
	
	while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS);	//接受完一个字节后等待EV7
	Data = I2C_ReceiveData(I2C2);
	
	I2C_AcknowledgeConfig(I2C2,ENABLE);
	return Data;
	
}


void MPU6050_Init(void)
{

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	
	I2C_InitTypeDef I2C_InitStructure;
	
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	I2C_InitStructure.I2C_ClockSpeed = 50000;			//设置不同的通讯速度最高400KHZ,100KHZ以下为标准速率
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;	//配置时钟占空比,在标准模式下默认1:1,快速状态下低电平比高电平16:9
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//响应七位地址
	I2C_InitStructure.I2C_OwnAddress1 = 0x00;								//设置自生的作为从机的地址

	I2C_Init(I2C2,&I2C_InitStructure);
	I2C_Cmd(I2C2,ENABLE);

到了这里,关于STM32——I2C通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【STM32】STM32学习笔记-I2C通信外设(34)

    I2C(Inter-Integrated Circuit)总线 是一种由NXP(原PHILIPS)公司开发的两线式串行总线,用于连接微控制器及其外围设备。多用于主控制器和从器件间的主从通信,在小数据量场合使用,传输距离短,任意时刻只能有一个主机等特性。 串行的 8 位双向数据传输位速率在标准模式下可

    2024年01月17日
    浏览(64)
  • 【STM32】STM32学习笔记-I2C通信协议(31)

    I2C(Inter-Integrated Circuit)总线 是一种由NXP(原PHILIPS)公司开发的两线式串行总线,用于连接微控制器及其外围设备。多用于主控制器和从器件间的主从通信,在小数据量场合使用,传输距离短,任意时刻只能有一个主机等特性。 串行的 8 位双向数据传输位速率在标准模式下可

    2024年01月23日
    浏览(75)
  • day9 STM32 I2C总线通信

            I2C(Inter-Integrated Circuit)总线(也称IIC或I2C)是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备,是微电子通信控制领域广泛采用的一种总线标准。         它是同步通信的一种特殊形式,具有接口线少,控制方式简单,期间封装形式少,通

    2024年02月12日
    浏览(55)
  • 【STM32学习】——I2C通信协议&MPU6050姿态传感器&软件I2C读写MPU6050

    ​   目录 前言 一、I2C通信协议 1.简介 2.硬件电路设计 3.I2C时序(软件)

    2024年02月16日
    浏览(56)
  • 嵌入式中I2C 相关的硬件问题汇总及死锁解决办法

    本文主要介绍如何解决I2C设备硬件设计上的各种问题,希望对大家有所帮助! 关于I2C协议详细的讲解,可以参考之前的推文:全面解析 I2C 通信协议 一般情况下, i2c 设备焊接没什么问题,按照设备手册一步步来,基本上就顺风顺水能够用起来。如果这么一个简单的东西,有

    2024年02月19日
    浏览(63)
  • 嵌入式I2C 信号线为何加上拉电阻(图文并茂)

    IIC 是一个两线串行通信总线,包含一个 SCL 信号和 SDA 信号,SCL 是时钟信号,从主设备发出,SDA 是数据信号,是一个双向的,设备发送数据和接收数据都是通过 SDA 信号。   在设计 IIC 信号电路的时候我们会在 SCL 和 SDA 上加一个上拉电阻。   今天就来分享下,为什么要在

    2024年02月19日
    浏览(50)
  • STM32-I2C通信在AT24C02的应用

    AT24C02是一种失去电源供给后依旧能保持数据的储存器,常用来储存一些配置信息,在系统重新上电之后也可以加载。它的容量是2k bit的EEPROM存储器,采用I2C通信方式。 AT24C02支持两种写操作:字节写操作和页写操作。本实验中我们采用的是字节写操作,就是一个地址一个数据

    2024年02月09日
    浏览(53)
  • DMA技术在STM32中优化UART、SPI和I2C通信性能的研究与实现

    DMA(Direct Memory Access,直接存储器访问)技术可以在STM32微控制器上优化UART、SPI和I2C等通信性能。 DMA可以实现数据的高速传输,减轻CPU的负担,提高系统性能。在本篇文章中,我将探讨DMA技术在STM32中优化这些通信协议的研究和实现。 一、DMA工作原理 DMA可以实现外设与存储器

    2024年01月20日
    浏览(41)
  • 4针0.96寸OLED的HAL库代码(硬件I2C/全代码/stm32f1/CubeMX配置/包含有正负浮点数/100%一次点亮)

    一、HC-SR04超声波模块的使用 二、4针OLED的HAL库代码介绍及使用(本篇) 三、7针OLED的HAL库代码介绍及使用 四、编码电机以及双电机驱动 更多有意思的文章点击“我的主页” --------😐 更多有意思的视频 ----- B站 @想要亿只独角兽 --------😐 之前在做一些小项目时用到了OLED,到

    2024年02月10日
    浏览(40)
  • STM32串口通信详解(嵌入式学习)

    时钟信号在电子领域中是指用于同步和定时电路操作的周期性信号。它在数字系统和通信系统中起着至关重要的作用,用于协调各个组件之间的数据传输和操作。 时钟信号有以下几个重要的方面: 频率:时钟信号的频率是指单位时间内信号周期的数量。它通常以赫兹(Hz)为

    2024年02月09日
    浏览(69)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包