![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
sercankurt
Joined: 28 Aug 2021 Posts: 12
|
please help! QMC5883L compass library. upg: SOLVED! |
Posted: Sat Aug 28, 2021 9:41 am |
|
|
Hi everyone!
I have qmc5883L (address is 0x0d) compass sensor and i need library for ccs c. I use 16F887. I found many libraries on internet which are hmc5883 but they never worked for me at all
one of my friend said that to me " Hmc5883 libraries wont work for the QMC because qmc registers are completely different from the HMC... Even the operating modes are different... The QMC doesn't even have a single measurement mode (i did a really fast datasheet read)... " so it means that I need a new qmc5883 library according to datasheet. this sensor is key part of my project, looking for your help very much!
I do this as a hobby, still learning codes and trying to
understand i2c and i don't know how to read datasheets correctly for now:(
Thats why I need your help, Thank you!
This is a Library of hmc5883L. Maybe we can convert it to a QMC5883 Library according to QMC5883 datasheet ? What do you think?
Code: | // HMC5883 required Registers
#define W_DATA 0x3C //'Used to perform a Write operation
#define R_DATA 0x3D //'Used to perform a Read operation
#define CON_A 0x00
#define CON_B 0x01 //'Send continuous MeVARurement mode.
#define MOD_R 0x02 //'Read/Write Register, Selects the operating mode. Default = Single meVARurement
#define X_MSB 0x03 //'Read Register, Output of X MSB 8-bit value.
#define X_LSB 0x04 //'Read Register, Output of X LSB 8-bit value.
#define Z_MSB 0x05 //'Read Register, Output of Z MSB 8-bit value.
#define Z_LSB 0x06 //'Read Register, Output of Z LSB 8-bit value.
#define Y_MSB 0x07 //'Read Register, Output of Y MSB 8-bit value.
#define Y_LSB 0x08 //'Read Register, Output of Y LSB 8-bit value.
void hmc5883_write(int add, int data)
{
i2c_start();
i2c_write(W_DATA);
i2c_write(add);
i2c_write(data);
i2c_stop();
}
int16 hmc5883_read(int add){
int retval;
i2c_start();
i2c_write(W_DATA);
i2c_write(add);
i2c_start();
i2c_write(R_DATA);
retval=i2c_read(0);
i2c_stop();
return retval;
}
void hmc5883_init(){
hmc5883_write(MOD_R, 0x00);
delay_ms(100);
hmc5883_write(CON_A, 0x10);
delay_ms(100);
hmc5883_write(CON_B, 0x20);
delay_ms(100);
} |
And this is an example:
Code: | #include <16f877A.h>
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES HS //Dont change
#use delay(clock=20MHz)
#use I2C(master, sda=PIN_d0, scl=PIN_d1, slow) //You can change, according your board ports
#include "EXLCD.C" //You can change, according your board ports
#include "HMC5883.C"
#include "math.h"
int8 M_data[6]; //6 units 8 bit Measured datas
int16 Xm=0,Ym=0,Zm=0; //16 bit X,Y,Z variables
void main()
{
delay_ms(2);
lcd_init();
hmc5883_init();
printf(lcd_putc,"\f");
lcd_gotoxy(1,1);
printf(lcd_putc," HMC5883L ");
lcd_gotoxy(1,2);
printf(lcd_putc,"Digital Compass ");
delay_ms(1000);
printf(lcd_putc,"\f");
while(TRUE)
{
M_data[0]=hmc5883_read(0x04); //Read X (LSB)
M_data[1]=hmc5883_read(0x03); //Read X (MSB)
M_data[2]=hmc5883_read(0x08); //Read Y (LSB)
M_data[3]=hmc5883_read(0x07); //Read Y (MSB)
M_data[4]=hmc5883_read(0x06); //Read Z (LSB)
M_data[5]=hmc5883_read(0x05); //Read Z (MSB)
Xm=make16(M_data[1],M_data[0]);
Ym=make16(M_data[3],M_data[2]);
Zm=make16(M_data[5],M_data[4]);
float Heading = atan2((signed int16)Ym,(signed int16)Xm)* 180 / pi + 180;
lcd_gotoxy(1,1);
printf(lcd_putc,"X=%ld ",Xm);
lcd_gotoxy(9,1);
printf(lcd_putc,"Y=%ld ",Ym);
lcd_gotoxy(1,2);
printf(lcd_putc,"Z=%ld ",Zm);
lcd_gotoxy(9,2);
printf(lcd_putc,"H=%f ",Heading);
delay_ms(100);
}
}
|
I'm looking forward for your helps! Thanks!
Last edited by sercankurt on Sun Aug 29, 2021 2:00 pm; edited 2 times in total |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9168 Location: Greensville,Ontario
|
|
Posted: Sat Aug 28, 2021 10:43 am |
|
|
First question:
That PIC is a 5 volt device, and most peripherals today are 3 volt devices so...
do you have logic level conversion between them ?? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19358
|
|
Posted: Sat Aug 28, 2021 10:49 am |
|
|
Also you say 'address is 0xD', this sounds like a 7bit I2C address. If this
is the case the address for PIC I2C would be 1A for a write, and 1B for
reading. Not what you have in your code. |
|
![](templates/subSilver/images/spacer.gif) |
sercankurt
Joined: 28 Aug 2021 Posts: 12
|
|
Posted: Sat Aug 28, 2021 12:38 pm |
|
|
Ttelmah wrote: | Also you say 'address is 0xD', this sounds like a 7bit I2C address. If this
is the case the address for PIC I2C would be 1A for a write, and 1B for
reading. Not what you have in your code. |
Thanks for answering, I tried as you said, but heading is written 180 and doesn't change so didn't work :( Maybe its HMC library can't work because "registers and operating modes ar different" as I mentioned in post my friend said. What do you think ? because even I change to 0x0d, or like you say 0x1a or 0x01b it doesnt works but i realized that heading number turned to 180 and stays like that when i changed address to 1a and 1b
Code: | #define W_DATA 0x1A // **************
#define R_DATA 0x1B //'*************
#define CON_A 0x00
#define CON_B 0x01 //'Send continuous MeVARurement mode.
#define MOD_R 0x02 //'Read/Write Register, Selects the operating mode. Default = Single meVARurement
#define X_MSB 0x03 //'Read Register, Output of X MSB 8-bit value.
#define X_LSB 0x04 //'Read Register, Output of X LSB 8-bit value.
#define Z_MSB 0x05 //'Read Register, Output of Z MSB 8-bit value.
#define Z_LSB 0x06 //'Read Register, Output of Z LSB 8-bit value.
#define Y_MSB 0x07 //'Read Register, Output of Y MSB 8-bit value.
#define Y_LSB 0x08 //'Read Register, Output of Y LSB 8-bit value.
|
Last edited by sercankurt on Sat Aug 28, 2021 12:44 pm; edited 1 time in total |
|
![](templates/subSilver/images/spacer.gif) |
sercankurt
Joined: 28 Aug 2021 Posts: 12
|
|
Posted: Sat Aug 28, 2021 12:40 pm |
|
|
temtronic wrote: | first question
That PIC is a 5 volt device, and most peripherals today are 3 volt devices so...
do you have logic level conversion between them ?? |
Thanks for answering! I think its all about library :(
Because I tried on Ardunio it works perfectly with 5 vdc. |
|
![](templates/subSilver/images/spacer.gif) |
sercankurt
Joined: 28 Aug 2021 Posts: 12
|
|
Posted: Sat Aug 28, 2021 12:48 pm |
|
|
By the way I tried my QMC5883L with ardunio in order to test and works perfectly, with this library and header:
https://github.com/keepworking/Mecha_QMC5883L
Maybe somebody could help me converting this library to ccs library, I think it would be perfect because codes are similar! thanks all! |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9168 Location: Greensville,Ontario
|
|
Posted: Sat Aug 28, 2021 1:04 pm |
|
|
Go to 'code library', download PCM P's I2C scanner program, compile and test on PIC. It will tell you the address of the device, if it finds it !!
With any I2C device, this should be done.
Sometimes premade modules will NOT be their 'default' address.
As pointed out ...Ardunio code use 7 bit I2C addresses, CCS uses 8 bit. |
|
![](templates/subSilver/images/spacer.gif) |
sercankurt
Joined: 28 Aug 2021 Posts: 12
|
|
Posted: Sat Aug 28, 2021 1:44 pm |
|
|
temtronic wrote: | goto 'code library', download PCM P's I2C scanner program, compile and test on PIC. It will tell you the address of the device ,if it finds it !!
With any I2C device, this should be done.
Sometimes premade modules will NOT be their 'default' address.
As pointed out ...Ardunio code use 7 bit I2C addresses, CCS uses 8 bit. |
I did that (with my 16f887) i2c scanner and it found 1A! but it still doesn't work when i write to address in library :(
Code: |
#define W_DATA 0x1A // **************
#define R_DATA 0x1B //' when I write here 1B, heading written "180" and just stays like that, this is the only difference | *
and also I tried like
Code: |
#define W_DATA 0x1A // **************
#define R_DATA 0x1A //'************ | *
but doesn't work.. Can you recommend or write or send me a library which could work with QMC5883L ?
can you look at this datasheet, can we write a simpe datasheet according to this? : https://electropeak.com/learn/download/datasheet-qmc5883l/ |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19358
|
|
Posted: Sun Aug 29, 2021 9:24 am |
|
|
When you used the I2C scanner program, how was the I2C setup?.
Post the setup line you used for this.
Now there is a very significant issue, which comes down to understanding
voltages. The Arduino inputs use TTL threshold levels, so 2.4v is seen as
a logic '1'. On the PIC, the threshold levels depend on the pins being used,
and the peripheral involved. The actual I2C peripheral (if you used the
hardware), has it's '1' threshold as 4v. So a 3.3v device will not ever be
able to generate a logic 1. However if you set the hardware I2C to
SMBUS mode, this sets the hardware threshold down to a lower level
that should work.
The scanner program never has to actually see a logic '1' from the device
it is instead dependant only on the ACK/NACK bit.
Now you are showing the connections to a software I2C. The pins you show
(D0 & D1), have Schmidt input thresholds, so require the signal (with the
PIC at 5v), to get up to 3.5v, before a '1' will be seen. So not going to work.
Move your compass to connect to any of pins B1 to B5, A0 to A3, or A5.
These are the PIC pins on your chip, that have TTL input thresholds (so
like the Arduino pins).
The thresholds on the D pins, are Schmidt when it is used as a I/O port,
and TTL when used as a PSP port. So Schmitt for your code.
You are not understanding how voltage requirements are not just
dependant on being a 5v or 3.3v device, but depend on the actual pins
involved. |
|
![](templates/subSilver/images/spacer.gif) |
sercankurt
Joined: 28 Aug 2021 Posts: 12
|
|
Posted: Sun Aug 29, 2021 1:59 pm |
|
|
temtronic wrote: | Go to 'code library', download PCM P's I2C scanner program, compile and test on PIC. It will tell you the address of the device, if it finds it !!
With any I2C device, this should be done.
Sometimes premade modules will NOT be their 'default' address.
As pointed out ...Ardunio code use 7 bit I2C addresses, CCS uses 8 bit. |
Ttelmah wrote: | When you used the I2C scanner program, how was the I2C setup?.
Post the setup line you used for this.
Now there is a very significant issue, which comes down to understanding
voltages. The Arduino inputs use TTL threshold levels, so 2.4v is seen as
a logic '1'. On the PIC, the threshold levels depend on the pins being used,
and the peripheral involved. The actual I2C peripheral (if you used the
hardware), has it's '1' threshold as 4v. So a 3.3v device will not ever be
able to generate a logic 1. However if you set the hardware I2C to
SMBUS mode, this sets the hardware threshold down to a lower level
that should work.
The scanner program never has to actually see a logic '1' from the device
it is instead dependant only on the ACK/NACK bit.
Now you are showing the connections to a software I2C. The pins you show
(D0 & D1), have Schmidt input thresholds, so require the signal (with the
PIC at 5v), to get up to 3.5v, before a '1' will be seen. So not going to work.
Move your compass to connect to any of pins B1 to B5, A0 to A3, or A5.
These are the PIC pins on your chip, that have TTL input thresholds (so
like the Arduino pins).
The thresholds on the D pins, are Schmidt when it is used as a I/O port,
and TTL when used as a PSP port. So Schmitt for your code.
You are not understanding how voltage requirements are not just
dependant on being a 5v or 3.3v device, but depend on the actual pins
involved. |
Dear Temtronic and Ttelmah, thank you for your all reply!! I just solved it by coincidence ! I found the registers and some i2c numbers(I tried and worked by coincidence:)) ) from datasheet and changed on the library and it works perfectly now. Shame on me that I don't know how to read datasheet correctly, but I will learn by time. I was lucky for now!
I'm sharing the below:
Code: | // HMC5883 required Registers
#define W_DATA 0x1A //'Used to perform a Write operation
#define R_DATA 0x1B //'Used to perform a Read operation
#define CON_A 0xA0
#define CON_B 0x0B //'Send continuous Measurement mode.
#define MOD_R 0x09 //'Read/Write Register, Selects the operating mode. Default = Single meVARurement
#define X_MSB 0x01 //'Read Register, Output of X MSB 8-bit value.
#define X_LSB 0x00 //'Read Register, Output of X LSB 8-bit value.
#define Z_MSB 0X05 //'Read Register, Output of Z MSB 8-bit value.
#define Z_LSB 0X04 //'Read Register, Output of Z LSB 8-bit value.
#define Y_MSB 0X03 //'Read Register, Output of Y MSB 8-bit value.
#define Y_LSB 0X02 //'Read Register, Output of Y LSB 8-bit value.
void hmc5883_write(int add, int data)
{
i2c_start();
i2c_write(W_DATA);
i2c_write(add);
i2c_write(data);
i2c_stop();
}
int16 hmc5883_read(int add){
int retval;
i2c_start();
i2c_write(W_DATA);
i2c_write(add);
i2c_start();
i2c_write(R_DATA);
retval=i2c_read(0);
i2c_stop();
return retval;
}
void hmc5883_init(){
hmc5883_write(CON_B, 0x01);
delay_ms(100);
hmc5883_write(MOD_R, 0b10011001);
delay_ms(100);
hmc5883_write(CON_A, 0b10000001);
delay_ms(100);
} |
and example:
Code: | #include <16F887.h>
#fuses HS, NOWDT, NOPROTECT, NOMCLR
#use delay(clock=20M)
#use I2C(MASTER, sda=PIN_C4, scl=PIN_C3, fast=100000, force_hw) //You can change, according your board ports
#use RS232(BAUD = 9600, XMIT = PIN_C6, RCV = PIN_C7, STOP = 1, STREAM = Bluetooth)
#include "i2c_flex_lcd.c"
#include "HMC5883.c"
#include "math.h"
int8 M_data[6]; //6 units 8 bit Measured datas
int16 Xm=0,Ym=0,Zm=0; //16 bit X,Y,Z variables
void main()
{
delay_ms(10);
lcd_init(0x7e,16,2);
hmc5883_init();
lcd_clear();
while(TRUE)
{
M_data[0]=hmc5883_read(0x00); //Read X (LSB)
M_data[1]=hmc5883_read(0x01); //Read X (MSB)
M_data[2]=hmc5883_read(0x02); //Read Y (LSB)
M_data[3]=hmc5883_read(0x03); //Read Y (MSB)
M_data[4]=hmc5883_read(0x04); //Read Z (LSB)
M_data[5]=hmc5883_read(0x05); //Read Z (MSB)
Xm=make16(M_data[1],M_data[0]);
Ym=make16(M_data[3],M_data[2]);
Zm=make16(M_data[5],M_data[4]);
float Heading = atan2((signed int16)Ym-360,(signed int16)Xm-310) * 180 / pi + 180;
lcd_gotoxy(1,1);
printf(lcd_putc,"X=%ld ",Xm);
lcd_gotoxy(9,1);
printf(lcd_putc,"Y=%ld ",Ym);
lcd_gotoxy(1,2);
printf(lcd_putc,"Z=%ld ",Zm);
lcd_gotoxy(9,2);
printf(lcd_putc,"h=%f ",Heading);
fprintf(bluetooth,"\n h=%f ",Heading);
delay_ms(250);
}
} |
|
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9168 Location: Greensville,Ontario
|
|
Posted: Sun Aug 29, 2021 2:14 pm |
|
|
I'm happy you got it working !!!
Jay |
|
![](templates/subSilver/images/spacer.gif) |
cyril.carlita
Joined: 20 Jul 2023 Posts: 5
|
|
Posted: Thu Jul 20, 2023 1:41 pm |
|
|
Hello, i tried the first code, it works for me but the direction that indicate the north is not very well.
After i have tried the last code, it doesn't work for me, the lcd indicates
x=-1 y=-1 z=-1 h=49.25
Does the first code good for you? ![Question](images/smiles/icon_question.gif) |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|