Chinaunix首页 | 论坛 | 博客
  • 博客访问: 631851
  • 博文数量: 1008
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 5175
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-31 09:44
文章分类
文章存档

2012年(1008)

我的朋友

分类:

2012-08-01 11:03:39

/**

 * 模拟I2C总线内核驱动程序

 * 运行平台:CPU->9G45(ARM9) 系统:Linux

 * Lzy 2012-12-25

 */

#include

#include

#include

#include

#include "IIC.h"

 

/******************************9G45管脚控制部分****************************************/

/**

 * 功能:改变SDA引脚输入输出的状态

 * 输入:state-> 0:输出  1:输入

 */

static void setsda_dir(int state)

{

    if (state)

        at91_set_gpio_input(I2C_SDA, 0);

    else

        at91_set_gpio_output(I2C_SDA, 0);

}

 

/**

 * 功能:SDA引脚输出高低电平

 * 输入:state-> 1:高电平 0:低电平

 */

static void setsda_val(int state)

{

    at91_set_gpio_value(I2C_SDA, state);

}

 

/**

 * 功能:获取sda引脚电平

 */

static int getsda(void)

{

    return at91_get_gpio_value(I2C_SDA);

}

 

 

/**

 * 功能:改变SCL引脚输入输出的状态

 * 输入:state-> 0:输出  1:输入

 */

void setscl_dir(int state)

{

    if (state)

        at91_set_gpio_input(I2C_SCL, 0);

    else

        at91_set_gpio_output(I2C_SCL, 0);

}

 

/**

 * 功能:SCL引脚输出高低电平

 * 输入:state-> 1:高电平 0:低电平

 */

static void setscl_val(int state)

{

    at91_set_gpio_value(I2C_SCL, state);

}

 

/**

 * 功能:获取scl引脚电平

 */

static int getscl(void *data)

{

    return at91_get_gpio_value(I2C_SCL);

}

 

/******************************IIC驱动程序部分**************************************/

/*

*函数:I2C_Init()

*功能:I2C 总线初始化,使总线处于空闲状态

*说明:在 开始处,通常应当要执行一次本函数

*/

void I2C_Init(void)

{

    setscl_val(H);        /* 输出为高电平 */

    I2C_Delay();

  

    setsda_dir(OUT);

    setsda_val(H);

    I2C_Delay();

}

 

/**

 * 函数:I2C_Start()

 * 功能:产生I2C 总线的起始状态

 * 说明:

 *  SCL处于高电平期间,当SDA 出现下降沿时启动I2C 总线

 *  不论 SDA SCL 处于什么电平状态,本函数总能正确产生起始状态

 *  本函数也可以用来产生重复起始状态

 *  本函数执行后,I2C 总线处于忙状态

 */

void I2C_Start(void)

{

    I2C_Init();       /* 初始化I2C引脚 */

  

    setsda_val(L);    /* 产生开始信号 */

    I2C_Delay();

    setscl_val(L);

    I2C_Delay();

}

 

/**

 * 函数:I2C_Write()

 * 功能:向I2C 总线写1 个字节的数据

 * 参数:

 *      dat:要写到总线上的数据

 */

void I2C_Write(char dat)

{

    unsigned char t = 8;

 

    setsda_dir(OUT);      /* SDA设置为输出模式 */

    do

    {

        if(dat & 0x80)

            setsda_val(H);

        else

            setsda_val(L);      

        dat <<= 1;

        udelay(1);

        setscl_val(H);

        I2C_Delay();

        setscl_val(L);

        I2C_Delay();

    } while ( --t != 0 );

}

 

/**

 * 函数:I2C_Read()

 * 功能:从从机读取1 个字节的数据

 * 返回:读取的一个字节数据

 */

char I2C_Read(void)

{

    char dat;

    unsigned char t = 8;

  

    setsda_dir(IN);           /* SDA设置为输入模式 */ 

    udelay(1);

      

    do

    {

        setscl_val(H);

        I2C_Delay();

      

        setscl_val(L);

        I2C_Delay();

      

        dat <<= 1;

        if ( getsda() )

            dat |= 0x01;

 

       udelay(1);

    } while ( --t != 0 );

  

    return dat;

}

 

/**

 * 函数:I2C_GetAck()

 * 功能:读取从机应答位

 * 返回:

 *      0:从机应答

 *      1:从机非应答

 * 说明:

 *      从机在收到每个字节的数据后,要产生应答位

 *      从机在收到最后 1 个字节的数据后,一般要产生非应答位

 */

char I2C_GetAck(void)

{

    char ack = 1;

    I2C_Init();

  

    setsda_dir(IN);       /* SDA设置为输入模式 */

    udelay(2);

  

    ack = getsda();       /* 获得应答信号 */

  

    setscl_val(L);

    I2C_Delay();

  

    return ack;

}

 

/**

 * 函数:I2C_PutAck()

 * 功能:主机产生应答位或非应答位

 * 参数:

 *      ack=0:主机产生应答位

 *      ack=1:主机产生非应答位

 * 说明:

 *      主机在接收完每一个字节的数据后,都应当产生应答位

 *      主机在接收完最后一个字节的数据后,应当产生非应答位

 */

void I2C_PutAck(char ack)

{

    setsda_dir(OUT);      /* SDA设置为输出模式 */ 

    udelay(1);

  

    if(ack)

        setsda_val(H);

    else

        setsda_val(L);

    I2C_Delay();

  

    setscl_val(H);

    I2C_Delay();

    setscl_val(L);

    I2C_Delay();

}

 

