STM32 IIC详解

2023-05-16

目录

1、IIC定义

2、IIC协议规范

2.1 SDA和SCL信号

2.2 数据有效性​

2.3 开始和结束信号​

2.4 字节格式

2.5 从机地址和读写位​

3、计算IIC的频率

4、PCF8536

4.1 Acknowledge

4.2 Addressing

4.3 读写时序


1、IIC定义

IIC 即Inter-Integrated Circuit(集成电路总线),这种总线类型是由飞利浦半导体公司(后被NXP收购)在八十年代初设计出来的一种简单、双向、二线制、同步串行总线,主要是用来连接整体电路(ICS) ,IIC是一种多向控制总线,也就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实时数据传输的控制源。多主多从的通讯协议。

下文将结合NXP官方的IIC手册讲解IIC协议。下载链接见文末。

I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。速率最高400Kbit/s。

在1998年的修订中增加了高速模式,速率高达3.4Mbit/s。(这里不讲,只说快速模式)。

2、IIC协议规范

2.1 SDA和SCL信号

连接到总线的器件输出级必须是漏极开路或集电极开路才能执行线与的功能,当总线空

闲时这两条线路都是高电平。SDA 和SCL 都是双向线路都通过一个电流源或上拉电阻连接到正的电源电压。一般情况下我们都采用上拉电阻的方式

2.2 数据有效性

在SCL高电平的时候采样,也就是有效。低电平的时候切换数据

2.3 开始和结束信号

起始条件:SCL线是高电平时,SDA线从高电平向低电平切换。

停止条件:SCL线是高电平时,SDA线从低电平向高电平切换。

动画展示启动信号

代码实现

void I2C_Start(void)
{
  //IO输出
  SDA_OUT(); 
  SCL_OUT(); 
  I2C_DELAY();
  //IO置高
  SDA_SET();  
  SCL_SET(); 
  //延时
  I2C_DELAY();  
  //为低
  SDA_CLR();
  I2C_DELAY();
  I2C_DELAY();
  SCL_CLR();
}

结束信号时类似的方式(不是动图)

代码实现

void I2C_Stop(void)
{
  //IO输出
  SDA_OUT(); 
  SCL_OUT();
  //IO置0
  SDA_CLR();  
  SCL_CLR(); 
  I2C_DELAY();
  SCL_SET();
  //延时
  I2C_DELAY();  
  I2C_DELAY();
  I2C_DELAY();
  //SDA置1
  SDA_SET();
  I2C_DELAY();
  I2C_DELAY();
}

2.4 字节格式

SDA数据线上的每个字节必须是8位,每次传输的字节数量没有限制。每个字节后必须跟一个响应位(ACK)。首先传输的数据是最高位(MSB),SDA上的数据必须在SCL高电平周期时保持稳定,数据的高低电平翻转变化发生在SCL低电平时期。

每一个字节后面跟着一个ACK,有ACK就可以继续写或读。NACK,就停止

ACK:主机释放总线,传输完字节最后1位后的SCL的高电处,从机拉低电平。

NACK:主机释放总线,传输完字节最后1位后的SCL的高电处,从机无响应,总线为高电平。

动画描述写入的过程

代码实现

uint8_t I2C_Send_byte(uint8_t data)
{
  uint8_t k;
  //发送8bit数据
  for(k=0;k<8;k++){
    
    I2C_DELAY();
    if(data&0x80){
      SDA_SET();
    }
    else{
      SDA_CLR();
    }
    data=data<<1;
    I2C_DELAY();
    SCL_SET();
    I2C_DELAY();
    I2C_DELAY();
    SCL_CLR();
  }
  //延时读取ACK响应
  I2C_DELAY();
  SDA_SET();
  //置为输入线
  SDA_IN();
  I2C_DELAY();
  SCL_SET();   
  I2C_DELAY(); //这里出现了问题,延时变的无限大
  //读数据
  k=SDA_READ();
  if(k){ NACK响应
    return 0;
  }
  I2C_DELAY();
  SCL_CLR();
  I2C_DELAY();
  SDA_OUT();
  if(k){ NACK响应
    return 0;
  }
  return 1;
}

uint8_t I2C_Receive_byte(uint8_t flg)
{
  uint8_t k,data;
  //接收8bit数据
  //置为输入线
  
  SDA_IN();
  data=0;
  for(k=0;k<8;k++){
    I2C_DELAY();
    SCL_SET();
    I2C_DELAY();
    //读数据
    data=data |SDA_READ();
    data=data<<1;
    I2C_DELAY();
    SCL_CLR();
    I2C_DELAY(); 
  }
  data=data>>1; //往回移动1次
  //返回ACK响应
  //置为输出线
  SDA_OUT();
  if(flg){
    SDA_SET(); //输出1-NACK
  }else{
    SDA_CLR();//输出0-ACK
  }
  I2C_DELAY();
  SCL_SET();
  I2C_DELAY();
  I2C_DELAY();
  SCL_CLR();
  I2C_DELAY();
  SDA_OUT();
  //返回读取的数据
  return (uint8_t)data;
}

