Lectura PIC18 del sensor de color TCS34725

0

Estoy intentando leer el sensor de color TCS34725 ( hoja de datos ) sin embargo, no estoy teniendo mucho. suerte en realidad recuperar datos. Cuando hago una llamada para leer desde el sensor, los valores que estoy recibiendo son siempre cero.

Recientemente publiqué aquí preguntando por mis comparaciones, que he resuelto sin problemas. Creo que el problema está en el I2C que uso para leer desde el sensor. Si tiene tiempo, realmente me beneficiaría tener un par de ojos adicionales en mi código. ¡Estoy siguiendo el protocolo I2C de la hoja de datos hasta una T!

EDITAR (2017/02/22 14h12) : el PIC que estoy usando es el PIC18f4620. Aquí está mi código I2C:

#include <p18f4620.inc>
#include <lcd.inc>

errorlevel -302
errorlevel -305
errorlevel -205
errorlevel -203
errorlevel -207

;global labels

variable _waitknt=0

udata
regaddress res 1
databyte res 1
datachar res 1
data_colourL res 1
data_colourH res 1
tens_digit res 1
ones_digit res 1
convert_buffer res 1

global write_rtc,read_rtc,rtc_convert,i2c_common_setup, READ_COLOUR_I2C, WRITE_COLOUR_I2C
global regaddress, databyte, datachar, tens_digit, ones_digit, convert_buffer
global data_colourL, data_colourH

;; I2C MACROS
;;
;; Sebastian K, commit 110219-2208
;; forked off PIC16 sample code
;; for PIC18F4620
;; relocatable labels

i2c_common_check_ack macro err_address ;If bad ACK bit received, goto err_address
    btfsc   SSPCON2, ACKSTAT
    goto    err_address
endm

i2c_common_start macro 
    bsf     SSPCON2, SEN
    btfss   SSPCON1, WCOL   ; NOTE: I CHANGED THIS TO MAKE WORK, IDK Y THO
    bsf     PIR1, SSPIF
    btfss   PIR1, SSPIF
    bra     $-2
    bcf     PIR1, SSPIF ;clear SSPIF interrupt bit
endm

i2c_common_stop macro
    bsf     SSPCON2,PEN
    btfsc   SSPCON2,PEN
    bra     $-2
    bcf     PIR1, SSPIF
endm

i2c_common_repeatedstart macro
    bsf     SSPCON2,RSEN
    btfss   PIR1, SSPIF
    bra     $-2

    bcf     PIR1, SSPIF ;clear SSPIF interrupt bit
endm

i2c_common_ack macro
    bcf     SSPCON2,ACKDT
    bsf     SSPCON2,ACKEN
    btfsc   SSPCON2,ACKEN
    bra     $-2
endm

i2c_common_nack macro
    bsf     SSPCON2,ACKDT
    bsf     SSPCON2,ACKEN

    _waitl#v(_waitknt)
    btfsc   SSPCON2,ACKEN
    goto    _waitl#v(_waitknt)
    _waitknt    set _waitknt+1
endm

i2c_common_write macro 
    btfsc   SSPSTAT, BF
    bra     $-2
    movwf   SSPBUF
    btfss   PIR1, SSPIF
    bra     $-2
    bcf     PIR1, SSPIF ;clear SSPIF interrupt bit
endm

i2c_common_read macro
    bsf     SSPCON2,RCEN ;Begin receiving byte from
    btfss   PIR1, SSPIF
    bra     $-2
    bcf     PIR1, SSPIF
    movff   SSPBUF, WREG
endm

code

i2c_common_setup
    movlw   b'00000000'
    movwf   SSPSTAT ;set I2C line leves, clear all flags.

    movlw   24 ;100kHz baud rate: 10000000 osc / [4*100000] -1
    movwf   SSPADD ;RTC only supports 100kHz

    movlw   b'00101000' ;Config SSP for Master Mode I2C
    movwf   SSPCON1

    clrf    SSPCON2

    bsf     SSPCON1,SSPEN ;Enable SSP module

    bcf     PIR2, SSPIE
    bcf     PIR1, SSPIF
    bcf     SSPSTAT, BF
    i2c_common_stop ;Ensure the bus is free
