View previous topic :: View next topic |
Author |
Message |
Gerhard
Joined: 30 Aug 2007 Posts: 144 Location: South Africa
|
Problem displaying compass bearing on lcd |
Posted: Sat Sep 06, 2008 4:38 pm |
|
|
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
|
|
Posted: Sat Sep 06, 2008 6:23 pm |
|
|
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
|
|
Posted: Sat Sep 06, 2008 6:57 pm |
|
|
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
|
|
Posted: Sat Sep 06, 2008 10:45 pm |
|
|
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
|
|
Posted: Sun Sep 07, 2008 12:43 am |
|
|
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
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.
Sorry, I got bored and had to have a play about.
Cheers, Ray |
|
|
RayJones
Joined: 20 Aug 2008 Posts: 30 Location: Melbourne, Australia
|
|
Posted: Sun Sep 07, 2008 12:49 am |
|
|
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.
Cheers, Ray |
|
|
Ttelmah Guest
|
|
Posted: Sun Sep 07, 2008 2:51 am |
|
|
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 |
|
|
|