I2C转UART,51单片机普通IO口模拟I2C从机,解决UART不够的问题

/***************************************************************************
*    程序名:iic_uart.C
*    作者:
*    功能描述:实现IIC和UART数据交换
*    日期:2010.9.16   10.8最后修改
***************************************************************************/

#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define LOC_address 0x48

sfr  AUXR = 0x8e;                //定时器倍率选择寄存器    10.17  

sbit scl = P1^;                //P1^3
sbit sda = P1^;                //旧P1^4
sbit STROBE = P1^;                //P1^6
sbit disp_led = P1^;            //P3^7

void I2C_txbyte(uchar );
void uart_init(void );
void I2C_init(void );
void TIMER0_init(void );
void I2C_delay(void );
void I2C_respon(void );
uchar I2C_rxbyte(void );

void I2C_ack();
void start_scan();
void I2C_rxadd();
uchar I2C_rx7();
void uart_txbyte(uchar );

uchar xdata dat_I2C[] ,dat_UART[];    //10.16修改缓存大小 

uchar    num = ,
        RX_flag = ,
        NN, m = ,n = ,
        TX_over = ;
uchar     address = ,
        rx_data,
        START_flag = ,
        STOP_flag = ,
        PreState,
        NowState,
        DEV_address,
        R_W,
        uart_outtime=,
        I2C_rx_outtime=,
        TIME_MODE=;

/***************************************************************************
*    函数名:main()
*    功能描述:主程序
*
***************************************************************************/
void main()
{
    uart_init();                                        //串口中断初始化
    TIMER0_init();                                        //定时器0初始化
    STROBE = ;                                            //请求接受信号线初始化
    disp_led = ;                                        //指示灯初始化  1=熄灭  0=点亮  

    )
    {

        )                                //在接收数据吗?
        {

            )                        //等待数据超过0.5 秒了吗
            {

                TR0 = ;                                //关定时器0
                uart_outtime = ;                        //UART等待计时清零
                STROBE = ;                                //请求I2C上位机读数据
                RX_flag = ;                            //清计时标志 

                TIME_MODE = ;                            //进入等待I2C读取计时模式 ,超过4S清空数据
                TR0 = ;                                //开计时器0 ,10.17 

            }
        }

        start_scan();                                    //检测起始信号 

        )
        {

            START_flag = ;                                //开始信号清零 

            I2C_rxadd();                                //收取地址及命令
            if(DEV_address == LOC_address)                //判断是否为本机地址
            {

                );                        //给予应答 

                m = ;                                    //初始化m 

                )                            //主机向本机写数据
                {
                     STROBE = (~STROBE);                    //通知主机收到起始信号      10.13  

                    dat_I2C[m] = I2C_rxbyte();            //接收第一个字节     

                    );                    //等待低电平结束
                    STROBE = (~STROBE);                    //10.7添加
                    );
                    m++;
                    );

                    PreState = sda;                        //记录SDA状态
                    )
                    {
                        )                    //在SCL为高端平期间检测结束信号
                        {

                            NowState = sda;                //记录当前SDA状态
                            )            //上升沿说明收到结束信号
                            {
                                STOP_flag = ;            //收到结束信号 

                            }
                        }
                        else
                        {

                            dat_I2C[m] = I2C_rx7();        //继续接收剩下的7位数据
                            );
                            );
                            m++;
                            );
                        }
                    }

                    STOP_flag = ;

                     ;NN < m ;NN++)
                    {
                        uart_txbyte(dat_I2C[NN]);        //将收到的数据通过UART发送给上位机
                    }
                    m=;

                }
                )                        //主机向本机读数据
                {
                    TR0 = ;                            //关掉计时器 10 .17 

                    STROBE = (~STROBE);                    //通知主机收到起始信号      10.13              

                    );

                    I2C_txbyte(dat_UART[m]);
                    m++;
                    if(m == n)                            //如果数被读取完则通知上位机停止读
                    {
                        STROBE = ;
                    }
                    );
                    );

                    )
                    {
                        I2C_txbyte(dat_UART[m]);        //将从UART接收到的数据通过I2C发送给主设备
                        m++;
                        if(m == n)                        //判断是否发送完了
                        {
                            STROBE = ;
                        }
                        );                //等待低电平结束
                        );

                    }
                    );                

                    STROBE = ;
                    m = ;
                    n = ;

                    disp_led = ;                        //读走后将灯熄灭 

                    num = ;                            //清计时参数     10.17
                    TIME_MODE = ;                        //改回UART接收数据超时计时模式
                }
            }
        }
    }
}

/***************************************************************************
*    函数名:start_scan()
*    功能描述:起始信号检测子函数
*
***************************************************************************/
void start_scan()
{
    NN = ;
    PreState = sda;                                        //记录当前SDA状态,用作比较
     && NN--)
    {
        NowState = sda;
         && NowState == )                //如果为上升沿则为开始信号
        {
            START_flag = ;
        }
    }
}

/***************************************************************************
*    函数名:uart_init
*    功能描述:串口中断初始化子函数
*
***************************************************************************/
void uart_init()
{
    AUXR = 0x40;                                          //T1为1T工作模式 

    TMOD = 0x21;                                        //T1工作模式2
    TH1 = 0xf7;                                            //装填初值 .波特率为38400
    TL1 = 0xf7;                                            //f7
    TR1 = ;                                            //启动定时1
    SM0 = ;                                            //确定10位传输
    SM1 = ;
    REN = ;                                            //打开允许接收
    ES = ;                                                //开总中断和串口中断
    EA = ;
} 

/***************************************************************************
*    函数名:TIMER0_init()
*    功能描述:定时器0初始化子函数
*
***************************************************************************/
void TIMER0_init()
{
    TH0 = ( - ) / ;                        //装初值
    TL0 = ( - ) % ;
    ET0 = ;                                            //开定时器中断允许
}

/***************************************************************************
*    函数名:uart_service()
*    功能描述:UART中断服务程序
*
***************************************************************************/

{

    dat_UART[n] = SBUF;                                    //存收到的数据
    n++;
    TR0 = ;                                            //开定时器0 ,开始等待计时
    RX_flag = ;                                        //接收到数据标志,开始检测是否等待超时
    uart_outtime = ;                                    //等待超时计数清零
    RI = ;                                                //中断接收溢出标志位清零
}

/***************************************************************************
*    函数名:uart_txbyte()
*    功能描述:UART发送一个字节
*
***************************************************************************/
void uart_txbyte(uchar data1)
{
    ES = ;                                                //关串口中断
    SBUF = data1;                                        //发送数据
    while( ! TI);                                        //等待发送完毕
    TI = ;                                                //清溢出标志
    ES = ;
}

/***************************************************************************
*    函数名:timer0{}
*    功能描述:定时器0中断服务程序,用来计算UART是否等待超时
*
***************************************************************************/

{
    TH0 = ( - ) / ;                              //给定时器0装初值  50ms中断一次
    TL0 = ( - ) % ;
    num++;
    )                                        //用于UART接收数据超时计时
    {
        disp_led = ~disp_led;                                //显示灯闪     

        )                                        //等待超过0.5秒到了
        {
            uart_outtime = uart_outtime + ;                //等待超时计数加一
            num = ;

        }

    }
    )                                    //用于I2C读走数据超时计时     10.17
    {
        disp_led = ;                                        //灯常亮,等待读走 

        )                                        //超过2秒未读走
        {
            num = ;                                        //清计时参数
            STROBE = ;                                        //不通知I2C读取
            n = ;                                            //数据缓存下标清零 ,准备接收新数据
            TIME_MODE = ;                                    //改回UART接收数据超时计时模式  

            disp_led = ;                                    //超时未读走则熄灭
            TR0 = ;                                        //关定时器0
        }

    }

}

/***************************************************************************
*    函数名:I2C_txbyte()
*    功能描述:I2C发送一个字节
*
***************************************************************************/
void I2C_txbyte(uchar dat_byte)
{
    uchar i,temp;
    temp = dat_byte;
    );
    );                                    //等待主机释放数据总线
     ;i <  ;i++)                                //从最高位开始,依次发送8位
    {
        temp = temp << ;                                 //将要发送的数最高位移到CY中
        sda = CY;                                        //数据线发送CY中存的位数据
        );
        );
    }
    sda = ;                                             //发完释放数据总线
}

/***************************************************************************
*    函数名:I2C_rxadd()
*    功能描述:接收设备地址
*
***************************************************************************/
void I2C_rxadd()
{
    uchar i,j,k=;
    );
     ;i <  ;i++)
    {
        while( ! scl);                                    //等待SCL由0变为1
        )
            j = ;
        else
            j = ;
        k=(k << ) | j;                                    //将收到的位放入K中
        );                                //SCL高电平时等待
    }
    R_W=k&0x01;                                            //主机是读还是写
    DEV_address= (k >> ) & 0x7f;                        //求出前7位的设备地址
}

/***************************************************************************
*    函数名:I2C_rxbyte()
*    功能描述:I2C接收一个字节子函数
*
***************************************************************************/
uchar I2C_rxbyte()
{
    uchar i,j,k=;
    );                                    //等待SCL拉低
     ;i <  ;i++)
    {
        while( ! scl);                                    //等待SCL由0变为1
        )
            j = ;
        else
            j = ;
        k=(k << ) | j;
        while(scl);                                        //SCL高电平时等待
    }
    return(k);                                            //将接收到的数据返回
}

/***************************************************************************
*    函数名:I2C_rx7()
*    功能描述:检测结束信号时收数据子函数
*
***************************************************************************/
uchar I2C_rx7()
{
    uchar i,j,k=;
    k=(k << ) | PreState;                                //将上一个位数据存入K中
     ;i <  ;i++)
    {
        );                                //等待SCL变高
        )
            j = ;
        else
            j = ;
        k=(k << ) | j;                                    //将收到的位数据存入K
        );                                //等待SCL拉低
    }
    return(k);                                            //将收到的整个字节数据返回  

}

测试代码如下:

/***************************************************************************
*    程序名:test.c
*    作者:
*    功能描述:测试I2C_uart 转接器
*    日期:2010.10.8
***************************************************************************/
#include<reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char

sbit sda = P2^;                                  //定义数据线
sbit scl = P2^;                                //定义时钟线
sbit STROBE = P2^;                                //定义信号线 

,                                        //读数据缓存数组下标
    tx = ,
    rx_flag=;

uchar dat[];                                    //定义缓存数据数组 

void delay(unsigned int i)                        //延时程序 ,延时约i ms
{
    uint j,k;
     ;j--)
         ;k >  ;k--);
}

void flash()                                    //I2C所需时序延时  5us
{  ;  ; }

/***************************************************************************
*    程序名:start()
*    功能: I2C起始信号
*
***************************************************************************/
void start()                                    //启动I2C总线
{
    sda = ;
    flash();
    scl = ;
    flash();
    sda = ;
    flash();
    scl = ;
    flash();
}

/***************************************************************************
*    程序名: stop()
*    功能: I2C结束信号
*
***************************************************************************/
void stop()                                     //停止I2C总线
{
    sda = ;
    flash();
    scl = ;
    flash();
    sda = ;
    flash();
}

/***************************************************************************
*    程序名: writex (uchar j )
*    功能: I2C写一个字节子函数
*
***************************************************************************/
void writex(unsigned char j)
{
    unsigned char i,temp;
    temp = j;
        ;i <  ;i++)
      {
        temp = temp << ;
        scl = ;
        flash();
        sda = CY;                                 //将进位寄存器中的数赋给数据线
        flash();
        scl = ;
        flash();
    }
       scl = ;
    flash();
    sda = ;                                     //释放数据线
    flash();

}

/***************************************************************************
*    程序名: readx()
*    功能: I2C读一个字节子函数
*
***************************************************************************/
unsigned char readx()
{
       unsigned ;
       scl = ;
    flash();
    sda = ;                                    //释放数据线 

     ;i <  ;i++)
    {
        flash();
        scl = ;
        flash();
          )
            j = ;
        else
            j = ;
          k=(k << ) | j;
          scl = ;
    }
       flash();
    return(k);
}

/***************************************************************************
*    程序名: clock()
*    功能: I2C等待应答子函数
*
***************************************************************************/
void clock()
{
       unsigned ;

    scl=;
    flash();

    ) && (i < ))            //SDA=0时说明有应答,无应答则等待直到超时
    {
        i++;
       }

    scl = ;
    flash();
}

/***************************************************************************
*    程序名: IIC_read()
*    功能: I2C读数据
*
***************************************************************************/
void IIC_read()                                    //通过I2C读数据
{
    )                            //当STROBE=0则一直发送起始信号及首地址 ,直到转接器收到 ,将STROBE变为1
    {
        P1=;                                    //灯亮,作测试用 

        start();
        writex(0x91);                            //发器件地址和读指令
        clock();
    }    

    )                            //读取数据直到读完  ,转接器会将STROBE拉低以通知发送完毕
    {

        dat[m] = readx();                        //将读到的数据存入缓存数组中
        m++;                                     //缓存数组下标向下移一位
        clock();
    }        

    stop();                                        //发送结束信号     

}

/***************************************************************************
*    程序名: IIC_write(uchar info)
*    功能:通过I2C将一个字节数据发给转接器
*
***************************************************************************/
void IIC_write(uchar info)
{

    )                                //在STROBE=1时写数据 ,即无读请求时
    {
        )
        {
               start();
            writex(0x90);                    //10.13号修改,将首地址放到WHILE外
            clock();
        }

        writex(info);                            //写数据
        clock();
        stop();
     }
    else                                        //在STROBE=0时写数据 ,此时有读请求
    {
        )
        {
               start();
            writex(0x90);
            clock();
        }

        writex(info);                            //写数据
        clock();
        stop();
    }

}

/***************************************************************************
*    程序名: main()
*    功能: 程序主函数
*
***************************************************************************/
void main()
{                        

    scl = ;
    delay();                                    //初始化I2C
    sda = ;
    delay();

    )
       {

        )                            //读请求
        {
        //    IIC_write('g');
        //    IIC_write('e');
        //    IIC_write('t');                        //测试用
        //    IIC_write(':');

            IIC_read();                            //读数据
            delay();                            //稍作延时,约1毫秒  ,紧随读数据之后                  

            rx_flag = ;                        //读取到数据标志置1
            P1=dat[];                            //10.8,作测试用
        }

        )                        //读到数据了吗?
        {
            rx_flag = ;

             ;tx < m ;tx++)            //将收到的数据返回
            {
                IIC_write(dat[tx]);
            }
            m = ;                                //将数据缓存下标清零
        }
    }

}