return

write_rtc
    i2c_common_start

    movlw   0xD0 ;DS1307 address | WRITE bit
    i2c_common_write
    i2c_common_check_ack WR_ERR1_RTC

    ;Write data to I2C bus (Register Address in RTC)
    movff   regaddress, WREG ;Set register pointer in RTC
    i2c_common_write ;
    i2c_common_check_ack WR_ERR2_RTC

    ;Write data to I2C bus (Data to be placed in RTC register)
    movff   databyte, WREG ;Write data to register in RTC
    i2c_common_write
    i2c_common_check_ack WR_ERR3_RTC

    goto    WR_END_RTC

    WR_ERR1_RTC
    nop
    movlw   b'00001101'
    movwf   LATA    
    goto    WR_END

    WR_ERR2_RTC
    nop
    movlw   b'00001111'
    movwf   LATA
    bsf LATE,0
    goto    WR_END

    WR_ERR3_RTC
    nop
    movlw   b'00001001'
    movwf   LATA
    goto    WR_END
    WR_END_RTC
    i2c_common_stop ;Release the I2C bus
return

read_rtc
    i2c_common_start

    movlw   0xD0 ;DS1307 address | WRITE bit
    i2c_common_write ;
    i2c_common_check_ack RD_ERR1_RTC

    ;Write data to I2C bus (Register Address in RTC)
    movff   regaddress, WREG    ; Set register pointer in RTC
    i2c_common_write
    i2c_common_check_ack RD_ERR2_RTC

    ;Re-Select the DS1307 on the bus, in READ mode
    i2c_common_repeatedstart
    movlw   0xD1        ; DS1307 address | READ bit
    i2c_common_write
    i2c_common_check_ack RD_ERR3_RTC

    ;Read data from I2C bus (Contents of Register in RTC)
    i2c_common_read
    movwf   datachar
    i2c_common_nack ;Send acknowledgement of data reception

    goto RD_END_RTC

    RD_ERR1_RTC
    nop
    movlw   b'00000011'
    movwf   LATA
    goto    RD_END
    RD_ERR2_RTC
    nop
    movlw   b'00000101'
    movwf   LATA
    goto    RD_END
    RD_ERR3_RTC
    nop
    movlw   b'00000111'
    movwf   LATA
    goto    RD_END
    RD_END_RTC
    i2c_common_stop
return

rtc_convert
    movwf   convert_buffer  ; B1 = HHHH LLLL
    swapf   convert_buffer, WREG; W = LLLL HHHH
    andlw   0x0f        ; Mask upper four bits 0000 HHHH
    addlw   0x30        ; convert to ASCII
    movwf   tens_digit      ; saves into 10ths digit

    movff   convert_buffer, WREG
    andlw   0x0f        ; w = 0000 LLLL
    addlw   0x30        ; convert to ASCII
    movwf   ones_digit      ; saves into 1s digit
return

READ_COLOUR_I2C  
    i2c_common_start

    movlw   0x52        ; TCS34725 address 0x29 << 1, WRITE bit (+0)
    i2c_common_write  
    i2c_common_check_ack RD_ERR1

    ;Write command to I2C bus (Register Address in TCS34725)
    movff   regaddress, WREG
    iorlw   0x80        ; command bit
    i2c_common_write
    i2c_common_check_ack RD_ERR2

    ;Re-Select the TCS34725 on the bus, in READ mode
    i2c_common_repeatedstart
    movlw   0x53        ; TCS34725 address 0x29 << 1, READ bit (+1)
    i2c_common_write
    i2c_common_check_ack RD_ERR3

    ;Read data from I2C bus (Contents of Register in TCS34725)
    i2c_common_read
    movwf   databyte
    i2c_common_nack     ; Send acknowledgement of data reception

    goto RD_END

    RD_ERR1
    nop
    movlw   b'00000011'
    movwf   LATA
    goto    RD_END
    RD_ERR2
    nop
    movlw   b'00000101'
    movwf   LATA
    goto    RD_END
    RD_ERR3
    nop
    movlw   b'00000111'
    movwf   LATA
    goto    RD_END
    RD_END
    i2c_common_stop
