Electronic Projects, forums and more.

Go Back   Electronic Circuits Projects Diagrams Free > Electronics Categories > Micro Controllers


Micro Controllers Discuss all aspects of micro controllers - building them, coding them, etc. All controllers are welcome - PIC, BASIC, Z8 Encore!, etc.

Reply
 
Tools
Old 22nd May 2007, 08:40 PM   #1
Default Using a PIC16F877 to read a Devantech CMPS03 compass and send the results over RS232

I feel like an idiot here, and I can't believe there aren't any examples of this on the web already somewhere...

Here is my schematic, very straight forward. 16F877 chip with a MAX232 interface chip, and a Devantech CMPS03 compass module.



And here is my code (written in CCS-C):
Code:
#include <16F877.h>
#device adc=10

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                       //High speed Osc (> 4mhz)
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES LVP                      //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected
#FUSES NODEBUG                  //No Debug mode for ICD

#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3)

long   read_compass()
{
   long   value;

   i2c_start();
   i2c_write( 0xC0 );   // The address of the compass (READ LOW)
   i2c_write( 0x02 );   // Command (read 360 degrees)

   i2c_start();         // Restart to change data dir
   i2c_write( 0xC1 );   // The address of the compass (READ HIGH)

   // Read 2 bytes (HI/LO) and combine into one LONG
   value = i2c_read() << 8;      // Read the HI value * 256
   value = value + i2c_read();   // Read the LO value and add it
   i2c_stop();

   return( value );
}

void main()
{
   long   heading;

   setup_adc_ports(AN0_AN1_AN2_AN3_AN4);
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_psp(PSP_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);

   do
   {
      // Take a compass reading
      heading = read_compass();

      printf("%Lu\r\n", heading );
      delay_ms( 1000 );
   } while( TRUE );
}
I expect to get a value between 0 and 3600 displayed once per second. I expect that while I am just sitting here, the value will be fairly consistent. What I actually get is this:

Code:
65534
1023
2710
65535
2710
65535
2713
65535
2706
65535
2713
245
65534
1023
2711
65535
2710
65535
2712
65535
2716
1525
Does anyone have any idea what I'm doing wrong? If I had to guess I would say that it's got something to do with a timing issue (notice the 6553x every 1-2 reads).

-- Rob
oeginc is offline  
Old 23rd May 2007, 01:24 AM   #2
Default

Why don't you use their example c code that uses the hardware directly instead of relying on the inbuilt i2c routines. Link

Mike.
Pommie is online now  
Old 23rd May 2007, 01:25 AM   #3
Default

Quote:
Originally Posted by Pommie
Why don't you use their example c code that uses the hardware directly instead of relying on the inbuilt i2c routines. Link

Mike.
Because that's for a different C compiler and the entire reason I switched to C from assembly was to make the code more readable in the first place.
oeginc is offline  
Old 23rd May 2007, 02:31 AM   #4
Default

And people argue that c makes code more portable.

That code should work in any compiler. You can turn it into a the relevant functions to make it more readable once you have it working. It will also confirm that your hardware is not the problem.

Mike.
Pommie is online now  
Old 23rd May 2007, 02:39 AM   #5
Default

Your output is almost correct except, once you get proper value ranging in 2710-2716 and second time 0xFFFF (65535) just check if you are reading CMPS03 very fast. Just try slowing down the reading. I haven't Checked your code but from output it seems this way
neelam29 is offline  
Old 23rd May 2007, 06:15 PM   #6
Default

Quote:
Originally Posted by neelam29
Your output is almost correct except, once you get proper value ranging in 2710-2716 and second time 0xFFFF (65535) just check if you are reading CMPS03 very fast. Just try slowing down the reading. I haven't Checked your code but from output it seems this way
That's what I was thinking originally, but I am only reading the sensor once per second, and this line in the manual made me believe that the output was buffered anyways, so it shouldn't matter.

"There is no synchronism between the PWM or I2C outputs and the conversion. They both retrieve the most recent internal reading, which is continuously converted, whether it is used or not."

Also note the ~1024 values and the 245 mixed in there as well, so which ones are correct?
oeginc is offline  
Old 23rd May 2007, 06:26 PM   #7
Default

