图解I2C写法

标准I2c是从高位到低位发送 

 

 

//IO 口模拟起始信号 
//产生起始信号 
void I2C_Start(void) 

    I2C_SDA_OUT(); //对于有准双向的IO口,可以不设置SDA的输入输出模式。比如51单片机。
  
    I2C_SDA_H; 
    I2C_SCL_H; 
    delay_us(5); 
    I2C_SDA_L; 
    delay_us(6); 
    I2C_SCL_L; 

/*防止冲突的写法
bool I2C_Start(void)
{
  SDA_H;I2C_delay();
  SCL_H;I2C_delay();
  if((SDA_read)==0)
  {
        return 0;
  }
  else
  {
    SDA_L;I2C_delay();
    if(SDA_read)
    {
      return 0;
    }
    else
    {
        SDA_L;
        I2C_delay();
        return 1;
    }
  }
}
*/ 

 


//IO 口模拟结束信号 
//产生停止信号 
void I2C_Stop(void) 

    I2C_SDA_OUT();     I2C_SCL_L; 
    I2C_SDA_L; 
    I2C_SCL_H; 
    delay_us(6); 
    I2C_SDA_H; 
    delay_us(6);
    I2C_SCL_L;
}

 

//主机产生应答信号 ACK 
void I2C_Ack(void) 

   I2C_SCL_L; 
   I2C_SDA_OUT(); 
   I2C_SDA_L; 
   delay_us(2); 
   I2C_SCL_H; 
   delay_us(5); 
   I2C_SCL_L; 
}  

 

 

//主机不产生应答信号 NACK 
void I2C_NAck(void) 

   I2C_SCL_L; 
   I2C_SDA_OUT(); 
   I2C_SDA_H; 
   delay_us(2); 
   I2C_SCL_H; 
   delay_us(5); 
   I2C_SCL_L; 

 

6. IO 口模拟发送一个字节数据 

//从scl拉低开始延时2us,写入数据到sda,再延时2us拉高scl
//I2C 发送一个字节 
void I2C_Send_Byte(u8 txd) 

    u8 i=0; 

    I2C_SDA_OUT(); 
    I2C_SCL_L;//拉低时钟开始数据传输
    delay_us(2);
    for(i=0;i<8;i++) 
    { 
        if((txd&0x80)>0) //0x80  1000 0000 
        I2C_SDA_H; 
        else 
        I2C_SDA_L; 

        delay_us(2); //等待数据稳定 
        txd<<=1; 
        I2C_SCL_H; 
        delay_us(4); //发送数据 
        I2C_SCL_L; 
        delay_us(2); 
    } 
}

 

//等待从机应答信号 

//从scl拉低开始延时4us,给从机写入数据的时间,然后开始读入数据
//返回值:1 接收应答失败 
//    0 接收应答成功 
u8 I2C_Wait_Ack(void) 

    u8 tempTime=0; 
    I2C_SCL_L;  //释放总线
    I2C_SDA_H; //释放总线
    I2C_SDA_IN();   
    delay_us(4); 
    I2C_SCL_H; 
    //delay_us(1); 

    while(GPIO_ReadInputDataBit(GPIO_I2C,I2C_SDA)){ 
        tempTime++; 
        if(tempTime>250){ 
            I2C_Stop(); 
            return 1; 
        }   
    } 

    I2C_SCL_L; 
    return 0; 

7. IO 口模拟接收一个字节数据 
//I2C 读取一个字节 

//从scl拉低开始延时4us,给从机写入数据的时间,然后开始读入数据
 
u8 I2C_Read_Byte(u8 ack) 

    u8 i=0,receive=0; 

   I2C_SDA_H; //准双向需要这一句,释放总线

    I2C_SDA_IN(); 


    for(i=0;i<8;i++){ 
        I2C_SCL_L; 
        delay_us(4); 
        I2C_SCL_H; 
        if(GPIO_ReadInputDataBit(GPIO_I2C,I2C_SDA)) 
        receive++;

       receive<<=1; 
        delay_us(1);  
    }
    if(ack==0){ 
        I2C_NAck(); 
    }else{ 
        I2C_Ack(); 
    }
    return receive; 
}   

17、模拟IIC编程

       (1)、开引脚的时钟:RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

       (2)、宏定义: 

