/********************************** I2C总线驱动 ********************************
模块名:I2C总线驱动 型号:I2C
功能描述:
        此模块包括发送数据及接收数据,应答位发送,并提供了几个直接面对器件的操作
    函数,能很方便的与用户程序进行连接并扩展。需要注意的是,函数是采用延时方法产
    生 SCL 脉冲,对高晶振频率要做一定的修改!!在写E2PROM的时候一定要延时!!!
说明:
    1us机器周期,晶振频率要小于12MHz
    返回 1 则操作成功,返回 0 则操作失败。
    sla 为器件从地址,suba 为器件子地址。
*******************************************************************************/
#include "AT89X52.h"
#include <intrins.h>
#define SomeNOP(); {_nop_();_nop_();_nop_();_nop_();_nop_();}    //定义空指令

sbit SDA = P1^;    //模拟I2C数据传输位
sbit SCL = P1^;    //模拟I2C时钟控制位
bit bdata I2C_Ack;    //应答标志位

/************************************ I2C_Start *********************************
函数名:void I2C_Start() 入口: 出口:
功能描述:启动I2C总线,即发送I2C初始条件
解释: 在I2C总线协议中规定的起始位格式是:在SCL高电平期间,SDA发生从高到低的电平跳变.它与其它数据格式的区别在于,协议中规定有效的数据必须在SCL的高电平期间保持不变,只有在SCL的低电平期间才能发生跳变.所以这一有别与其它格式的数据才能做为起始位.
调用函数:
全局变量:
*******************************************************************************/
void I2C_Start()
{
    SDA = ;    //发送起始条件的数据信号
    _Nop();
    SCL = ;
    SomeNOP();    //起始条件建立时间大于4.7us,延时
    SDA = ;    //发送起始信号
    SomeNOP();    //起始条件建立时间大于4us,延时
    SCL = ;    //钳住I2C总线准备发送或接收数据
    /******解释:I2C总线在空闲状态下都是被上拉为高电平的,所以当它们处于低电平时就表示忙的状态.***/
    _nop_();
    _nop_();
}

/************************************ I2C_Stop *********************************
函数名:void I2C_Stop() 入口: 出口:
功能描述:结束I2C总线,即发送I2C结束条件
解释:
    同起始条件的格式类似,结束条件的格式是在SCL高电平期间,SDA由低电平向高电平跳变.
调用函数:
全局变量:
*******************************************************************************/
void I2C_Stop()
{
    SDA = ;    //发送结束条件的数据信号
    _Nop();
    SCL = ;    //发送结束条件的时钟信号
    SomeNOP();    //结束条件建立时间大于4us,延时
    SDA = ;    //发送I2C总线结束信号
    SomeNOP();
}                                        

/************************************ I2C_CheckAck *****************************
函数名:bit I2C_CheckAck(void) 入口: 出口:0(无应答),1(有应答)
功能描述:
    检验I2C总线应答信号,有应答则返回1,否则返回0,超时值取255.
解释:
    I2C总线协议中规定传输的每个字节之后必须跟一个应答位,所以从器件在接收到每个
字节之后必须反馈一个应答信号给主控制器,而主控制器就需要检测从器件回传的应答信号,
根据其信息做出相应的处理.另外,主从之别是相对的,接收数据的即为从,发送数据的及为主.
再看看应答信号的格式:在由发送器产生的时钟响应周期里,发送器先释放SDA(置高),然后由
接受器将SDA拉低,并在这个时钟脉冲周期的高电平期间保持稳定的低电平.即表示从器件做
出了应答.
调用函数:void I2C_Stop()
全局变量:
*******************************************************************************/
bit I2C_CheckAck(void)
{
    uchar errtime = ; // 因故障接收方无 Ack,超时值为255
    SDA = ; //发送器先释放SDA
    SomeNOP();
    SCL = ;
    SomeNOP(); //时钟电平周期大于 4 us
    while(SDA) //判断SDA是否被拉低
    {
        errtime--;
        )
        {
            I2C_Stop();
            );
        }
    }
    SCL = ;
    _nop_();
    );
}

/************************************ I2C_SendB ********************************
函数名:void I2C_SendB(uchar c)
入口:uchar 型数据
出口:
功能描述:
    字节数据传送函数,将数据 c 发送出去,可以是地址,也可以是数据,发完后等待
应答,并对 此状态位进行操作
注意:
    在传送数据时,数据(SDA)的改变只能发生在SCL的低电平期间,在SCL的高电平期间保持不变
调用函数:bit I2C_CheckAck()
全局变量:I2C_Ack
*******************************************************************************/
void I2C_SendB(uchar c)
{
    uchar BitCnt;
    ; BitCnt<; BitCnt++) //要传送的数据长度为8位
    {
        if((c<<BitCnt)&0x80)    //判断发送位(从高位起发送)
        {
            SDA = ;
        }
        else
        {
            SDA = ;
        }
        _nop_();
        _nop_();
        SCL = ;                //置时钟线为高通知被控器开始接收数据位
        SomeNOP();                //保证时钟高电平周期大于 4us
        SCL = ;
    }
    _nop_();
    _nop_();
    I2C_Ack = I2C_CheckAck();    //检验应答信号,作为发送方,所以要检测接收器反馈的应答信号.
    _nop_();
    _nop_();
}

/************************************ I2C_RcvB *********************************
函数名:uchar I2C_RcvB()
入口:
出口:uchar型数据
功能描述:
    接收从器件传来的数据,并判断总线错误(不发应答信号),收完后需要调用应答函数。
调用函数:
全局变量:
*******************************************************************************/
uchar I2C_RcvB()
{
    uchar retc;
    uchar BitCnt; //位
    retc = ;
    SDA = ; //置数据总线为输入方式,作为接收方要释放SDA.
    ;BitCnt<;BitCnt++)
    {
        _nop_();
        SCL = ;            //置时钟线为低准备接收数据位
        SomeNOP();            //时钟低电平周期大于4.7us
        SCL = ;            //置时钟线为高使数据有效
        _nop_();
        _nop_();
        retc = retc<<; 

        )
        {
            retc = retc + ;//读数据位,接收的数据放入retc中
        }
        _nop_();
        _nop_();
    }
    SCL = ;
    _nop_();
    _nop_();
    return(retc);
}        

/************************************ I2C_Ackn *********************************
函数名:void I2C_Ackn(bit a)
入口:0或1
出口:
功能描述:
    主控制器进行应答信号(可以是应答或非应答信号)
说明:
    作为接收方的时候,必须根据当前自己的状态向发送器反馈应答信号
调用函数:
全局变量:
*******************************************************************************/
void I2C_Ackn(bit a)
{
    )        //在此发送应答或非应答信号
    {
        SDA = ;
    }
    else
    {
        SDA = ;
    }
    SomeNOP();
    SCL = ;
    SomeNOP();        //时钟电平周期大于 4 us
    SCL = ;        //清时钟线钳住I2C总线以便继续接收
    _nop_();
    _nop_();
}

/******************************** I2C_ISendB ***********************************
函数名:bit I2C_ISendB(uchar sla, uchar suba, uchar c)
入口:从器件地址 sla,子地址 suba, 发送字节 c
出口:0(操作有误),1(操作成功)
功能描述:
从启动总线到发送地址、数据,结束总线的全过程, 如果返回1,表示操作成功,否则操作有误。
调用函数:I2C_Start(),I2C_SendB(uchar c),I2C_Stop()
全局变量:I2C_Ack
*******************************************************************************/
bit I2C_ISendB(uchar sla, uchar suba, uchar c)
{
    I2C_Start();        //启动总线
    I2C_SendB(sla);        //发送器件地址
    if(!I2C_Ack)
    {
        );
    }
    I2C_SendB(suba);    //发送器件子地址
    if(!I2C_Ack)
    {
        );
    }
    I2C_SendB(c);        //发送数据
    if(!I2C_Ack)
    {
        );
    }                     

    I2C_Stop();            //结束总线
    );
}

/********************************** I2C_IRcvB **********************************
函数名:bit I2C_IRcvB(uchar sla, uchar suba, uchar *c)
入口:从器件地址 sla, 子地址 suba, 收到的数据在 c
出口:1(操作成功),0(操作有误)
功能描述:从启动总线到发送地址、读数据,结束总线的全过程。
调用函数: I2CS_tart(), I2C_SendB(uchar c), I2C_RcvB(), I2C_Ackn(bit a), I2C_Stop()
全局变量:I2C_Ack
创建者:陈曦
日期:2005-5-15
修改者:
日期:
*******************************************************************************/
bit I2C_IRcvB(uchar sla, uchar suba, uchar *c)
{
    I2C_Start();        //启动总线
    I2C_SendB(sla);
    if(!I2C_Ack)
    {
        );
    }
    I2C_SendB(suba);    //发送器件子地址
    if(!I2C_Ack)
    {
        );
    }
    I2C_Start();        //重复起始条件
    I2C_SendB(sla+);    //发送读操作的地址
    if(!I2C_Ack)
    {
        );
    }
    *c = I2C_RcvB();    //读取数据
    I2C_Ackn();        //发送非应答位
    I2C_Stop();            //结束总线
    );
}