hi rob,
I expect you have checked the RS232 system and 'maths' using a few fixed test values, rather than real time data from the Compass?

Is the 50MHz xtal on the circuit a typo?

EDIT: OK Rob, Its best to ask.
I dont use C, sorry.
__________________
Eric " Good enough is Perfect "
I will NOT answer PM's requesting technical help, please use the Forum
PIC tutorials: Nigel's www.winpicprog.co.uk/ Bill's: www.blueroomelectronics.com/

Last edited by ericgibbs; 23rd May 2007 at 06:48 PM.
ericgibbs is offline  
Old 23rd May 2007, 06:44 PM   #8
Default

Quote:
Originally Posted by ericgibbs
hi rob,
I expect you have checked the RS232 system and 'maths' using a few fixed test values, rather than real time data from the Compass?

Is the 50MHz xtal on the circuit a typo?
Yes, I have, and yes it is. I have been working with the SX28 chips recently and they run a 50 Mhz resonator.

I am running the PIC at 20 Mhz. They data being sent over the RS232 appears to be working fine.
oeginc is offline  
Old 23rd May 2007, 07:01 PM   #9
Default

Can you try this?

Code:
long read_compass()
{
   long value;

   i2c_start();
   i2c_write( 0xC0 );   // The address of the compass (READ LOW)
   i2c_write( 0x02 );   // Command (read 360 degrees)

   i2c_start();           // Restart to change data dir
   i2c_write( 0xC1 );   // The address of the compass (READ HIGH)

   // Read 2 bytes (HI/LO) and combine into one LONG
   value = i2c_read();      // Read the HI value * 256
   value = value << 8;
   value += i2c_read();   // Read the LO value and add it
   i2c_stop();

   return value;
}
eng1 is offline  
Old 24th May 2007, 03:21 PM   #10
Default

Quote:
Originally Posted by eng1
Can you try this?

Code:
long read_compass()
{
   long value;

   i2c_start();
   i2c_write( 0xC0 );   // The address of the compass (READ LOW)
   i2c_write( 0x02 );   // Command (read 360 degrees)

   i2c_start();           // Restart to change data dir
   i2c_write( 0xC1 );   // The address of the compass (READ HIGH)

   // Read 2 bytes (HI/LO) and combine into one LONG
   value = i2c_read();      // Read the HI value * 256
   value = value << 8;
   value += i2c_read();   // Read the LO value and add it
   i2c_stop();

   return value;
}
Yes, that is actually one of my original code samples, I've tried all combinations (that I could think of) of the above:

value = i2c_read() * 256;
value = i2c_read() << 8;
value = i2c_read(); value *= 256;
value = i2c_read(); value = value << 8;

and
value = value + i2c_read();
value += i2c_read();

all had the same results.
oeginc is offline  
Old 24th May 2007, 03:39 PM   #11
Default

Maybe you should try the example code as I suggested 2 days ago. At least you would now know if the problem is with the built in routines. BTW, how does the compiler know when you want to send a repeated start bit? Does the compiler have a different command?

Mike.
Pommie is online now  
Old 24th May 2007, 04:57 PM   #12
Default

Quote:
Originally Posted by Pommie
Maybe you should try the example code as I suggested 2 days ago. At least you would now know if the problem is with the built in routines. BTW, how does the compiler know when you want to send a repeated start bit? Does the compiler have a different command?

Mike.
Unfortunately that code doesn't compile under the CCS C compiler, it's made for the HiTech C compiler... I've downloaded and installed the HiTech demo, but it seems like it's going to be a lot of work to convert what I already have to work in HiTech's compiler (trying to figure out how to even get the serial routines to work at the moment).

With the CCS compiler, if you send another i2c_start without sending an i2c_stop it assumes you want a restart.
oeginc is offline  
Old 24th May 2007, 05:03 PM   #13
Default

Surely it's very simple to change the code so it does work. All it is doing is writing to SFRs and setting/clearing bits.

Mike.
Pommie is online now  
Reply

Tags
cmps03, compass, devantech, pic, read, results, rs232, send

Thread Tools
Display Modes




All times are GMT. The time now is 02:35 AM.


Electronic Circuits  |  Learning Electronics
eXTReMe Tracker