PDA

View Full Version : problem with HMC6352 compass



Macgman2000
- 25th May 2010, 22:12
Hello,

I tried to port this code from a BS2, to get it to work on a 16F877A. I am experiencing erratic
behavior. The display flickers terribly and the values are meaingless. What am I missing?



INCLUDE "Modedefs.Bas"
@ Device pic16F877A, HS_OSC, LVP_OFF, WDT_OFF,protect_off
DEFINE OSC 20


; Set port direction and turn off unused peripherals

CMCON = 7 ' shut offcomparators
TRISA = %00000000 ' Set PORTA to input "1" or output "0"
TRISB = %00000000 ' set portB to output "0" or input "1"
TRISC = %00000000
TRISD = %00000000
TRISE = %00000000

; initialize all ports to low

portA = %00000000
portB = %00000000
portC = %00000000
portD = %00000000
portE = %00000000

; define LCD 4 line x 20, 4 bit interface

Define LCD_DREG PORTD
Define LCD_DBIT 0
Define LCD_RSREG PORTD
Define LCD_RSBIT 4
Define LCD_EREG PORTD
Define LCD_EBIT 5
Define LCD_BITS 4
Define LCD_LINES 4
define LCD_COMMANDUS 1500
DEFINE LCD_DATAUS 44


'main2:

' Lcdout $fe, 1, $fe, $80 ' Clear LCD screen
' Lcdout $FE, $80, "testing"
' Pause 2000 ' Wait .5 second
' goto main2


' -----[ Pins/Constants/Variables ]-------------------------------------------
SDA VAR portB.0 ' PB0 transceives to/from SDA
SCL VAR portB.1 ' PB1 sends clock pulses

HMC6352_READ CON $43 ' HMC6352 read address
HMC6352_WRITE CON $42 ' HMC6352 write address
GET_HEADING CON $41 ' Read in the calculated heading
START_CALIB CON $43 ' Start the calibration routine
END_CALIB CON $45 ' Finish the calibration routine

Heading VAR Word ' Heading read from compass
I2C_DATA VAR Byte ' Temporary I2C variable
I2C_LSB VAR Bit ' Temporary I2C variable




' -----[ Main Routine ]-------------------------------------------------------


DO
pause 500
GOSUB Compass_Get_Heading ' Get angle

;DEBUG HOME, "Heading = ", DEC Heading / 10, " degrees" ' Print aingle
Lcdout $fe, 1, $fe, $80 ' Clear LCD screen
Lcdout $FE, $80, "Heading = ", DEC Heading / 10, " deg"

LOOP


' -----[ Subroutines ]--------------------------------------------------------

Compass_Get_Heading: ' Compass module subroutine

GOSUB I2C_Start ' Start communications on the I2C buss
I2C_DATA = HMC6352_WRITE
GOSUB I2C_Write ' Address the HMC6352 in write mode
I2C_DATA = GET_HEADING
GOSUB I2C_Write ' Send the get heading command
GOSUB I2C_Stop ' End communications on the I2C buss

GOSUB I2C_Start ' Start communications on the I2C buss
I2C_DATA = HMC6352_READ
GOSUB I2C_Write ' Address the HMC6352 in read mode
PAUSE 6 ' Give the HMC6352 time to calculate the heading
GOSUB I2C_Read
Heading.HIGHBYTE = I2C_DATA ' Read in the high byte
GOSUB I2C_ACK
GOSUB I2C_Read
Heading.LOWBYTE = I2C_DATA ' Read in the low byte
GOSUB I2C_NACK
GOSUB I2C_Stop ' End communications on the I2C buss

RETURN

I2C_Start:
LOW SDA ' Pull SDA low
LOW SCL ' Pull SCL low
RETURN

I2C_Stop:
LOW SDA ' Pull SDA low
INPUT SCL ' Let SCL float high
INPUT SDA ' Let SDA float high
RETURN

I2C_ACK:
LOW SDA ' Pull SDA low
INPUT SCL ' Let SCL float high
LOW SCL ' Pull SCL low
INPUT SDA ' Let SDA float high
RETURN

