Als eerste A/D project tracht ik de spanning van een 4,8V batterij te meten en aldus te bewaken. Spanning komt binnen op GP0 en referentie van 2,5V via zener diode op GP1. Ik stuur twee LED's aan op GP2 en GP3 als de spanning gelijk of hoger is dan 2,4V (spanningsdeler)
brandt de groene LED, als de spanning lager of gelijk is dan 2,35V pinkt de rode led en lager dan 2,3V blijft de rode led branden.

Na inlezen van het programma gebeurt er uiteraard niets... het is bij deze nogal blind werken en heb zelf geen programmeer ervaring.

Kan iemand mij hier door helpen...


Device = 12F675
 CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, MCLRE_OFF
 XTAL = 4
         
    DECLARE ADIN_RES 10          	 ' 10-bit resultaat 
    DECLARE ADIN_TAD FRC         	 ' interne OSC geselecteerd 
    DECLARE ADIN_STIME 50        	 ' selecteer 50µs sample tijd
                    
    TRISB = %00000011            		  ' Configure AN0 (PORTB.0 and 1) as an input 
    ADCON0 = %10000000          		  ' Set analogue input on PORTA.0 
    
    DIM VAR1 as WORD
    Dim AD_RESULT as ADRESL.WORD 	 ' Convert the ADRESL register into a WORD variable 
        
				 ' ADCON0 register's bits  
   
    Symbol GO_DONE = ADCON0.1    	 ' ADC Conversion status/ plus enable conversion-bit
    Symbol ADON = ADCON0.0       	 ' ADC Enable bit: 1 = enabled, 0 = disabled.
    
    Symbol LEDG = Portb.2         		 ' groene LED is output 2
    Symbol LEDR = portb.3        		 ' rode LED is output 3
               
    Delayms 500                 		  ' Wait for the PICmicro to stabilise
    Goto OVER_ADC_SUBS           	  ' Jump over the subroutines
        
                                 			  '---[START ADC CONVERSION]---
GET_ADC:

    ADON = 1                     		  ' Enable the ADC
    Delayus 50                  		  ' Wait for sample/hold capacitors to charge
    GO_DONE = 1                  		  ' Start conversion
    While GO_DONE = 1 : Wend      	  ' Poll the GO_DONE flag for completion of conversion
    ADON = 0                     		  ' Disable the ADC, to save power
Return
          
                                 			 '---[INITIALISE THE ADC REGISTERS]---
                                  			 ' Standard procedures for setting up the ADC 
OVER_ADC_SUBS:                


    TRISIO = %11111111           		 ' All pins set for input
        
    Ansel.4 = 1                   		 ' Setup ADC's clock for FRC (ADCS0)
    ANSEL.5 = 1                  		 ' Setup ADC's clock for FRC (ADCS1)
    ANSEL.6 = 0                  		 ' Setup ADC's clock for FRC (ADCS2)
     
    ADCON0.6 = 1                 		 ' VREF is set to extern zener diode (VCFG)
    ADCON0.7 = 1                 		 ' Right justify the ADC resul (ADFM)
        
    ANSEL.0 = 0                  		 ' Set AN0 (GPIO.0) as Digital input
    ANSel.1 = 0                  		 ' Set AN1 (GPIO.1) as Digital input
    ANSEL.2 = 1                 		 ' Set AN2 (GPIO.2) as Analogue input
    ANSEL.3 = 1                  		 ' Set AN3 (GPIO.3) as Analogue input
        
                                 			 '---[MAIN PROGRAM LOOP STARTS HERE]---
                                  			                                       
While 1 = 1                    			 ' Create an infinite loop
    VAR1 = AD_Result
    VAR1 = VAR1 * (0.006/100)
    IF VAR1 >= 240 Then LEDG = 1
    IF VAR1 >= 235 AND VAR1 < 240 Then LEDR = 1
    DelayMS 250
    IF VAR1 >= 235 Then LEDR = 0
    IF VAR1 < 230  Then LEDR = 1
    Delayms 50                   		 ' Wait for another conversion
Wend

[Bericht gewijzigd door Henry S. op (0%)]

