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

相关文章

Python 标准库time时间的访问和转换问题小结

《Python标准库time时间的访问和转换问题小结》time模块为Python提供了处理时间和日期的多种功能,适用于多种与时间相关的场景,包括获取当前时间、格式化时间、暂停程序执行、计算程序运行时... 目录模块介绍使用场景主要类主要函数 - time()- sleep()- localtime()- g

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

线性代数|机器学习-P36在图中找聚类

文章目录 1. 常见图结构2. 谱聚类 感觉后面几节课的内容跨越太大,需要补充太多的知识点,教授讲得内容跨越较大,一般一节课的内容是书本上的一章节内容,所以看视频比较吃力,需要先预习课本内容后才能够很好的理解教授讲解的知识点。 1. 常见图结构 假设我们有如下图结构: Adjacency Matrix:行和列表示的是节点的位置,A[i,j]表示的第 i 个节点和第 j 个