原创 STC12C2052模拟24C02

2009-3-4 13:06 3440 12 18 分类: MCU/ 嵌入式

为满足程序加载时,按用户的要求配置某IIC接口芯片配置寄存器,用STC单片机模拟24C02。


主模式的模拟很普遍,但该芯片复位后处于主模式,使得STC要配置它只能处于从模式状态,而IIC从模式的模拟却很少有现成的代码参考。下面是STC模拟被读一个字节的原代码,测试成功:


#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
//#include<intrins.h>
//#include <serial.h>


#define ack 0
#define noack 1
#define false 0
#define ture 1
//#define EE_ADD 0x00
#define EE_BYTEADD 0x00////
#define EE_WRITE 0xa0
#define EE_READ 0xa1


sbit scl="P1"^7;////STC2052.PIN19-SPICLK-SPIC
sbit sda="P1"^5;////STC2052.PIN17-MOSI-SPID
//bit ack_flag=0;////局部定义产生重入


//void iic_sdelay(uchar);
bit iic_start_decide();
bit iic_stop_decide();
void iic_ack_send(bit);
bit iic_ack_decide();
//void iic_ack();
//void iic_noack();
bit iic_send(uchar);//reentrant;
bit EEPROM_Imitate(uchar *p);
//uchar iic_receive();//reentrant;/////////////////////////////////////////////////////////////////
//bit iic_writestr(uchar*,uchar,uchar);
//bit iic_writeabyte(uchar,uchar);
//bit iic_readstr(uchar*,uchar,uchar);
//bit iic_readabyte(void);


bit iic_start_decide()////iic开始判断
{
while(0==scl);////开始条件不满足
while((1==scl)&&(1==sda));////开始条件正在建立,则等待


if((1==scl)&&(0==sda))////开始
{
while(1==scl);////等待到时钟线开始跳变
return ture;
}
else
return false;
}


bit iic_stop_decide()
{
while(0==scl);////结束条件不满足
while((1==scl)&&(0==sda));////结束条件正在建立,则等待


if((1==scl)&&(1==sda))////结束
return ture;
else
return false;
}



void iic_ack_send(bit a)////回应ACK或NOACK
{


if(ack==a)
sda=0;
else
sda=1;
while(0==scl);////等待SCL低电平
while(1==scl);////时钟线高电平时保持
}


bit iic_ack_decide()
{
bit ack_flag;////局部变量
//////////////////////////////////////sda=1;  ////8位发送完毕,释放数据线SDA,准备接收应答位
while(0==scl);////等待SCL变高电平
ack_flag=0;
if(0==sda)////sda==0说明有回应
ack_flag=1;////设置回应成功标志
else
ack_flag=0;
//scl=0;    ////嵌住总线,准备发送或接收数据
//iic_sdelay(4);
while(1==scl);
return(ack_flag);
}


bit iic_send(uchar sdata) //reentrant
{uchar i;
for(i=0;i<8;i++)
{
sda=(bit)(sdata&0x80);
sdata=sdata<<1;
while(0==scl);
while(1==scl);////检测scl,高电平时数据保持,scl跳到低电平才改变数据
}
return(iic_ack_decide());////判断主机有无回应
}


uchar iic_receive() //reentrant
{uchar i;
uchar rdata="0";
sda=1;
for(i=0;i<8;i++)
{
rdata<<=1;
while(0==scl);////当时钟线为低时,数据无效,等待
if(1==sda)
rdata++;
while(1==scl);////防止在一个高电平时读8次
}
//iic_sdelay(4);
//scl=0;   ////嵌住总线,准备发送或接收数据////这里使用的是从模式
//iic_sdelay(8);
return (rdata);
}


/*
void iic_sdelay(uchar i)
{for(;i>0;i--);
}*/