Weet je zeker dat je een 12F675 gebruikt?
Ik zie nl TRISB staan en deze uC kent alleen TRISIO.
Commentaar als PORTB en PORTA zal wel van een ander programma zijn geknipt en geplakt.
Vervolgens zet je met TRISIO alles op input, maar je zegt dat er led's aan moeten gaan. Dat gaat dus niet werken.

GET_ADC wordt overigens nergens aangeroepen, dus AD_Result zal een onvoorspelbare waarde hebben.

Ik heb het programma even gecompileerd...
Blijkt dat Proton PORTB gewoon herkent en implementeert als GPIO en TRISB als TRISIO.

Je programma doet het wel in de Sim van MPLab, maar noppes aan ADC.
In GPIO staan alle pinnen op input (logisch, dat heb je zelf zo aangezet).

Beste hadv, alvast bedankt voor uw antwoord, het is wel degelijk een 12F675 ik gebruik deze omdat ik de gratis versie van PROTON IDE gebruik. Ik heb enkele aanpassingen uitgevoerd, maar bezit niet de mogelijkheid om te testen, als het louter digitaal is lukt het allemaal vrij goed, maar ADC, eerlijk gezegd is misschien iets te hoog gegrepen. Alvast hieronder een nieuwe poging;


Device = 12F675
 CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, MCLRE_OFF
 XTAL = 4
         
    DECLARE ADIN_RES 10           ; 10-bit resultaat 
    DECLARE ADIN_TAD FRC          ; interne OSC geselecteerd 
    DECLARE ADIN_STIME 50         ; selecteer 50µs sample tijd
                    
    TRISB = %00000011             ' Configure AN0 (PORTB.0 and 1) as an input 
    ADCON0 = %10000000            ' Set analogue input on PORTA.0 
    
    DIM VAR1 as WORD
    Dim AD_RESULT as ADRESL.WORD  ' Convert the ADRESL register into a WORD variable 
        
' ADCON0 register's bits  
   
    Symbol GO_DONE = ADCON0.1     ' ADC Conversion status/ plus enable conversion-bit
    Symbol ADON = ADCON0.0        ' ADC Enable bit: 1 = enabled, 0 = disabled.
    
    Symbol LEDG = Portb.2         ' groene LED is output 2
    Symbol LEDR = portb.3         ' rode LED is output 3
               
    Delayms 500                   ' Wait for the PICmicro to stabilise
    Goto OVER_ADC_SUBS            ' Jump over the subroutines
        
                                  '---[START ADC CONVERSION]---
GET_ADC:

    ADON = 1                      ' Enable the ADC
    Delayus 50                    ' Wait for sample/hold capacitors to charge
    GO_DONE = 1                   ' Start conversion
    While GO_DONE = 1 : Wend      ' Poll the GO_DONE flag for completion of conversion
    ADON = 0                      ' Disable the ADC, to save power
Return
          
                                  '---[INITIALISE THE ADC REGISTERS]---
                                  ' Standard procedures for setting up the ADC 
OVER_ADC_SUBS:                
        

    Ansel.4 = 1                   ' Setup ADC's clock for FRC (ADCS0)
    ANSEL.5 = 1                   ' Setup ADC's clock for FRC (ADCS1)
    ANSEL.6 = 0                   ' Setup ADC's clock for FRC (ADCS2)
     
    ADCON0.6 = 1                  ' VREF is set to extern zener diode (VCFG)
    ADCON0.7 = 1                  ' Right justify the ADC resul (ADFM)
        
    ANSEL.0 = 0                   ' Set AN0 (GPIO.0) as Digital input
    ANSel.1 = 0                   ' Set AN1 (GPIO.1) as Digital input
    ANSEL.2 = 1                   ' Set AN2 (GPIO.2) as Analogue input
    ANSEL.3 = 1                   ' Set AN3 (GPIO.3) as Analogue input
        
                                  '---[MAIN PROGRAM LOOP STARTS HERE]---
                                       
While 1 = 1                       ' Create an infinite loop

    ADCON0 = ADCON0 | (2 << 2)    ' Select the channel to read
    Gosub GET_ADC                 ' Perform an ADC conversion

    VAR1 = AD_Result
    VAR1 = VAR1 * (0.006/100)
    IF VAR1 >= 240 Then LEDG = 1
    IF VAR1 < 238 AND VAR1 > 236 Then LEDR = 1
    DelayMS 250 
    IF VAR1 >= 235 Then LEDR = 0
    IF VAR1 < 230  Then LEDR = 1
    Delayms 50                    
