Sida 1 av 1

ADC på en 12F683, hur räkna ut rätt värde?

Postat: 19 september 2011, 09:50:00
av PopUnoNkoK
Vet inte riktigt hur jag ska döpa denna tråd. Tyvärr är detta en dubbelpost i stilen som jag har gjort förut en gång. En renrakad PIC fråga som drunknat långt bak i en Idetråd. Jag måste skaffa mig bättre fingertoppskännsla när det är bättre att posta här direkt för att slippa dubbelpost. Ber så mycket om ursäkt för det.

PIC: 12F683

Jag har fått ADCn att fungera i praktiken med en LDR. När jag lyser på motståndet tänds en LED i ett par sekunder (delay rutin) och slocknar sen. (Om jag inte lyser på motståndet fortfarande det vill säga.) Jag kan även ändra i koden så att det krävs mer eller mindre ljus för att "trigga" lysdioden.

I praktiken är det bra, det var dit jag ville komma med mitt första test.

MEN jag är inte alls nöjd med "siffrorna" bakom det som händer.
När jag mäter spänningen som går in på PICen så krävs det ca 3,6v för att trigga så att LEDen tänds. Trots att koden ser ut så här.

Kod: Markera allt

START
		BANKSEL 	GPIO 		;
		CLRF 		GPIO 		;Init GPIO
		MOVLW 		b'110' 		;Set GP<0> to Analog
		BANKSEL		CMCON0
		MOVWF 		CMCON0 		;Set GP<1,2>digital I/O

		MOVLW 		b'000001'
		BANKSEL		TRISIO
		MOVWF 		TRISIO
		BANKSEL		ANSEL
		MOVWF       ANSEL
		BANKSEL		ADCON0
		MOVLW 		B'10000001' ;<7> Right Justified, <0> ADC On
		MOVWF 		ADCON0

		BCF			GPIO,1			;Släck Diod
Här har jag alltså satt mina 10 bitars ADC "Right Justified" vilket innebär (om jag förstått allt rätt) att de 8 bitarna i "ADRESL" fylls med de första 8 bitarn i 10bitars värdet medan de 2 resterande bitarna läggs i "ADRESH" registret.
Jag har även satt "VCFG" biten till att använda VDD som referens, vilket i detta fall innebär ca 4.8v

Sedan ser koden ut så här:

Kod: Markera allt

START1 
		CLRF 	GPIO
		BSF 	ADCON0,GO 	  ;take an ADC reading


WAITADC 
		BTFSC 	ADCON0,GO		; poll for reading to complete
		GOTO 	WAITADC			; if not done, keep polling 
		MOVLW 	B'00000011'		; place in compare register 
		SUBWF 	ADRESL,C		; compare instruction
		BTFSC 	STATUS,C		; if ADC reading is more than "compare register", "signal" has been detected
		GOTO 	NEXT	  		; if "signal" has been detected, to go NEXT routine
		GOTO 	START1			; if not, start from beginning of program
Här jämför jag alltså registret "ADRESL" med binära talet '00000011' (.3) LEDen triggas om "ADRESL" är högre än b'00000011'.
Om jag delar VDD (4.8v) med 10 bitar (1023) så får jag ca 0.0047v om jag gångrar det med 3(som jag jämför med) får jag 0.014v.
Alltså att det bara ska krävas 0.014v för att trigga LEDen. Men det krävs alltså ca 3.6v.

Är det någon som ser vart jag uppenbarligen tänkt fel eller gjort fel?

Tacksam för all hjälp jag hittils fått och hjälpen jag hoppningsvis kommer att få. =)

MVH Peter

Koden i sin helhet:

Kod: Markera allt

;******************************************************************************
;   This file is a basic code template for object module code                 *
;   generation on the PIC12F683. This file contains the                       *
;   basic code building blocks to build upon.                                 *
;                                                                             *
;   Refer to the MPASM User's Guide for additional information on             *
;   features of the assembler and linker (Document DS33014).                  *
;                                                                             *
;   Refer to the respective PIC data sheet for additional                     *
;   information on the instruction set.                                       *
;                                                                             *
;******************************************************************************
;                                                                             *
;    Filename:      xxx.asm                                                   *
;    Date:                                                                    *
;    File Version:                                                            *
;                                                                             *
;    Author:                                                                  *
;    Company:                                                                 *
;                                                                             *
;                                                                             *
;******************************************************************************
;                                                                             *
;    Files required: P12F683.INC                                              *
;                                                                             *
;******************************************************************************
;                                                                             *
;    Notes:                                                                   *
;                                                                             *
;******************************************************************************

