CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

I2C Communication Problem using PIC16F877A
Goto page Previous  1, 2, 3, 4  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Apr 13, 2007 12:23 pm     Reply with quote

You're repeating the same mistakes that have already been discussed
in this thread. You need to read the thread and study each little detail.

For example, what parameter is missing from the line shown in bold
below ?
Quote:

void getHeading(){
disable_interrupts(global);
i2c_start();
i2c_write(COMP_W_ADDY);
i2c_write(GET_DATA_CMD);
i2c_stop();
delay_ms(6);
i2c_start();
i2c_write(COMP_R_ADDY);
msb = i2c_read();
lsb = i2c_read();
i2c_stop();
heading = ((int16)lsb | ((int16)msb << 8));
enable_interrupts(global);
}

axmanjr



Joined: 07 Aug 2007
Posts: 25
Location: Las Vegas, NV

View user's profile Send private message

PostPosted: Tue Sep 25, 2007 12:56 pm     Reply with quote

Hi, I'm having trouble implementing this device. I am using a PIC18F4680 chip with the breakout board from Sparkfun. I tried using the exact code as posted in the 1 st page of this thread. I even tried making slight modifications to the code, such as outputting "msb", "lsb", and "heading" to double check that I'm getting anything, and I'm having no luck. I even switched the order of this OR statement, as someone else had previously mentioned:
Code:
  heading = ((int16)lsb | ((int16)msb << 8));


I made sure to use resistors from SDA/SCL to high. I've messed with various values (10k, 5k, 1k...) and nothing. Do I have to configure the SDA/SCL pins as input/output using the TRIS command? Or am I missing something? Is there a way to "debug" the device? Anyone that has experience with this device could you please help. Thanks in advance!
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Sep 25, 2007 1:52 pm     Reply with quote

1. Post your CCS compiler version. This is a number such as 3.249,
or 4.013, or 4.056, etc. It's given at the top of the .LST file for
your project. The .LST file is in the project directory.

2. Post the code that you're using. The code on the 1st page is short,
and won't take up a lot of space if you post your slightly modified
version of it. The reason for you to post it is so we can look at your
fuse settings and anything else that might cause a problem with the
18F4680.

3. Post a detailed list of the connections between the PIC and the
HMC unit. Be sure to post the power and ground connections.

4. Have you ever made this PIC board do anything ? In other words,
can you make it blink an LED ?

5. This person has successfully used the code. Look at this page:
http://www.charlie-roberts.com/blindshot/blindshot.c
axmanjr



Joined: 07 Aug 2007
Posts: 25
Location: Las Vegas, NV

View user's profile Send private message

PostPosted: Tue Sep 25, 2007 2:15 pm     Reply with quote

1. 3.222

2.
Code:

// Compass Test
// 9/20/07

#include <18F4680.H>
#fuses XT,NOPROTECT,NOBROWNOUT,NOWDT,NOLVP,PUT
#use delay(clock=4000000)
#use i2c(Master,sda=PIN_C4,scl=PIN_C3,Force_HW)

#include <stdlib.h>
#include "dxLCD.c"  // my LCD driver

char myText[82];

void main()
{
   int heading1 = 0;
   int heading2 = 0;
   long answer;

   sprintf(myText, "\fCompass test:");
   lcd_print(myText);
   delay_ms(1000);

while(1)
{
   i2c_start();
   i2c_write(0x42);  //slave address of HMC6352
   i2c_write(0x41);   //have also tried i2c_write('A');
   i2c_stop();

   delay_ms(6);   //requires 6mS before data is ready to be read

   i2c_start();
   i2c_write(0x43);  // READ
   heading1 = i2c_read();
   heading2 = i2c_read(0);
   i2c_stop();

   answer = (int16)msb | ((int16)lsb << 8);
   sprintf(myText, "%d, %d, %ld", heading1, heading2, answer);
   lcd_printat(1,3,myText);
   delay_ms(3000);
}
}


3. I'm using the breakout board from sparkfun.com, which has only 4 pins. I have GND and 3.3 connected to ground and 3.3V. I have SDA connected to pin C4 with a 10k resistor connected from the same pin to 3.3V high. I also have SCL connected to pin C3 , with a 10k resistor pulling it to high as well. I have tried with several values, as was recommened from other sites (5k, 1k, etc...) but the datasheet says 10k should work.

4. Yes, this is the same PIC board that I use for all my prototyping. After being tired of troubleshooting the compass, I re-programmed the PIC with another code and it worked without a problem.