2.5 从机地址和读写位

开始信号—>地址—>读写位—>ACK—>数据—>ACK.............—>停止位

这里只说7位地址,前7位为地址,最后一位为读写位,1表示读操作,0表示写操作

主机发给从机数据,也就是写,没有数据转向时

主机立即读从机数据,从第一个字节

(Combined)综合数据格式

3、计算IIC的频率

通信频率由主机掌控,也就是代码中的延时函数决定的

从上面,我们得知最高速为400Kbit/s。我们设计300Kbit/s。

速率300Kbit/s,对应周期1/300ms=10/3us≈3us,4分频就是3/4us。

我们使用的延时是,1/120MHZ*3*30 =3/4us

也就是频率是300Kbit/s

和SPI类似,时钟下降沿时,数据转换,时钟上升沿时,采样数据。也就是时钟高电平数据有效。

/*120Mhz时钟时,当ulCount为1时,函数耗时3个时钟,延时=3*1/120us=1/40us*/
/*
SystemCoreClock=120000000

us级延时,延时n微秒
SysCtlDelay(n*(SystemCoreClock/3000000));

ms级延时,延时n毫秒
SysCtlDelay(n*(SystemCoreClock/3000));

m级延时,延时n秒
SysCtlDelay(n*(SystemCoreClock/3));
*/

#if defined   (__CC_ARM) /*!< ARM Compiler */
__asm void
SysCtlDelay(unsigned long ulCount)
{
    subs    r0, #1;
    bne     SysCtlDelay;
    bx      lr;
}
#elif defined ( __ICCARM__ ) /*!< IAR Compiler */
void
SysCtlDelay(unsigned long ulCount)
{
    __asm("    subs    r0, #1\n"
       "    bne.n   SysCtlDelay\n"
       "    bx      lr");
}

#elif defined (__GNUC__) /*!< GNU Compiler */
void __attribute__((naked))
SysCtlDelay(unsigned long ulCount)
{
    __asm("    subs    r0, #1\n"
       "    bne     SysCtlDelay\n"
       "    bx      lr");
}

#elif defined  (__TASKING__) /*!< TASKING Compiler */                           
/*无*/
#endif /* __CC_ARM */


/*
 * @brief  SysCtlDelay
 * @param  ulCount 延时值,必须大于0
 * @retval None
 */
void SysCtlDelay_IIC(unsigned long ulCount)
{
	SysCtlDelay(ulCount);
}


/定义时钟频率,300KHz
#define I2C_DELAY()  SysCtlDelay_IIC(30)

4、PCF8536

4.1 Acknowledge

这个地方能看到关于2.4节关于ACK和NACk的说明

4.2 Addressing

这里直接给出读地址和写地址,也就是最后一位的区别

4.3 读写时序

其实就是按照IIC协议的

读指定器件的指定寄存器

主机设置完寄存器地址之后,再去读写

注意:读取多个字节,最后一个字节的回包应该是NACK

主机立即从机第一个字节读取

注意:读取多个字节,最后一个字节的回包应该是NACK

开源地址:

https://github.com/strongercjd/STM32F207VCT6

点击查看本文所在的专辑,STM32F207教程

资料下载:

百度网盘-链接不存在   提取码:cwsx

如果链接失效,请关注微信公众号,找到下载专区->博客附件,编号0012的下载资源,免费获得。

12

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32 IIC详解 的相关文章

