STM32的I2C通讯配置(硬件实现)——学习笔记(6-2)

发布者:数据旅人最新更新时间:2021-10-14 来源: eefocus关键字:STM32  I2C通讯  配置 手机看文章 扫描二维码
随时随地手机看文章

文章内容根据野火学习教程进行整理,仅仅是学习记录。


开发板: 野火STM32F429-挑战者V2

官方固件库版本: STM32F4xx_DSP_StdPeriph_Lib_V1.8.0


这里以与EEPROM进行通讯的代码作为例子。


一、看电路图

1、要得知那些信息

从电路图上主要是要知道3点关键信息


I2C设备挂载在I2C1、I2C2、I2C3的哪一个总线上

SDA、SCL接的是哪两个GPIO

I2C设备地址(有的是可以选择的,比如这个EEPROM)

2、挂在哪个I2C总线以及哪个GPIO

从电路图上可以看出:


挂载在I2C1上的

SDA接的是PB7引脚

SCL接的是PB6引脚

这个一般硬件工程师都会在电路图上标出来吧。


另外如果只标出了使用的GPIO引脚,也可以通过 《STM32F4xx中文数据手册》 查找相关GPIO的复用得知所挂的I2C总线。

在这里插入图片描述

3、I2C设备地址

查看EPPROM的参考手册可以得知设备地址是由1010 A2A1A0一共位组合而成,而从电路图可以得知A2=0、A1=0、A0=0,所以最终的I2C地址位101 0000(0x50)。

其实在I2C总线上只要设备地址是唯一的就可以了。

在这里插入图片描述

二、开始编码

由于是使用I2C对EEPROM进行读写,所以编码主要是分为I2C配置和对EEPROM读写两个部分。


1、I2C配置

(1)宏定义声明

根据电路连接情况就可以知道GPIO引脚以及哪个I2C总线啦。


#define I2C1_OwnAddress                         0X0A                           /* STM32的I2C1设备自身地址,自定义,与其他I2C设备地址不同即可 */

#define I2C1_Speed                              400000                         /* I2C1设备速率400KHz */

#define I2C1_GPIO_PORT                          GPIOB                          /* I2C1所接GPIO的端口 */

#define I2C1_SCL_PIN                            GPIO_Pin_6                     /* I2C1的SCL所接的GPIO引脚 */

#define I2C1_SDA_PIN                            GPIO_Pin_7                     /* I2C1的SDA所接的GPIO引脚 */

#define I2C1_SCL_SOURCE                         GPIO_PinSource6                /* I2C1的SCL所接的GPIO引脚序号 */

#define I2C1_SDA_SOURCE                         GPIO_PinSource7                /* I2C1的SDA所接的GPIO引脚序号 */

#define I2C1_GPIO_AF                            GPIO_AF_I2C1                   /* I2C1的SDA、SCL的GPIO引脚复用功能 */


I2C速率:有三种,标准模式(100kbit/s)、快速模式(400kbit/s)、Hs模式(3.4Mbit/s)。我自己试了一下速率过低是会有问题的,过高似乎没有什么问题,一般就填400K好了。

(2)使能GPIO和I2C总线时钟

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);                      /* 初始化GPIO端口时钟 */


RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);                       /* 初始化I2C1的外围时钟 */


不管是使用GPIO还是I2C,相应的总线时钟都是要使能的。


(3)初始化GPIO

/**************************************************************************************************

**  函数名称:  gpio_cfg

**  功能描述:  I2C的GPIO配置

**  输入参数:  无

**  输出参数:  无

**  返回参数:  无

**************************************************************************************************/

static void gpio_cfg(void)