5. I have seen his code and have tried modeling mine after that (I think he got his code from you Very Happy ).

I read somewhere that maybe I could have accidently changed the slave address of the device (0x42). If that's the case, is there a way to restore the default slave address to its original value?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Sep 25, 2007 4:16 pm     Reply with quote

What's the Vdd voltage for the PIC ? Is it 5v or 3.3v ?
axmanjr



Joined: 07 Aug 2007
Posts: 25
Location: Las Vegas, NV

View user's profile Send private message

PostPosted: Tue Sep 25, 2007 5:38 pm     Reply with quote

the pic is 5V
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Sep 25, 2007 5:53 pm     Reply with quote

That's probably why it doesn't work. Pins C3 and C4 have Schmitt
trigger CMOS inputs. The PIC data sheet says the high level input
voltage is 0.8 x Vdd for those pins. That's 4 volts. You have +3.3v
on the i2c bus pull-ups. They'll never get up to 4 volts.

There are a few ways to fix this problem. The two easiest ways are:

1. Change the voltage for the compass and the pull-ups voltage to +5v.
According to the HMC6352 data sheet, it can run at 5v:
Quote:
Low Voltage Operation (2.7 to 5.2V)

http://www.ssec.honeywell.com/magnetic/datasheets/HMC6352.pdf

The circuit board from Sparkfun says 3.3v on it. But on the webpage
link that you posted, Sparkfun says this:
Quote:
Features:
Simple I2C interface
2.7 to 5.2V supply range

So, you should be able to change the compass board and the pull-ups
to +5v operation, unless there is some other limitation that I don't
know about.

2. You could move the i2c bus to some other pins that have TTL levels.
Most pins on Port A and Port B have TTL levels. This means the
logic high level is only 2.0 volts. The 3.3v pullups will easily work
with TTL input pins on the PIC. However, you would have to use
the software i2c CCS library code. You can't use FORCE_HW on
pins other than C3 and C4.
But there's probably no real reason why you need to use hardware i2c.
axmanjr



Joined: 07 Aug 2007
Posts: 25
Location: Las Vegas, NV

View user's profile Send private message

PostPosted: Tue Sep 25, 2007 6:25 pm     Reply with quote

okay, so for some reason after uploading the following code into the pic, I started getting some response:

Code:

#include <18F4680.H>
#fuses XT,NOPROTECT,NOBROWNOUT,NOWDT,NOLVP,PUT
#use delay(clock=4000000)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3, FORCE_HW)

#include <stdlib.h>
#include "dxLCD.c" //my LCD driver

#define HMC6352_I2C_WRITE_ADDRESS 0x42
#define HMC6352_I2C_READ_ADDRESS  0x43
#define HMC6352_GET_DATA_COMMAND 0x41

char myText[82];

// Read the compass heading.  This is in units
// of 1/10's of a degree, from 0 to 3599.
int16 HMC6352_read_heading(void)
{
int8 lsb;
int8 msb;

i2c_start();
i2c_write(HMC6352_I2C_WRITE_ADDRESS);
i2c_write(HMC6352_GET_DATA_COMMAND);
i2c_stop();

delay_ms(7);  // Allow 1 ms extra for safety

i2c_start();
i2c_write(HMC6352_I2C_READ_ADDRESS);
msb = i2c_read();
lsb = i2c_read(0);
i2c_stop();

//return((int16)msb | ((int16)lsb << 8));
return((int16)lsb | ((int16)msb << 8));
}

//===================================
void main()
{
int16 heading;

while(1)
  {
   heading = HMC6352_read_heading();
   sprintf(myText,"Degrees = %lu\r", heading/10);
   lcd_printat(1,3,myText);
   delay_ms(1000);
  }

}


However, for the output, im getting a messed up reading. It reads from 100-999, when it should be reading from 1-360, but reading is not spread out. When I rotate the board around counterclockwise, it'll read from like 180 to 100 in steps of 5 or 10. Real smooth. but once it hits 100, it goes to 999 (or close to) and starts decrementing in steps of 100, while I'm still rotating it slowly. When it reaches the 360 area, it'll decrement slow again. So I'm not sure what this reading is telling me.

I tried your other methods too. Changing the voltage for the chip and the SDL/SCL highs to 5V made no difference for the output readings. And your other recommendation was spitting out wrong readings as well, sometimes locking up.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Sep 25, 2007 7:03 pm     Reply with quote

