IIC总线协议与软件实现

本博客大部分参考了其它人的文章,仅用来学习存储,知识积累

IIC总线协议与软件实现

第一次写博客,主要是将自己自学的一点东西记下来,与其做笔记,不如写博客。这几天看了I2C协议,这是大部分芯片必用的协议,花了几天时间,找了很多资料,终于有所悟,我来分享给大家。

一、I2C协议时序图
写时序:
IIC总线协议与软件实现_第1张图片

  1. 起始信号:处理器将SCL置高电平,SDA下降沿,进入数据传输状态。
  2. 数据传输:不论是写还是读,i2c规定SCL被拉高之前,数据必须放在SDA上待读取,SCL一旦处于高电平,SDA上的数据必须稳定,如果有跳变就会成为起始信号和停止信号发生错误,这点在写程序时一定要注意。
  3. 读写位:高电平读,即主机接收从机发来的数据;低电平写,即主机将数据发送给从机。
  4. 应答信号:总线上每传完一个字节,被传送方都会在第9个时钟总线拉低,以示回应。
  5. 停止信号:SCL高电平时,SDA上升沿,结束此次传输。
    整个传输过程就是:
    主机发出起始信号->高7位写设备地址,低0位写0->等待回应->写设备内部寄存器地址->等待回应->写n个字节,并等待回应(你>=1)->主机发出停止信号

读时序:

IIC总线协议与软件实现_第2张图片

  1. 读信号。
  2. 应答信号:和写入不同,应该由主机发出,读取一个字节发出一个应答信号。
  3. 无应答信号:第9个时钟不拉低SDA。注意,在一次读取多个字节的时候,最后一个字节应该不应答,直接stop,否则出错,实测。
    整个流程如下:
    主机发出起始信号->写7位从机地址+1位写信号->等从机应答->写寄存器地址->等从机应答->主机发出起始信号->写7位从机地址+1位读信号->等从机应答->读字节->发出应答信号->…->读字节->无应答->主机发出停止信号

    注意几点:

1、 i2c总线在硬件上,应该保证线与,即一条线上有一个位低,那么整条线就为低。解决办法就是挂载在总线上的设备io口设置为开漏模式,并挂一个上拉电阻。
2、 在不需要使用SDA的时候,主机应该释放,保证从机能够传输电平信号,比如上图的ack by slave,如果主机不释放SDA,始终为低电平,根本无法判断是主机拉低的还是从机拉低的。
3、 在进入传输状态的时候,如果没有传输数据,SCL应该为 低电平,因为SCL如果为高电平,SDA有任何的抖动都会被识别为起始或是停止信号,导致此次传输失败。

二、C代码
OIIC.h

/***************************************************************
portable iic driver
author:logic
date:2016-7-23
***************************************************************/

#ifndef _OIIC_H
#define _OIIC_H
#include "MK60_port.h"
#include "MK60_gpio.h"


/*
*public:
*/
void OIIC_init();
void OIIC_writeByte(unsigned char devAddr,unsigned char regAddr,unsigned char byte);
void OIIC_writeWord(unsigned char devAddr,unsigned char regAddr,unsigned int word);
void OIIC_writeBytes(unsigned char devAddr,unsigned char regAddr,unsigned char *bytes,int length);
unsigned char OIIC_readByte(unsigned char devAddr,unsigned char regAddr);
unsigned int OIIC_readWord(unsigned char devAddr,unsigned char regAddr);
void OIIC_readBytes(unsigned char devAddr,unsigned char regAddr,unsigned char *bytes,int length);

/*
*private:
*/
void OIIC_delay(int t);
void OIIC_start();
void OIIC_stop();
void OIIC_waitForResponse();
void OIIC_response();
void OIIC_noResponse();
void OIIC_putByteOnBus(unsigned char byte);
unsigned char getByteOnBus();

#define OSCL_H() (PTXn_T(PTE25,OUT)=1)
#define OSCL_L() (PTXn_T(PTE25,OUT)=0)
#define OSCL_V() PTXn_T(PTE25,IN)
#define OSDA_H() (PTXn_T(PTE24,OUT)=1)
#define OSDA_L() (PTXn_T(PTE24,OUT)=0)
#define OSDA_V() PTXn_T(PTE24,IN)
#define OSDA_OUT() (1==1)//ignore it when GPIO is openDrain and pullUp mode 
#define OSDA_IN() (1==1)




#endif

OIIC.c

#include "OIIC.h"


void OIIC_delay(int t)
{
    while(t>0)
    {
        t-=2;//adjustable
    }
}

void OIIC_init()
{
    /*
    initialize handware
    */
    gpio_init(PTE24,GPO,1);
    gpio_init(PTE25,GPO,1);
    port_init_NoALT(PTE24,ODO|PULLUP);//openDrain and pullUp
    port_init_NoALT(PTE25,ODO|PULLUP);


    OSCL_H();
    OSDA_H();
}

void OIIC_start()
{
    OSCL_H();
    OIIC_delay(1000);
    OSDA_L();
    OIIC_delay(1000);
    OSCL_L();//wait for data
    OIIC_delay(1000);
    //OSDA_H();
    //OIIC_delay(1000);
}