{

    GPIO_InitTypeDef GPIO_def;

    

    GPIO_def.GPIO_Pin = I2C1_SCL_PIN | I2C1_SDA_PIN;                           /* 要配置的GPIO的PIN脚 */

    GPIO_def.GPIO_Mode = GPIO_Mode_AF;                                         /* 要配置的GPIO模式(复用) */

    GPIO_def.GPIO_Speed = GPIO_Speed_50MHz;                                    /* 要配置的GPIO速率(50MHz) */

    GPIO_def.GPIO_OType = GPIO_OType_OD;                                       /* 输出类型(开漏) */

    GPIO_def.GPIO_PuPd = GPIO_PuPd_UP;                                         /* 引脚默认状态(上拉) */

    

    GPIO_Init(I2C1_GPIO_PORT, &GPIO_def);

    

    GPIO_PinAFConfig(I2C1_GPIO_PORT, I2C1_SCL_SOURCE, I2C1_GPIO_AF);           /* 配置复用类型 */

    GPIO_PinAFConfig(I2C1_GPIO_PORT, I2C1_SDA_SOURCE, I2C1_GPIO_AF);           /* 配置复用类型 */

}


GPIO类型必须配置成 开漏输出 ,因为这样I2C设备才能输出 低电平 和 高阻态。因为 SCL 和 SDA 连接上拉电阻到电源,那么GPIO输出低电平则拉低,输出高阻态则拉高。高阻态可类似看为开路。


(4)初始化I2C

/**************************************************************************************************

**  函数名称:  i2c_cfg

**  功能描述:  I2C配置

**  输入参数:  无

**  输出参数:  无

**  返回参数:  无

**************************************************************************************************/

static void i2c_cfg(void)

{

  I2C_InitTypeDef  I2C_def;

  

  I2C_def.I2C_Mode = I2C_Mode_I2C;                                             /* I2C模式选择 */

  I2C_def.I2C_DutyCycle = I2C_DutyCycle_2;                                     /* 低电平时间:高电平时间 = 2:1 */

  I2C_def.I2C_OwnAddress1 = I2C1_OwnAddress;                                   /* I2C设备地址 */

  I2C_def.I2C_Ack = I2C_Ack_Enable;                                            /* 使能应答 */

  I2C_def.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;              /* I2C的寻址模式 */

  I2C_def.I2C_ClockSpeed = I2C1_Speed;                                         /* 通信速率 */

  I2C_Init(I2C1, &I2C_def);                                                    /* I2C初始化 */

  

  I2C_Cmd(I2C1, ENABLE);                                                       /* 使能I2C */

  I2C_AcknowledgeConfig(I2C1, ENABLE);                                         /* 使能指定I2C总线的应答功能 */

}


SCL占空比:当I2C设置为快速模式时,可以配置SCL的占空比,有两个选项。一:I2C_DutyCycle_2(低电平:高电平=2:1),二:I2C_DutyCycle_16_9(低电平:高电平=16:9)。其实配哪个好像没啥区别。

I2C设备自身地址位数:有两种选择,可以选7位的也可以选10位的。其实都可以用,不过一般情况下是配置7个位的。

I2C设备自身地址:只要与I2C总线上其他设备的地址不同即可。前7位或10位有效,根据配置。

2、对EEPROM进行读写

(1)宏定义声明

#define EE_I2C                                  I2C1                           /* 所挂载的I2C总线 */


#define EE_I2C_ADDR                             0XA0                           /* EEPROM的I2C设备地址 1010000(0x50), (0x50 << 1)*/


#define EE_SHORT_TIMEOUT                        0x1000                         /* I2C检测短等待超时时间 */

#define EE_LONG_TIMEOUT                         0xA000                         /* I2C检测长等待超时时间 */

#define EE_WAIT_TIMES                           300                            /* I2C检测设备状态最大次数 */


#define TEST_ADDR                               0x30                           /* 要写入数据的EEPROM地址 */

#define TEST_DATA                               0x55                           /* 要写入的数据 */


设备地址:由上面分析的结果可以的得知设备地址为101 0000(0x50),那么由于最后一位为读写位,所以需要左移1位,最终的到1010 0000(0XA0)。

(2)检测I2C事件的封装函数

在I2C通讯中根据协议会需要检测EV5、EV6、EV7、EV8、EV9等事件。