Wend

[Bericht gewijzigd door Henry S. op (0%)]


Device = 12F675
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, MCLRE_OFF
XTAL = 4

Dit klopt al niet, je zegt dat je de interne clock gebruikt maar je zet er XTAL = 4 bij.


         ;543210                          ; hulpregel
GPIO   = %000000                          ; maak poort laag
TRISIO = %001011                          ; in en uitgangen

Je poorten zet je zo neer.


         ;76543210                        ; hulpregel controlregister
ADCON0 = %00000001                        ; A/D control register 

Zo zet je je adcon neer.

Je hebt nu in je programma gedifinieerd dat je tien bits gebruikt, is dat nodig. Met acht bits werkt dit net zo goed, dan heb je 0.0196078 / V per stapje.

Goed, de volgende ronde...

Wat doet de volgende regel?

ADCON0 = ADCON0 | (2 << 2) ' Select the channel to read

Het ziet er naar uit dat je twee verschillende kanalen wilt gebruiken. Eerlijk gezegd krijg ik jeuk van dit soort C constructies omdat ik nooit precies weet hoe het werkt. Bovendien vraag ik me af of je wel bitwise mag shiften op een constante...waar moet de compiler het resultaat laten?
En zelfs al zou het kunnen, wat is het effect?
De kanalen zitten op bits 2 en 3 van het ADCON0 register en je verandert ook de rest van het ADCON0 register...
Ik zie overigens nergens code die iets met de referentie doet en de code die je gebruikt doet dus voor beide kanalen het zelfde...

Wat doet de volgende regel?

VAR1 = VAR1 * (0.006/100)

Let op: VAR1 is een Word, maar je gebruikt een float berekening. Zou zomaar helemaal niet goed kunnen gaan.
Stel, ADRESL bevat 255 en stel dat Proton dat in runtime gewoon floating point uitrekent...255 * 0,006 / 100 = 0,0153.
Zeg maar 0.

Wat doet de volgende regel?

IF VAR1 < 238 AND VAR1 > 236 Then LEDR = 1

If VAR1 = 237 then LEDR = 1

Wat doet de while-wend 1=1 lus?
Haal de Analoge waarde op
Maak er een heeeeeel klein getal van
Laat LEDG misschien branden (die blijft wsl altijd uit)
Laat LEDR misschien branden (idem)
wacht effekes
Zet LEDR aan of uit (dat wordt wsl altijd aan)
wacht heel effekes
...en weer van voor af aan

Het effect is een knipperende LEDR zonder enige relatie met de ingangsspanning.

ADC testen zonder bv een display is best lastig, maar er zijn wel trucjes voor.
De manier waarop jij dat doet is overigens een prima voorbeeld van zo'n trucje.
Om zeker te zijn dat je de boel goed hebt aangesloten en geconfigureerd kun je het volgende doen:
Sluit een potmeter aan met de ene kant aan de 5v en de andere kant aan de gnd. Hang de loper aan de AD-ingang.
Onderdruk even alle instellingen van het ADCON0 register zodat Proton de zaak kan instellen.
Pas je mainloop zodanig aan dat je bv 3 ledjes laat branden afhankelijk van de AD-waarde, bv
while 1 = 1
Led1 = 0
Led2 = 0
Led3 = 0
VAR1 = ADIN x ; de x is het kanaal dat je gebruikt
select VAR1
case 0 - 85: Led1 = 1
case 86 - 170: Led2 = 1
case 171 - 255: Led3 = 1
endselect
whend
draai aan de as van de pot om te zien of het zaakje het doet.

hier heb je een voorbeeld:


Device 12F675                             ; processor type

XTAL 10                                   ; crystal 10 Mhz

Config WDT_OFF,_                          ; WatchDog Timer uit
       PWRTE_ON,_                         ; Power-up Timer Enable aan
       MCLRE_OFF,_                        ; Externe Master Reset Enable uit
       HS_OSC                             ; X-tal groter dan 4MHz
     
ALL_DIGITAL true                          ; alle poorten digitaal

Symbol aan = 1                            ; 1 is hoog
Symbol uit = 0                            ; 0 is laag

Symbol led = GPIO.2                       ; led op poort_2

Declare ADIN_RES   = 8                    ; resolutie 8 bits      
Declare ADIN_TAD   = frc                  ; Set rc osc     
Declare ADIN_STIME = 50                   ; sample tijd 5        
                                       
Dim potmeter As Byte                      ; variabele potmeter

Clear                                     ; wis geheugen
 
DelayMS 1000                              ; stabilisering

         ;543210                          ; hulpregel
GPIO   = %000000                          ; maak poort laag
TRISIO = %000001                          ; poort I/O

         ;76543210                        ; hulpregel control register
ADCON0 = %00000001                        ; A/D control register 

run:                                      ; run programma
    potmeter = ADIn 0                     ; potmeter op analoog_0
    If potmeter > 250 Then                ; als potmeter groter is als 250 dan
     led = aan                            ; led is aan
      If potmeter < 200 Then              ; als potmeter kleiner is dan 200 dan  
       led = uit                          ; led is uit
      EndIf                               ; einde als
    EndIf                                 ; einde als
GoTo run                                  ; ga naar run programma

End                                       ; einde programma

Probeer dit eest eens aan de praat te krijgen, en dan kan je er je eigen aanvulling aan geven.
En zorg er voor dat pin_4 (MCLRE) van je 12F675 via een 10K weerstand aan de 5VDC ligt. En deze pin kan alleen als ingang of als reset gebruikt worden.

Je XTAL en je Config even aanpassen natuurlijk.

Beste Lambiek en hadv ik ga achter een potmeter van 10K en probeer dit alvast uit, ik begrijp dus als ik de potmeter vervang door de spanning van de batterij via een spanningsdeler in te lezen dat ik in feite hetzelfde resultaat krijg.

Ik laat iets weten...

Op 16 januari 2012 21:27:27 schreef Lambiek:


CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, MCLRE_OFF
XTAL = 4

Dit klopt al niet, je zegt dat je de interne clock gebruikt maar je zet er XTAL = 4 bij.

Lambiek, dat klopt wel. Ook al gebruik je een interne oscillator, dan nog moet je Proton laten weten op welke snelheid deze draait omdat deze waarde wordt gebruikt voor alle tijd-gerelateerde berekeningen.

4MHz wordt automatisch aangenomen als je geen waarde opgeeft.

If the Declare is not used in the program, then the default frequency is 4MHz.

Het is voor de duidelijkheid wel handig altijd de Xtal declaratie te gebruiken.

Hallo hier ben ik terug schakeling gemaakt met pot de LED gaat aan maar gaat dan niet meer uit, als ik de spanning weghaal en opnieuw begin is het net hetzelfde moet ik ergens het geheugen niet resetten er staat ergens een clear commando maar moet dat niet in het RUN programma staan en wat doen beide endif daar... alvast het ding werkt nu analoog in en digitaal uit wat ben ik blij... hoe configureer ik dit signaal naar bijvoorbeeld de helft van de voedingsspanning

Die endif was er teveel aan... en XTAL = 4 toch terug geplaatst hieronder het aangepast programma.


Device 12F675                     ; processor type
XTAL = 4
 
Config WDT_OFF,_                  ; WatchDog Timer uit
       PWRTE_ON,_                 ; Power-up Timer Enable aan
       MCLRE_OFF,_                ; Externe Master Reset Enable uit
       INTRC_OSC_NOCLKOUT         ; Gebruik interne klok
       
ALL_DIGITAL true                  ; alle poorten digitaal
 
Symbol aan = 1                    ; 1 is hoog
Symbol uit = 0                    ; 0 is laag
 
Symbol led = GPIO.2               ; led op poort_2
 
Declare ADIN_RES   = 8            ; resolutie 8 bits      
Declare ADIN_TAD   = frc          ; Set rc osc     
Declare ADIN_STIME = 50           ; sample tijd 50µs        
 
Dim pot1 As Byte                   ; variabele potmeter
 
Clear                             ; wis geheugen
 