;------------------------------------------------------------------------------
; PROCESSOR DECLARATION
;------------------------------------------------------------------------------

     LIST      P=12F683              ; list directive to define processor
     #INCLUDE <P12F683.INC>          ; processor specific variable definitions

;------------------------------------------------------------------------------
;
; CONFIGURATION WORD SETUP
;
; The 'CONFIG' directive is used to embed the configuration word within the 
; .asm file. The lables following the directive are located in the respective 
; .inc file.  See the data sheet for additional information on configuration 
; word settings.
;
;------------------------------------------------------------------------------

    __CONFIG   _FCMEN_ON & _IESO_OFF & _CP_OFF & _CPD_OFF & _BOD_OFF & _MCLRE_ON & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT 
	errorlevel   -302

;------------------------------------------------------------------------------
; VARIABLE DEFINITIONS
;------------------------------------------------------------------------------

; example of using Shared Uninitialized Data Section
INT_VAR     UDATA_SHR      
W_TEMP      RES     1             ; variable used for context saving 
STATUS_TEMP RES     1             ; variable used for context saving
d1			RES		1
d2			RES		1
d3			RES		1
c1			RES		1				;Till ADC delayen

;------------------------------------------------------------------------------
; EEPROM INITIALIZATION
;
; The 12F683 has 256 bytes of non-volatile EEPROM, starting at address 0x2100
; 
;------------------------------------------------------------------------------

DATAEE    CODE  0x2100
    DE    "MCHP"          ; Place 'M' 'C' 'H' 'P' at address 0,1,2,3

;------------------------------------------------------------------------------
; RESET VECTOR
;------------------------------------------------------------------------------

RESET_VECTOR  CODE    0x0000  ; processor reset vector
        GOTO    START         ; go to beginning of program

;------------------------------------------------------------------------------
; INTERRUPT SERVICE ROUTINE
;------------------------------------------------------------------------------

INT_VECTOR    CODE    0x0004  ; interrupt vector location
        MOVWF   W_TEMP        ; save off current W register contents
        MOVF    STATUS,w      ; move status register into W register
        MOVWF   STATUS_TEMP   ; save off contents of STATUS register

; isr code can go here or be located as a call subroutine elsewhere

        MOVF    STATUS_TEMP,w ; retrieve copy of STATUS register
        MOVWF   STATUS        ; restore pre-isr STATUS register contents
        SWAPF   W_TEMP,f
        SWAPF   W_TEMP,w      ; restore pre-isr W register contents
        RETFIE                ; return from interrupt

;------------------------------------------------------------------------------
; MAIN PROGRAM
;------------------------------------------------------------------------------

MAIN_PROG     CODE

START
		BANKSEL 	GPIO 		;
		CLRF 		GPIO 		;Init GPIO
		MOVLW 		b'110' 		;Set GP<0> to Analog
		BANKSEL		CMCON0
		MOVWF 		CMCON0 		;Set GP<1,2>digital I/O

		MOVLW 		b'000001'
		BANKSEL		TRISIO
		MOVWF 		TRISIO
		BANKSEL		ANSEL
		MOVWF       ANSEL
		BANKSEL		ADCON0
		MOVLW 		B'10000001' ;<7> Right Justified, <0> ADC On
		MOVWF 		ADCON0

		BCF			GPIO,1			;Släck Diod




;------------------------------------------------------------------------------
; PLACE USER PROGRAM HERE
;------------------------------------------------------------------------------
MainCode
START1 
		CLRF 	GPIO
		BSF 	ADCON0,GO 	  ;take an ADC reading


WAITADC 
		BTFSC 	ADCON0,GO		; poll for reading to complete
		GOTO 	WAITADC			; if not done, keep polling 
		MOVLW 	B'00000011'		; place in compare register 
		SUBWF 	ADRESL,C		; compare instruction
		BTFSC 	STATUS,C		; if ADC reading is more than "compare register", "signal" has been detected
		GOTO 	NEXT	  		; if "signal" has been detected, to go NEXT routine
		GOTO 	START1			; if not, start from beginning of program

