当前位置:   article > 正文

STM32 IIC详解(软件模拟)_模拟iic

模拟iic

目录

一、IIC协议基本原理

1.IIC协议概述

2.时序图分析

二、代码分析

1.IIC初始化

2.IIC起始信号

3.IIC发送数据

4.获取应答信号

5.读一个字节

6.产生ACK应答

7.不产生ACK应答


IIC(Inter-Integrated Circuit)在嵌入式系统中是一种常见的数据通信接口,日常工作中许多传感器都是基于IIC来传输数据的,所以掌握这个接口对我们来说非常重要。

一、IIC协议基本原理

1.IIC协议概述

IIC也被称为I2C和I²C,硬件方面由于存在专利,所以日常中我们常以两个IO口用软件模拟IIC来使用。IIC串行总线有两根信号线:数据线SDA和时钟线SCL。IIC总线上的设备通过地址进行区分,不同种类的设备地址不同。只要不超过IIC总线上的电容限制(一般不超过400pf),就可以连接任意数量的从机,在通信时刻,只能有一个作为主机,其他的都为从机。高速IIC总线一般可达400kbps以上。

2.时序图分析

SCL为时钟线,SDA为数据线,SCL和SDA默认都是高电平,两条线相互配合会产生三种信号构成时序。

开始信号:SCL 为高电平时,SDA 由高电平向低电平跳变。
结束信号:SCL 为高电平时,SDA 由低电平向高电平跳变。
应答信号:接收数据的设备在接收到 8位 数据后,向发送数据的设备发出特定的低电平,表示已收到数据。主机设备向从机设备发出一个信号后,等待从机设备发出一个应答信号,主机设备接收到应答信号后,根据实际情况作出是否继续传递信号。若未收到应答信号,由判断为受控单元出现故障。

IIC在开始信号发出后开始发送数据,数据以8位传输,SCL高电平的时候SDA读到的数据有效,然后经历8位数据传输以后,第九次检测应答信号,如果检测到从机将SDA置为低电平,说明从机设备有应答(ACK),如果保持高电平,说明从机设备没有应答(NACK)。

二、代码分析

本文基于STM32F429的HAL库为例讲解IIC的使用,定义宏参数如下图所示

1.IIC初始化

  1. void IIC_Init(void)
  2. {
  3. GPIO_InitTypeDef GPIO_Initure;
  4. __HAL_RCC_GPIOH_CLK_ENABLE(); //使能GPIOH时钟
  5. //PH4,5初始化设置
  6. GPIO_Initure.Pin=GPIO_PIN_4|GPIO_PIN_5;
  7. GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
  8. GPIO_Initure.Pull=GPIO_PULLUP; //上拉
  9. GPIO_Initure.Speed=GPIO_SPEED_FAST; //快速
  10. HAL_GPIO_Init(GPIOH,&GPIO_Initure);
  11. IIC_SDA=1;
  12. IIC_SCL=1;
  13. }

初始化IIC,使能PH4,PH5推挽输出、上拉、快速,然后又将SDA和SCL拉高。

2.IIC起始信号

  1. void IIC_Start(void)
  2. {
  3. SDA_OUT(); //sda线输出
  4. IIC_SDA=1;
  5. IIC_SCL=1;
  6. delay_us(4);
  7. IIC_SDA=0;//拉低电平
  8. delay_us(4);
  9. IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
  10. }

在SDA和SCL高电平的同时,将SDA拉低产生一个下降沿。

3.IIC发送数据

  1. void IIC_Send_Byte(u8 txd)
  2. {
  3. u8 t;
  4. SDA_OUT();
  5. IIC_SCL=0;//拉低时钟开始数据传输
  6. for(t=0;t<8;t++)
  7. {
  8. IIC_SDA=(txd&0x80)>>7;
  9. txd<<=1;
  10. delay_us(2);
  11. IIC_SCL=1;
  12. delay_us(2);
  13. IIC_SCL=0;
  14. delay_us(2);
  15. }
  16. }

切换SDA为输出模式,拉低SCL电平,依次发送8位数据, 每次写好SDA位的时候,将SCL拉高后等待2us再拉低。

4.获取应答信号

  1. //返回值:1,接收应答失败
  2. // 0,接收应答成功
  3. u8 IIC_Wait_Ack(void)
  4. {
  5. u8 ucErrTime=0;
  6. SDA_IN(); //SDA设置为输入
  7. IIC_SDA=1;delay_us(1);
  8. IIC_SCL=1;delay_us(1);
  9. while(READ_SDA)
  10. {
  11. ucErrTime++;
  12. if(ucErrTime>250)
  13. {
  14. IIC_Stop();
  15. return 1;
  16. }
  17. }
  18. IIC_SCL=0;//时钟输出0
  19. return 0;
  20. }

将SDA设置为输入模式,将SDA和SCL拉高,如果SDA在规定时间内依然是拉高的状态,说明从机没有应答,反之则说明从机应答。

5.读一个字节

  1. 1个字节,ack=1时,发送ACK,ack=0,发送nACK
  2. u8 IIC_Read_Byte(unsigned char ack)
  3. {
  4. unsigned char i,receive=0;
  5. SDA_IN();//SDA设置为输入
  6. for(i=0;i<8;i++ )
  7. {
  8. IIC_SCL=0;
  9. delay_us(2);
  10. IIC_SCL=1;
  11. receive<<=1;
  12. if(READ_SDA)receive++;
  13. delay_us(1);
  14. }
  15. if (!ack)
  16. IIC_NAck();//发送nACK
  17. else
  18. IIC_Ack(); //发送ACK
  19. return receive;
  20. }

读取数据的时候,先将SDA设置成输入,然后依次拉低拉高SCL 8次,读取8位数据,如果还想继续读取,就产生ACK应答,如果不想继续读取了,就产生nACK应答。

6.产生ACK应答

  1. void IIC_Ack(void)
  2. {
  3. IIC_SCL=0;
  4. SDA_OUT();
  5. IIC_SDA=0;
  6. delay_us(2);
  7. IIC_SCL=1;
  8. delay_us(2);
  9. IIC_SCL=0;
  10. }

先将SCL拉低,然后改SDA为输出模式,拉低SDA后拉高SCL后再拉低。

7.不产生ACK应答

  1. //不产生ACK应答
  2. void IIC_NAck(void)
  3. {
  4. IIC_SCL=0;
  5. SDA_OUT();
  6. IIC_SDA=1;
  7. delay_us(2);
  8. IIC_SCL=1;
  9. delay_us(2);
  10. IIC_SCL=0;
  11. }

先将SCL拉低,然后改SDA为输出模式,拉高SDA后拉高SCL后再拉低,就可以告诉从机不再继续读取数据。

总体来说,IIC的通讯只用到了SCL(时钟线)和SDA(数据线)两条线,实现起来还是比较简单的,希望本文能帮助你理解IIC如何使用。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/974928
推荐阅读
相关标签
  

闽ICP备14008679号