STC8 & I2C总线通信

前段时间家里有事,I2C拖到现在才告一段落。
主要的工作是熟悉I2C的软件,硬件实现(STC8支持硬件I2C)。主要实现写,读PCF8563时钟芯片,再从串口1传给PC。
硬件实现就是套官方的例程。改了SDA,SCL引脚,理论上讲是可以直接实现的,为什么调试半天只能读出0XFF呢?手头没有逻辑分析仪,不知道问题所在。后来刁神一语惊醒梦中人,I2C硬件实现是通过芯片内部电路实现的,而默认的I2C引脚不是2.4,2.5脚。查看了Datasheet确实是如此。随后更改了P_SW2的设置将其配置到对应引脚马上就调试成功了。硬件I2C主要是通过配置相应寄存器,由于例程是编好的,还算比较顺利。
随后是软件模拟I2C,我使用的是之前学89C51用的I2C程序,碰到了一些问题,一个是结果显示写数据成功,但读不出来正确数据,一个是程序不能正常ending。
第一个问题,在查阅了很多资料和程序后,确定程序i2c.c本身逻辑问题没有。那么在不同的单片机上区别是什么呢?我又想到了芯片频率问题。STC8A的主频是24MHz,89C51的主频6MHz,中间4倍的差距直接导致_nop_指令运行的时间不同。6M晶振一个_nop_是2us,24M晶振则是0.5us。而I2C协议要求的电平维持时间大多为4.7us。要接近10个空指令才能满足。想到这里,我马上开始着手修改函数中的间隔时间。当然由于保险起见,把中间几乎所有延时都改成了5us,必然会减少I2C通信效率,但效率是在后面考虑的事情。调整完毕通信马上就正常了。
但是,程序没办法正常结束问题还是存在。程序没有循环,但串口一直输出数据。并且编译结果也是有警告的。搜索了警告“unterminated conditionals”发现是.h文件编写的问题,因为是直接复制的程序,在文件最后遗漏了#endif。而#ifndef 和 #endif是配套出现的,少了结尾就不能结束程序。添加了#endif后,程序也变得可以结束了。I2C的复习就到这里告一段落,下面是主程序部分

#include "STC8.h"
#include "intrins.h"
#include "UART1.h"
#include "i2c.h"
#define  FOSC            24000000UL


void Delay500ms()		//@24.000MHz
{
    unsigned char i, j, k;

    _nop_();
    _nop_();
    i = 46;
    j = 153;
    k = 245;
    do
    {
        do
        {
            while (--k);
        } while (--j);
    } while (--i);
}
void main()
{
    Delay500ms();
    UartInit();
//    UartSendStr("Uart test");

//    P_SW2 |= 0x10;									//Special function register is on extended ram,to access them,Set B7 as 1
//	  I2CCFG = 0xe0;                              //1110,Enable I2C,ZHU mode.Wait time is 65T
//    I2CMSST = 0x00;
    I2C_init();
    buffer[0]=I2C_TransmitData(0x02,0x00);	//ADDR+sec DATA
    buffer[1]=I2C_TransmitData(0x03,0x00);	//ADDR+min DATA
    buffer[2]=I2C_TransmitData(0x04,0x12);	//ADDR+hour DATA
    UartSend(buffer[0]);
    UartSend(buffer[1]);
    UartSend(buffer[2]);
				Delay500ms();
				Delay500ms();
	
    while(1)
    {
        buffer[3] = I2C_ReceiveData(0x02);
        buffer[4] = I2C_ReceiveData(0x03);
        buffer[5] = I2C_ReceiveData(0x04);
        UartSend(buffer[5]);
        UartSend(buffer[4]);
        UartSend(buffer[3]);

				Delay500ms();
				Delay500ms();
    }
}

I2C代码部分

#include "stc8.h"
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned  int

sbit    SDA         =   P2^4;
sbit    SCL         =   P2^5;

