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