STM32标准库学习笔记-11.I2C通信

2024-08-20 16:12

本文主要是介绍STM32标准库学习笔记-11.I2C通信,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

参考教程:【STM32入门教程-2023版 细致讲解 中文字幕】

I2C通信
  • I2C(Inter IC Bus)是由Philips公司八十年代推出的一种通用数据总线
  • 两根通信线:SCL(Serial Clock)、SDA(Serial Data) 同步,半双工 带数据应答
  • 支持总线挂载多设备(一主多从、多主多从)

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

I2C时序基本单元
  • 起始条件:SCL高电平期间,SDA从高电平切换到低电平

  • 终止条件:SCL高电平期间,SDA从低电平切换到高电平

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

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

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

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

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

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

  • 指定地址读
  • 对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据(Data)

        Sr为重复起始

代码实现软件I2C通信
#include "stm32f10x.h"                  // Device header
#include "Delay.h"//标准库I2C函数以I2C开头,这里自己实现用IIC作为前缀#define IIC_PORT GPIOB
#define IIC_SCL GPIO_Pin_10
#define IIC_SDA GPIO_Pin_11void IIC_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_InitStructure.GPIO_Pin = IIC_SCL | IIC_SDA;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStructure);//默认状态给高电平GPIO_SetBits(IIC_PORT,IIC_SCL | IIC_SDA);
}void IIC_W_SCL(uint8_t BitVal)
{GPIO_WriteBit(IIC_PORT,IIC_SCL,(BitAction)BitVal);Delay_us(10);
}void IIC_W_SDA(uint8_t BitVal)
{GPIO_WriteBit(IIC_PORT,IIC_SDA,(BitAction)BitVal);Delay_us(10);
}uint8_t IIC_R_SDA(void)
{uint8_t Bitval = GPIO_ReadInputDataBit(IIC_PORT,IIC_SDA);Delay_us(10);return Bitval;
}void IIC_Start(void)
{IIC_W_SDA(1);IIC_W_SCL(1);IIC_W_SDA(0);IIC_W_SCL(0);
}void IIC_End(void)
{//其余的函数保证了SCL结束操作时是0IIC_W_SDA(0);IIC_W_SCL(1);IIC_W_SDA(1);
}void IIC_SendByte(uint8_t Byte)
{uint8_t i;for(i = 0;i < 8;i++){//00000001IIC_W_SDA(Byte & (0x80 >> i));IIC_W_SCL(1);IIC_W_SCL(0);}
}void IIC_SendAck(BitAction Ack)
{IIC_W_SDA(Ack);IIC_W_SCL(1);IIC_W_SCL(0);
}uint8_t IIC_ReceiveByte(void)
{uint8_t i;uint8_t Byte = 0x00;IIC_W_SDA(1);for(i = 0;i < 8;i++){IIC_W_SCL(1);if(IIC_R_SDA()){Byte |= (0x80 >> i);}IIC_W_SCL(0);}return Byte;
}uint8_t IIC_ReceiveAck(void)
{uint8_t Ack;IIC_W_SDA(1);   //主机释放SDA,以接受从机AckIIC_W_SCL(1);Ack = IIC_R_SDA();IIC_W_SCL(0);return Ack;
}
MPU6050使用软件I2C通信
#include "stm32f10x.h"                  // Device header
#include "IIC_SOFTWARE.h"
#include "MPU6050.h"
#include "MPU6050_Regs.h"void MPU6050_WriteRegData(uint8_t RegAddr,uint8_t Data)
{IIC_Start();IIC_SendByte(MPU6050_DEVICE_ADDRESS);IIC_ReceiveAck();IIC_SendByte(RegAddr);IIC_ReceiveAck();IIC_SendByte(Data);IIC_ReceiveAck();IIC_End();
}uint8_t MPU6050_ReadRegData(uint8_t RegAddr)
{uint8_t RegData;IIC_Start();IIC_SendByte(MPU6050_DEVICE_ADDRESS);IIC_ReceiveAck();IIC_SendByte(RegAddr);IIC_ReceiveAck();IIC_Start();IIC_SendByte(MPU6050_DEVICE_ADDRESS | 0x01);IIC_ReceiveAck();RegData = IIC_ReceiveByte();IIC_SendAck(1);IIC_End();return RegData;
}uint8_t MPU6050_ReadID(void)
{return MPU6050_ReadRegData(MPU6050_WHO_AM_I);
}void MPU6050_GetData(MPU6050_GYRO_TypeDef *MPU6050_GYRO_Structure,MPU6050_ACCEL_TypeDef *MPU6050_ACCEL_Structure)
{uint16_t Reg_H,Reg_L;//MPU6050_GYRO_OUTReg_H = MPU6050_ReadRegData(MPU6050_GYRO_XOUT_H);Reg_L = MPU6050_ReadRegData(MPU6050_GYRO_XOUT_L);MPU6050_GYRO_Structure->GYRO_XOUT = (Reg_H << 8) | Reg_L;Reg_H = MPU6050_ReadRegData(MPU6050_GYRO_YOUT_H);Reg_L = MPU6050_ReadRegData(MPU6050_GYRO_YOUT_L);MPU6050_GYRO_Structure->GYRO_YOUT = (Reg_H << 8) | Reg_L;Reg_H = MPU6050_ReadRegData(MPU6050_GYRO_ZOUT_H);Reg_L = MPU6050_ReadRegData(MPU6050_GYRO_ZOUT_L);MPU6050_GYRO_Structure->GYRO_ZOUT = (Reg_H << 8) | Reg_L;//MPU6050_ACCEL_OUTReg_H = MPU6050_ReadRegData(MPU6050_ACCEL_XOUT_H);Reg_L = MPU6050_ReadRegData(MPU6050_ACCEL_XOUT_H);MPU6050_ACCEL_Structure->ACCEL_XOUT = (Reg_H << 8) | Reg_L;Reg_H = MPU6050_ReadRegData(MPU6050_ACCEL_YOUT_H);Reg_L = MPU6050_ReadRegData(MPU6050_ACCEL_YOUT_H);MPU6050_ACCEL_Structure->ACCEL_YOUT = (Reg_H << 8) | Reg_L;Reg_H = MPU6050_ReadRegData(MPU6050_ACCEL_ZOUT_H);Reg_L = MPU6050_ReadRegData(MPU6050_ACCEL_ZOUT_H);MPU6050_ACCEL_Structure->ACCEL_ZOUT = (Reg_H << 8) | Reg_L;
}
void MPU6050_MeasureData(MPU6050_GYRO_TypeDef *MPU6050_GYRO_Structure,MPU6050_ACCEL_TypeDef *MPU6050_ACCEL_Structure,MPU6050_Measure_TypeDef *MPU6050_Measure_Structure)
{MPU6050_Measure_Structure->Gx = ((float)MPU6050_GYRO_Structure->GYRO_XOUT)/32768.0*2000.0;MPU6050_Measure_Structure->Gy = ((float)MPU6050_GYRO_Structure->GYRO_YOUT)/32768.0*2000.0;MPU6050_Measure_Structure->Gz = ((float)MPU6050_GYRO_Structure->GYRO_ZOUT)/32768.0*2000.0;MPU6050_Measure_Structure->Ax = ((float)MPU6050_ACCEL_Structure->ACCEL_XOUT)/32768.0*16.0;MPU6050_Measure_Structure->Ay = ((float)MPU6050_ACCEL_Structure->ACCEL_YOUT)/32768.0*16.0;MPU6050_Measure_Structure->Az = ((float)MPU6050_ACCEL_Structure->ACCEL_ZOUT)/32768.0*16.0;
}void MPU6050_Init(void)
{IIC_Init();MPU6050_WriteRegData(MPU6050_PWR_MGMT_1,0x00);MPU6050_WriteRegData(MPU6050_PWR_MGMT_2,0x00);MPU6050_WriteRegData(MPU6050_SMPRT_DIV,0x00);MPU6050_WriteRegData(MPU6050_CONFIG,0x06);MPU6050_WriteRegData(MPU6050_GYRO_CONFIG,0x18);MPU6050_WriteRegData(MPU6050_ACCEL_CONFIG,0x18);
}float MPU6050_Abs(float num)
{return num < 0 ? -num:num;
}
I2C外设简介
  • STM32内部集成了硬件I2C收发电路,可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能,减轻CPU的负担
  • 支持多主机模型
  • 支持7位/10位地址模式
  • 支持不同的通讯速度,标准速度(高达100 kHz),快速(高达400 kHz)
  • 支持DMA
  • 兼容SMBus协议
  • STM32F103C8T6 硬件I2C资源:I2C1、I2C2

I2C外设基本结构

I2C主机发送数据

I2C主机接收数据

MPU6050使用I2C外设通信
#include "stm32f10x.h"                  // Device header
#include "MPU6050.h"
#include "MPU6050_Regs.h"#define IIC_PORT GPIOB
#define IIC_SCL GPIO_Pin_10
#define IIC_SDA GPIO_Pin_11void MPU6050_WriteRegData(uint8_t RegAddr,uint8_t Data)
{
//    IIC_Start();
//    IIC_SendByte(MPU6050_DEVICE_ADDRESS);
//    IIC_ReceiveAck();
//    IIC_SendByte(RegAddr);
//    IIC_ReceiveAck();
//    IIC_SendByte(Data);
//    IIC_ReceiveAck();
//    IIC_End();I2C_GenerateSTART(I2C2,ENABLE);while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);I2C_Send7bitAddress(I2C2,MPU6050_DEVICE_ADDRESS,I2C_Direction_Transmitter);while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);I2C_SendData(I2C2,RegAddr);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_ReadRegData(uint8_t RegAddr)
{uint8_t RegData;//    IIC_Start();
//    IIC_SendByte(MPU6050_DEVICE_ADDRESS);
//    IIC_ReceiveAck();
//    IIC_SendByte(RegAddr);
//    IIC_ReceiveAck();
//    
//    IIC_Start();
//    IIC_SendByte(MPU6050_DEVICE_ADDRESS | 0x01);
//    IIC_ReceiveAck();
//    RegData = IIC_ReceiveByte();
//    IIC_SendAck(1);
//    IIC_End();I2C_GenerateSTART(I2C2,ENABLE);while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);I2C_Send7bitAddress(I2C2,MPU6050_DEVICE_ADDRESS,I2C_Direction_Transmitter);while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);I2C_SendData(I2C2,RegAddr);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_DEVICE_ADDRESS,I2C_Direction_Receiver);while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS);I2C_AcknowledgeConfig(I2C2,DISABLE);I2C_GenerateSTOP(I2C2,ENABLE);while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS);RegData = I2C_ReceiveData(I2C2);I2C_AcknowledgeConfig(I2C2,ENABLE);return RegData;
}uint8_t MPU6050_ReadID(void)
{return MPU6050_ReadRegData(MPU6050_WHO_AM_I);
}void MPU6050_GetData(MPU6050_GYRO_TypeDef *MPU6050_GYRO_Structure,MPU6050_ACCEL_TypeDef *MPU6050_ACCEL_Structure)
{uint16_t Reg_H,Reg_L;//MPU6050_GYRO_OUTReg_H = MPU6050_ReadRegData(MPU6050_GYRO_XOUT_H);Reg_L = MPU6050_ReadRegData(MPU6050_GYRO_XOUT_L);MPU6050_GYRO_Structure->GYRO_XOUT = (Reg_H << 8) | Reg_L;Reg_H = MPU6050_ReadRegData(MPU6050_GYRO_YOUT_H);Reg_L = MPU6050_ReadRegData(MPU6050_GYRO_YOUT_L);MPU6050_GYRO_Structure->GYRO_YOUT = (Reg_H << 8) | Reg_L;Reg_H = MPU6050_ReadRegData(MPU6050_GYRO_ZOUT_H);Reg_L = MPU6050_ReadRegData(MPU6050_GYRO_ZOUT_L);MPU6050_GYRO_Structure->GYRO_ZOUT = (Reg_H << 8) | Reg_L;//MPU6050_ACCEL_OUTReg_H = MPU6050_ReadRegData(MPU6050_ACCEL_XOUT_H);Reg_L = MPU6050_ReadRegData(MPU6050_ACCEL_XOUT_H);MPU6050_ACCEL_Structure->ACCEL_XOUT = (Reg_H << 8) | Reg_L;Reg_H = MPU6050_ReadRegData(MPU6050_ACCEL_YOUT_H);Reg_L = MPU6050_ReadRegData(MPU6050_ACCEL_YOUT_H);MPU6050_ACCEL_Structure->ACCEL_YOUT = (Reg_H << 8) | Reg_L;Reg_H = MPU6050_ReadRegData(MPU6050_ACCEL_ZOUT_H);Reg_L = MPU6050_ReadRegData(MPU6050_ACCEL_ZOUT_H);MPU6050_ACCEL_Structure->ACCEL_ZOUT = (Reg_H << 8) | Reg_L;
}
void MPU6050_MeasureData(MPU6050_GYRO_TypeDef *MPU6050_GYRO_Structure,MPU6050_ACCEL_TypeDef *MPU6050_ACCEL_Structure,MPU6050_Measure_TypeDef *MPU6050_Measure_Structure)
{MPU6050_Measure_Structure->Gx = ((float)MPU6050_GYRO_Structure->GYRO_XOUT)/32768.0*2000.0;MPU6050_Measure_Structure->Gy = ((float)MPU6050_GYRO_Structure->GYRO_YOUT)/32768.0*2000.0;MPU6050_Measure_Structure->Gz = ((float)MPU6050_GYRO_Structure->GYRO_ZOUT)/32768.0*2000.0;MPU6050_Measure_Structure->Ax = ((float)MPU6050_ACCEL_Structure->ACCEL_XOUT)/32768.0*16.0;MPU6050_Measure_Structure->Ay = ((float)MPU6050_ACCEL_Structure->ACCEL_YOUT)/32768.0*16.0;MPU6050_Measure_Structure->Az = ((float)MPU6050_ACCEL_Structure->ACCEL_ZOUT)/32768.0*16.0;
}void MPU6050_Init(void)
{
//    IIC_Init();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 = IIC_SCL | IIC_SDA;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStructure);I2C_InitTypeDef I2C_InitStructure;I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;I2C_InitStructure.I2C_ClockSpeed = 50000;I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;I2C_InitStructure.I2C_OwnAddress1 = 0x00;I2C_Init(I2C2,&I2C_InitStructure);I2C_Cmd(I2C2,ENABLE);MPU6050_WriteRegData(MPU6050_PWR_MGMT_1,0x00);MPU6050_WriteRegData(MPU6050_PWR_MGMT_2,0x00);MPU6050_WriteRegData(MPU6050_SMPRT_DIV,0x00);MPU6050_WriteRegData(MPU6050_CONFIG,0x06);MPU6050_WriteRegData(MPU6050_GYRO_CONFIG,0x18);MPU6050_WriteRegData(MPU6050_ACCEL_CONFIG,0x18);
}float MPU6050_Abs(float num)
{return num < 0 ? -num:num;
}

I2C通信只需要SDA和SCL两根通信线,节省IO口,一般常用软件实现。

这篇关于STM32标准库学习笔记-11.I2C通信的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1090543

相关文章

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

RabbitMQ工作模式中的RPC通信模式详解

《RabbitMQ工作模式中的RPC通信模式详解》在RabbitMQ中,RPC模式通过消息队列实现远程调用功能,这篇文章给大家介绍RabbitMQ工作模式之RPC通信模式,感兴趣的朋友一起看看吧... 目录RPC通信模式概述工作流程代码案例引入依赖常量类编写客户端代码编写服务端代码RPC通信模式概述在R

在Spring Boot中实现HTTPS加密通信及常见问题排查

《在SpringBoot中实现HTTPS加密通信及常见问题排查》HTTPS是HTTP的安全版本,通过SSL/TLS协议为通讯提供加密、身份验证和数据完整性保护,下面通过本文给大家介绍在SpringB... 目录一、HTTPS核心原理1.加密流程概述2.加密技术组合二、证书体系详解1、证书类型对比2. 证书获

go rate 原生标准限速库的使用

《gorate原生标准限速库的使用》本文主要介绍了Go标准库golang.org/x/time/rate实现限流,采用令牌桶算法控制请求速率,提供Allow/Reserve/Wait方法,具有一定... 目录介绍安装API介绍rate.NewLimiter:创建限流器limiter.Allow():请求是否

Python模拟串口通信的示例详解

《Python模拟串口通信的示例详解》pySerial是Python中用于操作串口的第三方模块,它支持Windows、Linux、OSX、BSD等多个平台,下面我们就来看看Python如何使用pySe... 目录1.win 下载虚www.chinasem.cn拟串口2、确定串口号3、配置串口4、串口通信示例5

基于C#实现MQTT通信实战

《基于C#实现MQTT通信实战》MQTT消息队列遥测传输,在物联网领域应用的很广泛,它是基于Publish/Subscribe模式,具有简单易用,支持QoS,传输效率高的特点,下面我们就来看看C#实现... 目录1、连接主机2、订阅消息3、发布消息MQTT(Message Queueing Telemetr

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析