void delay_5us()		//@24.000MHz
{
    unsigned char i;

    _nop_();
    _nop_();
    i = 27;
    while (--i);
}

void I2C_init()
{
    SDA = 1;
    _nop_();
    SCL = 1;
    _nop_();
}

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

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

/*ZHU send ACK*/
void Master_ACK(bit i)	//¶ÁÊý¾ÝʱÓÉÖ÷É豸·¢ACK£¬Èô¶ÁÍêÊý¾ÝÔò·¢NACK
{
    SCL = 0; // allow SDA change
    delay_5us();//  relax
    if (i)	 //	 i=1 ZHU ack
    {
        SDA = 0;
    }
    else
    {
        SDA = 1;	 //i=0 ZHU nck
    }
    delay_5us();// relax
    SCL = 1;// raise SCL, allow CONG read ACK
    delay_5us();
    SCL = 0;// pull down SCL and occupy bus
    delay_5us();
    SDA = 1;//release SDA
    delay_5us();
}

/*Test CONG ack*/
bit Test_ACK()		//Ç°8bits·¢Íêºó´ÓÉ豸»ñµÃSDA¿ØÖÆȨ£¬ÈôÆäÔڵھŸöʱÖÓÂö³å֮ǰÀ­µÍSDAÔòÖ¤Ã÷ÊÕµ½Êý¾Ý
{
    SCL = 1;
    delay_5us();
    if (SDA)				//SDA=1 nck
    {
        SCL = 0;
        delay_5us();
        I2C_Stop();
        return(0);
    }
    else							//SDA=0 ack
    {
        SCL = 0;
        delay_5us();
        return(1);
    }
}

void I2C_send_byte(uchar byte)
{
    uchar i;
    for(i = 0 ; i < 8 ; i++)
    {
        SCL = 0;			//allow communicate
        delay_5us();
        if (byte & 0x80)		//From high to low
        {
            SDA = 1;
            delay_5us();
        }
        else
        {
            SDA = 0;
            delay_5us();
        }
        SCL = 1;
        delay_5us();
        byte <<= 1;
    }
    SCL = 0;		//pull down SCL ,ready for next transfer
    _nop_();
    SDA = 1;		//release SDA,CONG control bus
    _nop_();
}

uchar I2C_read_byte()
{
    uchar dat,i;
    SCL = 0;
    delay_5us();
    SDA = 1;
    delay_5us();
    for(i = 0 ; i < 8 ; i++)
    {
        SCL = 1;		//while SCL is high,data is stable enough to receive
        delay_5us();
        if (SDA)
        {
            dat |= 0x01;
        }
        else
        {
            dat &=  0xfe;	//1111 1110
        }
        delay_5us();
        SCL = 0 ;
        delay_5us();
        if(i < 7)
        {
            dat = dat << 1;
        }
    }
    return(dat);
}

/*I2C????*/
bit I2C_TransmitData(uchar ADDR, DAT)		//any address write 1 byte. return result
{
    I2C_Start();
    I2C_send_byte(0xa2);
    if (!Test_ACK())
    {
        return(0);
    }
    I2C_send_byte(ADDR);
    if (!Test_ACK())
    {
        return(0);
    }
    I2C_send_byte(DAT);
    if (!Test_ACK())
    {
        return(0);
    }
    I2C_Stop();
    return(1);
}

/*I2C????*/
uchar I2C_ReceiveData(uchar ADDR)
{
    uchar DAT;
    I2C_Start();
    I2C_send_byte(0xa2);
    if (!Test_ACK())
    {
        return(0);
    }
    I2C_send_byte(ADDR);
    Master_ACK(0);
    I2C_Start();
    I2C_send_byte(0xa3);
    if (!Test_ACK())
    {
        return(0);
    }
    DAT = I2C_read_byte();
    Master_ACK(0);
    I2C_Stop();
    return(DAT);
}

你可能感兴趣的:(51)