NEXT
	NOP
	BANKSEL	GPIO
	BSF		GPIO,1
	CALL	Delay
	CALL	Delay
	CALL	Delay
	CALL	Delay
	CALL	Delay
	CALL	Delay
	CALL	Delay
	CALL	Delay
	BCF		GPIO,1
	GOTO	START1


;------------------------------------------------------------------------------
; SubRoutines
;------------------------------------------------------------------------------
Delay        
	movlw	0x03
	movwf	d1
	movlw	0x18
	movwf	d2
	movlw	0x02
	movwf	d3
Delay_0
	decfsz	d1, f
	goto	$+2
	decfsz	d2, f
	goto	$+2
	decfsz	d3, f
	goto	Delay_0

			;6 cycles
	goto	$+1
	goto	$+1
	goto	$+1
	RETURN



        END                       ; directive 'end of program'


Re: ADC på en 12F683, hur räkna ut rätt värde?

Postat: 19 september 2011, 10:14:51
av sodjan
> BANKSEL ADCON0
> MOVLW B'10000001' ;<7> Right Justified, <0> ADC On
> MOVWF ADCON0

När det gäller bitar i register som inte har något direkt samband
(d.v.s som *inte* har ett gemensam "värde") så är det tydligare
med BCF/BSF. Koden ovan skrivs alltså bättre med :

BANKSEL ADCON0
CLRF ADCON0
BSF ADCON0, ADFM
BSF ADCON0, ADON

Notera hur kommentarerna nästan blir överflödiga, i alla fall fall den om "ADC on".

Men det är inte det som är "problement"... :-)

Du använder alltså enbart ADRESL ?
Notera att den kommer att gå från 0-255 *4* gånger över ADC'ns hela område.
Medan ADRESH räknar 0,1, 2 och 3 (men det användere du ju inte)
Är det det du ville ?

Om man enbart behöver ett 8-bitars resultat så kör man med ADFM=0
och använder ADRESH.

Re: ADC på en 12F683, hur räkna ut rätt värde?

Postat: 19 september 2011, 11:18:29
av PopUnoNkoK
Ja där har vi nog felet. Jag hade alltså tänkt fel.

Jag tänkt att om jag bara använde "ADRESL" så skulle jag få 10 bitars upplösning men bara använda de nedersta bitarna. Tänkte aldrig på att den kommer att räkna 0-255 flera (4) ggr.

Blir alltså att testa i kväll att ändra tillbaka till "Left Justified" och sedan bara använda "ADRESH" och helt enkelt nöja sig med 8 bitars upplösning.

Tusen tack för svaret.


Vad det gäller ditt "kodformat" tips så ser det mycket tydligare ut. Jag uppskattar verkligen den typen av tips, tack. Hur gör du i ett register som tex en del av bitarna "hör i hop" som tex prescalern till TMR0 eller liknande?

MVH Peter

Re: ADC på en 12F683, hur räkna ut rätt värde?

Postat: 19 september 2011, 11:29:54
av sodjan
T.ex ett timer-register där värdet ju är 0-255 så är det rimliga
att sätta det i HEX eller DEC beroende på vilket som är tydligast.
Att sätta det binärt finns sällan/aldrig någon anledning och självklart
inte att sätta alla 8 bitarna separat med BCF/BSF.

Däremot alla kontrollregister, där de enskilda bitarna har var för
sig oberoende funktion, är enklare att hantera med BCF/BSF.

> ...så skulle jag få 10 bitars upplösning men bara använda de nedersta bitarna.

Hur sjutton skulle du kunna få 10 bitars upplösning med bara 8 bitar ??

> Tänkte aldrig på att den kommer att räkna 0-255 flera (4) ggr.

Det är exakt samma sak som att räkna 1-100 men bara "använda" entalssiffran.
Det blir 0-9 10 gånger eller hur...

Re: ADC på en 12F683, hur räkna ut rätt värde?

