STM32F1战舰的II2C-正点原子的个人梳理(1)

II2C通信考虑两大问题:怎样区分发送和接收,怎样区分位和字节
由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,高速IIC总线一般可达400kbps以上。IIC是半双工通信方式。
这里写图片描述
(1)空闲状态
I2C总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。
(2)开始信号
起始信号:当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。

void IIC_Start(void)
{   
    SDA_OUT();//设置SDA线为输出模式
    IIC_SDA=1;
    IIC_SCL=1;
    delay_us(4);
    IIC_SDA=0; //在此处SDA数据线出现了下降沿 
           //START:when CLK is high,Data change from high to low
        delay_us(4);
    IIC_SCL = 0; //钳住I2C总线,准备发送或接收数据
}

(3)停止信号
停止信号:当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。

//产生 IIC 停止信号
void IIC_Stop(void)
{
SDA_OUT(); //sda 线输出
IIC_SCL=0;
IIC_SDA=0; //STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL=1;
IIC_SDA=1; //发送 I2C 总线结束信号
delay_us(4);
}

(4)应答信号ACK,非应答信号NACK,等待应答信号的到来(重点看图,理解图)
正点原子讲的有点抽象,看个人注释就好
发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。
1)产生有效应答(用于发送):应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;【个人注释:在一个SCL完全跳变周期内,SDA保持为低电平】

//产生 ACK 应答
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}

2)非有效应答(用于发送):应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
【个人注释:在一个SCL完全跳变周期内,SDA保持为高电平】
//不产生 ACK 应答//NACK

void IIC_NAck(void)
{ IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}

3)等待应答信号的到来(这里是接收)接收告诉单片机两种状态,成功(0)or失败(1)

//等待应答信号到来
//返回值: 1,接收应答失败
// 0,接收应答成功
u8 IIC_Wait_Ack(void)
{
    u8 ucErrTime=0;
    SDA_IN(); //SDA 设置为输入
    IIC_SDA=1;delay_us(1); //默认拉高,因为有效相应为低电平,用高电平去捕捉低电平
    IIC_SCL=1;delay_us(1);
    while(READ_SDA)//#define READ_SDA   PBin(7)  //输入SDA
    { 
        ucErrTime++;
        if(ucErrTime>250)
        { 
            IIC_Stop();
            return 1;
        }
    }
    IIC_SCL=0; //时钟输出 0
    return 0;
}

4)对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。
【这里我解释一下:有效应答的要求之一时,在第9个时钟整周期中,SDA需要保持完整的低电平】
这里写图片描述
5)如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK(非应答高电平)信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。
(5)数据的有效性:【个人理解,SCL是衡量,也就是说SCL是不变的,SDA要配合SCL,如何想数据有效,在SCL完整的周期内,SDA必须稳定】
(6)数据传输(A:发送一个字节 B:接收一个字节)主要先看这个图,虽然个人认为没什么用
这里写图片描述
个人理解:这段代码是怎么写出来的,怎么考虑的,主要是以SCL为主,先写SCL的电平。
个人理解:SCL为低电平,才能改变SDA,因为SCL一旦是高电平就要传输数据,同时要求SDA不能再改变

A:发送一个字节 8位
txd是一个字节,需要一位一位读取

//IIC 发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(u8 txd)
{ 
    u8 t;  //用于计数
    SDA_OUT(); //传输数据,用于输出
    IIC_SCL=0;//拉低时钟开始数据传输,应该说在SCL低电平才能改变数据,在高电平时传输数据
    for(t=0;t<8;t++)
    { 
        IIC_SDA=(txd&0x80)>>7;//1000 0000最高位的读出来,然后将其移到最低位
        txd<<=1;//将最高位挪走。这时候数据已经准备好
        delay_us(2); //对 TEA5767 这三个延时都是必须的,等待
        IIC_SCL=1; //给高电平,传输数据
        delay_us(2);//让他传一会
        IIC_SCL=0; //传完。拉低,为下一次传位做准备。
        delay_us(2);
    }
}

**B是接收一个字节,也是8位,跟刚才原理不一样,读的时候SCL为高电平才能说明有SDA传输过来。
所以SDA需要在SCL高电平期间去读数据。**
但是读与写有一区别,读要将数据读出来,通过函数返回,所以为非空函数,需要接收的数据return回来。

u8 IIC_Read_Byte(unsigned char ack) //输入为应答
{ 
    unsigned char i,receive=0; //清楚零,数据不能乱
    SDA_IN(); //SDA 设置为输入
    for(i=0;i<8;i++ )
    { 
        IIC_SCL=0; //数据要改变SCL需要变为低电平
        delay_us(2);
        IIC_SCL=1; //设置为高电平
        receive<<=1;//receive左移动一位,如果是高电平就要加1,不是就是0,发送是最高位,接收是最低位
        if(READ_SDA)receive++;
        delay_us(1);
    }
    if (!ack)
    IIC_NAck(); //发送 nACK
    else
    IIC_Ack(); //发送 ACK
    return receive;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值