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 CCS Technical Support

Problem displaying compass bearing on lcd

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Gerhard



Joined: 30 Aug 2007
Posts: 144
Location: South Africa

View user's profile Send private message Send e-mail

Problem displaying compass bearing on lcd
PostPosted: Sat Sep 06, 2008 4:38 pm     Reply with quote

Hi. I have a HMC6352 honeywell compass conected to a PIC16f886 using i2c. Problem is that the LCD is working and i get correct readout of other variables but when i use the compass i only get garbage.

Please advice if i made a common mistake.

Code:
#include <16F886.H>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=20000000)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3, FORCE_HW)
#include <Flex_LCD420.c>
#define HMC6352_I2C_WRITE_ADDRESS 0x42
#define HMC6352_I2C_READ_ADDRESS  0x43
#define HMC6352_GET_DATA_COMMAND 0x41
int16 heading;
void setup()
{
     
 //    setup_timer_0(RTCC_INTERNAL | RTCC_DIV_32);
  //   enable_interrupts(INT_TIMER0);
 //    enable_interrupts(global);
 //    set_rtcc (100);
     lcd_init();
}

int16 HMC6352_read_heading(void);
void clearLCD();
//===================================
void main()
{
   setup();
   clearLCD();
while(1)
  {
   
   heading = HMC6352_read_heading();
   heading=heading/100;
   lcd_gotoxy(1,1);
   printf(lcd_putc, "heading");
   lcd_gotoxy(1,2);
   printf(lcd_putc,"%lu", heading);
   delay_ms(1000);  }

}
//==================================
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); 

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

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

//==================================================
void clearLCD()
{
    printf(lcd_putc, "\f");
    delay_ms(100);
}
RayJones



Joined: 20 Aug 2008
Posts: 30
Location: Melbourne, Australia

View user's profile Send private message Visit poster's website

PostPosted: Sat Sep 06, 2008 6:23 pm     Reply with quote

First obvious thing is you've assembled the 16 bit integer incorrectly.

You have

Code:
return((int16)msb | ((int16)lsb << 8));


This should be

Code:
return((int16)lsb | ((int16)msb << 8));


Ray
Gerhard



Joined: 30 Aug 2007
Posts: 144
Location: South Africa

View user's profile Send private message Send e-mail

PostPosted: Sat Sep 06, 2008 6:57 pm     Reply with quote

Thanks.

Between you and PCM programmer a driver has been written perfectly.
It should be posted in the Code library so it could help others in future.
Works perfectly
andrewg



Joined: 17 Aug 2005
Posts: 316
Location: Perth, Western Australia

View user's profile Send private message Visit poster's website

PostPosted: Sat Sep 06, 2008 10:45 pm     Reply with quote

Instead of
Code:
return((int16)lsb | ((int16)msb << 8));
I prefer to use
Code:
return make16(msb, lsb);
which is a teeny bit more efficient.
_________________
Andrew
RayJones



Joined: 20 Aug 2008
Posts: 30
Location: Melbourne, Australia

View user's profile Send private message Visit poster's website

PostPosted: Sun Sep 07, 2008 12:43 am     Reply with quote

Granted, but even more efficient using standard C functionality would be:

Code:

typedef union {
  int16 word;
  struct {
    int8 lsb;
    int8 msb;
  } bytes;
} Val16 ;

int16 example1()
{
  Val16 heading;

  heading.bytes.msb = i2c_read();
  heading.bytes.lsb = i2c_read(0);

  return heading.word;
}

ie. the compiler directly places the values in the memory locations for the 16 bit word and no further fiddling is required Very Happy

Even more efficient, utilising some of the C++ functionality in the CCS compiler, try this:
Code:

void example2(Val16& heading)
{
  heading.bytes.msb = i2c_read();
  heading.bytes.lsb = i2c_read(0);
}

Once again, this puts the values directly into a 16 bit value, but even better than that, the pass by reference puts these writes smack bang into the calling routine's 16 bit value. Laughing

Sorry, I got bored and had to have a play about. Wink

Cheers, Ray
RayJones



Joined: 20 Aug 2008
Posts: 30
Location: Melbourne, Australia

View user's profile Send private message Visit poster's website

PostPosted: Sun Sep 07, 2008 12:49 am     Reply with quote

Oh yeah, for OP's benefit, the way you'd call these are:

Code:

main() {
  int16 heading;

  heading = example1();

  example2(heading);
}


All tested on my copy of CCS. Smile

Cheers, Ray
Ttelmah
Guest







PostPosted: Sun Sep 07, 2008 2:51 am     Reply with quote

Yes.
The compiler is pretty efficient in this area, and will optimise to very nearly the same code for each approach to combining the bytes, but the union approach, is 'standard C', and will work (with caveats about byte order), on any C, while the 'make16' function is CCS specific.

Best Wishes
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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