DelayMS 1000                      ; stabilisering
 
         ;543210                  ; hulpregel
GPIO   = %000000                  ; maak poort laag
TRISIO = %000001                  ; poort I/O
 
         ;76543210                ; hulpregel control register
ADCON0 = %00000001                ; A/D control register 
 
run:                              ; run programma
    pot1 = ADIn 0                 ; potmeter op analoog_0
    If pot1 > 250 Then led = aan  ; als potmeter groter is als 250 dan led is aan
    If pot1 < 200 Then led = uit  ; als potmeter kleiner is dan 200 dan led is uit                           
GoTo run                          ; ga naar run programma
 
End                               ; einde programma

Mod-edit: De edit en code-tags gebruiken, zie de FAQ.

[Bericht gewijzigd door Henry S. op (66%)]

Waarschijnlijk schommelt de waarde een beetje en blijft deze hoger dan 200 en dan zal deze nooit uit gaan, pak een weerstandje van bijvoorbeeld 10K en trek de AD ingang naar gnd.

@ Stan1,
Dat kan natuurlijk niet, als je de potmeter goed aansluit dan wordt de waarde op de loper groter of kleiner. Je draaid hem naar de plus of de gnd.

@ Flaybaby,
Dit moet werken zo, hier werkt het ook.

Zet voor de zekerheid even ADCON0 bit 7 op 1 (rechts oplijnen).
Test nu eens rond de 127.

Op 17 januari 2012 22:24:05 schreef Lambiek:
@ Stan1,
Dat kan natuurlijk niet, als je de potmeter goed aansluit dan wordt de waarde op de loper groter of kleiner. Je draaid hem naar de plus of de gnd.

Dat ben ik met je eens, alleen heeft de TS vermoedelijk de pot alleen aan de Vcc hangen.

De potmeter is tussen VCC en GND aangesloten de schakeling werkt met het laatste programma nu heb ik nog één vraag i.v.m. ADC.
Kan ik een tweede spanning aan bv. GP1 aansluiten en hoe ziet dan het programma er uit:

TRISIO = %000011 ; poort I/O

;76543210 ; hulpregel control register
ADCON0 = %00000011 ; A/D control register

run: ; run programma
pot1 = ADIn 0 ; potmeter op analoog_0
pot2 = ADIn 1 ; potmeter op analoog_1
If pot1 > pot2 Then led = aan

enz....

Ik zie reeds een klein lichtje aan het eind van de tunnel...

Probeer het zo eens, zo moet het zeker werken.


run:                                     

    potmeter = ADIn 0                    
     If potmeter > 250 Then               
      led = aan 
     endif 
    potmeter = ADin 0                      
     If potmeter < 100 Then            
      led = uit                        
     EndIf                                                           
GoTo run                                
 
End                                      

EDIT:
En in jou geval erbij zetten:
Else led = uit

Hey Lambiek, het werkt, heb je mijn vorige en laatste vraag gezien i.v.m. een tweede ADIN op poort 1...

De EndIf geeft een fout bij compilen als ik hem gebruik zoals in uw voorbeeld; onderstaande werkt wel. Nu nog een tweede ADIN, is onderstaande mogelijk.?

pic basic code:


Device 12F675 ; processor type
XTAL = 4

Config WDT_OFF,_ ; WatchDog Timer uit
PWRTE_ON,_ ; Power-up Timer Enable aan
MCLRE_OFF,_ ; Externe Master Reset Enable uit
INTRC_OSC_NOCLKOUT ; Gebruik interne klok

ALL_DIGITAL true ; alle poorten digitaal

Symbol aan = 1 ; 1 is hoog
Symbol uit = 0 ; 0 is laag

Symbol ledr = GPIO.2 ; ledr op poort_2
Symbol ledg = GPIO.3 ; ledg op poort_3

Declare ADIN_RES = 8 ; resolutie 8 bits
Declare ADIN_TAD = frc ; Set rc osc
Declare ADIN_STIME = 50 ; sample tijd 50µs

Dim pot1 As Byte ; variabele potmeter 1
Dim pot2 As Byte ; variabele potmeter 2

Clear ; wis geheugen

DelayMS 1000 ; stabilisering

;543210 ; hulpregel
GPIO = %000000 ; maak poort laag
TRISIO = %000011 ; poort I/O

;76543210 ; hulpregel control register
ADCON0 = %00000011 ; A/D control register

run: ; run programma
pot1 = ADIn 0 ; potmeter op analoog_0
If pot1 > 250 Then ledr = aan ENDIF ; als potmeter groter is als 250 dan led is aan
If pot1 < 200 Then ledr = uit EndIf ; als potmeter kleiner is dan 200 dan led is uit
pot2 = ADIn 1
If pot2 > 250 Then ledg = aan ENDIF ; als potmeter groter is als 250 dan led is aan
If pot2 < 200 Then ledg = uit EndIf ; als potmeter kleiner is dan 200 dan led is uit
GoTo run ; ga naar run programma

End 

[Bericht gewijzigd door Henry S. op (88%)]

zo zou het moeten werken


TRISIO = %000011 

;76543210
ADCON0 = %00000011 

run: 

  pot1 = ADIn 0
  pot2 = ADIn 1
  If pot1 > pot2 Then 
   led = aan
    else led = uit
  eindif

end

Dringend verzoek aan de TS de FAQ eens te gaan lezen!

Als ik VREF wil gebruiken moet ik het ADCON0 = %01000001 aldus definiëren maar moet ik dan ook het TRISIO = % 00000011 als analoog input definiëren ik denk van wel maar ben niet zeker.

Wat doe ik verkeerd... ik wil absoluut GPIO3 als analoge ingang gebruiken kan iemand mij hier verder helpen

Device 12F675                             ; processor type
 
XTAL = 4                                  ; crystal 4Mhz
 
Config WDT_OFF,_                          ; WatchDog Timer uit
       PWRTE_ON,_                         ; Power-up Timer Enable aan
       MCLRE_OFF,_                        ; Externe Master Reset Enable uit
       HS_OSC                             ; X-tal groter dan 4MHz
 
ALL_DIGITAL true                          ; alle poorten digitaal
 
Symbol aan = 1                            ; 1 is hoog
Symbol uit = 0                            ; 0 is laag
 
Symbol led = GPIO.2                       ; led op poort_2
 
Declare ADIN_RES   = 8                    ; resolutie 8 bits      
Declare ADIN_TAD   = frc                  ; Set rc osc     
Declare ADIN_STIME = 50                   ; sample tijd 5        
 
Dim potmeter As Byte                      ; variabele potmeter
 
Clear                                     ; wis geheugen
 
DelayMS 1000                              ; stabilisering
 
         ;543210                          ; hulpregel
GPIO   = %000000                          ; maak poort laag
TRISIO = %000000                          ; poort I/O
ANSEL  = %001000
 
         ;76543210                        ; hulpregel control register
ADCON0 = %00000001                        ; A/D control register                        ; 
 
run:                                      ; run programma
    potmeter = ADIn 3                     ; potmeter op analoog_0
    If potmeter > 250 Then                ; als potmeter groter is als 250 dan
     led = aan                            ; led is aan
      If potmeter < 200 Then              ; als potmeter kleiner is dan 200 dan  
       led = uit                          ; led is uit
      EndIf                               ; einde als
    EndIf                                 ; einde als
GoTo run                                  ; ga naar run programma
 
End                                       ; einde programma

Je zet dit neer:


         ;543210                          ; hulpregel
GPIO   = %000000                          ; maak poort laag
TRISIO = %000000                          ; poort I/O
ANSEL  = %001000

Bij TRISIO heb je alles als uitgang staan, je moet AN3 wel als ingang zetten natuurlijk.

GPIO3 kan niet als analoge input worden gebruikt. (Zie de datasheet)

Het moet zo worden:


 
         ;543210         ; hulpregel
GPIO   = %000000         ; maak poort laag
TRISIO = %010000         ; poort I/O

         ;76543210       ; hulp regel                  
ANSEL  = %00001000       ; ansel register

         ;76543210       ; hulpregel control register
ADCON0 = %00000001       ; A/D control 

[Bericht gewijzigd door Lambiek op (15%)]

Dat is GPIO4, niet GPIO3 (zoals gevraagd)...