Digital Compass QMC5883L vs. HMC5883L aka GY-271 Infos & more questions

68gt500

New Member
While waiting for my new RTC module to arrive and having had first I2C success reading it, I ventured a step further..

I hooked up my new Compass Module GY-273 which was supposed to be a HMC5883L

Since i found some code on the Net I figured - piece of cake - set the adress, read in the variables and ready...

No GO!

I just get zeros, no data for x,y or z.
sertxd:
:2 x:0 y:0 z:0 temp:0
t:4 x:0 y:0 z:0 temp:0
t:6 x:0 y:0 z:0 temp:0
t:8 x:0 y:0 z:0 temp:0
t:10 x:0 y:0 z:0 temp:0
t:12 x:0 y:0 z:0 temp:0

Asking Dr. Google I found out that the chip is probably a QMC5883L and that it has a different adress & registers from the original.
I even found a Datasheet, with a lot of Info. --> here: http://qqtrading.com.my/index.php?route=product/product/download&product_id=195&download_id=21
From what I could decipher:
I2C Adress = 0x0D - that would be $1A (ok?? either shift left or multiply by 2 ? - found that in some snippets)

Compass data registers: 00 -> 05
Temp registers 06 & 07

The adapted code:
Code:
symbol x = w0 
symbol y = w1 
symbol z = w2 
symbol T = w3
hi2csetup i2cmaster, %00011010, i2cslow_32, i2cbyte ;
hi2cout 0, ( %00010000 ) ; Don´t know if req.
hi2cout 1, ( %00100000 ) ; Don´t know if req.
hi2cout 2, ( %00000000 ) ; Don´t know if req.

Do
hi2cin 3, ( b1,b0 , b3,b2 , b5,b4 ) ; also tried 0
hi2cin 7, (b6,b7); 
	sertxd ("t:",#time," x:",#x," y:",#y," z:",#z, "temp: ", #T, CR,LF)

loop
The more i read the more I realize, that there is a lot to be learned...
How do i write the config registers
where do i specify the starting point for reading registers ..

Greetings

Mike
 

68gt500

New Member
Some add. infos I found:
Need Modify
1) I2c addr : write 0x1a,read 0x1b
2) Init_Config:
0x0B = 0x01;
0x20 = 0x40;
0x21 = 0x01;
0x09 = 0x0d/0x1d; /*OSR=512, RNG=+/-2G or +/-8G,
ODR=200Hz, MODE= continuous*/
3) Read output data register: 0x00~0x05
4) Output register: First byte is LSB, second byte is MSB, different before.
5) Data ready register:
0x06[bit0] DRDY , "0": no new data; "1": have new data;
6) Output data sensitivity, Follow to the Range param :
If Range = +/- 2G , 12000 LSB/G
If Range = +/- 8G , 3000 LSB/G

...
 

hippy

Technical Support
Staff member
Always start simple; start with just reading the $0D register which is the CHIP_ID, check the result is as expected.

Also start at default operating speed. If you are not using 32MHz it shouldn't be I2CSLOW_32, just I2CSLOW.

That you are getting zeroes rather than 255 as results suggests it's wired up correctly and responding, so probably just needs initialising properly. Haven't read the datasheet fully so can't say what that initialisation would be at present.
 

AllyCat

Senior Member
Hi Mike,

I've not looked at the data sheet, but normally the first thing to do is to try to READ something simple from the chip, probably an ID or Status byte, using hi2cin .... . That should give some confirmation that the chip and communications are at least working.

Then work slowly through the data sheet starting with the simplest commands or modes until you can get some responses that look "correct". Maybe you'll be lucky and someone will have actually programmed the chip, but I'm afraid most just rely on an Arduino "library" these days.

Cheers, Alan.
 

68gt500

New Member
Thanks for all the input.

Checked the data sheet, the device has to be configured, before it provides data.
Reading the 0DH Register - should return FF..

First Q: When do you have modify the adress from the published 0x0D - to $1A (if i understand correctly)


Could you please assist in the following:
I have to configure the device by:
- writing O9H register with: 01000000 - (this should configure for continous mode, output data rate = 10Hz, 2G Scale and 512 over sample ratio)
- writing 0AH register with 00000000 - probably not needed, since all default
and
- reading 00H thru 05H for the data

I don´t know how to adress the registers

So far as I understand
- hi2csetup - you specify the device adress
- hi2cout - write How do you specify the register?
- hi2cin - read -- same as above?

When do you have modify the adress from the published 0x0D - to $1A (if i understand correctly)

That should get me a step further..

Thanks

Mike
 

hippy

Technical Support
Staff member
When do you have modify the adress from the published 0x0D - to $1A (if i understand correctly)
That $0D is specified as a 7-bit I2C Device Address. The PICAXE system uses 8-bit I2C Device Address. So 7-bit $0D, binary %0001101, has to have an extra 0 added to the righthand side to make it 8-bit, turning that %0001101 into %00011010, which in hexadecimal is $1A.

The HI2CIN and HI2COUT commands then take care of ensuring the correct $1A or $1B is used for reading and writing as appropriate.

I don´t know how to adress the registers
The register address is what is used as the address within the Hi2CIN and HI2COUT commands -

HI2cin register, (b0) etc

Reading the 0DH Register - should return FF
That's an annoying and less than useful value for them to have chosen as an ID as it's what one would see if the I2C bus were faulty. Ideally an ID should be a mix of zeroes and one so one can determine it is an ID read and the bus isn't held low or held high.

Never the less; reading ID ($0D) and Status ($06) should determine if what is being read is as expected -

Code:
HI2cSetup I2CMASTER, $1A, I2CSLOW, I2CBYTE

Do
  HI2cIn $0D, (b0) : SerTxd( "ID = "       ) : Gosub DumpB0
  HI2cIn $06, (b0) : SerTxd( ", Status = " ) : Gosub DumpB0
  SerTxd( CR, LF )
  Pause 1000
Loop