我自己把检测I2C事件函数封装了一下,加入了超时跳出的机制,方便调用。


/**************************************************************************************************

**  函数名称:  i2c_check_event

**  功能描述:  检测I2C设备的事件

**  输入参数:  无

**  输出参数:  无

**  返回参数:  检测成功返回0,失败返回-1

**************************************************************************************************/

static s32 i2c_check_event(u32 i2c_event)

{

    __IO u32 timeout;


    timeout = EE_SHORT_TIMEOUT;

    while(SUCCESS != I2C_CheckEvent(EE_I2C, i2c_event)) {

        timeout--;

        if (timeout == 0) {

            return -1;

        }

    }

    

    return 0;

}


(3)检测I2C寄存器标志位封装函数

在I2C通讯中会有需要检测寄存器标志位状态的时候。

我把检测标志位的函数封装了一下,加入了期望值匹配状态以及超时机制,也是为了方便使用。


/**************************************************************************************************

[1] [2] [3]
关键字:STM32  I2C通讯  配置 引用地址:STM32的I2C通讯配置(硬件实现)——学习笔记(6-2)

上一篇:STM32-IIC通信(基于AT24C02的软件IIC通信)
下一篇:STM32之IIC通讯升级版--SHT30温湿度读取

推荐阅读最新更新时间:2024-11-17 11:33

STM32单片机ISP下载的方法解析
STM32支持仿真器和串口下载程序。将要介绍的内容,属于串口下载,即我们通常说的ISP下载。 手动ISP下载程序,我们已经知道了,控制BOOT0引脚实现。STM32上电,会自动检测BOOT0引脚是什么电平,如果是高电平,等待用户下载程序;如果是低电平,运行用户之前下载到单片机的程序。所以我们需要把BOOT0引脚引出,然后控制其接地或接VCC来下载程序或者运行程序。在调试过程中,我们需要不断的控制BOOT0,非常麻烦。那么,自动ISP就该出场了。 自动ISP,把BOOT0与地直接连接,那么每次上电就会运行程序,而且只要点击电脑上的“下载”按钮,就开始下载程序,下载完程序,就开始执行。实现此目的,需要借助串口握手信号DTR和R
[单片机]
<font color='red'>STM32</font>单片机ISP下载的方法解析
stm32 pwm 呼吸灯
#include main.h #include stm32f0xx_hal.h /* USER CODE BEGIN Includes */ int i=0; /* USER CODE END Includes */ /* Private variables ---------------------------------------------------------*/ TIM_HandleTypeDef htim3; UART_HandleTypeDef huart1; /* USER CODE BEGIN PV */ /* Private variables --------------------
[单片机]
<font color='red'>stm32</font> pwm 呼吸灯
STM32的SPI采用DMA方式传输测试
环境: 主机:WIN7 开发环境:MDK4.23 MCU:STM32F103CBT6 说明: 参考链接: http://www.openedv.com/posts/list/3159.htm SPI传输数据分为连续传输和非连续传输. 连续传输时序图: 非连续传输时序图: 非连续传输模式可以参考上篇文章: http://blog.csdn.net/jdh99/article/details/7598573 官方pdf关于连续和非连续传输的说明: 当在主模式下发送数据时,如果软件足够快,能够在检测到每次TXE的上升沿(或TXE中断),并立即在正在进行的传输结束之前写入SPI_DR寄存器,则能够实现连续的通信;此时,
[单片机]
如何设计基于stm32的数字示波器
随着集成电路的发展和数字信号处理技术的采用,数字示波器已成为集显示、测量、运算、分析、记录等各种功能于一体的智能化测量仪器。数字示波器在性能上也逐渐超越模拟示波器,并有取而代之的趋势。与模拟示波器相比,数字示波器不仅具有可存储波形、体积小、功耗低,使用方便等优点,而且还具有强大的信号实时处理分析功能。因此,数字示波器的使用越来越广泛。目前我国国内自主研发的高性能数字示波器还是比较少,广泛使用的仍是国外产品。因此,有必要对高性能数字示波器进行广泛和深入研究。 本文通过采用高速高性能器件,设计了一实时采样率为60 msa/s的宽带数字示波器。 1 数字示波器的性能参数设计 数字存储示波器的指标很多,包括采样率、带宽、灵敏度、通
[测试测量]
如何设计基于<font color='red'>stm32</font>的数字示波器
深度解读STM32数据保存与毁灭
一、认识ADC兼进一步看懂STM的库 ADC是多少位的? 12位 ADC有多少个? 1个、2个或多至3个,视不同的器件而不同;每个又有多个通道。 关于通道的名堂: 10.3.3 通道选择 有16个多路通道。可以把转换分成两组:规则的和注入的。在任意多个通道上以任意顺序进行的一系列转换构成成组转换。例如,可以如下顺序完成转换:通道3、通道8、通道2、通道2、通道0、通道2、通道2、通道15。 ● 规则组由多达16个转换组成。规则通道和它们的转换顺序在ADC_SQRx寄存器中选择。规则组中转换的总数写入ADC_SQR1寄存器的L[3:0]位中。 ● 注入组由多达4个转换组成。注入通道和它们的转换顺序在ADC_JSQR寄存器中选择。注入
[单片机]
STM32时钟配置及相关问题
Ⅰ、写在前面 最近有很多朋友问: 1.我的USART串口打印出来的数据是乱码? 2.我的TIM定时器延时或定时不准确? 常见可能原因: 1.晶振问题:外部晶振不起振、或频率与配置不匹配。 2.软件问题:分频、倍频、时钟源选择等。 总结来说,主要还在于软件的问题。因为即使没有外部晶振,也可以使用内部晶振。 其实,软件的问题是容易得到解决的,只要你了解了STM32时钟配置里面具体内容就知道了。 关于本文的详细内容请看下面章节 Ⅱ、本文要点 要了解时钟的配置,就需要知道它在哪里配置,也就是还需要了解软件执行的流程。 1.软件流程 说软件流程是让大家知道系统时钟配置的位置。不管是使用寄存器开发,还是使用库(标准库、
[单片机]
<font color='red'>STM32</font>时钟<font color='red'>配置</font>及相关问题
STM32单片机(六)-STM32F103 时钟与F407时钟
STM32f103的时钟有四个来源 高速外部时钟信号(HSE)、低速外部时钟信号(LSE)、高速内部时钟信号(HSI)和低速内部时钟信号(LSI),图中分别用蓝色的①~④标注。 ①HSE高速外部时钟:由外部4~16MHz的晶体或有源晶振提供,通常采用8MHz,ST三合一板上的也是8MHz。 ②LSI低速外部时钟:外部晶体提供,主要是给实时时钟(RTC),一般为32.768kHz。 ③HSI高速内部时钟:由内部RC振荡器产生的8MHz时钟,但不够稳定。④LSI低速内部时钟:内部RC振荡器产生的供给RTC的时钟,频率在30kHz~60kHz之间,通常约40kHz。 时钟在STM32内部最终是供给四大块,图中用红色
[单片机]
<font color='red'>STM32</font>单片机(六)-STM32F103 时钟与F407时钟
ST 最新STM32 Primer开发工具可玩Maze和Breakout
完整、独立、预编程的评估工具套件,既有充满趣味性的功能介绍,又有严肃的开发工具,可以链接到在线开发社区 中国,2007年10月15日 — 意法半导体(纽约证券交易所代码:STM)今天推出了一套价格低廉的开发工具,这款代号为STM32 Primer开发工具是一套完整的学习与娱乐相结合的趣味性应用开发工具,用于ST的STM32系列基于具有突破性的ARM Cortex-M3内核的闪存微控制器。这套工具包含一个创新的用户界面、多个游戏和向新用户介绍该系列产品的产品入门功能,以及用于高级开发和编程的Raisonance软件工具。 STM32 Primer是一个手持评估开发工具,力图通过简单和有趣的介绍,让用户了解STM32的强大功能。紧
[新品]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved