⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iic_analog.c

📁 AT89C51系列单片机模拟i2C驱动完整源码
💻 C
字号:
/*************************************************************************\
**  filename:   iic.c
**   author:    rui
**   creat date:2008/05/01
**   version:   1.0
**   modify record:
*************************************************************************/
#include "iic.h"

/****************type define*************************/
typedef unsigned char       u_char;
enum {
    FALSE,
    TRUE,
    ILLEGAL
};

/***************macro define*************************/
#define WAIT_SLAVE(time)    {while((time-- > 0) && (!SCL));}    //wait slave device
#define WRADDR(svnbits_addr)  ((svnbits_addr << 1) & 0xfe)
#define RDADDR(svnbits_addr)  ((svnbits_addr << 1) | 0x01)

/************************iic driver**************************************/
/**
 * notice: you should ensure:
 *     1. setup time of start and stop 
 *     2. setup time of data
 *     3. bus free time between two operations
 *
 * so, always, it must have delay before "scl = 1", it needn't to delay after "scl = 0" 
 * because hold time can be zero.
 *
 * you should be warn when bus control right will be changed.
 *
 **/


static void start()
{
    SCL = 1;
    SDA = 1;
    delay_5us();
    SDA = 0;
    delay_5us();
    SCL = 0;
        
}

static void send_one_byte(u_char content)
{
    u_char msb, cnt,tmp;

    cnt = 8;
    while (cnt > 0)
    {
        msb = (content & 0x80);
        SDA = ((msb == 0x80) ? 1 : 0); //send from msb to lsb
        delay_5us();                                 //setup time of data
        SCL = 1;
        tmp = 100;
        WAIT_SLAVE(tmp);
        delay_5us();
        SCL = 0;
        
        content = (content << 1);
        cnt--;
    }
    SDA = 1;                                   //give the right of bus control to slave device 
}

static u_char wait_ack()
{
    u_char cnt;

    cnt = 100;
    delay_5us();
    SCL = 1;
    WAIT_SLAVE(cnt);
    delay_5us();

    if (SCL != 1)
        return ILLEGAL;

    if (SDA == 0)
    {
        SCL = 0;
        return TRUE;
    }
    else
    {
        SCL = 0;
        return FALSE;
    }
    
}

static u_char receive_one_byte()
{
    u_char rcv_content, cnt, tmp;

    cnt = 8;
    rcv_content = 0;
    while (cnt > 0)
    {
        delay_5us();     //setup time of data
        SCL = 1;
        tmp = 100;
        WAIT_SLAVE(tmp);
        delay_5us();
        rcv_content <<= 1;
        rcv_content |= ((SDA == 1) ? 0x01 : 0x00);     //rcv from msb to lsb
        SCL = 0;

        cnt--;
    }
    return rcv_content;
}

static void send_ack()
{
    SDA = 0;
    delay_5us();
    SCL = 1;
    delay_5us();
    SCL = 0;
    SDA = 1;       //release data line  for slave device to use   
}

static void send_nack()
{
    SDA = 1;
    delay_5us();
    SCL = 1;
    delay_5us();
    SCL = 0;
}

static void stop()
{
    SDA = 0;
    delay_5us();
    SCL = 1;
    delay_5us();         //setup time of stop
    SDA = 1;
    delay_5us();         //ensure free time of bus > 4.7us between operation on iic twice
    
}


/*****************iic bus level driver*******************************/
static u_char send_data_to_iic(u_char num, u_char *piicdata, u_char flag_start, u_char flag_stop)
{

    if (TRUE == flag_start)
    {
        start();
    }
    while (num > 0)
    {
        send_one_byte(*piicdata);
        if (TRUE != wait_ack() )
        {
            stop();
            return FALSE;
        }
        else
        {
            piicdata++;
            num--;
        }
    }
    
    if (TRUE == flag_stop)
        stop();
    
    return TRUE;
}

static void receive_data_from_iic(u_char num, u_char *paddr_data_save)
{
    while (num > 1)
    {
        *paddr_data_save = receive_one_byte();
        send_ack();
        paddr_data_save++;
        num--;
    }
    
    *paddr_data_save = receive_one_byte();
    send_nack();
    stop();

}


/***************************device level driver*******************/
u_char write_device_by_iic0(u_char svnbits_dev_addr, u_char *reg_addr, u_char num_addr, u_char *pcontent, u_char num_data)
{
    u_char tmp;
    u_char addr[3];


    addr[0] = (svnbits_dev_addr << 1) & 0xfe;
    addr[1] = *reg_addr;
    addr[2] = *(reg_addr + 1);

    if (2 == num_addr)
    {
        tmp = send_data_to_iic(3, (u_char *)addr, TRUE, FALSE); //send device address & register address
    }
    else if (1 == num_addr)
    {
        tmp = send_data_to_iic(2, (u_char *)addr, TRUE, FALSE);

    }
    else
    {
        return FALSE;
    }

    if (FALSE == tmp)
        return FALSE;

    tmp = send_data_to_iic(num_data, pcontent, FALSE, TRUE);    //send data writed
    
    if (FALSE == tmp)
        return FALSE;
    else 
        return TRUE;
    
}

u_char  read_device_by_iic0(u_char svnbits_dev_addr, u_char *reg_addr, u_char num_addr, u_char *paddr_data_save, u_char num_data)
{
    u_char tmp;
    u_char addr[3];
    
    addr[0] = (svnbits_dev_addr<< 1) & 0xfe;
    addr[1] = *reg_addr;
    addr[2] = *(reg_addr+1);

    if (2 == num_addr)
    {
        tmp = send_data_to_iic(3, (u_char *)addr, TRUE, FALSE); //send device address & register address
    }
    else if (1 == num_addr)
    {
        tmp = send_data_to_iic(2, (u_char *)addr, TRUE, FALSE);
    }
    else
    {
        return FALSE;
    }
    
    if (FALSE == tmp)
        return FALSE;
    
    addr[0] = (svnbits_dev_addr << 1)  | 0x01;
    tmp = send_data_to_iic(1, (u_char *)addr, TRUE, FALSE);     //send restart and read flag
    if (FALSE == tmp)
        return FALSE;

    receive_data_from_iic(num_data, paddr_data_save);

    return TRUE;
}


u_char iic_bus0_initial()
{
    u_char tmp;

    tmp = 0;

    SCL = 1;
    SDA = 1;
    while (tmp < 9)
    {
        SCL = 0;
        delay_5us();
        SCL = 1;
        delay_5us();
        if (SDA == 1)
        {
            start();
            break;
        }
        tmp++;
    }
    
    if (9 == tmp)
        return FALSE;
    else
    {
        stop();                 //here maybe need modify
        return TRUE;
    }
        
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -