I2C example code for 359.9 degrees with CMPS03 Compass

elanman99

Senior Member
I want to use (preferably an 08M) with a serial LCD to display heading with a resolution of 0.1 degrees.

There are many examples of code on this forum but after several thorough searches I can only find I2C code to read the compass with one byte (0-255) which obviously give less than 1 degree resolution.

In the finished project I may end up suppressing the figure after the decimal point but I want to start with as much data as possible.

This is my first foray into I2C and would appreciate any help.

Thanks

Ian P
 

hippy

Ex-Staff (retired)
Assuming this is the CMPS03 ...

http://www.robot-electronics.co.uk/htm/cmps3tech.htm

It seems the heading in word form is stored in registers 2 and 3 so it should be a simple case of (untested ) ...

I2cSlave $C0, I2cSlow, I2cByte
I2cRead 2, ( b13, b12 ) ' Msb:Lsb of w6 = b13:b12
BinToAscii w6, b1,b2,b3,b4,b5
SerTxd( "Heading = ", b1, b2, b3, b4, ".", b5, CR, LF )

On the 08M you'll have to replace all the I2C commands with bit-banged code to implement I2C. It would be strongly recommended to choose a PICAXE which supports I2C or HI2C commands.
 

elanman99

Senior Member
Assuming this is the CMPS03 ...

On the 08M you'll have to replace all the I2C commands with bit-banged code to implement I2C. It would be strongly recommended to choose a PICAXE which supports I2C or HI2C commands.
Yes, it is a CMPS03. In my naivety I just assumed an 08M would be OK but I am not up to bit banging! so I will use an 18m. I am currently reading the compass using its PWM output (with Pulsin) but I am only getting readings up to 255. I am sure the Pulsin command is capable of reading the PWM to get 0.1 degree resolution as the data sheet recommends not reading to anything better than 0.1 degrees.

Ian P
 

BCJKiwi

Senior Member
Perhaps you might post your existing code using Pulsin as the pwm output should be good for 0.1degree as per the documentation and as you have noted.
 

elanman99

Senior Member
Perhaps you might post your existing code using Pulsin as the pwm output should be good for 0.1degree as per the documentation and as you have noted.
This code is as far as I have got at the moment (and its bedtime here!) so its a bit unfinished, its also a bit flaky as I dont think I am talking to the LCD correctly. In other words its rubbish! I just used it to make sure I had wired it up right.

Ian P
 

Attachments

BCJKiwi

Senior Member
OK, A few points;
1. Pulsin delivers data to a word variable so b0 needs to be changed to Wx. Would suggest, as a matter of principle, to avoid using b0 or w0 in this manner as it is then available for bitwise use - suggest W6.
2. debug b1. b1 is not used so perhaps you intended b0. However I prefer to sertxd (to the PE serial window when testing with the programming cable connected). Debug does not always (in my experience) behave the way expected.
3. Pulsin measures in 10uS units @ 4MHz which is 1/10th of a degree. Suggest you use a setfreq m8 to improve the sensitivity to 5uS
4. The word variable (Bearing) will contain a value representing the length of the pulse as the number of 5uS units. As the pulse width varies from 1mS to 36.99mS this results in 5uS increments (@ 8MHz clock) from 20 to 20*359.9 + 20 = 7218
The maths should take account of the offsets (1ms for 0 degrees from the compass), and the pulsin count starting at 1 rather than zero.
To avoid hunting, the value used to decide which tenth of a degree to use should target values midway between each tenth rather than the value representing a tenth of a degree.
As each tenth of a degree is represented by 10uS, this will show as an increment of the Pulsin Value of 2 per tenth of a degree.
So halfway between 0 and 0.1 degrees is represented by a pulsin value of 21. Each 1/10th of a degree is then represented by a further increment of 2 to the pulsin value.
Accordingly the Bearing variable needs to have 20 deducted, then be divided by 2 to get the number (up to 4 digits) representing the number of tenths of degrees.
The output to the display then needs to manipulate this number into degrees, decimal point, and tenths.

See attached suggested code producing output in tenths of a degree. Search the forum for examples of how to change the output to degrees and tenths.

Code:
Suggestion only - appears to work in the simulator - BCJ
 
'For Picaxe 08M
'Filename:- Compass PWM to Picaxe.bas
'Hardware setup
'Input pulse from CMPS03 on 3 (IC pin 4)
'Serial output to LCD    on 2 (IC pin 5) LCD is 2x16
[B][I]SETFREQ m8[/I][/B]
'Variables setup
SYMBOL Bearing = [B][I]W6[/I][/B]
[I][B]SYMBOL Degrees = W5[/B][/I]
INPUT  3                 'Confirms i/o pin as input (not sure if I need this)
'Serout 2,N2400,(254,1) 'Clear LCD (Run once here instead of in main loop?)
Pause 100               'Delay to let LCD Initialise fully
Main:
 
PULSIN 3,1,Bearing                  'Get reading from CMPS03
 
[B][I]Degrees = Bearing -20 /2[/I][/B]
'bearing = (Bearing -500)/50        'Calculate Bearing in degrees (Definately wrong!)
 
Serout 2,N2400,(254,1)              'Clear LCD
Serout 2,N2400,(254,128," Bearing") 'Value of B0 on top line of LCD
Serout 2,N2400,(254,196, #Degrees)  'Text on bottom line
 
GOTO main
The clear display could be used once only as could the output of the word "Bearing".
Then, only the changing value would need to be send to the LCD.
Search the Forum for techniques to send the full set of data to write the full number of places each time with leading blanks to clear higher numbers of digits when writing lesser numbers of digits, and, a zero for degrees if bearing less than 1 degree.
 
Last edited:

elanman99

Senior Member
BCJ

Thanks for the most helpful reply, I've not been able to work on the project since but will update you later in the week.

Ian
 
Top