DumpB0:
  SerTxd( #bit7, #bit6, #bit5, #bit4, " "            )
  SerTxd( #bit3, #bit2, #bit1, #bit0, " (", #b0, ")" )
  Return
That should show something like -

ID = 1111 1111 (255), Status = 0000 0001 (1)
 

AllyCat

Senior Member
Hi,

That's an annoying and less than useful value for them to have chosen as an ID as it's what one would see if the I2C bus were faulty. Ideally an ID should be a mix of zeroes and one so one can determine it is an ID read and the bus isn't held low or held high.
Yes, you can say that again; one wonders what **** chose that value. The only justification might be that it's an OTP ROM field to be set by / for specific customers. However, it does appear that you should be able to receive plenty of values containing zeros from the registers, even in the default (power-up) mode.

To get it out of standby seems to just need the Mode set to 01, i.e. hi2cout $09,($01), after using the hi2csetup command. That should allow you to read some "changing" values from the registers and you can start to try to see what the numbers actually mean. ;)

You might also need to change the Set/Reset register, since the manual simply says "It is recommended that the register 0BH is written by 0x01." without explaining what it does!

Cheers, Alan.
 

68gt500

New Member
Okay - that helped!

ID = 1111 1111 (255), Status = 0000 0000 (0)

Then I issued: hi2cout $09,($01)

ID = 1111 1111 (255), Status = 0000 0101 (5)

Seems like I can communicate.
Question though. are the bits reversed? I thought: writing O9H register with: 01000000 --> hi2cout $09,(%01000000)

Anyway, I appended some code:
Code:
#picaxe 08M2 
#no_data 
#terminal 4800

HI2cSetup I2CMASTER, $1A, I2CSLOW, I2CBYTE
pause 200
hi2cout $09,($01)
pause 200
hi2cout $0A, ($00)
Do
  pause 500
  ; HI2cIn $0D, (b0) : SerTxd( "ID = "       ) : Gosub DumpB0
  HI2cIn $06, (b0) : SerTxd( ", Status = " ) : Gosub DumpB0
  HI2cIn $00, (b0) : SerTxd( ", $00 = " ) : Gosub DumpB0
  ;HI2cIn $01, (b0) : SerTxd( ", $01 = " ) : Gosub DumpB0
  HI2cIn $02, (b0) : SerTxd( ", $02 = " ) : Gosub DumpB0
  ;HI2cIn $03, (b0) : SerTxd( ", $03 = " ) : Gosub DumpB0
  HI2cIn $04, (b0) : SerTxd( ", $04 = " ) : Gosub DumpB0
  ;HI2cIn $05, (b0) : SerTxd( ", $05 = " ) : Gosub DumpB0
  ;HI2cIn $06, (b0) : SerTxd( ", Temp $06 = " ) : Gosub DumpB0
  SerTxd( CR, LF )
  Pause 1000
Loop

DumpB0:
  ;SerTxd( #bit7, #bit6, #bit5, #bit4, " "            )
  ;SerTxd( #bit3, #bit2, #bit1, #bit0, " (", #b0, ")" )
  Sertxd (" (", #b0, ")" )
  Return
And getting some changing data out of $00, $02 and $04

Modified the output:
Status = (5), $00 = (133), $02 = (208), $04 = (55), $05 = (15)
, Status = (5), $00 = (105), $02 = (9), $04 = (75), $05 = (15)
, Status = (5), $00 = (90), $02 = (198), $04 = (40), $05 = (15)
, Status = (5), $00 = (70), $02 = (230), $04 = (30), $05 = (15)
, Status = (5), $00 = (100), $02 = (240), $04 = (55), $05 = (15)
, Status = (5), $00 = (128), $02 = (230), $04 = (45), $05 = (15)
, Status = (5), $00 = (90), $02 = (250), $04 = (2), $05 = (15)

It is important to access $05 - otherwise the data registers are not updated. ;)

Wow! This is exiting.

Now on to make sense out of the data... :rolleyes:

Thanks

Mike
 

hippy

Technical Support
Staff member
Then I issued: hi2cout $09,($01)

ID = 1111 1111 (255), Status = 0000 0101 (5)
That is encouraging and it now seems things are working.

Question though. are the bits reversed? I thought: writing O9H register with: 01000000 --> hi2cout $09,(%01000000)
I would have thought the same so it probably depends on what you think "01000000" means.

In binary, for byte values, bit 7 is on the left ( most significant bit) and bit 0 is on the right ( least significant bit ).

The spec for register $09 is "OSR[1:0] | RNG[1:0] | ODR[1:0] | MODE[1:0]" with MODE as the two least significant bits and defined as -

00 Standby
01 Continuous
10 Reserved
11 Reserved

So you need to put "01" into the MODE part of register $09 for continuous readings. That is -

Hi2cOut $09, ( %00000001 ), or

Hi2cOut $09, ( $01 )

Using "Hi2cOut $09, ( %01000000 )" will set OSR to "01" but set MODE to "00", which will leave the device in standby.
 

hippy

Technical Support
Staff member
I would try this to make more sense of your X, Y and Z readings ...

Code:
#Picaxe 08M2
#Terminal 4800
#No_Data

HI2cSetup I2CMASTER, $1A, I2CSLOW, I2CBYTE

Hi2cOut $09, ($01)
Do
  Do
    HI2cIn $06, (b0)
  Loop Until bit0 = 1
  HI2cIn $00, (b0,b1) : SerTxd(      "X = " ) : Gosub DumpW0
  HI2cIn $02, (b0,b1) : SerTxd( TAB, "Y = " ) : Gosub DumpW0
  HI2cIn $04, (b0,b1) : SerTxd( TAB, "Z = " ) : Gosub DumpW0
  HI2cIn $07, (b0,b1) : SerTxd( TAB, "T = " ) : Gosub DumpW0
  SerTxd( CR, LF )
  Pause 1000
Loop

DumpW0:
  If w0 >= $8000 Then
    w0 = -w0
    SerTxd( "-", #w0 )
  Else
    SerTxd( #w0 )
  End If
  Return
 
Last edited:

68gt500

New Member
Wow Hippy!

With your code I am getting variable results, when moving the sensor in the 3 planes:


X = 1882 Y = -2335 Z = 3752 T = -1633
X = 1857 Y = -2345 Z = 3712 T = -1624
X = 2042 Y = -2362 Z = 3662 T = -1624
X = 2042 Y = -2265 Z = 3712 T = -1616
X = 2130 Y = 507 Z = 3732 T = -1631
X = 852 Y = 380 Z = 3945 T = -1631
X = 847 Y = 390 Z = 4005 T = -1622
X = 910 Y = 255 Z = 4025 T = -1605
X = 1007 Y = 200 Z = 3980 T = -1605
X = 1612 Y = -250 Z = 4025 T = -1607
X = 1330 Y = -1417 Z = 4045 T = -1607
X = 1225 Y = -1380 Z = 4040 T = -1607
X = 1272 Y = -1400 Z = 4065 T = -1599
X = 2302 Y = -3605 Z = 2795 T = -1603
X = 2980 Y = -4730 Z = 1267 T = -1603
X = 3312 Y = -4827 Z = 557 T = -1593
X = 3517 Y = -4827 Z = 260 T = -1590
X = 3595 Y = -4760 Z = 295 T = -1590
X = 3467 Y = -4807 Z = 250 T = -1585
X = 2985 Y = -4877 Z = 1112 T = -1573
X = 2365 Y = -1360 Z = 3885 T = -1573
X = 2202 Y = -1585 Z = 3900 T = -1576
X = 2177 Y = -1467 Z = 3870 T = -1566
X = 2017 Y = -1175 Z = 3945 T = -1566
X = -1185 Y = -435 Z = 3792 T = -1560
X = -2027 Y = -565 Z = 3207 T = -1557
X = -2027 Y = -565 Z = 3152 T = -1557
X = -1987 Y = -507 Z = 3225 T = -1547
X = -1960 Y = -590 Z = 3265 T = -1542
X = -1660 Y = -620 Z = 3485 T = -1542
X = 1717 Y = -1585 Z = 4055 T = -1539
X = 1665 Y = -1775 Z = 4040 T = -1531

Going thru the motions the range is about:

x -2000 --> 3200 Y -5500-->3400 Z -5000--> 4000


Mike
 

julianE

Senior Member
Excellent work! I went and ordered QMC5883L it's a significant improvement over HMC5883L that I have been tinkering with.

Mike if you can let the unit run for a while and keep it in one spot away from ferric materials I'm curious to know how steady are the values, I expect them to vary I'm just wondering how large the variance is. I'm curious if it can be used as a magnetometer.

thanks.
 

68gt500

New Member
Julian,

sure, I can do that.

What I have noticed though is that the values do change after a power off sequence.

@ All

The only reason for me to deal with this module - besides gather know how - was to get a heading Display, like 0-360 Degrees. Accuracy within several degrees would be completely ok.

I found the following code (for the HMC chip, not the QMC) , but its math around arc-tan has me lost, specially since the comments are in Czech or Polish...

I can see that he uses some EEPROM data points to get an approximation - that would be totally acceptable.

Also acceptable that it is not tilt corrected - using it in a car, with too much tilt you´ll have other - much more pressing problems.

Maybe one of you experts could look into it??

Code:
#picaxe 08M2
;#no_data

; zpracování dat z I2C magnetometru HMC5883L (modul GY-271)
; C.0 - sertxd (sériový výstup k PC nebo k dalšímu PICAXE)
; C.1 - SCL (k magnetometru)
; C.2 - SDA (k magnetometru)
; C.3 - in (-- nepoužito --)
; C.4 - out (LED, připojena přes odpor cca 800 ohm k zemi nebo k + napájení)
; C.5 - serin (-- nepoužito --)
; napájení 5V (4x AA NiMH nabíjitelné akumulátory) [pro PICAXE i modul současně]
; měřený rozsah v každé ose magnetometru je cca 1200 (+-600), šum cca 30

eeprom 0, (0,6,11,17,22,27,31,35,39,42,45) ; předpočítaná tabulka úhlů (atan)

symbol xm = w0           ; měřená osa X magnetometru
symbol ym = w1           ; měřená osa Y magnetometru
symbol zm = w2           ; měřená osa Z magnetometru
symbol cas = w3          ; pro sledování změn proměnné "time"
symbol cyklu = w4        ; počítadlo cyklů (pro měření rychlosti zpracování dat)
symbol azimut = w5       ; výsledný přepočítaný azimut

symbol uhel0 = w6        ; pomocný úhel (bude to pamět zákl. azimutu po zapnutí)
symbol uhel = b14        ; výsledný úhel po výpočtu arctan
symbol uhel2 = b15       ; pomocný úhel určený z tabulky
symbol tan100 = b16      ; tangens * 100 (X / Y * 100)
symbol index = b17       ; vypočítaný index do tabulky
symbol offset = b18      ; vypočítaný posun mezi body indexu
symbol kvadrant = b19    ; kvadrant azimutu podle hodnot X a Y

symbol x = w10           ; zkalibrovaná a normalizovaná hodnota X (0 - 200)
symbol y = w11           ; zkalibrovaná a normalizovaná hodnota Y (0 - 200)
symbol z = w12           ; zkalibrovaná a normalizovaná hodnota Z (0 - 200)

setfreq m32              ; zvýšení frekvence procesoru (max. 32 MHz [8x normal])

pause 100                ; počkáme na ustálení napájení a vstupů po startu
sertxd ("PICAXE 08M2 kompas s HMC5883L",CR,LF)

hi2csetup i2cmaster, $3C, i2cfast_32, i2cbyte  ; inicializace I2C na adrese 3C
hi2cout 0, ( %01010100 ) ; config A - 4 averaged, 30Hz updates, normal measurement
hi2cout 1, ( %00100000 ) ; config B - 1.3Ga gain
hi2cout 2, ( %00000000 ) ; mode - continuous conversion

sertxd ("setup OK",CR,LF)

do
  inc cyklu
  if time>cas then       ; měříme a vypisujeme po každé změně "time" (2x za sec.)
    cas = time
    hi2cin 3, ( b1,b0 , b3,b2 , b5,b4 ) ; načtení holých dat z magnetometru (x,y,z)
    xm = xm + 800 / 8    ; normalizace X do max. rozsahu 0 - 200 se středem 100
    ym = ym + 800 / 8    ; normalizace Y do max. rozsahu 0 - 200 se středem 100
    zm = zm + 800 / 8    ; normalizace Z do max. rozsahu 0 - 200 se středem 100
    x = xm
    y = 200 - ym min 0 max 200
    z = zm
    gosub atan2           ; výpočet azimutu
    sertxd ("time:",#time,"  azimuth:",#azimut,CR,LF)
    toggle C.4           ; kontrolní blikání LEDkou
    cyklu = 0
  endif
  ;gosub atan2            ; jen pro odhad rychlosti výpočtu
loop

atan2:
  ; výpočet azimutu podle X a Y (arcustangens a kvadrant)
  ; hodnoty X a Y musí být předem normalizovány do rozsahu 0 - 200
  ; nula je na hodnotě 100 (pro X i pro Y)
  if x>=100 then
    x = x - 100
    if y>=100 then
      y = y - 100
      kvadrant = 0
    else
      y = 100 - y
      kvadrant = 3
    endif
  else
    x = 100 - x
    if y>=100 then
      y = y - 100
      kvadrant = 1
    else
      y = 100 - y
      kvadrant = 2
    endif
  endif
  tan100 = 100
  if x>y then
    tan100 = 100 * y / x
  else if y>x then
    tan100 = 100 * x / y
  endif
  ; výpočet atan interpolací mezi dvěma předpočítanými hodnotami z tabulky (0 - 45°)
  index = tan100 / 10
  offset = tan100 % 10
  read index,uhel
  inc index
  read index,uhel2
  azimut = uhel2 - uhel * offset / 10 + uhel
  ; posun azimutu do správného kvadrantu
  if y>=x then
    azimut = 90 - azimut
  endif
  if kvadrant = 1 or kvadrant = 3 then
    azimut = kvadrant * 90 - azimut + 90
  else
    azimut = kvadrant * 90 + azimut
  endif
return
Thanks

Mike
 

hippy

Technical Support
Staff member
I found the following code (for the HMC chip, not the QMC) , but its math around arc-tan has me lost
It appears to use the DATA table to store pre-calculated ATAN(n) values, eg

ATAN(0) = 0
ATAN(10) = 6
ATAN(20) = 11
etc
ATAN(100) = 45

The uses linear interpolation to calculate for the values in between. For example ATAN(15) is calculated as -

( ( ATAN(20) - ATAN(10) ) * (15-10) / 10 ) + ATAN(10)
 

MartinM57

Moderator
Let me translate the top half for you :)
Code:
#picaxe 08M2
#no_data

; data processing from the I2C magnetometer HMC5883L (module GY-271)
; C.0 - sertxd (serial output to PC or to another PICAXE)
; C.1 - SCL (for magnetometer)
; C.2 - SDA (for magnetometer)
; C.3 - in (- not used -)
; C.4 - out (LED, connected via resistance of approx. 800 ohm to ground or k + power supply)
; C.5 - serin (- not used)
; 5V power supply (4x AA NiMH rechargeable batteries) [for both PICAXE and Module]
; the measured range in each axis of the magnetometer is approximately 1200 (+ -600), noise approx. 30

eeprom 0, (0,6,11,17,22,27,31,35,39,42,45); Predicted Angle Table (atan)

symbol xm = w0; measured X magnetometer axis
symbol ym = w1; measured Y magnetometer axis
symbol zm = w2; measured magnetometer axis
symbol cas = w3; to track variations of the "time"
cycle symbol = w4; Cycle counter (for data rate measurement)
azimut symbol = w5; resulting rectilinear azimuth

symbol uhel0 = w6; auxiliary angle (this will be the basic azimuth memory after switching on)
charcoal symbol = b14; the resulting angle after the arctan calculation
charcoal symbol = b15; the auxiliary angle determined from the table
symbol tan100 = b16; tangent * 100 (X / Y * 100)
symbol index = b17; calculated index to table
symbol offset = b18; calculated shift between index points
quadrant = b19; azimuth quadrant by X and Y values

symbol x = w10; calibrated and normalized X value (0 - 200)
symbol y = w11; calibrated and normalized Y (0 - 200)
symbol z = w12; Calibrated and normalized Z value (0 - 200)

setfreq m32; Increase processor frequency (up to 32 MHz [8x normal])

pause 100; wait for power and input after startup
sertxd ("PICAXE 08M2 compass with HMC5883L", CR, LF)

hi2csetup i2cmaster, $ 3C, i2cfast_32, i2cbyte; initialization of I2C at 3C
hi2cout 0, (% 01010100); config A - 4 averaged, 30Hz updates, normal measurement
hi2cout 1, (% 00100000); config B - 1.3Ga gain
hi2cout 2, (% 00000000); mode - continuous conversion
I don't understand a word of czech but Mr. Google does (google for "czech to English translation", pasted (the top half - it's too big to enter it all in one go) and it appears on the right :))
...a good translation and excellently commented as well
...exercise for the student to do the bottom half but the atan2: subroutine seems understandable in principle as it is
 

AllyCat

Senior Member
Hi,

Yes, the Function/subroutine you need is called ATAN2. For modest (single-byte) accuracy a simple "two lines" (per Octant) interpolation is good enough. I posted one example in #20 of this thread a few years ago.

For better accuracy there is the problem that PICaxe only supports unsigned integer numbers, whilst all values of SIN, COS (and TAN within an octant) are less than unity. Therefore, for much higher accuracy Trig routines I've used Word values to represent Signed, "Fractional Binary" values. All ATAN2 values can be kept below unity by swapping X and Y when required and angles are defined as a fractional part of a full revolution (360 degrees). That makes defining the octants very easy.

So far I've only posted code for SIN and COS in this code snippet but here is the main part from a "Work in Progress". Typically, I use 16 interpolation lines per quadrant for SIN and COS and 8 lines for the ATAN2 octants, but more are possible.

Code:
;ARCTAN2 subroutine , AllyCat October 2017
#picaxe 08m2          ; And most others
symbol negx = 32768
symbol wx = w2
symbol wy = w3
symbol atanbase = 0
data atanbase,(0,0,17,5,251,9,158,14,228,18,194,22,56,26,74,29,3,32);   Max 8192 = unity

arctan2:
	b1 = 0 						; First octant (0 - $1FFF)	
	if wx >= negx then 			; Value is negative
		b1 = 7
		wx = -wx					; Convert negative to positive
	endif							; WX is (now) positive
	if wy >= negx then 				; Value is negative
		b1 = b1 xor 3
		wy = -wy			
	endif						; WY is (now) positive
	if wx > wy then 				; WX/WY is not a proper fraction (< 1) so swap
		b1 = b1 xor 1					; Mark that WX > WY (Octant 1,2 etc)
		w1 = wx						; )
		wx = wy						; }Exchange WX and WY (~5 code bytes less than SWAP)
		wy = w1						; )
	endif								; Divisor larger than numerator so "fractional" result
	w1 = 0							; Numerator Low word and part of result (if <16 loops)