I2C转UART的更多相关文章

  1. SPI、I2C、UART(转)

    UART与USART(转) UART需要固定的波特率,就是说两位数据的间隔要相等. UART总线是异步串口,一般由波特率产生器(产生的波特率等于传输波特率的16倍).UART接收器.UART发送器组成 ...

  2. SPI、I2C、UART、I2S、GPIO、SDIO、CAN 简介

    转自http://sanwen.net/a/fmxnjoo.html SPI.I2C.UART.I2S.GPIO.SDIO.CAN,看这篇就够了 总线 总线,总要陷进里面.这世界上的信号都一样,但是总 ...

  3. SPI、I2C、UART三种串行总线协议的区别和SPI接口介绍(转)

    SPI.I2C.UART三种串行总线协议的区别 第一个区别当然是名字: SPI(Serial Peripheral Interface:串行外设接口); I2C(INTER IC BUS) UART( ...

  4. SPI、I2C、UART、I2S、GPIO、SDIO、CAN

    总线,总线,总要陷进里面.这世界上的信号都一样,但是总线却成千上万,让人头疼. 总的来说,总线有三种:内部总线.系统总线和外部总线.内部总线是微机内部各外围芯片与处理器之间的总线,用于芯片一级的互连: ...

  5. 串行总线 —— I2C、UART、SPI

    I2C,也叫 IIC,是一种常见的串行总线,它只需要两根线即可在连接于总线上的器件之间传送信息. 0. 电气知识 开漏输出:Open drain output,不输出电压,低电平时接地,高电平时不接地 ...

  6. I2S/PCM/IOM-2、I2C/SPI/UART/GPIO/slimbus

    概述 I2S,PCM,IOM-2都是数字音频接口,传数据的. I2C,SPI,UART,GPIO是控制接口,传控制信令的. I2S I2S(Inter-IC Sound Bus)是飞利浦公司为数字音频 ...

  7. SPI、I2C、UART三种串行总线协议的区别

    第一个区别当然是名字: SPI(Serial Peripheral Interface:串行外设接口); I2C(INTER IC BUS) UART(Universal Asynchronous R ...

  8. UART,USART,SPI,I2C等总线的介绍与区别20160526

    首先来说一下UART和USART的区别: 1.字面意义: UART:universal asynchronous receiver and transmitter通用异步收发器: USART:univ ...

  9. SPI,UART,I2C都有什么区别,及其各自的特点

    区别: SPI:高速同步串行口.3-4线接口,收发独立.可同步进行 UART:通用异步串行口.按照标准波特率完成双向通讯,速度慢 I2C:一种串行传输方式,三线制,网上可找到其通信协议和用法的 3根线 ...

随机推荐

  1. clock_gettime测代码运行时间

    //函数原型: // long clock_gettime (clockid_t which_clock, struct timespec *tp); //参数列表: // CLOCK_REALTIM ...

  2. Android自己定义控件而且使其能够在xml中自己定义属性

    为什么要自己定义View android开发中自己定义View的优点是显而易见的.比方说以下的这个顶部导航,它被设计出如今应用的每一个界面,但每次的内容却不尽同样.我们不能在每一个layout资源中都 ...

  3. android 06 LinearLayout

    xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:la ...

  4. 走进 Facebook POP 的世界

    POP: 一个流行的可扩展的动画引擎iOS,它支持spring和衰变动态动画,使其可用于构建现实,基于物理交互.Objective - C API允许快速集成, 对于所有的动画和过渡他是成熟的. 解释 ...

  5. ckeditor 敏感词标记显示处理方法

    直接在原型添加方法: (function () { /* * 取消所有高亮 */ CKEDITOR.editor.prototype.CancleSensitiveWordsHighlight = f ...

  6. 他们都没告诉你适配 Android N 需要注意什么

    还记得 6.0 对 Apache Http 库的废除导致的应用崩溃吗?还记得 6.0 中 MAC id 始终返回为空导致的唯一 id 混合生成算法大幅失效吗? 1. Android 中 Java 的实 ...

  7. Driving the Activity Lifecycle

    Before Robolectric 2.2, most tests created Activities by calling constructors directly, (new MyActiv ...

  8. hadoop集群环境搭建之zookeeper集群的安装部署

    关于hadoop集群搭建有一些准备工作要做,具体请参照hadoop集群环境搭建准备工作 (我成功的按照这个步骤部署成功了,经实际验证,该方法可行) 一.安装zookeeper 1 将zookeeper ...

  9. 自己写的自动生成动态边框的jquery小插件

    思路就是在元素四周添加<ul>列表,然后周期性地改变它的颜色,实现动态的效果,不支持ie7.ie8 预览链接http://gorey.sinaapp.com/myBorder/border ...

  10. 关于c++中的引用

    引用是个别名. 1.引用是否占用空间 引用是否占用空间,此处是指广义上的占用内存空间,即为该对象新开辟一块内存.这个需要分不同的情况. 首先看一下常引用(const 引用). 这里关于常引用在c++  ...