I2C_NACK:
INPUT SDA ' Let SDA float high
INPUT SCL ' Let SCL float high
LOW SCL ' Pull SCL low
RETURN

I2C_Read:
SHIFTIN SDA, SCL, MSBPRE, [I2C_DATA] ' Read in 8 bits, MSB first
RETURN

I2C_Write:
I2C_LSB = I2C_DATA.BIT0 ' Store the status of the LSB
I2C_DATA = I2C_DATA / 2
SHIFTOUT SDA, SCL, MSBFIRST, [I2C_DATA\7] ' Write out the first 7 bits, MSB first
IF I2C_LSB THEN
INPUT SDA
ELSE
LOW SDA ' Write the 8th bit
endif
INPUT SCL ' Using an open collector output
LOW SCL
INPUT SDA ' Leave SDA as an input
INPUT SCL ' Ignore the ACK bit
LOW SCL
RETURN

BobK
- 26th May 2010, 00:31
At a quick glance you didn't turn off the analog inputs. Get the datasheet.

BobK

Macgman2000
- 26th May 2010, 15:30
I added ADCON1 = 7, still nothing. It's actually irrelevent because I am not even using port A for
anything. There are no interrupts in the code or timers. I can't tell if it's the module or the code that
is the issue. I ported the code from a BS2......it was not THAT drastic of a change over...so I assume
the code should work. Does anyone have test code for this module?

Nick

mark_s
- 26th May 2010, 15:52
Do you have pull up resisters on your I2C, clock and data lines? Also I
find it helps not to clear the LCD on each loop and just over write to the location
that is changing. This helps avoid flicker.

Regards

Macgman2000
- 26th May 2010, 16:57
I have a couple 10K pull ups on the lines. Still works erratically, then freezes. I am running my MCU
at 20 MHz, could it operate too quickly porting it to PIC? Maybe the timing is all messed up?

Nick

Macgman2000
- 26th May 2010, 17:10
OK...found the problem. I added a delay in the screen update. Also timing within the I2C was off. I
corrected it. See working code below.


INCLUDE "Modedefs.Bas"
@ Device pic16F877A, HS_OSC, LVP_OFF, WDT_OFF,protect_off
DEFINE OSC 20


; Set port direction and turn off unused peripherals

ADCON1 = 7
CMCON = 7 ' shut offcomparators
TRISA = %00000000 ' Set PORTA to input "1" or output "0"
TRISB = %00000000 ' set portB to output "0" or input "1"
TRISC = %00000000
TRISD = %00000000
TRISE = %00000000

; initialize all ports to low

portA = %00000000
portB = %00000000
portC = %00000000
portD = %00000000
portE = %00000000

; define LCD 4 line x 20, 4 bit interface

Define LCD_DREG PORTD
Define LCD_DBIT 0
Define LCD_RSREG PORTD
Define LCD_RSBIT 4
Define LCD_EREG PORTD
Define LCD_EBIT 5
Define LCD_BITS 4
Define LCD_LINES 4
define LCD_COMMANDUS 1500
DEFINE LCD_DATAUS 44


'main2:

' Lcdout $fe, 1, $fe, $80 ' Clear LCD screen
' Lcdout $FE, $80, "testing"
' Pause 2000 ' Wait .5 second
' goto main2


' -----[ Pins/Constants/Variables ]-------------------------------------------
SDA VAR portB.0 ' PB0 transceives to/from SDA
SCL VAR portB.1 ' PB1 sends clock pulses

HMC6352_READ CON $43 ' HMC6352 read address
HMC6352_WRITE CON $42 ' HMC6352 write address
GET_HEADING CON $41 ' Read in the calculated heading
START_CALIB CON $43 ' Start the calibration routine
END_CALIB CON $45 ' Finish the calibration routine

Heading VAR Word ' Heading read from compass
I2C_DATA VAR byte ' Temporary I2C variable
I2C_LSB VAR Bit ' Temporary I2C variable




' -----[ Main Routine ]-------------------------------------------------------


DO

GOSUB Compass_Get_Heading ' Get angle

