Previous in Forum: Truck Communication Systems   Next in Forum: TJX Hacker gets 20 year jail term...
Close
Close
Close
8 comments
Rate Comments: Nested
Active Contributor

Join Date: Mar 2010
Posts: 10

What's Wrong With My Code?

03/25/2010 5:19 AM

Dear all,

i meet with a problem recently, and i need your help.

I'm trying to read and write from the 24AA01 using the I2C .

my design is this: first, i write a data 0x88 into the 24AA01 (address 0x02).then, i want to read the data (0x88) from the 24AA01. theoritically, i will get the data 0x88. but what i get is 0xFF. and whatever i change the data , i can only get the data 0xFF. i don't know what's wrong with my code, maybe something wrong with the hardware.
the picture and the c code are attached. so, i need your help. thank you.

#include<reg51.h>


#define uchar unsigned char
#define uint unsigned int

sbit SCL=P2^0;
sbit SDA=P2^1;
bit flag1;
bit flag2;
bit flag3;
bit flag4;
bit flag5;
bit flag6;
bit flag7;
uchar result;


void dly_usec(uchar t)
{
uint i;
for(i=t;i>0;i--);
}


void init_i2c()
{ SDA=1;
SCL=1;
}


void start(void)
{
SDA = 1 ;
SCL = 1 ; // initial state of the I2C bus
dly_usec(7) ;
SDA = 0 ; // SCL=1 , SDA=0 after 7 usecs
dly_usec(5) ;
SCL = 0 ; // SCL=0 , SDA=0 after other 5 usecs
}


void stop(void)
{
SDA = 0 ; // SDA=0,SCL=0, initial state of I2C
dly_usec(2) ;
SCL = 1 ; // SDA=0,SCL=1, after 2 usecs
dly_usec(6) ;
SDA = 1 ; // SDA=1,SCL=1, after other 5 usecs
}

void ACK(void)
{
SDA = 0 ;
dly_usec(3) ; // SDA=0,SCL=0 for 3 usec
SCL = 1 ;
dly_usec(6) ; // +pulse SCL for 6 usec
SCL = 0 ;
dly_usec(2) ; // 2 usec stabilization for SCL
SDA = 1 ;
dly_usec(2) ; // prepare SDA for reception
}


void NO_ACK(void)
{
SDA = 1 ;
dly_usec(3) ; // SDA=1,SCL=0 for 3 usecs
SCL = 1 ;
dly_usec(6) ; // SDA=1,SCL=1 for 6 usecs ; +pulse SCL
SCL = 0 ;
dly_usec(2) ; // SDA=1,SCL=0,SCL stabilization 2us
}


void BYTE_WRITE(uchar w_address,uchar w_add)
{
uchar w_control_word=0xa0;
uchar j,k,m;
start();
for(j=0;j<8;j++)
{
SCL=0;
dly_usec(3);
SCL=1;
dly_usec(3);
SDA=(bit)(w_control_word&0x80);
flag1=SDA;
w_control_word<<=1;
}
ACK();
for(k=0;k<8;k++)
{
SCL=0;
dly_usec(3);
SCL=1;
dly_usec(3);
SDA=(bit)(w_address&0x80);
flag2=SDA;
w_address<<=1;
}
ACK();
for(m=0;m<8;m++)
{
SCL=0;
dly_usec(3);
SCL=1;
dly_usec(3);
SDA=(bit)(w_add&0x80);
flag3=SDA;
w_add<<=1;
}
ACK();
stop();
}


uchar BYTE_READ(uchar r_address)
{
uchar r_control_word=0xa1;
uchar w_control_word=0xa0;
uchar r_data=0x00;
uchar a,b,c,d;
start();
for(a=0;a<8;a++)
{
SCL=0;
dly_usec(3);
SCL=1;
dly_usec(3);
SDA=(bit)(w_control_word&0x80);
flag4=SDA;
w_control_word<<=1;
}
ACK();
for(b=0;b<8;b++)
{
SCL=0;
dly_usec(3);
SCL=1;
dly_usec(3);
SDA=(bit)(r_address&0x80);
flag5=SDA;
r_address<<=1;
}
ACK();
start();
for(c=0;c<8;c++)
{
SCL=0;
dly_usec(3);
SCL=1;
dly_usec(3);
SDA=(bit)(r_control_word&0x80);
flag6=SDA;
r_control_word<<=1;
}
ACK();
for(d=0;d<8;d++)
{
r_data<<=1;
dly_usec(3);
SCL=1;
dly_usec(3);
flag7=SDA;
dly_usec(4);
if(SDA==1) r_data++;
SCL=0;
dly_usec(4);
}
NO_ACK();
stop();
return(r_data);
}


void main(void)
{
init_i2c();
P1=0xff;
BYTE_WRITE(0x02,0x88);
result=BYTE_READ(0x02);
P1=result;
while(1);
}

Register to Reply
Interested in this topic? By joining CR4 you can "subscribe" to
this discussion and receive notification when new comments are added.
Guru

Join Date: Dec 2005
Location: Etats Unis
Posts: 1871
Good Answers: 45
#1

Re: What's Wrong With My Code?

03/25/2010 11:07 PM

You don't need R1 since the processor always drives the clock but it should not cause a problem. You should make R2 1K.

Timing is critical on the ACK, haven't analyzed your code in detail but I've written many bit banging I2C interfaces. Make sure your read timing is correct.