Postat: 19 september 2011, 13:04:18
av PopUnoNkoK
Hur sjutton skulle du kunna få 10 bitars upplösning med bara 8 bitar ??
Jag ska försöka förklara i decimalform hur jag tänkte.
Som exempel kan vi säga att jag delar 5volt i 100, då har jag hundra (enheters) upplösning. Men att jag struntar i att titta på hundratalen. Alltså då kan jag ha upplösningen från hundra men bara använda ental och tiotal. Ungefär så tänkte jag.


Angående TMR0 frågan var jag otydlig.
Det var OPTION_REG jag menade, alltså att ställa in prescalern. Då de tre lägsta bitarna "hör i hop" och bildar prescalerns inställning medans de andra bitarna är mer "fristående". Hur skriver du mest tydligt då? Sätter du "PS0 - PS2" som enskilda bitar?

Det är exakt samma sak som att räkna 1-100 men bara "använda" entalssiffran.
Det blir 0-9 10 gånger eller hur...
Så sant så sant. =)


MVH Peter

Re: ADC på en 12F683, hur räkna ut rätt värde?

Postat: 19 september 2011, 13:09:22
av sodjan
> Som exempel kan vi säga att jag delar 5volt i 100, då har jag hundra (enheters) upplösning.

Jo, men det du gjorde var att (för att fortsätta på ditt exempel) dela 5V med 400
och bara titta tiotal och ental. Det går ju inte. :-)

> Sätter du "PS0 - PS2"

Ja, det där är ju en gråzon. Nu är det ju så att detta oftast enbart görs en
gång per spänningstillslag i någon "init" rutin, så det finns ingen prestanda
att ta hänsyn till (d.v.s antalet instruktioner). Så gör som du finner tydligast.

Re: ADC på en 12F683, hur räkna ut rätt värde?

Postat: 19 september 2011, 19:16:00
av PopUnoNkoK
Jepps, nu fungerar det prima. =)

Rent av barnsligt kul när det fungerar och man förstår vad man gör. =)
Tusen tack för hjälpen.

Det jag ändrade i koden var att sätta tillbak till "Left justify" och sedan bara använda mig av "ADRESH".

MVH Peter.

Re: ADC på en 12F683, hur räkna ut rätt värde?

Postat: 19 september 2011, 23:11:00
av sodjan
Kul ! :-)
Varför inte ta ett par andra småsaker som kanske är mer kosmetiska...

> MOVLW b'110' ;Set GP<0> to Analog
> BANKSEL CMCON0
> MOVWF CMCON0 ;Set GP<1,2>digital I/O

Personligen tycker jag att det är tydligare om man alltid anger *8*
bitar i alla binära konstanter. Även om registret inte använder alla.
Speciellt i detta fall där CMCON0 faktiskt har *6* aktiva bitar. Det
är inte tydligt att du faktiskt har tänkt på de övriga bitarna. D.v.s
att man inte vet om du har gjort det med avsikt eller av misstag.

> BCF GPIO,1 ;Släck Diod
> BSF GPIO,1

Om du i brjan av programmet lägger till en :

#define lysdiod GPIO, 1

så kan du istället skriva :

> BCF lysdiod
> BSF lysdiod

Och det blir bara *ett* ställe att ändra på om du bestämmer dig
för att flytta lysdioden (i #define'en).

Sen så är det lite rörigt med både "main_prog" och "maincode" samt
både "start" och "start1", men det är också bara detaljer... :-)

Re: ADC på en 12F683, hur räkna ut rätt värde?

Postat: 20 september 2011, 12:04:30
av PopUnoNkoK
Att sätta alla åtta bitar i ett register typ CMCON0 är förstås rätt. I detta fall tror jag faktiskt att det rör sig om en Copy/Paste från internet. Det börjar ofta så för mig när jag ska ge mig på något nytt. Brukar skriva om koden eftersom och kommentera med "mitt eget språk" för att förstå varje rad. Jag HATAR att ha lånade rader av kod som jag inte förstår varför dom fungerar. Lånad kod som jag förstår precis vad den gör är inte alls lika illa. =)

Jag använde #define för 2 år sedan när jag programmerade och jag vet TYP hur det fungerar. Det ska kollas upp för i och med att projekten växer är det ovärderligt.
Desamma gäller "equ".

Ditt sista stycke är dock mycket intressant. Du har helt rätt, just i detta fall har det som så många andra gånger gått fort, alldeles för fort.

