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