模拟I2C从机

时间:2021-04-21 01:58:43

模拟I2C主机的比较多,但是从机相对主机而言要难很多,这个供大家借鉴。
这个从机程序支持主机对它的随机写和随机读,连续读和连续写没做,有兴趣的可以完善下,呵呵。

//Microcontrol CODE 

#include <msp430x22x4.h>
#define SDA BIT1
#define SCL BIT2 

#define SEG_A 0xA0 //0x0200---0x027F
#define SEG_B 0xB0 //0x0280---0x02FF
#define SEG_C 0xC0 //0x0300---0x037F 

//0x0380---0x0400
__no_init char wokao@0x243;
//=============================
char *send_ptr;
;
;
;
;
;
;
;
//*********************函数声明*************************************
void ACK(void); 

//****************************************************************
void main( void )
{
    // Stop watchdog timer to prevent time out reset
    WDTCTL = WDTPW + WDTHOLD; 

    //======================MCLK=16MHz=====================================
    DCOCTL = CALDCO_16MHZ;
    BCSCTL1 = CALBC1_16MHZ; //MCLK=DCO=16MHz
    P3DIR &= ~(SDA+SCL); 

    )
    {
        NN=;
        PreState = READ_SDA; 

        while(READ_SCL && NN--)
        {
            NowState = READ_SDA;
            if(PreState && !NowState)
            {
                START_flag = ;
                _DINT();
            }
            if(!PreState && NowState)
            {
                STOP_flag = ;
                _EINT();
            }

            PreState = NowState; 

            if(START_flag)
            {
                START_flag=;
                while(READ_SCL); //START时的SCL高电平状态就等待
                ;gg>;gg--) //接收器件地址
                {
                    while(!READ_SCL); //SCL低电平状态就等待 

                    DEVICE_ADR<<=;
                    if(READ_SDA) //数据的第一个CLK高电平来临
                    DEVICE_ADR |= 0x01; 

                    while(READ_SCL); //SCL高电平状态就等待
                }
                ACK(); //对设备地址ACK应答信
                //-----------以上收到了设备地址,并知晓主机要对从机进行读还是写操作--- 

                ;gg>;gg--) //接收内存单元地址
                {
                    while(!READ_SCL); 

                    WORD_ADR<<=;
                    if(READ_SDA)
                    WORD_ADR |= 0x01; 

                    while(READ_SCL);
                }
                //-----------以上就已经接收到内存单元地址------------
                ACK(); //对内存单元ACK应答信号 

                if(DEVICE_ADR & 0x01) //从机发数据给主机 R/W=1
                {
                    if(DEVICE_ADR==SEG_A+0x01)
                    {
                        send_ptr =(char*)(0x0200 + WORD_ADR);
                    }
                    else if(DEVICE_ADR==SEG_B+0x01)
                    {
                        send_ptr =(char*)(0x0280 + WORD_ADR);
                    }
                    else if(DEVICE_ADR==SEG_C+0x01)
                    {
                        send_ptr =(char*)(0x0300 + WORD_ADR);
                    } 

                    //--------以上是判断出为主机读从机,要把要读的地址单元赋给指针--- 

                    ;gg>;gg--)
                    {
                        while(!READ_SCL);
                        if( *send_ptr & 0x80)
                        _NOP();
                        else
                        {
                            P3DIR |= SDA; //输出0
                        }
                        while(READ_SCL); //SCL为1,就保持SDA输出不变
                        P3DIR &= ~SDA; //SCL为0,就把SDA从新切换到接收状态
                        *send_ptr <<=;
                    }
                    ACK(); //从机数据发送完毕,应答信号
                    _NOP();
                    //------------------以上是从机发数据给主机-----------------
                }
                else //主机写从机 R/W=0
                {
                    ;gg>;gg--) //接收主机要写到该器件内存单元的数据
                    {
                        while(!READ_SCL); 

                        REC_DATA <<=;
                        if(READ_SDA)
                        REC_DATA |= 0x01; 

                        while(READ_SCL);
                    }
                    if(DEVICE_ADR==SEG_A)
                    {
                        send_ptr =(char*)(0x0200 + WORD_ADR);
                        *send_ptr = REC_DATA;
                    }
                    else if(DEVICE_ADR==SEG_B)
                    {
                        send_ptr =(char*)(0x0280 + WORD_ADR);
                        *send_ptr = REC_DATA;
                    }
                    else if(DEVICE_ADR==SEG_C)
                    {
                        send_ptr =(char*)(0x0300 + WORD_ADR);
                        *send_ptr = REC_DATA;
                    }
                    ACK();
                    _NOP();
                    while(!READ_SCL);
                }
            }// if(START_flag) 

        }//while(NN--)
        _EINT();
        _NOP();
    }//while(1)
} 

//****************************************************
void ACK(void)
{
    // while(READ_SCL);
    while(!READ_SCL);
        P3DIR |= SDA; //第9个CLK变高的情况下,SDA输出0
    while(READ_SCL);
        P3DIR &= ~SDA; //第9个CLK变低的情况下,SDA输出1
}