专注电子技术学习与研究
当前位置:单片机教程网 >> STM32 >> 浏览文章

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

作者:明入如di   来源:明入如di的博客   点击数:  更新时间:2014年05月18日   【字体:

从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才会拉高
 
上图为I2C通信的时序图
 
其中起始信号:在SCL为高电平时,SDA电平由高变低,且高电平SDA高电平持续时间要大于4.7us,在SCL由高电平变低时,SDA的低电平持续时间要大于4us
 
终止信号:在SCL为高电平期间,SDA电平由低变高,且高电平持续时间大于4.7us,低电平持续时间大于4us
 
起始信号和终止信号无论何时都是由主设备产生的
 
数据帧:在SCL为高电平期间,SDA的电平保持稳定
 
主向从写数据

期间地址为八位:其中高四位为固定位,bit3—bit1为可变位,最低位为操作位 为0时为写操作,为1时是读操作
地址发送完成之后,等待从器件的应答信号,切记此时要将SDA配置为上拉输入模式

应答信号即为,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);
}
关闭窗口

相关文章