/*
用页写CAT24WC01 可一次写入8 个字节数据CAT24WC02/04/08/16 可以一次写入16 个字节的
数据页写操作的启动和字节写一样不同在于传送了一字节数据后并不产生停止信号主器件被允许
发送P CAT24WC01 P="7" CAT24WC02/04/08/16 P="15" 个额外的字节每发送一个字节数据后
CAT24WC01/02/04/08/16 产生一个应答位并将字节地址低位加1 高位保持不变
如果在发送停止信号之前主器件发送超过P+1个字节地址计数器将自动翻转先前写入的数据被
覆盖
接收到P+1字节数据和主器件发送的停止信号后CAT24CXXX启动内部写周期将数据写到数据区所
有接收的数据在一个写周期内写入CAT24WC01/02/04/08/16
*/
/*
bit iic_writestr(uchar *s,uchar num)
//bit iic_writeabyte(uchar s,uchar subadd)
{
uchar i;
//iic_start_check();


for(i=0;i<num;i++)
{
if(!iic_send(*s))
//iic_send(s);
return 0;
s++;
}
if(iic_stop_decide())
return ture;
}
*/
/*
选择性读
选择性读操作允许主器件对寄存器的任意字节进行读操作主器件首先通过发送起始信号从器件
地址和它想读取的字节数据的地址执行一个伪写操作在CAT24WC01/02/04/08/16 应答之后主器件重
新发送起始信号和从器件地址此时R/W 位置1 CAT24WC01/02/04/08/16 响应并发送应答信号然后
输出所要求的一个8 位字节数据主器件不发送应答信号但产生一个停止信号
*/
//bit EEPROM_Imitate(uchar *p,uchar num)
bit EEPROM_Imitate(uchar *p)
{
//uchar i;
uchar s;
while(!iic_start_decide());//等待IIC开始


s=iic_receive();////器件地址
//serial_send(s);
if(EE_WRITE==s)
{
iic_ack_send(ack); ////回应
//serial_send(s);
}
else
{
iic_ack_send(noack);
goto enderr;
}


s=iic_receive();////存储字节地址
//serial_send(s);


if(EE_BYTEADD==s)
iic_ack_send(ack); ////回应
else
{
iic_ack_send(noack);
goto enderr;
}


while(!iic_start_decide());//如果iic开始


s=iic_receive();////器件地址
//serial_send(s);
if(EE_READ==s) ////主机要读EE的数据
iic_ack_send(ack); ////回应
else
{
iic_ack_send(noack);
goto enderr;
}


/*for(i=0;i<num;i++)
{
if(!iic_send(*p))////如果主机没有回应,则发送失败
return false;
p++;
}*/
while(iic_send(*p)){p++;};////判断有NOACK后停止发送,接着判断停止位
if(iic_stop_decide())
return ture;
enderr:
scl=sda=1;
return false;
}

PARTNER CONTENT

文章评论6条评论)

登录后参与讨论

用户977176 2009-3-9 09:52

这个太乱了!!!!!!!!!!! 有没有好的模式?

用户977176 2009-3-9 09:51