随机推荐

  • Linux中使用curl命令发送带参数的get请求和post请求

    1 curl与wget 命令的区别 相似之处 xff1a wget 和 cURL 都可以下载内容 xff0c 都可以向互联网发送请求并返回请求项 xff0c 也可以进行 HTTP POST 请求 xff0c 它们都是命令行工具 xff0c
  • STM32片上Flash内存映射、页面大小、寄存器映射

    本文以STM32F103RBT6为例介绍了片上Flash Embedded Flash 若干问题 xff0c 包括Flash大小 内存映射 块大小 页面大小 寄存器 二 块大小 Flash先分块再分页 xff0c 擦除是按块进行 xff0c
  • keil 修改RAM、ROM

  • 单片机flash不足,keil如下方式进行优化

    单片机的flash不够的时候可以使用keil的优化等级进行优化 xff1b 但是使用Opt进行优化的时候会遇到难以预料的错误 xff0c 所以使用时要对一些变量进行标识 xff0c 比如使用volatile关键字 还有其他方式也能减少内存的
  • msp430看门狗定时器

    看门狗定时器用来防止程序因供电电源 空间电磁干扰或其它原因引起的强烈干扰噪声而跑飞的事故 在很多单片机中都内置了看门狗 xff0c 看门狗本身是一个定时器 xff0c 当定时器溢出时即进行系统复位 xff0c 因此需要在程序中对看门狗定时器
  • UART、SPI和IIC详解与比较(超级实用的调试经验)

    1 UART UART有4个pin xff08 VCC GND RX TX xff09 用的TTL电平 低电平为0 0V xff0c 高电平为1 xff08 3 3V或以上 xff09 UART使用的是异步串行通信 UART是两线 xff0
  • RS232、RS485和CAN协议总结与对比

    一 RS232串口是计算机上一种非常通用的设备通信协议 串口的电气特性 xff1a 1 RS 232串口通信最远距离是50英尺 xff1b 2 RS232可做到双向传输 xff0c 全双工通讯 xff0c 最高传输速率20kbps xff1
  • STM32 GPIOx_CRL/GPIOx_CRH 寄存器

    GPIOx CRL GPIOx CRH xff08 x xff1a A F xff09 寄存器用来对GPIO进行端口设置 xff0c 如 xff1a 设置GPIO为输入模式或输出模式 每个寄存器含有32位 xff0c 每4位用来设置1个GP
  • SHT10 温湿度传感器的程序以及调试总结

    没有其他东西 直接上调试注意事项和代码 xff01 xff01 调试要点 xff1a 1 DATA加10K上拉电阻 2 注意示波器观察各个信号 基础要点 xff1a 1 串行时钟输入 xff08 SCK xff09 单片机模拟时钟 2 串行
  • 晶振原理解析

    目录 01 压电效应 02 晶体振荡器的应用 03 无源晶振和有源晶振的区别 04 STM32外接晶振 下文将进一步讲解晶振的原理 xff0c 以及晶振和STM32的关系 01 压电效应 压电效应 xff1a 某些电介质在沿一定方向上受到外
  • 字符串大小的比较

    字符串大小比较的步骤 xff1a 从左至右一位一位比较 xff0c 如果相同 xff0c 则继续下一位 xff0c 如果不同 xff0c 则谁的ASCII大谁的字符串就大如果比较到其中一者已经结束了 xff0c 还没有分出大小 xff0c
  • STM32延时函数的四种方法

    目录 1 普通延时 2 定时器中断 3 查询定时器 4 汇编指令 单片机编程过程中经常用到延时函数 xff0c 最常用的莫过于微秒级延时delay us 和毫秒级delay ms 本文基于STM32F207介绍4种不同方式实现的延时函数 1
  • STM32的FSMC外设简介

    目录 01 FSMC特点 02 AHB接口 03 外部设备地址映射 04 NOR PSRAM控制器 05 外部存储器接口信号 06 NOR PSRAM控制器异步事务 07 模式1 08 模式A 09 代码说明 01 FSMC特点 Flexi
  • STM32使用DMA接收串口数据

    目录 01 概述 02 DMA接收 03 中断 04 代码 01 概述 在之前的文章里 STM32串口详解 和 STM32 DMA详解 文章中 xff0c 详细讲解了STM32的串口和DMA外设 xff0c 本篇文章将不在细述串口和DMA的
  • 指针与数组

    1 定义 指针 xff1a C语言中某种数据类型的数据存储的内存地址 xff0c 例如 xff1a 指向各种整型的指针或者指向某个结构体的指针 数组 xff1a 若干个相同C语言数据类型的元素在连续内存中储存的一种形态 数组在编译时就已经被
  • 关于软件定时器的一些讨论

    1 简介 这里先介绍下软件定时器和硬件定时器的区别 硬件定时器 xff1a CPU内部自带的定时器模块 xff0c 通过初始化 配置可以实现定时 xff0c 定时时间到以后就会执行相应的定时器中断处理函数 硬件定时器一般都带有其它功能 xf
  • 表驱动法在STM32中的应用

    1 概念 所谓表驱动法 Table Driven Approach 简而言之就是用查表的方法获取数据 此处的 表 通常为数组 xff0c 但可视为数据库的一种体现 根据字典中的部首检字表查找读音未知的汉字就是典型的表驱动法 xff0c 即以
  • 关于共享资源保护的思考

    1 引言 先聊聊分享这篇文章的原因 xff0c 在使用STM32时 xff0c 我发现对于GPIO输出操作 xff0c 可以使用GPIOx ODR寄存器 xff0c 也可以使用GPIOx BSRR寄存器 对应的标准外设库API接口有 voi
  • 预编译#error的使用

    1 引言 说到预编译 xff0c 大家立刻就能想到 define if ifdef和 ifndef等熟悉的预编译命令 其实 include xff0c 我们通常放在源文件用来包含头文件 xff0c 它也是预编译命令 当然这不是这篇文章的重点
  • STM32 IIC详解

    目录 1 IIC定义 2 IIC协议规范 2 1 SDA和SCL信号 2 2 数据有效性 2 3 开始和结束信号 2 4 字节格式 2 5 从机地址和读写位 3 计算IIC的频率 4 PCF8536 4 1 Acknowledge 4 2