return

WRITE_COLOUR_I2C
    i2c_common_start

    movlw   0x52        ; TCS34725 address | WRITE bit
    i2c_common_write
    i2c_common_check_ack WR_ERR1

    ;Write data to I2C bus (Register Address in TCS34725)
    movff   regaddress, WREG
    iorlw   0x80        ; command bits
    i2c_common_write
    i2c_common_check_ack WR_ERR2

    ;Write data to I2C bus (Data to be placed in TCS34725 register)
    movff   databyte, WREG
    i2c_common_write
    i2c_common_check_ack WR_ERR3

    goto    WR_END

    WR_ERR1
    nop
    movlw   b'00001101'
    movwf   LATA    
    goto    WR_END

    WR_ERR2
    nop
    movlw   b'00001111'
    movwf   LATA
    bsf LATE,0
    goto    WR_END

    WR_ERR3
    nop
    movlw   b'00001001'
    movwf   LATA
    goto    WR_END
    WR_END
    i2c_common_stop     ; Release the I2C bus

return
end

Aquí está el código que utilizo para configurar mi sensor de color:

    extern  i2c_common_setup, regaddress, databyte, datachar, READ_COLOUR_I2C, WRITE_COLOUR_I2C, WR_DATA, data_colourL, data_colourH, delay5ms