如果使用中断的话,SCL频率是不是可以进一步提高? 下面也是也是一个模拟I2C slave的例子,看看有没有参考价值: Sample I2C Slave Routines for the 83C751 ;***************************************************************************** ; Sample I2C Slave Routines for the 83C751 ; This program performs slave functions on the 83/87C751 microcontroller. ; The program uses separate transmit and receive data buffers that are each ; eight bytes deep. The main program simply copies received data to the ; transmit buffer such that transmitted data can be read back. The 751 will ; accept only eight data bytes in any one I2C transmission, additional bytes ; will not be acknowledged. Similarly, only eight data bytes may be read from ; the 751 in any one I2C transmission. Beyond this, the 751 will simply ignore ; the I2C bus. ;***************************************************************************** $TITLE(83C751 Slave I2C Routines) $DATE(04/25/90) $MOD751 $DEBUG ; Value definitions. CTVAL EQU 02h ;CT1, CT0 bit values for I2C. MaxBytes EQU 8 ;Maximum # of bytes to be sent or ; received. ; Masks for I2CFG bits. BTIR EQU 10h ;Mask for TIRUN bit. BMRQ EQU 40h ;Mask for MASTRQ bit. ; Masks for I2CON bits. BCXA EQU 80h ;Mask for CXA bit. BIDLE EQU 40h ;Mask for IDLE bit. BCDR EQU 20h ;Mask for CDR bit. BCARL EQU 10h ;Mask for CARL bit. BCSTR EQU 08h ;Mask for CSTR bit. BCSTP EQU 04h ;Mask for CSTP bit. BXSTR EQU 02h ;Mask for XSTR bit. BXSTP EQU 01h ;Mask for XSTP bit. ; RAM locations used by I2C routines. RcvDat DATA 10h ;I2C receive data buffer (8 bytes). ; addresses 10h through 17h. XmtDat DATA 18h ;I2C transmit data buffer (8 bytes). ; addresses 18h through 1Fh. Flags DATA 20h ;I2C software status flags. NoAck BIT Flags.7 ;Holds negative acknowledge flag. DatFlag BIT Flags.6 ;Tells whether an I2C write operation ; has occurred. BitCnt DATA 21h ;I2C bit counter. ByteCnt DATA 22h ;Send/receive byte counter. TDAT DATA 23h ;Temporary holding register. MyAddr DATA 24h ;Holds address of THIS slave. AdrRcvd DATA 25h ;Holds received slave address + R/W. RWFlag BIT AdrRcvd.0 ;Slave read/write flag. ;***************************************************************************** ; Begin Code ;***************************************************************************** ; Reset and interrupt vectors. AJMP Reset ;Reset vector at address 0. ; A timer I timeout usually indicates a 'hung' bus. ORG 1Bh ;Timer I (I2C timeout) interrupt. AJMP TimerI ; I2C interrupt is used to detect a start while the slave is idle. ORG 23h ;I2C interrupt. PUSH PSW ;Save status. PUSH ACC ;Save accumulator. CLR EI2 ;Disable I2C interrupt. ACALL ClrInt ;Re-enable interrupts. ;***************************************************************************** ; Main Transmit and Receive Routines ;***************************************************************************** Slave: MOV I2CON,#BCARL+BCSTP+BCSTR+BCXA ;Clear start status. JNB ATN,$ ;Wait for next data bit. MOV BitCnt,#7 ;Set bit count. ACALL RcvB2 ;Get remainder of slave address. MOV AdrRcvd,A ;Save received address + R/W bit. CLR ACC.0 CJNE A,MyAddr,GoIdle ;Enter idle mode if not our address. JB RWFlag,Read ;Read or Write? MOV R0,#RcvDat ;Set up receive buffer pointer. MOV ByteCnt,#MaxBytes ;Max 4 bytes can be received. WrtLoop: ACALL SendAck ;Send acknowledge. ACALL RcvByte ;Get data byte from master. JNB DRDY,WLEx ;Must be end of frame? MOV @R0,A ;Save data. INC R0 ;Advance buffer pointer. DJNZ ByteCnt,WrtLoop ;Back to receive if buffer not full. ACALL SendAck ;Send acknowledge. ACALL RcvByte ;Get, but do not store add'l data. MOV I2DAT,#80h ;Send negative acknowledge. JNB ATN,$ ;Wait for acknowledge sent. WLEx: SETB DatFlag ;Flag main that data has been received. SJMP MsgEnd ;Buffer full, enter idle mode. Read: MOV R0,#XmtDat ;Set up transmit buffer pointer. MOV ByteCnt,#MaxBytes ;Max bytes to be sent. ACALL SendAck ;Send address acknowledge. RdLoop: MOV A,@R0 ;Get data byte from buffer. INC R0 ;Advance buffer pointer. ACALL XmitByte ;Send data byte. JB NoAck,RLEx ;Exit if NAK. DJNZ ByteCnt,RdLoop ;Back if more data requested & avail. RLEx: SJMP MsgEnd ;Done, enter idle mode. MsgEnd: JNB ATN,$ ;Wait for stop or repeated start. JB STR,Slave ;If repeated start, go to slave mode, ; else enter idle mode. GoIdle: MOV I2CON,#BCSTP+BCXA+BCDR+BCARL+BIDLE ;Enter slave idle mode. POP ACC ;Restore accumulator. POP PSW ;Restore status. SETB EI2 ;Re-enable I2C interrupts. RET ;***************************************************************************** ; Subroutines ;***************************************************************************** ; Byte transmit routine. ; Enter with data in ACC. XmitByte: MOV BitCnt,#8 ;Set 8 bits of data count. XmBit: MOV I2DAT,A ;Send this bit. RL A ;Get next bit. JNB ATN,$ ;Wait for bit sent. DJNZ BitCnt,XmBit ;Repeat until all bits sent. MOV I2CON,#BCDR+BCXA ;Switch to receive mode. JNB ATN,$ ;Wait for acknowledge bit. MOV Flags,I2DAT ;Save acknowledge bit. RET ; Byte receive routines. ; RDAck : receives a byte of data, then sends an acknowledge. ; RcvByte : receives a byte of data. ; Data returned in ACC. RdAck: ACALL RcvByte ;Receive a data byte. SendAck: MOV I2DAT,#0 ;Send receive acknowledge. JNB ATN,$ ;Wait for acknowledge sent. RET RcvByte: MOV BitCnt,#8 ;Set bit count. RcvB2: CLR A ;Init received byte to 0. RBit: ORL A,I2DAT ;Get bit, clear ATN. RL A ;Shift data. JNB ATN,$ ;Wait for next bit. JNB DRDY,RBEx ;Exit if not a data bit. DJNZ BitCnt,RBit ;Repeat until 7 bits are in. MOV C,RDAT ;Get last bit, don't clear ATN. RLC A ;Form full data byte. RBEx: RET ; Timer I timeout interrupt service routine. TimerI: SETB CLRTI ;Clear timer I interrupt. MOV I2CFG,#0 ;Turn off I2C. MOV I2CON,#BCXA+BCDR+BCARL+BCSTR+BCSTP ;Reset I2C flags. ACALL ClrInt ;Clear interrupt pending flag. AJMP Reset ;Return to mainline. ClrInt: RETI ;***************************************************************************** ; Main Program ;***************************************************************************** Reset: MOV SP,#07h ;Set stack location. MOV IE,#90h ;Enable I2C interrupt. MOV R0,#RcvDat ;Set up pointer to data area. MOV R1,#2*MaxBytes ;Set up buffer length counter. RLoop: MOV @R0,#0 ;Clear buffer memory. INC R0 ;Advance to next buffer position. DJNZ R1,RLoop ;Repeat until done. MOV MyAddr,#40h ;Set slave address. MOV Flags,#0 ;Clear system flags. MOV I2CFG,#80h+CTVAL ;Enable slave functions. MOV I2CON,#BIDLE ;Put slave into idle mode. SETB ETI ;Enable timer I interrupts. SETB TIRUN ;Turn on timer I. ; The mainline program simply copies the input buffer to the output buffer ; whenever there is an I2C write operation. MainLoop: JNB DatFlag,$ ;Wait for data sent from I2C. MOV R0,#RcvDat ;Set input buffer start pointer. MOV R1,#XmtDat ;Set output buffer start pointer. MOV R2,#MaxBytes ;Set buffer length counter. ML2: MOV A,@R0 ;Get data from input buffer. MOV @R1,A ;Store data in output buffer. INC R1 ;Increment input buffer pointer. INC R0 ;Increment output buffer pointer. DJNZ R2,ML2 ;Repeat until entire buffer is updated. CLR DatFlag ;Clear I2C transmission flag. SJMP MainLoop ;Wait for next I2C transmission. END

