View previous topic :: View next topic |
Author |
Message |
elizabeth ann
Joined: 16 Feb 2008 Posts: 33
|
cannot read from an input (switch) over i2c...(SOLVED) |
Posted: Wed Apr 30, 2008 10:35 pm |
|
|
i am trying to read from a microswitch (similar to a push button) over the i2c communication so i developed a code that will constantly read from the source (10 microswitches installed in Port Expander 1) and feed it to another i2c device (10 LEDs installed in Port Expander 2) in order to turn an LED off until all the 10 LEDs are OFF. for example, if i have pressed SWITCH 1, then LED 1 should be OFF.
however, this code seems to have a problem.... i have tried to load the program in my microcontroller but nothing happens....
also, i have a question about the byte received during the READ process, is it simply 0 or 1 and 0 means low, and 1 is high? i hope someone can enlighten me....
thank you.
note:
slave addresses:
0x32=10 LEDs (preconfigured as output)
0xA0=10 switches (preconfigured as input)
Code: |
BYTE byte1, byte2;
do
{
while( !byte1 && !byte2 )
{
i2c_start();
i2c_write(0xA0);
i2c_write(0x02);
i2c_start(); //START READING REGISTER
i2c_write(0xA1);
byte1=i2c_read(1); //ex. if switch1 is pressed, byte1=0x7F
byte2=i2c_read(); //READ 2ND BYTE
i2c_read(0); //STOP READING
i2c_stop();
break;
}
i2c_start();
i2c_write(0x32); //UPDATE LEDs WITH SWITCH STATE
i2c_write(0x02); //ACCESS OUTPUT REGISTER
i2c_write(byte1); //WRITE BYTE1 (FROM READ MODE) TO LED
i2c_write(byte2); //WRITE BYTE2 (FROM READ MODE) TO LED
i2c_stop();
} while ( (byte1!=0x00) && (byte2!=0x00) );
|
perhaps something is wrong with my WRITE MODE/PROCESS? corrections are very much welcomed...
Last edited by elizabeth ann on Mon May 12, 2008 7:55 am; edited 2 times in total |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu May 01, 2008 8:50 am |
|
|
Here you made the error of mixing the logical AND '&&' with the binary AND '&'. As the code is now it will change byte1 to TRUE or FALSE (0 or 1).
I guess you intended to do: Code: | byte1=byte1 & 0xFF; | Which is valid code but will do nothing as byte1 is an 8 bit variable and performing an AND with 0xFF will return the exact same result. This code only makes sense when executing on a 16 or 32-bit processor, but even then is not required.
Best is to remove these two lines from your program.
What are the type numbers of the I/O expanders? |
|
|
elizabeth ann
Joined: 16 Feb 2008 Posts: 33
|
|
Posted: Thu May 01, 2008 9:52 pm |
|
|
oh, sorry... i was working on another loop with the slave addresses and that lines must have probably mixed up with this one. my mistake though...
by the way, as to the port expander, i am using MAX7318 [url] http://pdf1.alldatasheet.com/datasheet-pdf/view/197255/MAXIM/MAX7318.html [/url] and i have based my i2c routines on the information found in that datasheet.
since i need only 10 of each of the ports, i only used the first 5 bits of Port 1 and another 5 bits of Port 2 to make it 10. this is true for both the LED and the Switch as they have separate port expanders...
hope this helps make my problem better to understand...
by the way, i removed that line already but it still didn't work.... is there anything else wrong with my code? |
|
|
elizabeth ann
Joined: 16 Feb 2008 Posts: 33
|
|
Posted: Fri May 02, 2008 11:47 pm |
|
|
edited the code with a few modifications...
Code: |
BYTE byte1, byte2;
do
{
i2c_start();
i2c_write(0xA0);
i2c_write(0x02);
i2c_start(); //START READING REGISTER
i2c_write(0xA1);
byte1=i2c_read(1); //ex. if switch1 is pressed, byte1=0x7F
byte2=i2c_read(); //READ 2ND BYTE
i2c_read(0); //STOP READING
i2c_stop();
i2c_start();
i2c_write(0x32); //UPDATE LEDs WITH SWITCH STATE
i2c_write(0x02); //ACCESS OUTPUT REGISTER
i2c_write(byte1); //WRITE BYTE1 (FROM READ MODE) TO LED
i2c_write(byte2); //WRITE BYTE2 (FROM READ MODE) TO LED
i2c_stop();
} while ( (byte1!=0x00) & (byte2!=0x00) );
|
but still not a good code...it's not working any better...no response from the LED as it should be turned off by a switch press...can somebody help me |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat May 03, 2008 12:39 am |
|
|
Post a list of your connections to the AD0, AD1, and AD2 pins on the
MAX7318 chips. There may be a problem with your interpretation of
the slave address of the MAX7318 chip. But to know for sure, I must
get the list of your connections to those three pins.
Also, you have two sections of i2c code. The 2nd section is presumably
talking to the MAX7318. What chip is the 1st section talking to ?
Finally, what PIC are you using, and what is your compiler version ?
Do you have pull-up resistors on the SDA and SCL signals ? |
|
|
elizabeth ann
Joined: 16 Feb 2008 Posts: 33
|
|
Posted: Sun May 04, 2008 12:48 am |
|
|
Here are the pin connections:
Code: |
APPLICATION TYPE SLAVE ADDRESS AD0 AD1 AD2
LED indicator output 0x32 SDA SCL GND
Switch input 0xA0 GND SCL SCL
|
By the way, i am using PIC16F877A, my compiler version is 4.057 and yes, we do have pull-up resistors in SDA and SCL (10kOhms each).
Note:
BOTH SECTIONS are talking to the MAX7318, only that the first one is talking to the SWITCH (waiting for a press) and the second section is talking to the LEDs (to be turned off when a press is detected). both sections use a separate MAX7318 but in a different application.
this is the first i2c section:
here, the MAX7318 of the SWITCHES are on a READ MODE, MAX7318 waits for a switch press and the data will be saved in byte1 and byte2, which will be fed to the MAX7318 of the LEDs in the second section of the program.
Code: |
i2c_start();
i2c_write(0XA0);
i2c_write(0x02);
i2c_start(); //START READING REGISTER
i2c_write(0XA1); //0XA1 = IN READ MODE
byte1=i2c_read(1); //if switch1 is pressed,byte1=0111 1111
byte2=i2c_read(); //READ 2ND BYTE
i2c_read(0); //STOP READING
i2c_stop();
|
this is the second section:
here, i2c is talking to the MAX7318 of the LEDs and dictates which LEDs are to be turned off, based on the value of byte1 and byte2.
Code: |
i2c_start();
i2c_write(0X32); //UPDATE LEDs WITH SWITCH STATE
i2c_write(0x02); //ACCESS OUTPUT REGISTER
i2c_write(byte1); //WRITE BYTE1 (FROM READ MODE) TO LED
i2c_write(byte2); //WRITE BYTE2 (FROM READ MODE) TO LED
i2c_stop();
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun May 04, 2008 2:06 am |
|
|
Quote: | i2c_start();
i2c_write(0XA0);
i2c_write(0x02);
i2c_start(); //START READING REGISTER
i2c_write(0XA1); //0XA1 = IN READ MODE
byte1=i2c_read(1); //if switch1 is pressed,byte1=0111 1111
byte2=i2c_read(); //READ 2ND BYTE
i2c_read(0); //STOP READING
i2c_stop(); |
The value in bold (0x02) is not a read command. According to the
data sheet, it's the "output Port 1" command.
You actually want to use this command:
Quote: |
byte1=i2c_read(1); //if switch1 is pressed,byte1=0111 1111
byte2=i2c_read(); //READ 2ND BYTE
i2c_read(0); //STOP READING
|
Also, the code above is not correct. There should only be two calls to
the i2c_read() function, and the 2nd call should have a parameter of 0.
The first call should not have a parameter. Get rid of the 3rd call.
Example:
Code: |
byte1 = i2c_read(); //if switch1 is pressed,byte1=0111 1111
byte2 = i2c_read(0); //READ 2ND BYTE
|
I noticed another problem. These MAX7318 chips power-up with all
the i/o pins configured as input pins. You have to write to a config
register, to turn them into output pins. You have to write to registers
0x06 and 0x07. You need to write 0x00 to each of them, if you want
to set all 16 bits on the MAX7318 to be output pins. You're not doing
this in the code that you posted for the LED driver chip.
Here is the required code:
Code: |
i2c_start();
i2c_write(0X32);
i2c_write(0x06);
i2c_write(0x00);
i2c_write(0x00);
i2c_stop(); |
This code should be placed before the code that turns on the LEDs. |
|
|
elizabeth ann
Joined: 16 Feb 2008 Posts: 33
|
|
Posted: Sun May 04, 2008 3:01 am |
|
|
[quote="PCM programmer"] Quote: | i2c_start();
I noticed another problem. These MAX7318 chips power-up with all
the i/o pins configured as input pins. You have to write to a config
register, to turn them into output pins. You have to write to registers
0x06 and 0x07. You need to write 0x00 to each of them, if you want
to set all 16 bits on the MAX7318 to be output pins. You're not doing
this in the code that you posted for the LED driver chip.
Here is the required code:
Code: |
i2c_start();
i2c_write(0X32);
i2c_write(0x06);
i2c_write(0x00);
i2c_write(0x00);
i2c_stop(); |
This code should be placed before the code that turns on the LEDs. |
thanks a lot for your attention....
regarding the input/ouput configuration of the switches' and LEDs' MAX7318, they have been configured with the same code you posted above (only that i did not post it beforehand ) anyways, that served as a verification that my preconfigurations are indeed correct. thanks....
i have modified the code according to your corrections:
Code: |
do
{
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_start(); //START READING REGISTER
i2c_write(0xA1); // 0xA1 = IN READ MODE
byte1=i2c_read(); //if switch1 is pressed, byte1=0111 1111
byte2=i2c_read(0); //READ 2ND BYTE
i2c_stop();
i2c_start();
i2c_write(0X32); //UPDATE LEDs WITH SWITCH STATE
i2c_write(0x02); //ACCESS OUTPUT REGISTER
i2c_write(byte1); //WRITE BYTE1 (FROM READ MODE) TO LED
i2c_write(byte2); //WRITE BYTE2 (FROM READ MODE) TO LED
i2c_stop();
}while ( (byte1!=0x00) && (byte2!=0x00) );
|
i have tested this new code just a few moments ago with my hardware but no response from the switch or the LEDs...
is there anything wrong with my loop?
do { } while ??? is my condition of loop termination correct? (byte1 and 2)
or could it be that the problem is switch debouncing? i am running out of ideas as to where my code would have gotten wrong...please help....thanks so much! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun May 04, 2008 3:22 am |
|
|
Write a program to test each MAX7318 independently.
For example, write a program that only tests the MAX7318 that drives
the LEDs. With your current program, you are testing both of them at
the same time. It could be that one of the MAX7318 chips is working
perfectly. If you do independent testing, you can learn if this is true.
Also, describe the LED circuits that are connected to one of the MAX7318
chips. Give component values and all connections. |
|
|
elizabeth ann
Joined: 16 Feb 2008 Posts: 33
|
|
Posted: Sun May 04, 2008 4:53 am |
|
|
tried that a few minutes ago...
i created two separate programs. here are the results:
the MAX7318 of the LED is working fine. i can successfully write to it as to which LEDs will be turned ON or OFF.
the MAX7318 of the Switch is okay. i can detect a LOW when i press the Switch. everything seems to be fine.
but with the two programs combined, i do not get any positive result. the MAX7318 of the Switch becomes LOW when pressed but it does not turn the LED off....
here is the schematic diagram of the LED and Switch with the MAX7318 and 16F877A... i showed only one LED and Switch for this diagram (which is supposed to be 10 each)...
[img]http://Documents and Settings\ABAD\Desktop\PIC.jpg[/img] |
|
|
elizabeth ann
Joined: 16 Feb 2008 Posts: 33
|
|
Posted: Sun May 04, 2008 5:04 am |
|
|
ooops....
i think i have a little problem posting my scanned schematic diagram....
sorry but how do i post a JPEG picture in this forum?
really sorry....the "insert image" did not work for my diagram...how do i do this?thanks. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun May 04, 2008 10:34 am |
|
|
CCS doesn't allow uploading images to their server. You need to upload
the image to some other server, and then put the link to it in your post.
Some people do it on their university server. Others use a free image
hosting service. You can find them with google. You'll need a junk
email address that you can get from Yahoo. |
|
|
foodwatch
Joined: 18 Apr 2006 Posts: 66
|
|
Posted: Sun May 04, 2008 11:02 am |
|
|
I'm not very familiar with the Max IC, but the problem might be contact bouncing on the switches. Most (if not all) mechanical switches "bounce" badly when you press them. This causes a string of on-off-on-off for as much as 30ms or more, The code may interpret this as turn on and turn off so fast it is wreaking havoc with the IIC.
The best way is to create a loop for the switch press so that it waits for 50ms (or more) in this loop to see if it is still "high" (or low if you are active low) at the end of this period. In this way the iic bus does not see anything until you are sure it is a single keypress and not 10 of them in rapid sequence due to debouncing. Too long a debounce period will prevent rapid keypresses to have the desired effect.
Hope this helps... Many pushbutton switch issue can be traced to not having any or enough "de-bounce". It can also be done in hardware, but that wouldn't be any fun .... |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun May 04, 2008 3:56 pm |
|
|
Your purpose is to make the output pins follow the state of the input pins.
Change your code as shown below. Read 16 bits from the "switches" chip.
Then write it to the LED driver chip. Don't do any math or logical
operations on it. This will prove if your basic concept is working:
Code: |
while(1)
{
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_start();
i2c_write(0xA1);
byte1=i2c_read(); // if sw1 is pressed, byte1=0111 1111
byte2=i2c_read(0);
i2c_stop();
i2c_start();
i2c_write(0X32);
i2c_write(0x02);
i2c_write(byte1);
i2c_write(byte2);
i2c_stop();
delay_ms(100);
}
|
|
|
|
elizabeth ann
Joined: 16 Feb 2008 Posts: 33
|
|
Posted: Mon May 05, 2008 12:39 am |
|
|
sorry for the delayed response...
i will try that code right away, sir
and be back in a few minutes with good news, i hope
thank you very much. |
|
|
|