;    #define TCS34725_ADDRESS          (0x29)
;
;    #define TCS34725_COMMAND_BIT      (0x80)
;
;    #define TCS34725_ENABLE           (0x00)
;    #define TCS34725_ENABLE_AIEN      (0x10)    /* RGBC Interrupt Enable */
;    #define TCS34725_ENABLE_WEN       (0x08)    /* Wait enable - Writing 1 activates the wait timer */
;    #define TCS34725_ENABLE_AEN       (0x02)    /* RGBC Enable - Writing 1 actives the ADC, 0 disables it */
;    #define TCS34725_ENABLE_PON       (0x01)    /* Power on - Writing 1 activates the internal oscillator, 0 disables it */
;    #define TCS34725_ATIME            (0x01)    /* Integration time */
;    #define TCS34725_WTIME            (0x03)    /* Wait time (if TCS34725_ENABLE_WEN is asserted) */
;    #define TCS34725_WTIME_2_4MS      (0xFF)    /* WLONG0 = 2.4ms   WLONG1 = 0.029s */
;    #define TCS34725_WTIME_204MS      (0xAB)    /* WLONG0 = 204ms   WLONG1 = 2.45s  */
;    #define TCS34725_WTIME_614MS      (0x00)    /* WLONG0 = 614ms   WLONG1 = 7.4s   */
;    #define TCS34725_AILTL            (0x04)    /* Clear channel lower interrupt threshold */
;    #define TCS34725_AILTH            (0x05)
;    #define TCS34725_AIHTL            (0x06)    /* Clear channel upper interrupt threshold */
;    #define TCS34725_AIHTH            (0x07)
;    #define TCS34725_PERS             (0x0C)    /* Persistence register - basic SW filtering mechanism for interrupts */
;    #define TCS34725_PERS_NONE        (0b0000)  /* Every RGBC cycle generates an interrupt                                */
;    #define TCS34725_PERS_1_CYCLE     (0b0001)  /* 1 clean channel value outside threshold range generates an interrupt   */
;    #define TCS34725_PERS_2_CYCLE     (0b0010)  /* 2 clean channel values outside threshold range generates an interrupt  */
;    #define TCS34725_PERS_3_CYCLE     (0b0011)  /* 3 clean channel values outside threshold range generates an interrupt  */
;    #define TCS34725_PERS_5_CYCLE     (0b0100)  /* 5 clean channel values outside threshold range generates an interrupt  */
;    #define TCS34725_PERS_10_CYCLE    (0b0101)  /* 10 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_15_CYCLE    (0b0110)  /* 15 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_20_CYCLE    (0b0111)  /* 20 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_25_CYCLE    (0b1000)  /* 25 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_30_CYCLE    (0b1001)  /* 30 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_35_CYCLE    (0b1010)  /* 35 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_40_CYCLE    (0b1011)  /* 40 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_45_CYCLE    (0b1100)  /* 45 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_50_CYCLE    (0b1101)  /* 50 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_55_CYCLE    (0b1110)  /* 55 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_60_CYCLE    (0b1111)  /* 60 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_CONFIG           (0x0D)
;    #define TCS34725_CONFIG_WLONG     (0x02)    /* Choose between short and long (12x) wait times via TCS34725_WTIME */
;    #define TCS34725_CONTROL          (0x0F)    /* Set the gain level for the sensor */
;    #define TCS34725_ID               (0x12)    /* 0x44 = TCS34721/TCS34725, 0x4D = TCS34723/TCS34727 */
;    #define TCS34725_STATUS           (0x13)
;    #define TCS34725_STATUS_AINT      (0x10)    /* RGBC Clean channel interrupt */
;    #define TCS34725_STATUS_AVALID    (0x01)    /* Indicates that the RGBC channels have completed an integration cycle */
;    #define TCS34725_CDATAL           (0x14)    /* Clear channel data */
;    #define TCS34725_CDATAH           (0x15)
;    #define TCS34725_RDATAL           (0x16)    /* Red channel data */
;    #define TCS34725_RDATAH           (0x17)
;    #define TCS34725_GDATAL           (0x18)    /* Green channel data */
;    #define TCS34725_GDATAH           (0x19)
;    #define TCS34725_BDATAL           (0x1A)    /* Blue channel data */
;    #define TCS34725_BDATAH           (0x1B)


    COLOUR_INIT macro
    COLOUR_WRITE    0x00, 0x01 ; Enable Register (0x00), Power ON (0x01)
    call    delay5ms
    COLOUR_WRITE    0x00, 0x02 ; Enable Register (0x00), RGBC enable (0x02)
    call    delay5ms
    COLOUR_WRITE    0x01, 0xff ; Timing Register (0x01), 2.4ms (0xff) cycle
    call    delay5ms
    COLOUR_WRITE    0x0f, 0x03 ; Control Register (0x0f), 60x gain (0x03)
    call    delay5ms
    endm

    COLOUR_READ  macro  address
    movlw   address
    movwf   regaddress
    call    READ_COLOUR_I2C
    endm

    COLOUR_WRITE macro address, datliteral
    movlw   address
    movwf   regaddress
    movlw   datliteral
    movwf   databyte
    call    WRITE_COLOUR_I2C
    endm

    COLOUR_GET_DATA macro clearL, clearH, redL, redH, greenL, greenH, blueL, blueH
    call    delay5ms

    COLOUR_READ 0x14    ; read clear colour address low, command bits set later
    movff   databyte, clearL
    COLOUR_READ 0x15    ; read clear colour address high, command bits set later
    movff   databyte, clearH

    COLOUR_READ 0x16    ; read red colour address low, command bits set later
    movff   databyte, redL
    COLOUR_READ 0x17    ; read red colour address high, command bits set later
    movff   databyte, redH

    COLOUR_READ 0x18    ; read green colour address low, command bits set later
    movff   databyte, greenL
    COLOUR_READ 0x19    ; read green colour address high, command bits set later
    movff   databyte, greenH

    COLOUR_READ 0x1a    ; read blue colour address low, command bits set later
    movff   databyte, blueL
    COLOUR_READ 0x1b    ; read blue colour address high, command bits set later
    movff   databyte, blueH
    endm