用户977176 2009-3-7 23:56

多谢! 此贴我转到: http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=3233053&bbs_page_no=1&search_mode=3&search_text=ninjia&bbs_id=9999

用户1270731 2009-3-7 16:13

时钟11.0592MHZ 我应用在81KHZ的SCL频率环境中,实验在125KHZ的频率下也可以。再高没试过,提高STC2052频率应该可以捕获更高速度的时钟应用。 这个代码就是完整的IIC.h,主程序就是引用了它的函数。

用户977176 2009-3-6 23:27

STC12C2052模拟24C02,STC12C2052的时钟是多少?I2C的时钟SCL100KHz还是400KHz? 能不能给出完成的参考代码吗? 我的邮箱:encijia@sohu.com

用户977176 2009-3-6 23:21

能不能给出完成的参考代码吗? 模拟的I2C时钟SCL可以到多少:100KHz还是400KHz?
相关推荐阅读
用户1270731 2011-03-22 09:41
模拟外调制器偏置电压自动控制实现之软件部分
attachment download   模拟外调制器偏置电压自动控制实现之软件部分  三、偏置电压自动控制的实现 两路导频信号1.硬件组成部分单片机外调制器高精度DA转换正负电压调节电路CSO分量...
用户1270731 2010-12-10 19:53
STC90LE58AD ENC28J60 WEB
拜读了某前辈的文章,看来我找到移植UIP0.9问题的关键了。通常ENC28J60的驱动程序只考虑发送参数packet指针指向的数据区,在HTTP需要回应的数据的时候,没有将需要的数据(UIP处理后放在...
用户1270731 2010-12-10 19:29
ENC28J60提供的超小协议栈
ENC28J60提供的超小协议栈,它用一个全局的数组来做接收和发送缓冲。部分发送数据包从接收包中更改标志和校验和得到,最大化的减少内存拷贝。实现TCP/IP协议收发数据包的各个子功能,如校验和计算,标...
用户1270731 2010-12-03 07:58
单片机以太网-web网页问题
uip协议栈,STC12LE58AD单片机。问题是得不到网页数据,10延迟后退出,发送无数据。调试httpd部分串口输出如下:ip: version4 header.ip: POSSIBLE TCP ...
用户1270731 2010-06-13 15:03
VC++6.0做的 RS232 数据帧类
// ZBL232Frame1.h: interface for the CZBL232Frame class.////////////////////////////////////////////...
用户1270731 2010-06-03 16:34
铌酸锂晶体横向电光调制实验
实验六 铌酸锂晶体横向电光调制实验<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> ...
EE直播间
更多
我要评论
6
12
关闭 站长推荐上一条 /3 下一条