|
|
View previous topic :: View next topic |
Author |
Message |
Jampe
Joined: 09 Mar 2012 Posts: 27
|
receive i2c data from pic16f887 to pc by rs232 |
Posted: Fri Mar 09, 2012 4:29 pm |
|
|
Hi everyone, I am new in pic so please try to be most understandable as you can.
I tried to receive data from my pic (pic16f887) and print the data by rs232 to my PC but without success.
I use ADXL345 and after a little search - I discovered that the i2c address of it is 0x53.
I connected the the SDA to pic C4 and SCL to pic C3 and my USB-RS232 connected and configure as well.
I used EX_SLAVE.C with my little changes.
I know that my code has a lot of mistakes because I'm new of this so please don't be cruel :P
Thanks a lot , Jampe.
Code: |
#if defined(__PCM__)
#include <16F887.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#elif defined(__PCH__)
#include <18F452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#endif
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0x53)
BYTE address, buffer[0x10];
#INT_SSP
void ssp_interupt ()
{
BYTE incoming, state;
state = i2c_isr_state();
if(state <= 0x80) //Master is sending data
{
incoming = i2c_read();
printf("%d",incoming);
if(state == 1) //First received byte is address
address = incoming;
if(state == 2) //Second received byte is data
buffer[address] = incoming;
}
if(state == 0x80) //Master is requesting data
{
i2c_write(buffer[address]);
}
}
void main ()
{
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
while (TRUE) {}
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Mar 09, 2012 4:39 pm |
|
|
I'm not sure what you want to do.
Is the ADXL345 supposed to be connected to your PIC ? If so, the
ADXL345 is the "slave". The PIC is the Master. You don't use Ex_slave.c
when you want to have the PIC control an i2c device.
Ex_Slave.c is used when you want the PIC itself to be an i2c slave device.
I don't think you want that.
Also, the ADXL345 data sheet clearly says, on page 10, what the Read
and Write i2c slave addresses are for the chip:
Quote: |
I2C
With the SDO/ALT ADDRESS pin high, the 7-bit I2C address for the device is 0x1D, followed by the R/W bit. This translates to 0x3A for a write and 0x3B for a read.
An alternate I2C address of 0x53 (followed by the R/W bit) can be chosen by grounding the SDO/ALT ADDRESS pin (Pin 12). This translates to 0xA6 for a write and 0xA7 for a read. |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19510
|
|
Posted: Fri Mar 09, 2012 4:40 pm |
|
|
Some comments:
1) The ADXL345, is a _slave_ device. You need to run your PIC as a master.
2) As a master you won't use INT_SSP. However in future, _never_ print inside this. There is _not_ time to do this. If you were running as a slave, you would have to buffer the data into RAM, and print it in the main code. Repeat the mantra "keep ISR's quick unless you know exactly what you are doing"...
An 'almost working' set of code to drive the ADXL, has been posted here in the past, together with the rest of the thread giving the fixes needed to get it working. Base your code on this.
Best Wishes |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Fri Mar 09, 2012 4:40 pm |
|
|
my first comment is that
Quote: |
printf("%d",incoming);
|
DOES NOT belong in the ISR
i suggest you put your data into a global variable array structure and print it OUTSIDE the ISR |
|
|
Jampe
Joined: 09 Mar 2012 Posts: 27
|
Thank you all for your rapid replies. |
Posted: Fri Mar 09, 2012 6:18 pm |
|
|
I am trying to print the data of the accelerometer.
ADXL345 is connected to the pic.
Because your posts I know that my understanding of i2c is wrong.
I will search a sample code like Ttelmah said.
Thanks everybody for your helping, I will update soon about my progress.
Jampe. |
|
|
Jampe
Joined: 09 Mar 2012 Posts: 27
|
|
Posted: Sat Mar 10, 2012 3:12 am |
|
|
Sorry about my double post.
I've tried to write a new code but it's written me always "FF" in any address.
this is my i2c.h file (created by pic wizard) :
Quote: |
#include <16F887.h>
#device adc=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#use delay(clock=20000000)
|
this is my i2c.c file :
Quote: |
#include <i2c4.h>
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)
#define WRT_ADDR 0x3A
#define READ_ADDR 0x3B
//====================================
void main()
{
int8 data;
while(TRUE)
{
i2c_start();
i2c_write(READ_ADDR);
data = i2c_read(0);
i2c_stop();
printf("read %X \n\r", data);
delay_ms(1000);
}
}
|
I tried to change these bold address in 0xa6 and 0xa7 but without success.
Like you see , this is my first project with pic and i2c so please be patient and explain me where am I worng.
Thanks ,
Jampe. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19510
|
|
Posted: Sat Mar 10, 2012 7:04 am |
|
|
You have got the pull up resistors on the I2C lines?.
_Necessary_.
CS pin pulled to 5v. Needed for I2C operation.
Is the ALT ADDRESS pin tied high or low?. It needs to be high for the 0x£A/3B address.
Key paragraph in the data sheet:
"There are no internal pull-up or pull-down resistors for any unused pins; therefore, there is no known state or default state
for the CS or ALT ADDRESS pin if left floating or unconnected.
It is required that the CS pin be connected to VDD I/O and that the ALT ADDRESS pin be connected to either VDD I/O or GND when using I2C."
Then you are not saying what register in the device you want to read. The default could be anything (not specified in the data sheet), so could be an invalid 'empty' register...
Best Wishes |
|
|
Jampe
Joined: 09 Mar 2012 Posts: 27
|
|
Posted: Sat Mar 10, 2012 1:35 pm |
|
|
Thank you Ttelmah for your reply.
I even tried to use SRF08 (ultrasonic) but it still "FF" (with 0xE0 address).
I don't understand where am I worng...
This code is for "SRF08" :
Code: |
#include <16F887.h>
#device adc=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)
#define READ_ADDR 0xE0
//====================================
void main()
{
int8 data;
while(TRUE)
{
i2c_start();
i2c_write(READ_ADDR);
data = i2c_read(0);
i2c_stop();
printf("read %X \n\r", data);
delay_ms(1000);
}
}
|
Thanks all ,
Jampe. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19510
|
|
Posted: Sat Mar 10, 2012 1:51 pm |
|
|
You are still missing the point about telling the unit what register you want to talk to.
In I2C, the standard communication sequence is:
START
SEND WRITE ADDRESS
SEND register number to talk to
SEND any commands needed to this register(optional)
RESTART
SEND READ ADDRESS
READ - (NACK last byte if doing multiple reads)
STOP
For the SRF, you need to talk to the command register, and tell it to start a reading, then select the result register, and read from this.
Best Wishes |
|
|
Jampe
Joined: 09 Mar 2012 Posts: 27
|
|
Posted: Sun Mar 11, 2012 12:11 am |
|
|
Ttelmah thank you again for your reply.
I understand where is my problem but even with your explanation I can't write a code (because my meager knowledge).
Code: | #include <i2c4.h>
#use i2c(Master,sda=PIN_C4,scl=PIN_C3)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
void main()
{
int8 data;
while(TRUE)
{
i2c_start(); // initiate start condition
i2c_write(0x51); // device address
i2c_write(0x00); // register address
i2c_stop();
i2c_start();
i2c_write(0xE0);
data=i2c_read(1);
i2c_stop();
printf("data=%x\n",data);
}
}
|
The problem is it's written me all the time "FF".
I believe there's something worng in my address settings but I really don't get it.
Thanks ,
Jampe. |
|
|
Jampe
Joined: 09 Mar 2012 Posts: 27
|
|
Posted: Mon Mar 12, 2012 8:31 am |
|
|
Does anyone know what can I do?
This problem is very common and I don't find the solution.
Thanks ,
Jampe. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1348
|
|
Posted: Mon Mar 12, 2012 8:54 am |
|
|
Well, for starters
1. You still aren't using the right addresses. You even use two completely different addresses for the operation, which is a no no
2. You don't need to issue an i2c_stop after the first part, just at the end.
3. You still don't NACK the last byte read like you should be. Read the documentation on i2c_read() to see how to NACK
From looking at your code, this is what your posted code is doing:
1. You tell device 0x28 that you want to read from it (by sending 0x51)
2. You then write to the device instead, even though you told it you were gonna read from it.
3. You stop the the communications when all you need is just the i2c_start() to issue a restart
4. You tell device 0x70 that you want to write to it (by sending 0xE0)
5. You then read from the device instead, even though you told it you were gonna write to it. On top of that, you ACK the last byte instead of NACK'ing the last byte
I'm not saying it this way to be mean. I want you to understand what you are doing wrong.
Ask yourself a couple of questions:
What is the device address that I am supposed to use? If you need 0x1D, then you NEED to use 0x3A to write to the device and 0x3B to read from the device. If you need 0x53, then you NEED 0xA6 to write to the device and 0xA7 to read from the device. You cannot use 0xE0 or 0x51 to do it.
So which address do you need? Did you set SDO/ALT ADDRESS high or low? This will determine which address to use.
Once you know that, then use
#DEFINE I2C_READ_ADDR 0x3A //0xA6 if alternate address
#DEFINE I2C_WRITE_ADDR 0x3B //0xA7 if alternate address
Then go back into your last code and replace the 0x51 with the I2C_WRITE_ADDR and the 0xE0 with the I2C_READ_ADDR. After that, remove the first i2c_stop() call. After that, fix the i2c_read() to NACK the byte it reads.
Post the code you have changed for this. |
|
|
Jampe
Joined: 09 Mar 2012 Posts: 27
|
|
Posted: Mon Mar 12, 2012 9:27 am |
|
|
Thank you jeremiah for your rapidly and effective post!
Your message very helped me to understand!
I don't know if you saw but now I spoke about STF08 sensor and its datasheet wrote these address here but nevermind..
Quote: |
Then go back into your last code and replace the 0x51 with the I2C_WRITE_ADDR and the 0xE0 with the I2C_READ_ADDR. After that, remove the first i2c_stop() call. After that, fix the i2c_read() to NACK the byte it reads."
|
This is my new code for ADXL345 :
Code: |
#include <16F887.h>
#device adc=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#use i2c(Master,sda=PIN_C4,scl=PIN_C3)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#DEFINE I2C_READ_ADDR 0x3B
#DEFINE I2C_WRITE_ADDR 0x3A
void main()
{
int8 data;
while(TRUE)
{
i2c_start(); // initiate start condition
i2c_write(I2C_WRITE_ADDR); // device address
i2c_write(0x32); // register address
i2c_start();
i2c_write(I2C_READ_ADDR);
data=i2c_read(0);
i2c_stop();
printf("data=%x\n",data);
}
}
|
When I use :
Code: |
#DEFINE I2C_READ_ADDR 0xA7
#DEFINE I2C_WRITE_ADDR 0xA6
|
I receive "00".
Is that mean I alternative addresses?
I'm sorry about my lack of information that I give you , It's my first time with it like I wrote before.
Thank you for your help and your patience,
Jampe. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1348
|
|
Posted: Mon Mar 12, 2012 10:36 am |
|
|
Nah, I missed that you switched to a different chip. I thought you were still using the other chip. I'll look at the datasheet on that when I have a spare minute. If you are using that SRF08 chip, then make the I2C_WRITE_ADDRESS 0xE0 and the I2C_READ_ADDR 0xE1
For giggles, try
Code: |
i2c_start(); // initiate start condition
i2c_write(I2C_WRITE_ADDR); // device address
i2c_write(0x00); // register address
i2c_start();
i2c_write(I2C_READ_ADDR); // device address
data = i2c_read(0);
i2c_stop();
|
use the 0xE0 and 0xE1 addresses |
|
|
Jampe
Joined: 09 Mar 2012 Posts: 27
|
|
Posted: Mon Mar 12, 2012 10:55 am |
|
|
I tried your code and it doesn't work.
I tried these two sensors each one alone for testing and the result is the same ("FF");
To be sure , It's the way I connected the sensor to the pic :
This is the full specs file of the sensor (here).
Thanks,
Jampe. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|