Y finalmente, aquí está mi lógica en general:

CHECK_CLEAR
    SUB16   CLEAR, RED          ; check first against red
    btfss   STATUS, C
    return                  ; RED > CLEAR

    SUB16   CLEAR, GREEN            ; check against green
    btfss   STATUS, C
    return                  ; GREEN > CLEAR

    SUB16   CLEAR, BLUE         ; check against blue
    btfss   STATUS, C
    return                  ; BLUE > CLEAR

    movlw   'c'             ; CLEAR > everything else
    call    WR_DATA
    bra LOOPING
CHECK_RED
    SUB16   RED, CLEAR          ; check first against clear
    btfss   STATUS, C
    return                  ; CLEAR > RED

    SUB16   RED, GREEN          ; check against green
    btfss   STATUS, C
    return                  ; GREEN > RED

    SUB16   RED, BLUE           ; check against blue
    btfss   STATUS, C
    return                  ; BLUE > RED

    movlw   'r'             ; RED > everything else
    call    WR_DATA
    bra LOOPING
CHECK_GREEN
    SUB16   GREEN, CLEAR            ; check first against clear
    btfss   STATUS, C
    return                  ; CLEAR > GREEN

    SUB16   GREEN, RED          ; check against red
    btfss   STATUS, C
    return                  ; RED > GREEN

    SUB16   GREEN, BLUE         ; check against blue
    btfss   STATUS, C
    return                  ; BLUE > GREEN

    movlw   'g'             ; GREEN > everything else
    call    WR_DATA
    bra LOOPING
CHECK_BLUE
    SUB16   BLUE, CLEAR         ; check first against clear
    btfss   STATUS, C
    return                  ; CLEAR > BLUE

    SUB16   BLUE, RED           ; check against red
    btfss   STATUS, C
    return                  ; RED > BLUE

    SUB16   BLUE, GREEN         ; check against green
    btfss   STATUS, C
    return                  ; GREEN > CLEAR

    movlw   'b'             ; BLUE > everything else
    call    WR_DATA
    return

COLOUR_TEST

LOOPING
    Delay50N delayR, 0x28
    call    ClrLCD
    COLOUR_GET_DATA CLEAR+0, CLEAR+1, RED+0, RED+1, GREEN+0, GREEN+1, BLUE+0, BLUE+1
    Delay50N delayR, 0x02

;   movlw   0x01        ;testing
;   movwf   CLEAR+1
;   movlw   0x06
;   movwf   GREEN+0
;   movlw   0x03
;   movwf   RED+0
;   movlw   0x01
;   movwf   BLUE+0

    movlw   d'0'
    cpfseq  CLEAR+1
    movlw   'w'
    call    WR_DATA

;   call    CHECK_CLEAR
;   call    CHECK_RED
;   call    CHECK_GREEN
;   call    CHECK_BLUE
    bra LOOPING

SUB16   macro   x, y        ; does not modify x nor y
    local   RESULTS
    movff   y+1, WREG   ; move high y into working register
    subwf   x+1, 0      ; do subtraction xH - yH => w
    btfss   STATUS, Z   ; check if subtraction is zero (if Z=1)
    goto    RESULTS     ; if it is, need to check lower bytes (so skip this)

    movff   y+0, WREG
    subwf   x+0, 0  
RESULTS             ; if... x=y => z=1, x<y => c=0, x>=y => c=1
    endm

Muchas gracias por ayudarme. Sé que esto es mucho para lanzar, y agradecería cualquier pensamiento / idea.

Mateo

    
pregunta mreiter

0 respuestas

Lea otras preguntas en las etiquetas