stm32与AT24C02的I2C通信总结(模拟时序)

从51的时候就学习了I2C通信协议,但51的功能就那些,内部没有集成I2C模块,所以只能通过模拟I2C通信的时序来和EEPROM进行通信,stm32内部集成了I2C通信的片上外设,但由于内部I2C外设复杂和不稳定行,所以用的人不是很多,而基本上使用I2C的通信都是通过模拟时序的方式来实现的

首先I2C是同步半双工的通信方式,需要两条线即可,SCL时钟线,同步时钟由主机产生,SDA数据线用来发送接收数据,任何时候只能一台主机发送数据。

在编程的时候碰到了很多问题,其中一项就是等待从机的应答程序

开始的时候编写如下

void iic_wait_ack()   错误                                                   void iic_wait_ack()          正确的程序            

{                                                                                  {

 SCL=1;                                                                        iic_sda_in();

iic_sda_in();                                                                 SCL=1;

delay_us(2);                                                                delay_us(2);

SDA=1;                                                                       SDA=1;

while(SDAIN);                                                            while(SDAIN);

SCL=0;                                                                       SCL=0;

}                                                                                   }

程序运行的时候总是死在红色部分的程序,后来用debug单步调试,慢慢的发现了规律,以下为个人观点,不敢保证一定正确:

                    1.SDAIN只会在SCL为低电平的时候拉低

                    2.且在SCL保持高电平的时候,SDAIN比保持低电平

                    3.在SCL变为高电平之后,SDAIN才会拉高

stm32与AT24C02的I2C通信总结(模拟时序)
 

上图为I2C通信的时序图

其中起始信号:在SCL为高电平时,SDA电平由高变低,且高电平SDA高电平持续时间要大于4.7us,在SCL由高电平变低时,SDA的低电平持续时间要大于4us

终止信号:在SCL为高电平期间,SDA电平由低变高,且高电平持续时间大于4.7us,低电平持续时间大于4us

起始信号和终止信号无论何时都是由主设备产生的

数据帧:在SCL为高电平期间,SDA的电平保持稳定

主向从写数据

stm32与AT24C02的I2C通信总结(模拟时序)
期间地址为八位:其中高四位为固定位,bit3—bit1为可变位,最低位为操作位 为0时为写操作,为1时是读操作

地址发送完成之后,等待从器件的应答信号,切记此时要将SDA配置为上拉输入模式

stm32与AT24C02的I2C通信总结(模拟时序)
应答信号即为,SCL保持高电平时 SDA一直为低电平。

然后再发送要写入数据的地址,收到应答再写入数据,最后是停止信号

首先先配置IO口,PB10为SCL,PB.11为SDA

#include

void gpio_init()

{

 RCC->APB2ENR|=1<<2;

 GPIOA->CRH&=0xfffff00f;

 GPIOA->CRH|=0x000008b0;

 GPIOA->ODR|=3<<9;

 RCC->APB2ENR|=1<<3;

 GPIOB->CRH&=0xfffff0ff;

 GPIOB->CRH|=0x00000300;

 GPIOB->ODR|=1<<10;

}

void iic_sda_out()//此时为主器件发送数据

{

 RCC->APB2ENR|=1<<3;

 GPIOB->CRH&=0xffff0fff;

 GPIOB->CRH|=0x00003000;

 GPIOB->ODR|=1<<11;

}

void iic_sda_in()//此时为主器件接收数据或等待从器件发送应答信号

{

 RCC->APB2ENR|=1<<3;

 GPIOB->CRH&=0xffff0fff;

 GPIOB->CRH|=0x00008000;

 GPIOB->ODR|=1<<11;

}

然后是为头文件iic.h,如下

#define iic_write 0xa0

#define iic_read 0xa1

void iic_start(void);//起始信号

void iic_end(void);//终止信号

void iic_senddata(u8 data);//主器件发送一个字节数据

void iic_master_ack(void);//主机应答信号

void iic_master_nack(void);//主机非应答信号

void iic_wait_ack(void);//等待从机应答信号

void iic_master_write(u8 type,u8 address,u8 data);

u8 iic_master_read(u8 address);

u8 iic_readdata(void);

iic.c文件如下

#include

#include"gpio.h"

#include"delay.h"

#include"iic.h"

#include"sys.h"

void iic_start()

{

 iic_sda_out();

 SDA=0;

 SCL=1;

 SDA=1;

 delay_us(5);

 SDA=0;

 delay_us(5);

}

void iic_end(void)

{

 iic_sda_out();

 SCL=0;

 SDA=0;

 delay_us(2);

 SCL=1;

 delay_us(5);

 SDA=1;

 delay_us(5);

 SDA=0;

}

void iic_senddata(u8 data)

{

 int i;

 iic_sda_out();

 for(i=7;i>=0;i--)

    {

     SCL=0;

SDA=(data>>i);

SCL=1;

delay_us(5);

SCL=0;

}

}

void iic_master_ack()

{

 iic_sda_out();

 SCL=0;

 SDA=0;

 SCL=1;

 delay_us(5);

 SCL=0;

 SDA=1;

}

void iic_master_nack()

{

 iic_sda_out();

 SCL=0;

 SDA=1;

 SCL=1;

 delay_us(5);

 SCL=0;

}

void iic_wait_ack()

{

 iic_sda_in();

 SDA=1;

 delay_us(1);

 SCL=1;

 delay_us(1);

 while(SDAIN);

 SCL=0;

}

void iic_master_write(u8 type,u8 address,u8 data)

{

 iic_start();

 iic_senddata(type);

 iic_wait_ack();

 iic_senddata(address);

 iic_wait_ack();

 iic_senddata(data);

 iic_wait_ack();

 iic_end();

 delay_ms(10);

}

u8 iic_master_read(u8 address)

{

 u8 dcb;

 iic_start();

 iic_senddata(0xa0);

 iic_wait_ack();

 iic_senddata(address);

 iic_wait_ack();

 iic_start();

 iic_senddata(0xa1);

 iic_wait_ack();

 dcb=iic_readdata();

 iic_master_nack();

 iic_end();

 return dcb;

}

u8 iic_readdata()

{

  int k;

  u8 receive;

  iic_sda_in();

   for(k=7;k>=0;k--)

   {

    SCL=0;

delay_us(2);

SCL=1;

receive<<=1;

if(SDAIN==1)

receive|=1<<0;

else

receive&=~(1<<0);

   }

   return receive;

}

主程序

#include

#include"delay.h"

#include"usart1.h"

#include"sys.h"

#include"gpio.h"

#include"iic.h"

int main()

{

 u8 temp;

 Stm32_Clock_Init(9);

 delay_init(72);

 gpio_init();

 usart1_init();

 iic_master_write(iic_write,0x00,0xdf);

 temp=iic_master_read(0x00);

 USART1->DR=temp;

 while(1);

}

猜你喜欢

转载自blog.csdn.net/weixin_42314225/article/details/82657398