Men något jag har märkt som irriterar mig är att de olika TEMPLATE filerna som jag brukar utgå ifrån (i MPLAB) ser olika ut till strukturen beroende på vilken PIC det handlar om.

Jag vet inte om det går att ställa en sån här fråga men jag provar.
Hur ser en "Pseudokods översikt" ut för er?

Exempel

Kod: Markera allt

Inc filer
Configbitar

Register setup (Namnge olika register som används)

RESET_VECTOR  CODE         GOTO   START

ISR

START
Setup olika register så som ADC, Comparator IOpinnar mm

Program loop, som snurrar hela tiden om inget annat händer "Interrupts osv"

SubRutiner

END
Kanske är en tråkig/konstig fråga men jag provar.

Ytterligare fråga.
Varför har man:

Kod: Markera allt

RESET_VECTOR  CODE    0x0000  ; processor reset vector
        GOTO    START         ; go to beginning of program
Alla mallar jag har sett ser ut så, alltså att den direkt gör en GOTO. Varför börjar man inte bara koden där?

MVH Peter



RESET_VECTOR CODE 0x0000 ; processor reset vector
GOTO START ; go to beginning of program

Re: ADC på en 12F683, hur räkna ut rätt värde?

Postat: 20 september 2011, 12:36:05
av sodjan
> Varför börjar man inte bara koden där?

Adress h'0000' är alltså "reset-vektorn".
Adress h'0004' är interrupt-vektorn.

Om man använder interrupt (i princip alla mikrokontroller applikationer
gör det) så måste man använda de 4 instruktionerna på adress 0,1,2 och 3
för att undvika att hamna på adress 4 !

4 instruktioner räcker till t.ex :

Kod: Markera allt

RESET_VECTOR  CODE    0x0000  ; processor reset vector
        PAGESEL START
        GOTO    START         ; go to beginning of program
Notera pagesel, det är inte säkert att "start" ligger i den första 2K sidan i programminnet !
(Hade en enkel LCD demo på en 16F690 som kraschade p.g.a av just det igår. Länkaren
flyttade min "start" till sidan 2 i programminnet. En extra pagesel som ovan fixade det...).

Re: ADC på en 12F683, hur räkna ut rätt värde?

Postat: 20 september 2011, 13:02:05
av labmaster
Tips: Om projekten växer är det värdefullt att övergå till C som programspråk, det har många fördelar.

Det jag kan se så här långt i din tråd så förefaller din kunskap om assemblerspråkat vara fullt tillräckligt för att räcka livet ut. Byter du processor räcker det med ett litet kort assemblerprogram för att du skall få kläm på hur det hänger ihop.

Innan du går vidare i projektet "tända blixten" så kan det vara lämpligt att hänga ett luftgevärshagel i ett tunt snöre och se om din applikation klarar att detektera en så liten projektil. Om det funkar med projektilen i snöre blir nästa steg att ladda luftgeväret och prova. Kulan kommer att passera dioden snabbt så det kan bli en utmaning att få till programmet som detekterar pulsen.

Re: ADC på en 12F683, hur räkna ut rätt värde?

Postat: 20 september 2011, 13:45:15
av PopUnoNkoK
Sodjan: Då förstår jag varför man kör GOTO direkt. Tack för tipset med PAGESEL, skulle förmodligen vara ett sådant problem som jag skulle ha svårt att hitta felet med om jag stötte på det. Ska försöka komma ihåg att lägga till det när man startar ett nytt projekt.

Labmaster: Jag tror jag håller mig till Assembler länge än. =) Måste säga att det är fruktansvärt roligt när saker börjar falla på plats. I alla fall litegran.
Jag har tänkt prova att trigga med Ljudet så kommer nog inte att hänga nåt luftpistolspellets i nåt snöre än. Men man vet aldrig. Skulle vara läckert att prova göra något så "känsligt" sen. Precisionen borde bli mycket högre.

Tack för alla svar.

MVH Peter

Re: ADC på en 12F683, hur räkna ut rätt värde?

Postat: 20 september 2011, 13:55:58
av sodjan
> ...så det kan bli en utmaning att få till programmet som detekterar pulsen.

Sannolikt har man någon enkel signalbehandling som ser till att det
fungerar för processorn/koden.

Och nej, det finns ingen större anledning att köra C på en 12F...