Code:
	' Name        : I2CSLAVE.pbp
' Compiler    : PICBASIC PRO Compiler 2.6
' Assembler   : PM or MPASM
' Target PIC  : 40-pin 16F877A
' Hardware    : Lab-X1
' Oscillator  : 4MHz internal or external
' Keywords    : I2CREAD, I2CWRITE, LCDOUT
' Description : PICBASIC PRO program for I2C slave program - PIC16F877/PIC-X1.
'
DEFINE  LOADER_USED 1  ' Using boot-Loader
Define HSER_CLROERR 1  'to automatically clear any buffer overflow of serial input
Define HSER_BAUD 4800  'Set to NMEA baud rate standard
' Define ADCIN parameters
Define    ADC_BITS    10    ' Set number of bits in result
Define    ADC_CLOCK    3    ' Set clock source (3=rc)
Define    ADC_SAMPLEUS    50    ' Set sampling time in uS
' Alias I2C pins
scl VAR PORTC.3        ' I2C clock input
sda VAR PORTC.4        ' I2C data input
' Define used register flags
SSPIF VAR PIR1.3       ' SSP (I2C) interrupt flag
BF    VAR SSPSTAT.0    ' SSP (I2C) Buffer Full
R_W   VAR SSPSTAT.2    ' SSP (I2C) Read/Write
D_A   VAR SSPSTAT.5    ' SSP (I2C) Data/Address
CKP   VAR SSPCON.4     ' SSP (I2C) SCK Release Control
SSPEN VAR SSPCON.5     ' SSP (I2C) Enable
SSPOV VAR SSPCON.6     ' SSP (I2C) Receive Overflow Indicator
WCOL  VAR SSPCON.7     ' SSP (I2C) Write Collision Detect
' Define constants
I2Caddress CON  $a0      ' Make our address 2
' Allocate alias
qUp     var     PORTA.2
qDown   var     PORTA.5
' Allocate variables
qpot    var     word 'raw potentiometer reading
qpotflt var     word 'raw pot filtered
xqpot   var     word 'used to compute average
qpotnb  var     byte 'filtering number
qpotold var     word
qpotCal var     byte 'calibrated pot reading (20 - 220)
qpos    var     byte  '0 down, 1 up
CalFlag var     byte 
x       var     word
y       var     word
QDmax   var     word
QUmax   var     word
Qmin    var     word
PotDA   var     word  'amplitude pot for Down position
PotDOf  var     word  
PotUA   var     word  'amplitude pot for up position
PotUOf  var     word  
QposPerc var    byte  
Qdraft  var     byte  
ind     var     byte
bogus   var     word  'dummy for div32
Qstatus var     byte  'to send status info to Master, 0 acq, 1 cal, 2 mov up, 3 mov down
datain  var     byte  'received data from Master
DataOut var     byte[4]
readcnt var     byte
result  VAR     BYTE       ' ADC result
' Initialize ports and directions
ADCON1 = %10010101         
TRISA = %11111111    ' Set PORTA to all input
' Initialize I2C slave mode
   SSPADD = I2Caddress ' Set our address
   SSPCON2 = 0         ' General call address disabled
   SSPCON = $36        ' Set to I2C slave with 7-bit address
   readcnt = 0         ' Zero counter
   GoTo mainloop       ' Skip over subroutines
   '*****************************QMove******************************************
QMove:
if qpotold > qpot then
    if qpotold-qpot > 4 then
        if qUp=1 then qPos=0
        if qDown=1 then qpos=1
    endif
else
    if qpot-qpotold > 4 then
        if qUp=1 then qPos=1
        if qDown=1 then qpos=0
    endif
endif
return
'*****************************CalProc****************************************
CalPROC:
if qUp=1 and qpos=1 then
  QUmax = QUmax max qpot
endif
if qDown=1 and qpos=0 then
  QDmax = QDmax max qpot  
endif
Qmin = Qmin min qpot
if qdown=1 then calflag=2                
if calflag=2 and qdown=0 then calflag=3  
if calflag=3 and qUp=1 then calflag=4    
if calflag=4 and qUp=0 then              
    PotDA=qdmax-qmin
    x=qmin*220
    y=div32 PotDa    
    PotDOf= 120-y      'offset +100 to avoid any negative number
    PotUA=qdmax-qmin
    x=qmin*220  
    y=div32 PotUa  
    PotUOf= 120-y      'offset +100 to avoid any negative number
    write 0, word potda, word PotDOf, word PotUA, word PotUOf, qpos 
    calflag=0          'back to acquisition mode