C51单片机模拟I2C总线驱动程序设计的更多相关文章

  1. 51单片机模拟I2C总线的C语言实现

    电路原理图   EEPROM为ATMEL公司的AT24C01A.单片机为ATMEL公司的AT89C51. 软件说明 C语言为Franklin C V3.2.将源程序另存为testi2c.c,用命令 C ...

  2. 51单片机 | 基于I2C总线的秒表模拟应用

    ———————————————————————————————————————————— 参考地址: http://blog.csdn.net/junyeer/article/details/4648 ...

  3. i2c总线驱动,总线设备(适配器),从设备,从设备驱动的注册以及匹配

    常用链接 我的随笔 我的评论 我的参与 最新评论 我的标签 随笔分类 ARM裸机(13) C(8) C++(8) GNU-ARM汇编 Linux驱动(24) Linux应用编程(5) Makefile ...

  4. I2C总线驱动框架详解

    一.I2C子系统总体架构 1.三大组成部分 (1)I2C核心(i2c-core):I2C核心提供了I2C总线驱动(适配器)和设备驱动的注册.注销方法,I2C通信方法(”algorithm”)上层的,与 ...

  5. STM32F4XX中断方式通过IO模拟I2C总线Master模式

    STM32的I2C硬核为了规避NXP的知识产权,使得I2C用起来经常出问题,因此ST公司推出了CPAL库,CPAL库在中断方式工作下仅支持无子地址 的器件,无法做到中断方式完成读写大部分I2C器件.同 ...

  6. I2C裸机驱动程序设计

    ① I2C(Inter-Integrated Circuit)总线是由飞利浦公司开发的两线式串行总线,用于连接微控制器及其外围设备 ② I2C总线有两根双向信号线 (1)SDA:Serial Data ...

  7. gpio模拟I2C,驱动pcf8574T

    一.pcf8574T介绍 查看pcf8574T的数据手册, A表示读或写,当A为1的时候表示读,当A为0的时候表示写.现把地址控制线,即A2.A1.A0全部接地,可以得到读控制指令为0x41,写控制指 ...

  8. 利用C51单片机模拟SPI进行双机通信

    SPI协议简述 SPI,是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口.由Motorola首创.SPI接口主要应用在 EEPROM,FLASH,实时时 ...

  9. I2C总线完全版——I2C总线的结构、工作时序与模拟编程

    I2C总线的结构.工作时序与模拟编程 I2C总线的结构.工作时序与模拟编程I2C总线(Inter Integrated Circuit)是飞利浦公司于上个世纪80年代开发的一种"电路板级&q ...

随机推荐

  1. yii基础知识-

    控制器 是 CController 或其子类的实例.它在当用户请求时由应用创建. 当一个控制器运行时,它执行所请求的动作,动作通常会引入所必要的模型并渲染相应的视图. 动作 的最简形式,就是一个名字以 ...

  2. spring框架源码编译

    程序猿小菜一枚,最近从github上面下载下来一份spring各个项目的源码一份,但是弄了很长时间,因为网速和(fanqiang)的速度,希望大家不要再为这种无谓的时间花费时间,简单来说github上 ...

  3. 学艺不精,又被shell的管道给坑了

    我用过bash shell,而且时间不短了.但我从来没学过shell,至少没有像C++这么认真去学.平时写些基本的脚本没问题,不懂也可以google.百度.可在2014最后一天,掉坑里了. 其实脚本也 ...

  4. js 写table 函数

    //创建 table函数 function table(row,col,b,w) { document.write('<table border='+b+'>'); for(var i=0 ...

  5. Unity调试中心

    渐渐在公司接SDK3个月了,一直没有参加项目的游戏功能编写几乎快忘记Unity了, 看到那些前辈编写游戏到发布游戏,总结了下 每一个游戏应该有一个调试中心, 方便策划 测试更好的了解游戏和测试游戏. ...

  6. nonatomic,assign,copy,retain的区别

    nonatomic:非原子性访问,不加同步,多线程并发访问会提高性能.如果不加此属性,则默认是两个访问方法都为原子型事务访问.                    (atomic是Objc使用的一种 ...

  7. C#使用自定义字体(从文件获取)

    在进行软件开发,尤其是开发WinForm程序时,有时为了实现界面的美化,不可避免的需要使用一些特殊的字体,但是在开发完成之后,将程序移到其他的机器上时,由于这些机器可能没有安装相应的字体,所以整个界面 ...

  8. Linux安装中文man手冊

    1.下载中文包: http://pkgs.fedoraproject.org/repo/pkgs/man-pages-zh-CN/manpages-zh-1.5.1.tar.gz/13275fd039 ...

  9. css3 在线编辑工具 连兼容都写好了

    http://www.css3maker.com/index.html

  10. ASP.NET网站与ASP.NET应用程序的区别

    我们使用VS做ASP.NET的时候,可以选择新建ASP.NET应用程序,同时也可以新建ASP.NET网站,两者有什么具体区别呢?今天真是很幸运,比别人多上了老师一节课,讲的是这两者之间的一些区别.我学 ...