problem with HMC6352 compass


Closed Thread
Results 1 to 9 of 9
  1. #1

    Question problem with HMC6352 compass

    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?

    Code:
               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
    Last edited by ScaleRobotics; - 26th May 2010 at 17:06. Reason: code brackets added

  2. #2
    Join Date
    Sep 2004
    Location
    Mentor, Ohio
    Posts
    352


    Did you find this post helpful? Yes | No

    Smile

    At a quick glance you didn't turn off the analog inputs. Get the datasheet.

    BobK

  3. #3


    Did you find this post helpful? Yes | No

    Default

    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

  4. #4


    Did you find this post helpful? Yes | No

    Default

    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

  5. #5


    Did you find this post helpful? Yes | No

    Default

    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

  6. #6


    Did you find this post helpful? Yes | No

    Default Fixed it

    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.
    Code:
               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
    Last edited by ScaleRobotics; - 26th May 2010 at 17:17. Reason: added code tags

  7. #7
    Join Date
    Feb 2006
    Location
    Gilroy, CA
    Posts
    1,530


    Did you find this post helpful? Yes | No

    Default

    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

  8. #8


    Did you find this post helpful? Yes | No

    Default

    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

  9. #9
    javierch's Avatar
    javierch Guest


    Did you find this post helpful? Yes | No

    Default Re: problem with HMC6352 compass

    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.

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts