;; Switch test ;; ;; Test switch with capacitance and without capacitance list p=16f877 ; list directive to define processor include ; processor specific variable definitions include ; 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