[Stm32f407] I2C test

One. I2C Introduction

The IIC (Inter - integratedcircuit) bus is a kind of PHILIPS developed two-wire serial bus, for connecting the microcontroller and its peripheral equipment. It is a data line SDA and the clock SCL configuration serial bus can transmit and receive data. In the CPU and charged IC between the IC and the IC bidirectional transfer between high-speed IIC bus generally up to 400kbps or more. Figure:

I2C protocol a total of 6 kinds of agreements signal

        idle state

        start signal

        stop signal

        response signal

        validity of data

        data transmission

1)  Idle Signal

I2C bus bus SDA and SCL when the two signal lines at a high level at the same time, a predetermined idle state of the bus. At this time, the output of each stage FET devices are in the OFF state, i.e., the bus is released by the two signal lines of each of the pull-up resistor deasserted.As shown in the red box:

2)  start signal

When the SCL high period, the SDA from high to low transition; activation signal is a level transition timing signal, rather than a signal level. Figure:

3)  stop signal

When the SCL high period, the SDA high to a low transition; stop signal level transitions is also a timing signal, rather than a signal level. Figure:

4)  the response signal

5)  The transmitter transmits each byte, the clock pulses in 9 released during a data line by a receiver feedback response signal.Response signal is low, a valid response to a predetermined bit ( the ACK referred acknowledge bit) indicating that the receiver has successfully received the byte; response signal is high, a predetermined non-acknowledge bit ( NACK ), reception generally represents this byte is not received successfully. 

For effective feedback acknowledge bit ACK request, the receiver at the 9 low-level period of the clock pulse before the SDA line low, and to ensure a high level during the low level of the clock is stable.如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P

6) 数据的有效性

I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。

即:数据在SCL的上升沿到来之前就需准备好。并在在下降沿到来之前必须稳定。

7) 数据传输

I2C总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。数据位的传输是边沿触发

二.软件模拟I2C

以下是参考原子模拟I2C的代码,因为ST公司可能为了规避飞利浦I2C的专利为题,把I2C设计的很复杂,并且不稳定

模拟I2C.h

//IO方向设置
#defineSDA_IN() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;}         //PB9输入模式
#defineSDA_OUT() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;}//PB9输出模式
//IO操作函数 
#defineIIC_SCL    PBout(8) //SCL
#defineIIC_SDA    PBout(9) //SDA       
#defineREAD_SDA   PBin(9)  //输入SDA 
 
//IIC所有操作函数
voidIIC_Init(void);                //初始化IIC的IO口                                     
voidIIC_Start(void);                                     //发送IIC开始信号
voidIIC_Stop(void);                          //发送IIC停止信号
voidIIC_Send_Byte(u8 txd);                       //IIC发送一个字节
u8IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8IIC_Wait_Ack(void);                              //IIC等待ACK信号
voidIIC_Ack(void);                                        //IIC发送ACK信号
voidIIC_NAck(void);                                     //IIC不发送ACK信号
 
voidIIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr);   

模拟I2C.c

#include"myiic.h"
#include"delay.h"
      
//初始化IIC
voidIIC_Init(void)
{                           
  GPIO_InitTypeDef  GPIO_InitStructure;
 
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
 
  //GPIOB8,B9初始化设置
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 |GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Mode =GPIO_Mode_OUT;//普通输出模式
  GPIO_InitStructure.GPIO_OType =GPIO_OType_PP;//推挽输出
  GPIO_InitStructure.GPIO_Speed =GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd =GPIO_PuPd_UP;//上拉
  GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
         IIC_SCL=1;
         IIC_SDA=1;
}
//产生IIC起始信号
voidIIC_Start(void)
{
         SDA_OUT();     //sda线输出
         IIC_SDA=1;                
         IIC_SCL=1;
         delay_us(4);
        IIC_SDA=0;//START:whenCLK is high,DATA change form high to low 
         delay_us(4);
         IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 
}          
//产生IIC停止信号
voidIIC_Stop(void)
{
         SDA_OUT();//sda线输出
         IIC_SCL=0;
         IIC_SDA=0;//STOP:when CLK is high DATAchange form low to high
        delay_us(4);
         IIC_SCL=1; 
         IIC_SDA=1;//发送I2C总线结束信号
         delay_us(4);                                                                  
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8IIC_Wait_Ack(void)
{
         u8 ucErrTime=0;
         SDA_IN();      //SDA设置为输入  
         IIC_SDA=1;delay_us(1);     
         IIC_SCL=1;delay_us(1);   
         while(READ_SDA)
         {
                   ucErrTime++;
                   if(ucErrTime>250)
                   {
                            IIC_Stop();
                            return 1;
                   }
         }
         IIC_SCL=0;//时钟输出0            
         return 0;  
} 
//产生ACK应答
voidIIC_Ack(void)
{
         IIC_SCL=0;
         SDA_OUT();
         IIC_SDA=0;
         delay_us(2);
         IIC_SCL=1;
         delay_us(2);
         IIC_SCL=0;
}
//不产生ACK应答             
voidIIC_NAck(void)
{
         IIC_SCL=0;
         SDA_OUT();
         IIC_SDA=1;
         delay_us(2);
         IIC_SCL=1;
         delay_us(2);
         IIC_SCL=0;
}                                                                                     
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答                        
voidIIC_Send_Byte(u8 txd)
{                        
    u8 t;  
         SDA_OUT();        
    IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        IIC_SDA=(txd&0x80)>>7;
        txd<<=1;            
                   delay_us(2);   //对TEA5767这三个延时都是必须的
                   IIC_SCL=1;
                   delay_us(2); 
                   IIC_SCL=0;        
                   delay_us(2);
    }        
}           
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8IIC_Read_Byte(unsigned char ack)
{
         unsigned char i,receive=0;
         SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
         {
        IIC_SCL=0; 
        delay_us(2);
                   IIC_SCL=1;
        receive<<=1;
        if(READ_SDA)receive++;   
                   delay_us(1); 
    }                                             
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}


发布了200 篇原创文章 · 获赞 548 · 访问量 76万+

Guess you like

Origin blog.csdn.net/XiaoXiaoPengBo/article/details/73527810