STM32 IIC详解

发布者:ikfnpo最新更新时间:2020-12-29 来源: eefocus关键字:STM32  IIC  集成电路总线 手机看文章 扫描二维码
随时随地手机看文章

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, #1n"

       "    bne.n   SysCtlDelayn"

       "    bx      lr");

}

 

#elif defined (__GNUC__) /*!< GNU Compiler */

void __attribute__((naked))

SysCtlDelay(unsigned long ulCount)

{

    __asm("    subs    r0, #1n"

       "    bne     SysCtlDelayn"

       "    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

关键字:STM32  IIC  集成电路总线 引用地址:STM32 IIC详解

上一篇:TQ210_裸机编程(二)——按键控制LED灯
下一篇:STM32 SPI详解

推荐阅读最新更新时间:2024-11-10 16:09

STM32 编译结果 map 之 code、RO-data、RW-data、ZI-data 字段解析
1、Code 即代码域,它指的是编译器生成的机器指令,这些内容被存储到ROM区。 2、RO-data Read Only data,即只读数据域,它指程序中用到的只读数据,这些数据被存储在ROM区,因而程序不能修改其内容。 例如: C语言中const关键字定义的变量就是典型的RO-data。 3、RW-data Read Write data,即可读写数据域,它指初始化为“非0值”的可读写数据,程序刚运行时,这些数据具有非0的初始值,且运行的时候它们会常驻在RAM区,因而应用程序可以修改其内容。 例如: C语言中使用定义的全局变量,且定义时赋予“非0值”给该变量进行初始化。 4、ZI-data Zero Ini
[单片机]
STM32开发板入门教程 - 串口通讯 UART
通用同步异步收发器(USART)提供了一种灵活的方法来与使用工业标准NR 异步串行数据格式的外部设备之间进行全双工数据交换。 USART利用分数波特率发生器提供宽范围的波特率选择。 它支持同步单向通信和半双工单线通信。它也支持LIN(局部互连网),智能卡协议和IrDA(红外数据组织)SIR ENDEC规范,以及调制解调器(CTS/RTS)操作。它还允许多处理器通信。用于多缓冲器配置的DMA方式,可以实现高速数据通信。 主要特性: 全双工的,异步通信 NR 标准格式 分数波特率发生器系统 -发送和接收共用的可编程波特率,最高到4.5Mbits/s 可编程数据字长度(8位或9位)
[单片机]
STM32--CAN总线应运
CAN 总线在控制领域使用的非常广泛,如今大多数CPU芯片外围都扩展CAN接口。本文重点介绍以STM32F103E系列芯片为基础介绍CAN 总线的使用方法。 1. 硬件基础 CAN总线工作需要两根数据线,RX和TX,即为输入总线和输出总线。一般CPU与外界通信需要接一个驱动芯片(这点很像UART接口),常用的CAN芯片主要有:SN65VHD230、PCA82C250T等,本系统使用SN65VHD230作为CAN接口芯片。而CPU提供的CAN接口为CAN_L和CAN_H。 2. 软件设计 在进行软件设计时,我们首先来看这样的一个结构体: typedef struct { uint32_t StdId;
[单片机]
9.STM32中对SysTick_Init()函数和Delay_us()的理解
STM32中对SysTick_Init()函数(sysTick_Config()、TimingDelay_Decrement()自定义)和Delay_us()的理解: 实验:3个LED灯以500ms的频率闪烁。
[单片机]
9.STM32中对SysTick_Init()函数和Delay_us()的理解
STM32之通用定时器输出比较模式
#include stm32f10x.h /* RCC时钟配置 */ void RCC_config() { ErrorStatus HSEStartUpStatus; /* RCC寄存器设置为默认配置 */ RCC_DeInit(); /* 打开外部高速时钟 */ RCC_HSEConfig(RCC_HSE_ON); /* 等待外部高速时钟稳定 */ HSEStartUpStatus = RCC_WaitForHSEStartUp(); if(HSEStartUpStatus == SUCCESS) { /* 设置HCLK = SYSCLK */ RCC_HCLKConfig(RCC_SYSCLK_Div1); /
[单片机]
STM32定时器和外部触发同步的应用
一、定时器和外部触发的同步 TIMx定时器能够在多种模式下和一个外部的触发同步:复位模式、门控模式和触发模式。 从模式:复位模式 复位模式时序图如下所示: 配置通道1以检测TI1的上升沿,配置定时器为复位模式,计数器为向上计数模式,选择T1位输入源。每一个计数器时钟周期计数器寄存器自增。当TI1产生一个上升沿时,计数器寄存器清0重新开始计数。 从模式:门控模式 门控模式时序图如下所示: 配置通道1以检测TI1的低电平,配置定时器为门控模式,计数器为向上计数模式,选择T1为输入源。每一个计数器时钟周期计数器寄存器自增。只要TI1为低,计数器开始依据内部时钟计数,在TI1为高电平时停止计数。 从模式:触
[单片机]
<font color='red'>STM32</font>定时器和外部触发同步的应用
基于STM32定时器输入捕获解析
输入捕获模式可以用来测量脉冲宽度或者测量频率。STM32的定时器,除了TIM6和TIM7,其他定时器都有输入捕获功能。STM32的输入捕获,简单的说就是通过检测TIMx_CHx上的边沿信号,在边 沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存(TIMx_CCRx)里面,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA 等 例如:我们用到TIM5_CH1来捕获高电平脉宽,也就是要先设置输入捕获为上升沿检测,记录发生上升沿的时候TIM5_CNT的值。然后配置捕获信号为下降沿捕获,当下降沿到来时,发生捕获,并记录此时的TIM5_CNT值。这样,前后两次T
[单片机]
STM32 FreeRTOS Keil环境搭建
由于FreeRTOS的官方已经支持STM32F1X系列的Cortex-M3的移植,所以只需要在Keil IDE中设置相关即可了; 在Keil中新建一工程,在工程中新建3个组,分别对应3个目录用来存放:user、rtos、stmlib user中添加用户自己的代码和头文件; rtos中添加rots的文件主要有:list.c、task.c、queue.c、head_2.c、port.c stmlib中添加STM32官方提供的STM32操作的lib库(注意stm32f10x_md.s中的内容和替换为FreeRTOS Demo 中的STM32F10X.s否则系统调度不能正常工作) 另外需要把FreeRTOS/source/inc
[单片机]
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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