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. [PWA] Keynote: Progressive Web Apps across all frameworks

    PWA: Add to home screen Angular Universal Server side rendering: for achieving better proference on ...

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

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

  3. css(字体,文本,边距,边框,阴影,背景,渐变,多重背景,列表)

    font-family 设置字体名称 可以使用多个名称,用逗号分隔,浏览器则按照先后顺序依次使用可用字体 p { font-family:'宋体','黑体','Arial'; } font-size ...

  4. cookie防篡改

    概述: 除了 session 外,一般不会在客户端的 cookies 里保存过于重要的凭据,但电商应用有时候不可避免地存储了一些敏感数据到客户端,当然不希望被篡改. 目的: 让服务器端能识别cooki ...

  5. OC - 27.CATransition

    概述 简介 CATransition又称转场动画,是CAAnimation的子类,可以直接使用 转场动画主要用于为图层提供移入/移出屏幕的动画效果 转场动画常见的应用是UINavigationCont ...

  6. JDK常用类_util

    集合 Collection:集合顶层接口 AbstractCollection:集合抽象类 关联数组 Map:顶层接口 AbstractMap:抽象类实现,提供了子类的通用操作 HashMap:哈希表 ...

  7. 明解C语言,练习13-3,从文件中读入个人信息,按身高排序后显示

    #include <stdio.h> #define NUMBER 6 #define F_PATH "D:\\C_C++\\ec13-3\\hw.dat" typed ...

  8. Python下调用json.dumps中文显示问题解决办法

    json.dumps在默认情况下,对于非ascii字符生成的是相对应的字符编码,而非原始字符,例如: import json js = json.loads('{"haha": & ...

  9. Mobile开发之meta篇

    Mobile开发之meta篇 <meta name="viewport" content="width=device-width, initial-scale=1, ...

  10. contos 安装jdk1.8

    JDK安装配置 查看centos系统32位还是64位, 使用命令uname -a;x86是386,586系列的统称,主要是指指令集合.X64才是cpu对64位计算的支持版本. 1. 下载jdk,本例使 ...