; Prepare to use Double-Word Division subroutine    W1 = WX:W1 / WY  (remainder in WX)
	call div31						; Result returned in w1, Now use VX,WY as temp variables
arctan:								; Max value in w1 = 2048 represents unity (45 degrees)
	call interpXtoY
	w1 = w1 * 4						; Width was 2048 for one octant
	if bit8 = 1 then				; LSB of b1
		w1 = $2000 - w1				; Reverse the sector from 90 to 45 degrees
	endif
	w1 = b1 & 7 * $2000 + w1			; Add the other octants
return

interpXtoY:	 
		wx = w1						; Frees up b2 and b3
		b2 = atanbase				; Address of start (word) of table
		b2 = b2 + b3 + b3			; Add 2* wx/256 (b3 still contains hi byte of w1) = base of cell
		b3 = b2 + 2					; Point to top of cell
		read b3,WORD wy
		b3 = b2 + 1					; Point to high byte
		read b2,b2					; Read low byte
		read b3,b3					; Read high byte
		wy = wy - w1 				; Calculate height of cell (wy - wx)
		wx = wx / 256 * 65280 + wx			; Horizontal distance across cell (65280 = -1 * 256)
		w1 = wx * 256 ** wy + w1		; Height inside cell (0<wx<256) * gradient + height of cell base
return
My "double-word" division subroutine is not included above but several versions have been documented in the Code Snippets section.

Cheers, Alan.
 

68gt500

New Member
Beeing old & lazy I found a much easier way to get a decent heading (within a few degrees)..

I am using an old Serial GPS Mouse that I have had laying around for ages.

This forum supplied the code to filter out the correct data out of the nmea sentences and voila! I not only have a heading but also can output speed and altitude, date, time an so on.

Much, much easier than struggling with that QMC5883L and the resulting data.

I also saw some integrated tilt compensated compass modules putting out corrected heading Infos via a serial interface.

I will probably get one of those Neo6M modules, because my old GPS takes a lot of time for a first fix.

Greetings

Mike
 
Top