;;  Switch test 
   ;;
   ;;  Test switch with capacitance and without capacitance


	list    p=16f877                ; list directive to define processor
	include <p16f877.inc>           ; processor specific variable definitions
        include <coff.inc>              ; Grab some useful macros


;------------------------------------------------------------------------
; gpsim command
.command macro x
  .direct "C", x
  endm


;----------------------------------------------------------------------
;----------------------------------------------------------------------
GPR_DATA                UDATA
temp            RES     1
temp1		RES	1
temp2		RES	1

  GLOBAL done



;----------------------------------------------------------------------
;   ********************* RESET VECTOR LOCATION  ********************
;----------------------------------------------------------------------
RESET_VECTOR  CODE    0x000              ; processor reset vector
        movlw  high  start               ; load upper byte of 'start' label
        movwf  PCLATH                    ; initialize PCLATH
        goto   start                     ; go to beginning of program


;----------------------------------------------------------------------
;   ******************* MAIN CODE START LOCATION  ******************
;----------------------------------------------------------------------
MAIN    CODE


;----------------------------------------------------------------------
; gpsim configuration script
;
; The configuration environment consists of a switch SW1 connecting
; portb0 and portc0 to portc1. Resistors on either side of the switch
; ensure that the nodes are never floating and allow the switch voltage
; to be checked.
;
; SW2.A is connected to the same node as SW1.A and SW2.B is connected to
; portc2. This allows checking of 2 switch infinite regression bug.
;
; Portb0 is used to drive the switch while portc 0-2 monitor the results
;
;               PU1   SW1
;                |   A \  B
;  portb0  >--+--+----O \O-----+--> portc1
;             |                |
;  portc0  <--+                |
;             |    A \  B     PD1
;             |-----O \O----------> portc2
;                   SW2
;
; The pull up and pull down resistors are modelled as parallel RC networks:
;
;
;           5V
;            ^                 x
;            |                 |
;         +--+--+           +--+--+
;         |     |           |     |
;      R  \    === C     R  \    === C
;         /     |           /     |
;         |     |           |     |
;         +--+--+           +--+--+
;            |                 |
;            x                ///
;
;        Pull up            Pull Down
;
; The 'x' is connection point.
;

   ;# Module libraries:
   .sim "module library libgpsim_modules"
   ;# The processor's reference designator is U1
   .sim "U1.xpos = 48.0"
   .sim "U1.ypos = 36.0"


   .sim "module load switch SW1"
   .sim "SW1.state=false"
   .sim "SW1.xpos = 216.0"
   .sim "SW1.ypos = 156.0"
   .sim "SW1.Ropen = 1.0e8"

   .sim "module load pullup PU1"
   .sim "PU1.resistance=1.0e8"
   .sim "PU1.capacitance=2.00e-07"
   .sim "PU1.xpos = 204.0"
   .sim "PU1.ypos = 36.0"

   .sim "module load pulldown PD1"
   .sim "PD1.resistance=5000."
   .sim "PD1.capacitance=4.00e-06"
   .sim "PD1.xpos = 204.0"
   .sim "PD1.ypos = 96.0"

   .sim "module load switch SW2"
   .sim "SW2.state=false"
   .sim "SW2.xpos = 216.0"
   .sim "SW2.ypos = 228.0"
   .sim "SW2.Ropen = 1.0e6"

    ;# Connections:
   .sim "node nb0"
   .sim "attach nb0 SW1.A portb0 portc0 PU1.pin SW2.A"

   .sim "node nc0"
   .sim "attach nc0 SW1.B PD1.pin portc1"

   .sim "node nc1"
   .sim "attach nc1 SW2.B portc2"

   .sim "frequency 10.0e6"

    ;# Scope monitoring
   .sim "scope.ch0=\"portb0\""
   .sim "scope.ch1=\"portc0\""
   .sim "scope.ch2=\"portc1\""
   .sim "scope.ch3=\"portc2\""

;# End of configuration
;
;------------------------------------------------------------------------


start

	BSF	STATUS,RP0

	movlw	0x07		; RC2,RC1 and RC0 are inputs
	movwf	TRISC
	CLRF	TRISB^0x80	;Port B is an output

	BCF 	STATUS,RP0

   ; The switch is open and portb0 is driving one side of it and portc0.
   ; The other side goes to portc1 and is pulled up by the pullup resistor
   ; Toggling portb0 should have no effect on portc1

	BCF	PORTB,0

	; both sides of switch should be 0
   .assert "(portc & 3) == 0, \"SW open, both sides 0\"" 
	nop

	BSF	PORTB,0

   .assert "(portc & 3) == 1, \"SW open, drive high\""	; drive side only high
	nop

   ; Close the switch because of capacitance portc1 will go high after a delay:	
   ; R=145, C=4.2e-6 TC=6.11e-4 or 1527 cycles 0-2 volts requires 0.51 Tc
   .command "SW1.state=true"
	nop

	; portc0 should be same as portc1
   .assert "(portc & 3) == 0, \"SW1 closed, cap holds low\""	
 	nop
 	nop

       movlw   1	; wait 1280 cycles
       call    delay
	nop

   .assert "(portc & 3) == 3, \"Sw1 closed, after < 1TC\""	
	nop

       movlw   8	; let voltage go all the way high
       call    delay

;  drive portb low, voltages should from ~5 to 1 volts in 1.6 TC
;  or 2443 cycles, but because of RC step need 3 delay loops
	BCF	PORTB,0		; change drive voltage



       movlw   3
       call    delay

   .assert "(portc & 3) == 0, \"drive low 1.6TC\""   ; both sides now low
	nop

       movlw   6	; let voltages go to 0
       call    delay


;
;	test capacitance delay on drive transition
;
	BSF	PORTB,0		; drive high again
        movlw	9
	call	delay

   .assert "(portc & 3) == 3, \"prepare switch open\""	; make sure both sides are high
	nop

   ; Open the switch, the time constant for the floating side is 0.02 sec.
   ; At 10 MHz oscillator frequency the time constant is 50,000 instruction
   ; cycles. To go from 5 to 0.5 volts requires 2.3 time constants or
   ; 1.15e5 cycles. As delay loop is 1277 want to delay 90 loops (5A hex).
   ; Note, although 1 Volt is the h2l transition voltage at 1.6 time constants,
   ; we miss this.
   ;
   ; The drive side time constant is 150 * 2e-7 = 3e-5 sec or 75 cycles
   ; so drive side goes low as soon as drive does.
   ;
   .command "SW1.state=false"
	nop

	; driven side still driven, floating side
	; held by capacitance.

   .assert "(portc & 3) == 3, \"SW1 open driving high\""   
	nop

	BCF	PORTB,0

   .assert "(portc & 3) == 2, \" SW1 open driving low\""
	nop

        movlw   0x29	; delay 52,480 cycles
	call	delay

   .assert "(portc & 3) == 2, \"SW1 open float still high\""
	nop

	movlw   0x31	; delay another 62,720 cycles
	call	delay
	nop

   .assert "(portc & 3) == 0, \"SW1 open float low after 115215 cycles\""
	nop

;	Turn off Capacitance to test DC behaviour
;
   .command "PD1.capacitance=0.0"
	nop
   .command "PU1.capacitance=0."
	nop

   .assert "(portc & 3) == 0"
	nop

	BSF	PORTB,0		; Drive one side of switch high
   .assert "(portc & 3) == 1, \"Drive side high C=0\""
	nop

   ; Close the switch:	
   .command "SW1.state=true"
	nop

   .assert "(portc & 3) == 3, \"Both sides high C=0\"" 
	nop

	BCF	PORTB,0
   .assert "(portc & 3) == 0, \"Both sides low C=0\""
	nop

   ; Close the SW2 switch, portc2 should be same as portc0 and portc1

	BSF	PORTB,0		; Drive one side of switch high

   .command "SW2.state=true"
	nop

   .assert "(portc & 7) == 7, \"2 Switch drive high\""
	nop

	BCF	PORTB,0
   .assert "(portc & 7) == 0, \"2 switch drive low\""
	nop

   ; Now test very large switch resistance
   .command "SW1.state=false"
        nop
   .command "SW2.state=false"
        nop
	BCF	PORTB,0

   .assert "(portc & 3) == 0, \"Both sides low C=0 Starting Large Ron\""
	nop

   .command "SW1.Rclosed=1e4"
	nop
   .command "PD1.capacitance=0.50e-06"
	nop
   .assert "(portc & 3) == 0, \"SW1.Rclosed = 10k\""
	nop

   .command "SW1.state=true"

   ; Now with the switch closed, the switch resistance and 
   ; the pull down resistance form a voltage divider:	
   ;
   ;                10k
   ;  portb0 -----/\/\/\---+----+------ portc0
   ;                       \    |
   ;                       /    |
   ;                   5k  \   === 4uF
   ;                       /    |
   ;                       |    |
   ;                      ///  ///
   ;
   ;  When portb0 is driven to 5.0V, portc0 will rise to 5/3=1.66V

	BSF	PORTB,0		; Drive one side of switch high

	movlw   30
	call    delay

	BCF	PORTB,0		; Drive the switch low again

	movlw   30
	call    delay

   ; Remove the pull down resistor by making its value very large
   ; Now when we drive portb0 high, the other side can rise to 5.0V

   .command "PD1.resistance=1.0e8"
	nop

	BSF	PORTB,0		; Drive one side of switch high

	movlw   9
	call    delay

	BCF	PORTB,0		; Drive the switch low again

	movlw   9
	call    delay

	nop

done:

  .assert  "\"*** PASSED Switch Test on 16f877\""
	goto	$

FAILED:
  .assert  "\"*** FAILED Switch Test on 16f877\""
	goto	$


delay		; W=9 = delay about 11,500 cycles or  1.2 ms at 10 Mhz
       movwf	temp2
       clrf    temp1
delay_loop
        decfsz  temp1,f
         goto   $+2
        decfsz  temp2,f
         goto   delay_loop
        return


  end


syntax highlighted by Code2HTML, v. 0.9.1