/**

 * 函数:I2C_Stop()

 * 功能:产生I2C 总线的停止状态

 * 说明:

 *      SCL处于高电平期间,当SDA 出现上升沿时停止I2C 总线

 *      不论 SDA SCL 处于什么电平状态,本函数总能正确产生停止状态

 *      本函数执行后,I2C 总线处于空闲状态

 */

void I2C_Stop(void)

{ 

    setsda_dir(OUT);      /* SDA设置为输出模式 */ 

  

    setsda_val(L);

    I2C_Delay();

    setscl_val(H);

    I2C_Delay();

    setsda_val(H);

    I2C_Delay();

    udelay(I2C_STOP_WAIT_VALUE);    //在下一次产生Start 之前,要加一定的延时

}

 

/**

 * 函数:I2C_Puts()

 * 功能:I2C 总线综合发送函数,向从机发送多个字节的数据

 * 参数:

 *     SlaveAddr:从机地址(7 位纯地址,不含读写位)

 *     SubAddr:从机的子地址

 *      SubMod:子地址模式,0-无子地址,1-单字节子地址,2-双字节子地址

 *      *dat:要发送的数据

 *      Size:数据的字节数

 * 返回:

 *      0:发送成功

 *      1:在发送过程中出现异常

 * 说明:

 *     本函数能够很好地适应所有常见的 I2C 器件,不论其是否有子地址

 *      当从机没有子地址时,参数 SubAddr 任意,而SubMod 应当为0

 */

 int I2C_Puts(unsigned char SlaveAddr, unsigned int SubAddr,

             unsigned char SubMod, char *dat, unsigned int Size)

{

    //定义临时变量

    unsigned char i;

    char a[3];

  

    //检查长度

    if ( Size == 0 ) return 0;

    //准备从机地址

    a[0] = (SlaveAddr << 1);

    //检查子地址模式

    if ( SubMod > 2 ) SubMod = 2;

  

    //确定子地址

    switch ( SubMod )

    {

    case 0:

        break;

    case 1:

        a[1] = (char)(SubAddr);

        break;

    case 2:

        a[1] = (char)(SubAddr >> 8);

        a[2] = (char)(SubAddr);

        break;

    default:

        break;

    }

  

    //发送从机地址,接着发送子地址(如果有子地址的话)

    SubMod++;

    I2C_Start();

    for ( i=0; i<SubMod; i++ )

    {

        I2C_Write(a[i]);

        if ( I2C_GetAck() )

        {

            I2C_Stop();

            return 1;

        }

    }

  

    //发送数据

   do

    {

        I2C_Write(*dat++);

        if ( I2C_GetAck() )

            break;

    } while ( --Size != 0 );

  

    //发送完毕,停止I2C 总线,并返回结果

    I2C_Stop();

    if ( Size == 0 )

    {

        return 0;

    }

    else

    {

        return 1;

    } 

}

 

/**

 * 函数:I2C_Gets()

 * 功能:I2C 总线综合接收函数,从从机接收多个字节的数据

 * 参数:

 *      SlaveAddr:从机地址(7 位纯地址,不含读写位)

 *      SubAddr:从机的子地址

 *      SubMod:子地址模式,0-无子地址,1-单字节子地址,2-双字节子地址

 *      *dat:保存接收到的数据

 *      Size:数据的字节数

 * 返回:

 *      0:接收成功

 *      1:在接收过程中出现异常

 * 说明:

 *      本函数能够很好地适应所有常见的 I2C 器件,不论其是否有子地址

 *      当从机没有子地址时,参数 SubAddr 任意,而SubMod 应当为0

 */

int I2C_Gets(unsigned char SlaveAddr, unsigned int SubAddr,

             unsigned char SubMod, char *dat, unsigned int Size)

{

    //定义临时变量

    unsigned char i;

    char a[3];

  

    //检查长度

    if ( Size == 0 ) return 0;

    //准备从机地址

    a[0] = (SlaveAddr << 1);

    //检查子地址模式

    if ( SubMod > 2 ) SubMod = 2;

  

    //如果是有子地址的从机,则要先发送从机地址和子地址

    if ( SubMod != 0 )

    {

        //确定子地址

        if ( SubMod == 1 )

        {

            a[1] = (char)(SubAddr);

        }

        else

        {

            a[1] = (char)(SubAddr >> 8);

            a[2] = (char)(SubAddr);

        }

        //发送从机地址,接着发送子地址

      

        SubMod++;

        I2C_Start();

        for ( i=0; i<SubMod; i++ )

        {

            I2C_Write(a[i]);

            if ( I2C_GetAck() )

            {

                I2C_Stop();

                return 1;

            }

        }

    }

  

    //这里的I2C_Start()对于有子地址的从机是重复起始状态

    //对于无子地址的从机则是正常的起始状态

    I2C_Start();

  

    I2C_Write(a[0]+1);       //发送从机地址 读

    if ( I2C_GetAck() )

    {

        I2C_Stop();

        return 1;

    }

  

    //接收数据

 

   for (;;)

    {

        *dat++ = I2C_Read();

 

       if ( --Size == 0 )

        {

            I2C_PutAck(1);

            break;

        }

        I2C_PutAck(0);

    }

    //接收完毕,停止I2C 总线,并返回结果

    I2C_Stop();

    return 0;

}

源码: IIC.rar   


阅读(192) | 评论(0) | 转发(0) |
0

上一篇:ZLG7290的9G45驱动程序

下一篇:9G45 - IIC驱动

给主人留下些什么吧!~~