1
2	list	p=16f88
3        include <p16f88.inc>
4        include <coff.inc>
5
6        __CONFIG  _CONFIG1, _CP_OFF & _WDT_OFF &  _INTRC_IO & _PWRTE_ON & _LVP_OFF & _BODEN_OFF & _MCLR_OFF
7        __CONFIG    _CONFIG2, _IESO_OFF & _FCMEN_OFF
8
9	;; The purpose of this program is to test gpsim's ability to
10	;; simulate a pic 16F88.
11	;; Specifically, the a/d converter is tested.
12
13        errorlevel -302
14
15; Printf Command
16.command macro x
17  .direct "C", x
18  endm
19
20;----------------------------------------------------------------------
21;----------------------------------------------------------------------
22GPR_DATA                UDATA_SHR
23
24x  RES  1
25t1 RES  1
26t2 RES  1
27avg_lo RES  1
28avg_hi RES  1
29w_temp RES  1
30status_temp RES  1
31
32
33;----------------------------------------------------------------------
34;   ********************* RESET VECTOR LOCATION  ********************
35;----------------------------------------------------------------------
36RESET_VECTOR  CODE    0x000              ; processor reset vector
37        movlw  high  start               ; load upper byte of 'start' label
38        movwf  PCLATH                    ; initialize PCLATH
39        goto   start                     ; go to beginning of program
40
41INT_VECTOR   CODE    0x004               ; interrupt vector location
42	;;
43	;; Interrupt
44	;;
45	movwf	w_temp
46	swapf	STATUS,W
47	movwf	status_temp
48
49	bcf	STATUS,RP0	;adcon0 is in bank 0
50
51	btfsc	INTCON,ADIE
52	 btfsc	PIR1,ADIF
53	  goto	check
54   .assert "'FAILED 16F88 unexpected interrupt'"
55	nop
56
57;;	An A/D interrupt has occurred
58check:
59	bsf	t1,0		;Set a flag to indicate we got the int.
60	bcf	PIR1,ADIF	;Clear the a/d interrupt
61
62	swapf	status_temp,w
63	movwf	STATUS
64	swapf	w_temp,F
65	swapf	w_temp,W
66	retfie
67
68
69
70;----------------------------------------------------------------------
71;   ******************* MAIN CODE START LOCATION  ******************
72;----------------------------------------------------------------------
73MAIN    CODE
74start:
75
76   .sim "p16f88.xpos = 72"
77   .sim "p16f88.ypos = 72"
78
79   .sim "module library libgpsim_modules"
80   ; Use a pullup resistor as a voltage source
81   .sim "module load pullup V1"
82   .sim "V1.resistance = 100.0"
83   .sim "V1.xpos = 240"
84   .sim "V1.ypos = 72"
85
86   .sim "module load pullup V2"
87   .sim "V2.resistance = 100.0"
88   .sim "V2.xpos = 84"
89   .sim "V2.ypos = 24"
90
91
92   ; V3 and node na0 required for A/D to see pin voltage
93   ; this may be a bug RRR 5/06
94
95   .sim "module load pullup V3"
96   .sim "V3.resistance = 10e6"
97   .sim "V3.xpos = 240"
98   .sim "V3.ypos = 120"
99
100   .sim "node na0"
101   .sim "attach na0 V3.pin porta0"
102   .sim "node na1"
103   .sim "attach na1 V1.pin porta1"
104
105   .sim "node na3"
106   .sim "attach na3 V2.pin porta3"
107
108
109	;; Let's use the ADC's interrupt
110    ; RA1 is an Analog Input.
111    ; RA0, RA2 - RA6 are all configured as outputs.
112    ;
113    ; Use VDD and VSS for Voltage references.
114    ;
115    ; PCFG = 1110  == AN0 is the only analog input
116    ; ADCS = 110   == FOSC/64
117    ; ADFM = 0     == 6 LSB of ADRESL are 0.
118    ;
119
120	bsf	STATUS,RP0	;adcon1 is in bank 1
121        movlw   3
122	movwf	ANSEL		; select AN0, AN1
123        movwf   TRISA
124
125        movlw   (1<<ADCS2) 	; A/D clock divided by 2
126        movwf   ADCON1
127        bsf     PIE1,ADIE       ;A2D interrupts
128	bcf	STATUS,RP0	;adcon0 is in bank 0
129        movlw   (1<<ADCS1) | (1<<ADON) | (1<<CHS0); Fosc/64, A2D on, Channel 1
130        movwf   ADCON0
131
132        bsf     INTCON,GIE      ;Global interrupts
133        bsf     INTCON,PEIE     ;Peripheral interrupts
134
135
136	call	Convert
137   .assert "adresh == 0xff, 'FAILED 16F88 inital test'"
138	nop
139
140	;; The next test consists of misusing the A/D converter.
141	;; TRISA is configured such that the I/O pins are digital outputs.
142	;; Normally you want them to be configued as inputs. According to
143	;; the data sheet, the A/D converter will measure the voltage produced
144	;; by the digital I/O output:	 either 0 volts or 5 volts (or Vdd).
145	;; [I wonder if this would be a useful way of measuring the power supply
146	;; level in the event that there's an external reference connected to
147	;; an3?]
148
149
150	movlw   0
151	bsf	STATUS,RP0
152	movwf	TRISA		;Make the I/O's digital outputs
153	movwf	ADCON1		;Configure porta to be completely analog
154	bcf	STATUS,RP0
155	bcf	ADCON0,CHS0	;select AN0
156	movwf	PORTA		;Drive the digital I/O's low
157
158	;;
159	;; First do a few conversion with porta configured as a digital output
160	;; that is driving low
161	;;
162
163	call	Convert
164
165  .assert "adresh == 0x00, 'FAILED 16F88 Digital low'"
166	nop
167
168	;;
169	;; Now do some with the digital output high
170	;;
171
172	movlw	0xff
173	movwf	PORTA
174
175	call	Convert
176
177  .assert "adresh == 0xff, 'FAILED 16F88 Digital high'"
178	nop
179	;;
180	;; Now make the inputs analog (like they normally would be)
181	;;
182
183
184	bsf	ADCON0,CHS0	;select AN1
185	bsf	STATUS,RP0
186	movlw	0xff
187	movwf	TRISA
188	bcf	STATUS,RP0
189
190	call	Convert
191
192  .assert "adresh == 0xff, 'FAILED 16F88 AN1=5V'"
193	nop
194
195  .command "V1.voltage=1.0"
196
197	call	Convert
198
199   .assert "adresh == 0x33, 'FAILED 16F88 AN1=1V'"
200	nop
201
202	;;
203	;; Now let's use the external analog signal connected to AN3
204	;; as the voltage reference
205
206	bsf	STATUS,RP0
207	bsf	ADCON1,VCFG1
208	bsf	ANSEL,3
209	bcf	STATUS,RP0
210
211  .command "V2.voltage=2.0"
212
213	call	Convert
214
215   .assert "adresh == 0x80, 'FAILED 16F88 AN1=1V Vref+=2V'"
216	nop
217
218  .assert  "'*** PASSED 16F88 a2d test'"
219
220	goto	$-1
221
222
223
224Convert:
225
226	clrf	t1		;flag set by the interrupt routine
227
228	bsf	ADCON0,GO	;Start the A/D conversion
229
230	btfss	t1,0		;Wait for the interrupt to set the flag
231	 goto	$-1
232
233        movf    ADRESH,W                ;Read the high 8-bits of the result
234
235	return
236
237	end
238