endif
return
'*****************************Getx*******************************************        
' Subroutine to get pot value
getx:
    ADCIN 0, qpot        ' Read channel 0 to qpot
    xqpot=xqpot+qpot
    qpotnb=qpotnb+1
    if qpotnb= 8 then
        qpotnb=0
        qpotflt=xqpot/8
        xqpot=0
        
        dataout[0]=qpotflt
        dataout[1]=qpotCal
        dataout[2]=Qstatus 
        hserout ["$pot,", dec qpotflt]
        hserout ["$qup,", dec qUp]
        hserout ["$qdown,", dec qDown]
        hserout ["$cf,", dec calflag]
        hserout ["$qdm,", dec qdmax]
        hserout ["$qum,", dec qumax]
        hserout ["$qm,", dec qmin]
        gosub QMove
        if calflag=0 then
          if qpos=0 then
            bogus = 220 * qpot
            qpotcal = div32 potda
            qpotcal=qpotcal+PotDOf-100
          else
            bogus = 220 * qpot
            qpotcal = div32 potUa
            qpotcal=qpotcal+PotUOf-100  
          endif
          gosub convert
        else
          gosub CalPROC
        endif
    endif
Return
'*******************************conversion***********************************
convert:
if qpos=0 then
  ' down position
  lookdown2 qpotcal,<=[20,22,26,33,42,55,73,96,127,167,192,206,230],ind
  lookup ind,[67,70,73,77,80,83,87,90,93,97,98,99,100], qposperc
  lookup ind,[166,171,176,180,184,187,191,193,196,198,199,200,200],qdraft
else
  ' up position
  lookdown2 qpotcal,<=[20,21,24,28,33,39,46,53,62,72,83,94,106,119,133,148,163,179,195,204,208,220],ind
  lookup ind,[63,60,57,53,50,47,43,40,37,33,30,27,23,20,17,13,10,7,3,2,1,0],qposperc
  lookup ind,[161,156,150,144,138,132,125,118,111,104,97,89,81,73,65,56,48,39,30,26,23,20],qdraft
endif
'dataout[0]= qposperc
'dataout[0]= qpot
''dataout[1]= qdraft
'dataout[1]= qpot
'dataout[2]= Qstatus
return
i2cslave:              ' I2C slave subroutine
   SSPIF = 0           ' Clear interrupt flag
   IF R_W = 1 Then i2crd   ' Read data from us
   IF BF = 0 Then i2cexit  ' Nothing in buffer so exit
   IF D_A = 1 Then i2cwr   ' Data for us (not address)
   IF SSPBUF != I2Caddress Then i2cexit ' Clear the address from the buffer
   readcnt = 0         ' Mark as first read
   GoTo i2cexit
i2cwr:                 ' I2C write data to us
   datain = SSPBUF     ' Put data into array
   if datain=127 then     
     calflag=1         ' goes into calibration mode
     qpos=1            ' calibration is started from keel
   endif
   wflag=0
   GoTo i2cexit
i2crd:                 ' I2C read data from us
   IF D_A = 0 Then
      readcnt = 0      ' Mark as first read
   EndIF
   SSPBUF = dataout[readcnt]    ' Get data from array
   CKP = 1                      ' Release SCL line
   readcnt = readcnt + 1        ' Move along read count
   GoTo i2cexit                 ' That's it
i2cexit:
   Return
mainloop:              ' Main program loop
   IF SSPIF  ' Check for I2C interrupt flag
        GoSub i2cslave
   EndIF
if calflag>0 then
  Qstatus=1
else
  if qUp=1 then 
    Qstatus=2
  elseif qDown=1 then 
    Qstatus=3
  else 
    Qstatus=0
  endif
endif
gosub getx
'dataout[0]=qpotflt                   '----------------With everything as comment, I2C works to write and read
'dataout[1]=qpotCal                  '---------------- if I uncomment all this, i2c still works with a read command
'dataout[2]=Qstatus                  '---------------- if I uncomment either the hserout or only the call to the subroutine
'hserout ["$pot,", dec qpotflt]      '---------------- read comment is still OK but write command fails
'hserout ["$qup,", dec qUp]
'hserout ["$qdown,", dec qDown]
'hserout ["$cf,", dec calflag]
'hserout ["$qdm,", dec qdmax]
'hserout ["$qum,", dec qumax]
'hserout ["$qm,", dec qmin]
'gosub QMove
'if calflag=0 then
'  if qpos=0 then
'    bogus = 220 * qpot
'    qpotcal = div32 potda
'    qpotcal=qpotcal+PotDOf-100
'  else
'    bogus = 220 * qpot
'    qpotcal = div32 potUa
'    qpotcal=qpotcal+PotUOf-100  
'  endif
'  gosub convert
'else
'  gosub CalPROC
'endif
   GoTo mainloop       ' Do it all forever
   End
 
				
Bookmarks