;DEBUG HOME, "Heading = ", DEC Heading / 10, " degrees" ' Print aingle
Lcdout $fe, 1, $fe, $80 ' Clear LCD screen
Lcdout $FE, $80, "Heading = ", DEC Heading / 10, " deg "
pause 200
LOOP


' -----[ Subroutines ]--------------------------------------------------------

Compass_Get_Heading: ' Compass module subroutine

GOSUB I2C_Start ' Start communications on the I2C buss
I2C_DATA = HMC6352_WRITE
GOSUB I2C_Write ' Address the HMC6352 in write mode
I2C_DATA = GET_HEADING
GOSUB I2C_Write ' Send the get heading command
GOSUB I2C_Stop ' End communications on the I2C buss

GOSUB I2C_Start ' Start communications on the I2C buss
I2C_DATA = HMC6352_READ
GOSUB I2C_Write ' Address the HMC6352 in read mode
PAUSE 6 ' Give the HMC6352 time to calculate the heading
GOSUB I2C_Read
Heading.HIGHBYTE = I2C_DATA ' Read in the high byte
GOSUB I2C_ACK
GOSUB I2C_Read
Heading.LOWBYTE = I2C_DATA ' Read in the low byte
GOSUB I2C_NACK
GOSUB I2C_Stop ' End communications on the I2C buss

RETURN

I2C_Start:
LOW SDA ' Pull SDA low
LOW SCL ' Pull SCL low
pause 1
RETURN

I2C_Stop:
LOW SDA ' Pull SDA low
INPUT SCL ' Let SCL float high
INPUT SDA ' Let SDA float high
pause 1
RETURN

I2C_ACK:
LOW SDA ' Pull SDA low
INPUT SCL ' Let SCL float high
LOW SCL ' Pull SCL low
INPUT SDA ' Let SDA float high
pause 1
RETURN

I2C_NACK:
INPUT SDA ' Let SDA float high
INPUT SCL ' Let SCL float high
LOW SCL ' Pull SCL low
pause 1
RETURN

I2C_Read:
SHIFTIN SDA, SCL, MSBPRE, [I2C_DATA] ' Read in 8 bits, MSB first
RETURN

I2C_Write:
I2C_LSB = I2C_DATA.BIT0 ' Store the status of the LSB
I2C_DATA = I2C_DATA / 2
SHIFTOUT SDA, SCL, MSBFIRST, [I2C_DATA\7] ' Write out the first 7 bits, MSB first
IF I2C_LSB THEN
INPUT SDA
ELSE
LOW SDA ' Write the 8th bit
endif
INPUT SCL ' Using an open collector output
LOW SCL
INPUT SDA ' Leave SDA as an input
INPUT SCL ' Ignore the ACK bit
LOW SCL
RETURN

ScaleRobotics
- 26th May 2010, 17:21
It's a little late now, as you have yours working nicely. But I was not sure if you saw this or not. It looks to be a bit unfinished. Thought you might be interested anyways:

http://www.picbasic.co.uk/forum/showthread.php?t=8310

Macgman2000
- 26th May 2010, 18:05
I saw that code. I actually have one module that is useless because I tried using that code to
calibrate. I don't know exactly what happened, maybe the timing is off on that routine also, but
the module never worked the same since. I will tweek the calibration code and see if I can restore
the calibration to a useable level.

Nick

javierch
- 29th July 2011, 17:17
Hello,

I have any problem with my code.
I am working with HMC6352 in PROTON but i have any problem with the sensor. I don`t know what happen, Please could you help me?

This is the code

device = 16f876
xtal 20

declare SDA_PIN PORTB.0
DECLARE SCL_PIN PORTB.1

DIM LSB AS WORD
DIM MSB As WORD
Main:
BusouT $42,[$43]
DELAYUS 10
DELAYMS 10000
BUSOUT $42,[$45]
DELAYMS 14
BUSOUT $42,[$4F]
DELAYMS 6
while 1=1
busout $42,[$41]
delayms 10
busin $43,[MSB, LSB]
HRSOUT "VALOR MSB ", DEC mSB, "LSB ", DEC LSB, 13
DELAYMS 500
wend
GOTO mAIN

The problem is that LSB date is incorrect. It is not read. Always show 65535 as value of LSB.