I have this project communicating MPR121 capacitive touch sensing keyboard with 8051 microcontroller, with some references I've implemented some I2C code for serial communication between master and slave, and I wanted to know whether the slave is responding to transmitted data, so whenever master sends the slave address and some other register or data I wanted to know whether there is a ACK or a NACK and show 1 in the 7seg display when is NACK as in 1-SDA high OR show 0 in 2nd 7seg display as in 0-SDA low, so I made
MOV P1,#00000001B
MOV P0, #00000111B ; when NACK
MOV P1,#00000010B
MOV P0, #01111111B ; when ACK
But the problem is that even with the right and the wrong slave address 0 is showing in the display, where I'm wrong, and btw I tried this code and technique with some other sensor and it worked, is my sensor gone or my code wrong help please ..
Here is all the code:
; MPR121 Address
slaveaddr EQU 10110100B
; I2C connections
SCLPin BIT P3.6 ;I2C serial clock line.
SDAPin BIT P3.7 ;I2C serial data line.
IRQ BIT P3.2
; I2C Data storage locations
BitCnt DATA 8H ;Bit counter for I2C routines.
ByteCnt DATA 9H ;Byte counter for I2C routines.
SlvAdr DATA 0DH ;Slave address for I2C routines.
SndDat DATA 21H ;I2C transmit buffer, 4 bytes max.
RcvDat DATA 25H ;I2C receive buffer, X bytes max.
Flags DATA 20H ;Location for bit flags
MPR_REG DATA 0CH ;Location for QMC bit flags
MPR_STATUS DATA 2BH ;QMC Status Register (06H in QMC)
MPR_RNG DATA 2CH ;QMC Range (2G or 8G)
NoAck BIT Flags.0 ;I2C no acknowledge flag.
BusFault BIT Flags.1 ;I2C bus fault flag.
I2CBusy BIT Flags.2 ;I2C busy flag.
org 0
ljmp reset
org 30H
;##############################
; I2C ROUTINES #
;##############################
BitDly: NOP ;NOPs to delay
NOP
RET
; SCLHigh - sends SCL pin high and waits for any clock stretching peripherals.
SCLHigh: SETB SCLPin ;Set SCL from our end.
JNB SCLPin,$ ;Wait for pin to actually go high.
RET
; SendStop - sends an I2C stop, releasing the bus.
SendStop: CLR SDAPin ;Get SDA ready for stop.
ACALL SCLHigh ;Set clock for stop.
ACALL BitDly
SETB SDAPin ;Send I2C stop.
ACALL BitDly
CLR I2CBusy ;Clear I2C busy status.
RET ;Bus should now be released.
; SendByte - sends one byte of data to an I2C slave device.
; Enter with:
; ACC = data byte to be sent.
SendByte: MOV BitCnt,#8 ;Set bit count.
SBLoop: CLR C
RLC A ;Send one data bit.
MOV SDAPin,C ;Put data bit on pin.
ACALL SCLHigh ;Send clock.
ACALL BitDly
CLR SCLPin
ACALL BitDly
DJNZ BitCnt,SBloop ;Repeat until all bits sent.
SETB SDAPin ;Release data line for acknowledge.
ACALL SCLHigh ;Send clock for acknowledge.
ACALL BitDly
JNB SDAPin,SBEX ;Check for valid acknowledge bit.
SETB NoAck ;Set status for no acknowledge.
MOV P1,#00000001B
;.gfedcba
MOV P0, #00000111B
SBEX:
MOV P1,#00000010B
;.gfedcba
MOV P0, #01111111B
CLR SCLPin ;Finish acknowledge bit.
ACALL BitDly
RET
; GoMaster - sends an I2C start and slave address.
; Enter with:
; SlvAdr = slave address.
GoMaster: SETB I2CBusy ;Indicate that I2C frame is in progress.
CLR NoAck ;Clear error status flags.
CLR BusFault
JNB SCLPin,Fault ;Check for bus clear.
JNB SDAPin,Fault
CLR SDAPin ;Begin I2C start.
ACALL BitDly
CLR SCLPin
ACALL BitDly ;Complete I2C start.
MOV A,SlvAdr ;Get slave address.
ACALL SendByte ;Send slave address.
RET
Fault: SETB BusFault ;Set fault status
RET ; and exit.
; SendData - sends one or more bytes of data to an I2C slave device.
; Enter with:
; ByteCnt = count of bytes to be sent.
; SlvAdr = slave address.
; @R1 = data to be sent (the first data byte will be the
; subaddress, if the I2C device expects one).
SendData: ACALL GoMaster ;Acquire bus and send slave address.
JB NoAck,SDEX ;Check for slave not responding.
SDLoop: MOV A,@R1 ;Get data byte from buffer.
ACALL SendByte ;Send next data byte.
INC R1 ;Advance buffer pointer.
JB NoAck,SDEX ;Check for slave not responding.
DJNZ ByteCnt,SDLoop ;All bytes sent?
SDEX: ACALL SendStop ;Done, send an I2C stop.
RET
;RcvByte - receives one byte of data from an I2C slave device.
; Returns:
; ACC = data byte received.
RcvByte: MOV BitCnt,#8 ;Set bit count.
CLR A
RBLoop: ACALL SCLHigh ;Read one data bit.
ACALL BitDly
MOV C,SDAPin ;Get data bit from pin.
RLC A ;Rotate bit into result byte.
CLR SCLPin
ACALL BitDly
DJNZ BitCnt,RBLoop ;Repeat until all bits received.
PUSH ACC ;Save accumulator
MOV A,ByteCnt
CJNE A,#1,RBAck ;Check for last byte of frame.
SETB SDAPin ;Send no acknowledge on last byte.
SJMP RBAClk
RBAck: CLR SDAPin ;Send acknowledge bit.
RBAClk: ACALL SCLHigh ;Send acknowledge clock.
POP ACC ;Restore accumulator
ACALL BitDly
CLR SCLPin
SETB SDAPin ;Clear acknowledge bit.
ACALL BitDly
RET
;RcvData - receives sends one or more bytes of data from an I2C slave device.
; Enter with:
; ByteCnt = count of bytes to be sent.
; SlvAdr = slave address.
; Returns:
; @R1 = data received.
; Note: to receive with a subaddress, use SendData to set the subaddress
; first (no provision for repeated start).
RcvData:
ACALL GoMaster
MOV A, QMC_REG ; Start reading from Register 00 of QMC
ACALL SendByte
ACALL SCLHigh
INC SlvAdr ;Set for READ of slave.
ACALL GoMaster ;Acquire bus and send slave address.
JB NoAck,RDEX ;Check for slave not responding.
RDLoop: ACALL RcvByte ;Recieve next data byte.
MOV @R1,A ;Save data byte in buffer.
INC R1 ;Advance buffer pointer.
DJNZ ByteCnt,RDLoop ;Repeat untill all bytes received.
RDEX: ACALL SendStop ;Done, send an I2C stop.
RET
reset: MOV SP,#2fH
MOV Flags, #0 ; Reset I2C Flags
MOV SndDat+0,#2BH ; MHDR register
MOV SndDat+1,#01H ; value to be written into 2Bh
Main:
MOV SlvAdr, #slaveaddr
MOV R1, #SndDat ;Start of data.
MOV ByteCnt, #2 ;Send register and value to be written
ACALL SendData
SJMP $
END