What code does the lcd_printat() routine have in it ?
Are you clearing the existing text off the LCD line before you
write new text on it ?
Are you sending the "clear screen" command to the LCD ?
Currently, your sprintf() statement does not have any "white space"
after the numbers field.

Suppose you display 3 digits, such as:
Quote:
360


Then you display two digits, such as:
Quote:
99


Now, if you don't ensure that all the digits in "360" are cleared away
before you write the new digits, you will get this:
Quote:
990
axmanjr



Joined: 07 Aug 2007
Posts: 25
Location: Las Vegas, NV

View user's profile Send private message

PostPosted: Wed Sep 26, 2007 6:02 pm     Reply with quote

my lcd_printat() is the same as my lcd_print() function, exact it prints the text at a particular line. I should use lcd_print instead. I like your point about clear the screen and/or line. I remember it doing that in another function I was working with, when printing from 3 digit characters to 1 and 2 digit characters . I'll implement that into my code tomorrow and cross my fingers.
axmanjr



Joined: 07 Aug 2007
Posts: 25
Location: Las Vegas, NV

View user's profile Send private message

PostPosted: Sat Nov 10, 2007 2:15 pm     Reply with quote

I don't mean to revive old threads but I have another question concerning the HMC6352.

How would I go about recalibrating the device? I read in the datasheet that you can calibrate it and I think that I may have to do this. The response that I have been receiving from it lately seem to be incorrect. It doesn't give me a full 360 degree reading. It's more like 140 degrees. When I rotate the device around it'll range from (estimate values) 150 to 290 degrees and when it reaches the min/max value, it'll reverse the value (meaning, when it reaches 290 while still rotating, it'll start going backwards down to 150 again).

Here's the familiar code that I'm using:
Code:
// Compass Test
// 9/27/07

#include <18F4680.H>
#fuses XT,NOPROTECT,NOBROWNOUT,NOWDT,NOLVP,PUT
#use delay(clock=4000000)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3, FORCE_HW)

#include <stdio.h>
#include <stdlib.h>
#include "myGLCD.c"

#define HMC6352_I2C_WRITE_ADDRESS 0x42
#define HMC6352_I2C_READ_ADDRESS  0x43
#define HMC6352_GET_DATA_COMMAND 0x41

char myText[82];

// Read the compass heading.  This is in units
// of 1/10's of a degree, from 0 to 3599.
void main()
{
   int lsb;
   int msb;
   long heading;

   while(1) {
      i2c_start();
      i2c_write(0x42);
      i2c_write(0x41);
      i2c_stop();

      delay_ms(7);  // Allow 1 ms extra for safety

      i2c_start();
      i2c_write(0x43);
      msb = i2c_read();
      lsb = i2c_read(0);
      i2c_stop();

      heading = ((long)lsb | ((long)msb << 8))/10;

      sprintf(myText,"\fDegrees = %lu   ", heading);
      lcd_print(myText);
      delay_ms(1000);
   }
}


Any help would be appreciated. Thanks!
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Nov 11, 2007 1:58 am     Reply with quote

My help would be to Google it.
Quote:
HMC6352 calibration CCS

The first hit is a thread on the Sparkfun forum and it has all the
routines you need, down at the end of the thread. The data sheet
describes what you need to do, while in calibration mode.
Guest








PostPosted: Wed Jul 22, 2009 5:21 pm     Reply with quote

I've been trying to calibrate the HMC6352. But I have no idea how do that. My default address is 0x21, so I do this: i2cwrite(0x42,0x43), cause: 0x42=0x21+'0' to write and 0x43='C'=calibration mode...but I have no response. Any idea?
Help would be appreciated.
Thanks!
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Jul 22, 2009 5:46 pm     Reply with quote

Do a Google search for this. Find other forums where they've already
done it:
Quote:
calibrate HMC6352

For example, there's some CCS code at the end of this thread. I don't
know if it works, but you can try it.
http://forum.sparkfun.com/viewtopic.php?p=28630

You can look at other hits from that search. Look at the compass.c
code that you can download from this page. It has a calibrate routine.
http://www.freelists.org/post/sharpclub/hmc6352-compass,4

In other words, if this forum doesn't have the information, probably
some other forum will. Use Google to find it.
Guest








PostPosted: Thu Jul 23, 2009 6:15 am     Reply with quote

Thanks for the quick answer, but I've already google a lot trying to find a solution....and still doesn't work.

Thanks.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2, 3, 4  Next
Page 3 of 4

 
Jump to:  
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