__________________
The hardest thing to overcome, is not knowing that you don't know.
Register to Reply
Guru

Join Date: May 2007
Location: Geelong, Australia
Posts: 1084
Good Answers: 54
#2

Re: What's Wrong With My Code?

03/26/2010 12:51 AM

The general idea is to break the system up into "blocks" and test each one. I'd check the hardware first.

First, perhaps get a 24AA01 (that you know is good) with some data in it, can you read it now? If not why not. Can you use another circuit board that is known to be good?

Are clock pulses/data signals appearing on the output lines? Can you use a logic probe to verify this? (A 555 can make a handy pulse stretcher)

Can you create pulse trains using your functions, is that dly_usec(..) being optimised away? etc.

Good luck and remember as Euclid said "There is no royal road to assembler"

__________________
If there's something you don't understand...Then a wizard did it. As heard on "The Simpsons".
Register to Reply
Guru
Popular Science - Weaponology - New Member Safety - ESD - New Member Hobbies - Fishing - New Member

Join Date: Sep 2006
Location: Near Frankfurt am Main, Germany. 50.390866N, 8.884827E
Posts: 17996
Good Answers: 200
#3

Re: What's Wrong With My Code?

03/26/2010 5:19 AM

There is a circuit for an I2C analyser designed by Elektor in 2008 (I can get exact details for you if needed) that you should buy and solder together, it was not expensive (around $50) I believe....it will help you fix all your interface problems....

If you are interested send me your proper email address via the CR4 email and I will send you a copy of the article.

PCBs are usually available from the Elektor supplier for many years after publication, I bought PCB from an Elektor 2003 article in 2009 with no problems at all.....good quality PCBs too. Sometimes complete kits are also available....

I don't know where you live by but Elektor covers Europe and the USA/Canada......at least.

__________________
"What others say about you reveals more about them, than it does you." Anon.
Register to Reply
Active Contributor

Join Date: Mar 2010
Posts: 10
#5
In reply to #3

Re: What's Wrong With My Code?

03/28/2010 8:29 PM

thanks for your reply! what i want to san first is i am a Chinese student. and i live in TianJin(China) now. anyway, thanks.

Register to Reply
Guru
Popular Science - Weaponology - New Member Safety - ESD - New Member Hobbies - Fishing - New Member

Join Date: Sep 2006
Location: Near Frankfurt am Main, Germany. 50.390866N, 8.884827E
Posts: 17996
Good Answers: 200
#7
In reply to #5

Re: What's Wrong With My Code?

03/29/2010 7:20 AM

Elektor magazine is allso sold in China.....in Chinese.

__________________
"What others say about you reveals more about them, than it does you." Anon.
Register to Reply
Guru

Join Date: Dec 2009
Posts: 581
Good Answers: 15
#4

Re: What's Wrong With My Code?

03/26/2010 11:15 AM

You asked, "What's wrong with my code?" not, "Why doesn't this code work?" so here's some style and good practice tips in addition to possible bug fixes.

Indent, if you haven't.

flag1-7 are diagnostic?

Use the volatile keyword on your i/o port variables (SDA and SCL) and turn compiler optimization completely off for your debug/prototype work. This could be the real culprit.

I don't understand what you're trying to do with ^ here, or what P2 is:

sbit SCL=P2^0;
sbit SDA=P2^1;

Test dly_usec to see if it's at all accurate. Feed it 10000 and use a stopwatch to count 10 seconds (change parameter to a uint). I suppose the chip doesn't have a timer. If it does, use it. This could also be the source of the problem - is the CPU really that slow?

You can re-use loop index variables. Minor advantages to using i for most every loop are slight gain in readability and tiny memory savings, but local variables go on the stack and if your stack is very tiny they could be significant.

if(SDA==1) r_data++;

That's not the usual way to put a 1 in the least significant bit but I can't see why it won't work.

If your system has source-level debugging it's usually worth setting it up.

__________________
Ignorance is no sin. Willful ignorance is unforgiveable.
Register to Reply
Active Contributor

Join Date: Mar 2010
Posts: 10
#6
In reply to #4

Re: What's Wrong With My Code?

03/28/2010 10:25 PM

yes,you are right, flag1-7 are diagnostic. "sbit SCL=P2^0;sbit SDA=P2^1;" is just a bit definition. thanks for your suggestion. As to "if(SDA==1) r_data++; ", i always use this kind of way. and could you tell me the usual way? thanks.

Register to Reply
Guru

Join Date: Dec 2009
Posts: 581
Good Answers: 15
#8
In reply to #6

Re: What's Wrong With My Code?

03/29/2010 9:46 AM

The usual way to set the least significant bit to 1 is by the bitwise OR operator. It's interesting that I've never seen (or at least can't remember seeing) someone use increment to do it. "Your" way might actually be more efficient in some cases, but I suspect "|= 1" is the fastest in most. (It's only a couple clock cycles so the difference is almost always negligible.)

I don't see P2 defined in the code. Presumably it's in reg51.h.

__________________
Ignorance is no sin. Willful ignorance is unforgiveable.
Register to Reply
Register to Reply 8 comments
Copy to Clipboard

Users who posted comments:

466576266 (2); Andy Germany (2); ffej (1); Lynn.Wallace (2); rcapper (1)

Previous in Forum: Truck Communication Systems   Next in Forum: TJX Hacker gets 20 year jail term...

Advertisement