void OIIC_stop()
{
    OSDA_L();
    OIIC_delay(1000);
    OSCL_H();
    OIIC_delay(1000);
    OSDA_H();
    OIIC_delay(1000);
}
void OIIC_waitForResponse()
{
    int i=0;
    OSDA_H();
    OIIC_delay(1000);
    OSCL_H();
    OSDA_IN();
    while(OSDA_V()&&i<255){i+=1;}
    OIIC_delay(1000);//can be removed
    OSDA_OUT();
    OSCL_L();
    OIIC_delay(1000);

}
void OIIC_response()
{
    OSDA_L();
    OIIC_delay(1000);
    OSCL_H();
    OIIC_delay(1000);
    OSCL_L();
    OIIC_delay(1000);
    OSDA_H();
    OIIC_delay(100);
}
void OIIC_noResponse()
{
    OSDA_H();//NACK
    OIIC_delay(1000);
    OSCL_H();
    OIIC_delay(1000);
    OSCL_L();
    OIIC_delay(1000);
}

void OIIC_putByteOnBus(unsigned char byte)
{
    int i;
    for(i=0;i<8;i+=1)
    {
        if(byte&(0x80>>i))
            OSDA_H();
        else
            OSDA_L();
        OIIC_delay(1000);
        OSCL_H();//send data
        OIIC_delay(1000);
        OSCL_L();
        OIIC_delay(1000);
    }
    OSDA_H();//release
    OIIC_delay(1000);
}
unsigned char OIIC_getByteOnBus()
{
    unsigned char data=0;
    int i;
    OSDA_H();//release SDA to get data
    OSDA_IN();
    OIIC_delay(1000);
    for(i=0;i<8;i+=1)
    {
        OSCL_H();//to get data
        OIIC_delay(1000);
        if(OSDA_V())
            data=data|(0x80>>i);
        OSCL_L();//to refresh data
        OIIC_delay(1000);
    }
    OSDA_OUT();
    return data;
}
void OIIC_writeByte(unsigned char devAddr,unsigned char regAddr,unsigned char byte)
{
    OIIC_start();
    OIIC_putByteOnBus((devAddr<<1)|0x00);
    OIIC_waitForResponse();
    OIIC_putByteOnBus(regAddr);
    OIIC_waitForResponse();
    OIIC_putByteOnBus(byte);
    OIIC_waitForResponse();
    OIIC_stop();
}
void OIIC_writeWord(unsigned char devAddr,unsigned char regAddr,unsigned int word)
{
    OIIC_start();
    OIIC_putByteOnBus((devAddr<<1)|0x00);
    OIIC_waitForResponse();
    OIIC_putByteOnBus(regAddr);
    OIIC_waitForResponse();
    OIIC_putByteOnBus((word>>8)&0xff);
    OIIC_waitForResponse();
    OIIC_putByteOnBus(word&0xff);
    OIIC_waitForResponse();
    OIIC_stop();
}
void OIIC_writeBytes(unsigned char devAddr,unsigned char regAddr,unsigned char *bytes,int length)
{
    int i;
    OIIC_start();
    OIIC_putByteOnBus((devAddr<<1)|0x00);
    OIIC_waitForResponse();
    OIIC_putByteOnBus(regAddr);
    OIIC_waitForResponse();
    for(i=0;i1)
    {    
        OIIC_putByteOnBus(bytes[i]);
        OIIC_waitForResponse();
    }
    OIIC_stop();
}
unsigned char OIIC_readByte(unsigned char devAddr,unsigned char regAddr)
{
    unsigned char byte;
    OIIC_start();
    OIIC_putByteOnBus((devAddr<<1)|0x00);
    OIIC_waitForResponse();
    OIIC_putByteOnBus(regAddr);
    OIIC_waitForResponse();
    OIIC_start();
    OIIC_putByteOnBus((devAddr<<1)|0x01);
    OIIC_waitForResponse();
    byte=OIIC_getByteOnBus();
    OIIC_noResponse();
    OIIC_stop();
    return byte;
}
unsigned int OIIC_readWord(unsigned char devAddr,unsigned char regAddr)
{
    unsigned int word=0;
    OIIC_start();
    OIIC_putByteOnBus((devAddr<<1)|0x00);
    OIIC_waitForResponse();
    OIIC_putByteOnBus(regAddr);
    OIIC_waitForResponse();
    OIIC_start();
    OIIC_putByteOnBus((devAddr<<1)|0x01);
    OIIC_waitForResponse();
    word=OIIC_getByteOnBus()<<8;
    OIIC_response();
    word|=OIIC_getByteOnBus();
    OIIC_noResponse();
    OIIC_stop();
    return word;
}
void OIIC_readBytes(unsigned char devAddr,unsigned char regAddr,unsigned char *bytes,int length)
{
    int i;
    OIIC_start();
    OIIC_putByteOnBus((devAddr<<1)|0x00);
    OIIC_waitForResponse();
    OIIC_putByteOnBus(regAddr);
    OIIC_waitForResponse();
    OIIC_start();
    OIIC_putByteOnBus((devAddr<<1)|0x01);
    OIIC_waitForResponse();
    for(i=0;i1)
    {
        bytes[i]=OIIC_getByteOnBus();
        if(i==length-1)
            OIIC_noResponse();
        else
            OIIC_response();
    }
    OIIC_stop();
}

备注:本博主致力于嵌入式开发,I2C协议,欢迎大神纠错!


你可能感兴趣的:(嵌入式)