#define I2C_SCL    GPIO_Pin_6
#define I2C_SDA   GPIO_Pin_7
#define GPIO_I2C  GPIOB
#define I2C_SCL_H GPIO_SetBits(GPIO_I2C, I2C_SCL)  //把PB6置高
#define I2C_SCL_L  GPIO_ResetBits(GPIO_I2C, I2C_SCL)  //把PB6置低
#define I2C_SDA_H  GPIO_ResetBits(GPIO_I2C, I2C_SDA)  //把PB7置高
#define I2C_SDA_L  GPIO_ResetBits(GPIO_I2C, I2C_SDA)  //把PB7置低
      

        (3)、配置函数

               void I2C_Init(void)   {

                    GPIO_InitTypeDef GPIO_InitStructure;

                    GPIO_InitStructure.GPIO_Pin=I2C_SCL | I2C_SDA;

                    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

                    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;  //推挽输出模式

                    GPIO_Init(GPIOB,&GPIO_InitStructure);

               }

 

       (4)、SDA有输出方向和输入方向,配置SDA的这两个模式:

               

               void I2C_OUT(void)    //SDA是输出方向

               {

                    GPIO_InitTypeDef GPIO_InitStructure;

                    GPIO_InitStructure.GPIO_Pin=I2C_SDA;

                    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

                    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;  //推挽输出模式

                    GPIO_Init(GPIOB,&GPIO_InitStructure);

 

                    I2C_SCL_H;

                    I2C_SDA_H;   //把两条线都变成高电平

                }

 

                void I2C_IN(void)    //SDA是输入方向

                {

                    GPIO_InitTypeDef GPIO_InitStructure;

                    GPIO_InitStructure.GPIO_Pin=I2C_SDA;

                    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

                    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_IPU;  //输入上拉模式

                    GPIO_Init(GPIOB,&GPIO_InitStructure);

                }

 原文:https://blog.csdn.net/shaguahaha/article/details/70766665 
 

I2C的六个信号

1. 起始信号

定义:SCL线为高电平期间,SDA线由高电平向低电平的变化。


void iic_start(void)
{
    SDA = 1;
    SCL = 1;
    delay_us(1);
    SDA = 0;
    delay_us(1);
    SCL = 0;
}
2. 终止信号
定义:SCL线为高电平期间,SDA线由低电平向高电平的变化。


void iic_stop(void)
{
    SDA = 0;
    SCL = 1;
    delay_us(1);
    SDA = 1;
    delay_us(1);
    SCL = 0;
}
3. 写数据信号
I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高低电平状态才允许变化。


bit iic_send_byte(unsigned char byte)
{
    unsigned char i;
    
    for(i = 0; i < 8; i++)
    {
        SDA = byte & 0x80;
        SCL = 1;
        delay_us(1);
        SCL = 0;
        byte <<= 1;
    }
    
    SCL = 1;
    SDA = 1;
    delay_us(1);
    if(0 == SDA)
    {
        ack = 1;
    }
    else
    {
        ack = 0;
    }
    
    SCL = 0;
    return ack;
}
4. 读数据信号
I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高低电平状态才允许变化。


unsigned char iic_rcv_byte(void)
{
    unsigned char i;
    unsigned char temp = 0;
    unsigned char a;
    
    SDA = 1;
    for(i = 0; i < 8; i++)
    {
        SCL = 0;
        delay_us(1);
        SCL = 1;
        if(SDA)
        {
            a = 0x01;
        }
        else
        {
            a = 0;
        }
        
        temp |= (a << (7 - i));
        delay_us(1);
    }
    
    SCL = 0;
    
    return temp;
}
5. 应答信号
I2C总线协议规定,每传送一个字节数据,都要有一个应答信号以确定数据传送是否被对方接收。应答信号由接收设备产生,在SCL为高电平期间,接收设备将SDA拉低为低电平,表示数据传输正确。


void iic_ack(void)
{
    SDA = 0;
    SCL = 1;
    delay_us(1);
    SCL = 0;
}
6. 非应答信号

 

void iic_noack(void)
{
    SDA = 1;
    SCL = 1;
    delay_us(1);
    SCL = 0;
}


原文:https://blog.csdn.net/zhengqijun_/article/details/52217101 
 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值