Enkel pic fråga gällande fördröjning

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
newbadboy
Inlägg: 2485
Blev medlem: 16 september 2006, 19:16:28
Ort: Landskrona
Kontakt:

Enkel pic fråga gällande fördröjning

Inlägg av newbadboy »

Ska bygga en timer som drar ett relä, detta relä skall vara draget i 8 timmar och av i 8 timmar.

Är det lämpligt att använda en PIC där man har tex en delay sats sedan ngn for eller while loop som räknar en konstant tills tiden går ut?

Är det risk att det kan driva i tid?

Ser ni ngn nackdel i min tanke?

Samt finns det ngn formel eller liknande som ger hur många ex while cykler det behövs för 8 timmar med en 4Mhz kristall. Kommer ihåg att i assmbler kunde man räkan ut hur lång ti en instruktion tog och byggde sedan delays med detta. Men nu kör jag i C för jag kan inte ett dugg om assembler.

Tack på förhand
Användarvisningsbild
netrunner
Inlägg: 5510
Blev medlem: 4 februari 2005, 12:26:05
Ort: 127.0.0.1

Re: Enkel pic fråga gällande fördröjning

Inlägg av netrunner »

Om du använder extern kristall och interupt för tid så kan du räkna med en 7-8 sekunders drift per månad.

Det är vad jag ha på min klocka med den setupen. Nu måste jag i alla fall ställa den för sommar och vinter tid så det funkar bra för mig.
Användarvisningsbild
newbadboy
Inlägg: 2485
Blev medlem: 16 september 2006, 19:16:28
Ort: Landskrona
Kontakt:

Re: Enkel pic fråga gällande fördröjning

Inlägg av newbadboy »

Det låter ju som ingenting.. perfekt ju.. måste bara öära mig vad fanken interrupt är :oops:
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Enkel pic fråga gällande fördröjning

Inlägg av sodjan »

Ett interrupt är när du sitter och jobbar med något och frugan/flickvännen
ropar att kaffet är klart. *Det* är ett interrupt/avbrott. Något som händer
som avbryter den normala verksamheten.

För en PIC kan deet t.ex vara att en timer har räknat till 0, ett tecken har
kommit in på USART'en eller att ADC'n har har gjort en konvertering klart.

> Är det risk att det kan driva i tid?

Det räcker inte med att kristallen "går rätt", även koden måste göra det.
Delaysatser kommer att bli svårt att få korrekt, satsat på timers.

Att räkna instruktionscykler är så klart svårare om inte omöjligt när man
kör i C. Man kan även säga att det är ointressant. Används timers. De
snurrar på oavsett vad koden gör för övrigt.
sugarman64
Inlägg: 349
Blev medlem: 24 oktober 2008, 19:40:50
Ort: Lomma

Re: Enkel pic fråga gällande fördröjning

Inlägg av sugarman64 »

En annan variant är ju att koppla en RTC (Real Time Clock) -krets till en PIC. Typ DS1307 el. liknande.
Kanske överkurs i detta fall men det skulle ge fördelar eftersom den har batteribackup oc inte tappar
tiden vid ett ev. strömavbrott.
Finns en hel del kod och exempel ute på nätet om hur den hanteras.
Och dessutom så lär man sig något nytt. PICen måste ha I2C port om man väljer just DS1307.
v-g
EF Sponsor
Inlägg: 7875
Blev medlem: 25 november 2005, 23:47:53
Ort: Kramforce

Re: Enkel pic fråga gällande fördröjning

Inlägg av v-g »

Precis som ovan sagt plus att du simulerar hur länge det hela tar, dock är det omöjligt (eller tar lång tid iaf) att simulera 8 timmar så man får göra så att man simulerar 8 minuter sen ökar man på en variabel med faktor 60 eller vad man nu tar så borde det stämma. Därefter gäller en vanlig klocka som kontrollmetod :)

Interuptet triggas rätt ofta om man inte har en långsam (låg frekvens) kristall så man har flera variabler som man räknar upp. Lämpligen gör man så att man får minuter och sen timmar dvs fixa först så du får en sekund räkna denna till 60 sen öka på minut räkna till 60 öka på timme räkna till 8 slå av/på osv

Är man extra busig så skickar man ut detta på tex display/uart så kan man enkelt kolla om klockan går rätt.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Enkel pic fråga gällande fördröjning

Inlägg av sodjan »

> dvs fixa först så du får en sekund räkna denna till 60 sen öka på minut räkna till 60 öka på timme räkna till 8 slå av/på osv

PIC'en behöver inte bry sig om min/Sek/timmar, det bara komplicerar det hela.
Kolla hur ofta timer-avbrottet inträffar, säg att det är 15 gånger per sekund.
Räkna 432000 avrott så har du 8 timmar. Om det är 13.25 gånger per sekund
så räknar du 381600 avbrott för att få 8 timmar. Det finns ingen som helst
anledning att försöka träffa 1 sekund eller 1 minut jämt bara för att räkna 8 timmar.

> Är man extra busig så skickar man ut detta på tex display/uart så kan man enkelt kolla om klockan går rätt.

Ja, om man har det kravet så är det ju en helt annan sak...
Användarvisningsbild
newbadboy
Inlägg: 2485
Blev medlem: 16 september 2006, 19:16:28
Ort: Landskrona
Kontakt:

Re: Enkel pic fråga gällande fördröjning

Inlägg av newbadboy »

Ok får ge bättre förklaring, jag vet vad interupt är men har aldrig skrivit och använt den. Så jag har inte heller riktigt känlsan vad styrkan och fördelen med detta är.

Ja jo det vore trevligt med displayer etc men det ska vara så enkelt och driftsäkert med så få funktioner som möjligt.
Användarvisningsbild
newbadboy
Inlägg: 2485
Blev medlem: 16 september 2006, 19:16:28
Ort: Landskrona
Kontakt:

Re: Enkel pic fråga gällande fördröjning

Inlägg av newbadboy »

sodjan skrev:> dvs fixa först så du får en sekund räkna denna till 60 sen öka på minut räkna till 60 öka på timme räkna till 8 slå av/på osv

PIC'en behöver inte bry sig om min/Sek/timmar, det bara komplicerar det hela.
Kolla hur ofta timer-avbrottet inträffar, säg att det är 15 gånger per sekund.
Räkna 432000 avrott så har du 8 timmar. Om det är 13.25 gånger per sekund
så räknar du 381600 avbrott för att få 8 timmar. Det finns ingen som helst
anledning att försöka träffa 1 sekund eller 1 minut jämt bara för att räkna 8 timmar.

> Är man extra busig så skickar man ut detta på tex display/uart så kan man enkelt kolla om klockan går rätt.

Ja, om man har det kravet så är det ju en helt annan sak...

låter so en mycket vettig förklaring... sen är det som sagt koden koden:) kan alla picar jobba med interrupt eller det en "inbyggd funktion"
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Enkel pic fråga gällande fördröjning

Inlägg av sodjan »

Alla datablad till alla PIC modeller har ett speciellt kapitel om interrupt/avbrott.
Har du kollat alls ? Och i så fall var det något specifikt som du undrar över ?

För att fortsätta med kaffe analogin...

Du kan i princip välja på att fråga frugan var 5'te minut "är kaffet klart ?".
Det kallas "pollning".

Eller så ber du frugan "säg till mig när kaffet är klart!". Det kallas interrupt/avbrott.

När det gäller en timer så "säger man till den" att "avbryt mig när du har kommit till noll"
genom att sätta några bitar i ett par kontrollregister.

Alla detaljer finns i databladet. Det är näst intill omöjligt att säga något mer när man inte
vet vad du har problem med.

> kan alla picar jobba med interrupt eller det en "inbyggd funktion"

Ska vara "och".
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Enkel pic fråga gällande fördröjning

Inlägg av jesse »

När du skriver en kod i C så innebär det som sagts innan att du kommer att få väldigt svårt att veta hur lång tid vissa instruktioner tar. Dessutom - när du sedan ska dra reläet så kommer processorn att göra annat för en stund, och det tar också okänd tid. Om du dessutom ska visa tiden på display eller kunna reagera på en knapptryckning eller vad som helst så kommer det till slut bli totalt omöjligt att veta tiden genom att räkna instruktioner. Alltså måste du mäta tiden på något annat vis.

Och det är här timers kommer in i bilden.

En timer kan ställas in så att den räknar upp ett steg med ett visst intervall - styrd av kristalloscillatorn. Den är alltså helt oberoende av vad processorn gör.

Antag att timern har 8 bitar, kristallen är på 3.6864 MHz. DU kan ställa in den på att räkna upp var 64:e klockcykel, dvs. 57600 ggr per sekund. Det betyder att den räknar från 0 till 255 225 gånger per sekund.
Varje gång den slår om från 255 till 0 kan du konfigurera timern så att den ger processorn "ett interrupt".

Ett interrupt sker alltså då 225 ggr/sek.

När processorn får ett interrupt så hoppar den till en speciell del i koden (i C skrivs den som en funktion).

Denna funktion kommer alltså att utföras exakt 225 ggr/sek oavsett vad processorn annars sysslar med.
Exempelvis kan den räkna upp en 8-bitars unsigned char som finns som "static" i funktionen (siffran glöms inte ort mellan anropen).

Sedan kan du jämföra med 225. Om det stämmer så ska den nollställas och du räknar upp en sekund i en annan variabel och sätta en "flagga" för att berätta för övriga programmet att "nu har det gått en sekund".

exempel:

Kod: Markera allt

// globala variabler
volatile unsigned char sekund = 0;
volatile unsigned char minut = 0;
volatile unsigned char timme = 0;
volatile unsigned char flagga = 0; // signalerar en gång per sekund

void interrupt( void ) {
    static unsigned char timer = 0; // starta med noll första gången
    static unsigned char sekund = 0;
    static
    timer++; // räkna upp 
    if (timer == 225) {
        sekund ++;
        flagga = 1;
        if (sekund == 60) {
            sekund = 0;
            minut++;
        }
    }
}

// i main har du sedan denna kod , som måste köras oftare än en gång per sekund för att du inte ska missa flaggan:

    if (flagga) {
        flagga = 0;
        // dags att kolla vad klockan är
        if (sekund == 0) {
            if (minut = 30) {
                // halvtimme slag
            }
        }
    }
För att kompilatorn ska veta att en viss funktion ska anropas vid interrupt så kan den ha ett speciellt namn. Det beror på biblioteken för just den processorn - t.ex. för en AVR processor kan in interrupt heta "TIM0_OVF_vect()". Vad det heter i PIC har jag ingen aning om.
Användarvisningsbild
Icecap
Inlägg: 26652
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Enkel pic fråga gällande fördröjning

Inlägg av Icecap »

I baseline PIC delar alla interrupt samma vektor - men om det bara är timern som gör en interrupt är det ju ganska enkelt.

Ett exempel på hur en interruptrutin kan se ut:

Kod: Markera allt

void interrupt(void)
  { // Timer to time out the heater
  PIR1.TMR2IF = false; // Clear interrupt flag
  if(Heater_Timer) Heater_Timer--;
  }
För att aktivera interrupten:

Kod: Markera allt

void Initialize_Timer(void)
  {
  PR2         = 100;
  T2CON       = 0b01111111;
  INTCON      = 0b11000000;
  PIE1.TMR2IE = true;
  PIR1.TMR2IF = false;
  }
Med databladet i handen får du själv klura ut vilken hastighet timern ger interrupt osv.

Om du tänker dig att det finns två program i PIC'en blir det lite lättare att förstå interrupt. Jag hade själv en del problem med att fatta hur man gjorde men numera är interrupt essenstiellt att använda till nästan allt.

De två program som kör i processorn är "main loop", det kallar jag bakgrundsprogrammet (eller main loop för enkelhetens skull).

Sedan finns det ett program som kör när en interrupt kommer, det program stoppar helt sonika main loop när det fullför en instruktion och kör rutinen som heter "void interrupt(void)". Just det namn säger till kompilern att det är en ISR (Interrupt Service Routine), namnet kan dock variera med olika kompilatorer, det kan även vara att man måste ange på ett speciellt sätt att just en viss rutin är en ISR.

Man vet aldrig när interrupt-snutten kör i förhållande till main loop, det kommer bara helt plötsligt. Därför får man se till att ändringar av värden sker under kontrollerade former, ibland för man stänga av interrupten om man ändrar ett värde i main loop, exempel nedan:

Kod: Markera allt

// Del av att skriva till EEPROM
    do
      {
      INTCON.GIE  = false; // << STOPPA INTERRUPT
      }
    while(INTCON.GIE); // Säkerställer att interrupts verkligen blir stoppat, info. i databladet
    EECON2      = 0x55; // Specifik sekvens för att starta skriva till EEPROM
    EECON2      = 0xAA; // Specifik sekvens för att starta skriva till EEPROM
    EECON1.WR   = true; // The write will now start
    INTCON.GIE  = true; // << OK, LÅT INTERRUPTS KOMMA IGEN
    while(EECON1.WR);  // Wait for it to finish before doing next
Interrupts är guld värda när man har lärt sig använda dom, större funktioner är snudd på omöjliga att klara av utan faktisk.
PopUnoNkoK
Inlägg: 789
Blev medlem: 10 december 2007, 12:40:08
Ort: Piteå

Re: Enkel pic fråga gällande fördröjning

Inlägg av PopUnoNkoK »

Här är en kod som jag skrivit som gör det du vill.

Jag vill UNDERSTRYKA att jag gjort detta för min egen skull. Jag tycker att det är kul att testa nya saker. Jag hade tex aldrig räknat på så höga tal (8timmar) och jag hade aldrig använt TMR1.

Som jag har räknat funkar detta och precisionen (den teoretiska, i simulatorn) borde var under en sekund fel.
MEN jag använder dock den interna klockan på 4MHz så den faktiska precisionen är inte lika hög.

PICen är en 16f690 (för att jag hade en egen "grundkod" till den)
Som koden är skriven här ligger reläet på PORTA bit O. (PORTA,0)
Det är juh dock skrivet i Assembler.
Relääet växlar var 8e timma.

Som sagt detta är inte tänkt som "här har du den perfekta lösningen". Det är säkert långt ifrån. Men jag tyckte att det var kul att testa.

MVH Peter F

Kod: Markera allt

;**********************************************************************
;   This file is a basic code template for object module code         *
;   generation on the PIC16F690. 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: P16F690.INC                                      *
;                                                                     *
;                                                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes:                                                           *
;                                                                     *
;                                                                     *
;                                                                     *
;                                                                     *
;**********************************************************************

    list      p=16F690           ; list directive to define processor
    #include <p16F690.inc>        ; processor specific variable definitions

    errorlevel  -302              ; suppress message 302 from list file

    __CONFIG   _CP_OFF & _CPD_OFF & _BOR_OFF & _MCLRE_ON & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _FCMEN_OFF & _IESO_OFF 

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


#define	relayPort	PORTA
#define	relayBit	0





;***** VARIABLE DEFINITIONS (examples)

d1_value	EQU		.219	;
d2_value	EQU		.250	;
d3_value	EQU		.181	;



; 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
pclath_temp RES     1       ; variable used for context saving


	udata	0x20				;Minnesbanker som används i koden
d1			res	1					;Tilläggs räknare till TMR0 för att öka tiden		
d2			res	1					;Råvärdet för sec, min hour dagar, 2 siffror
d3			res	1
	
setting		res	1					;För att ställa in vilket läge counten är min,hour eller dagar.

shadow		res	1

t1			res 1
w2			res 1

debug		res	1


;**********************************************************************
RESET_VECTOR    CODE    0x0000       ; processor reset vector
        goto    start                ; go to beginning of program

INT_VECTOR      CODE    0x0004       ; interrupt vector location

INTERRUPT

        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
        movf    PCLATH,w          ; move pclath register into W register
        movwf   pclath_temp       ; save off contents of PCLATH register
; isr code can go here or be located as a call subroutine elsewhere

	


	BCF			PIR1, TMR1IF	;Nolla TMR1s interrupt flagga

	BTFSC		setting,0		;Kolla om vi ska gå till sista räknaren
	goto		slutraknare

	DECFSZ		d1				;Räkna ner TMR1 tillägsräknare, kolla om den är noll
	GOTO		endIsr			;NEJ, fortsätt räkna
	movlw		d1_value		;JA, Återställ d1 Tillägsräknare
	movwf		d1
	DECFSZ		d2				;Räkna ner TMR1 tillägsräknare, kolla om den är noll
	GOTO		endIsr			;NEJ, fortsätt räkna
	movlw		d2_value		;JA, Återställ d2 Tillägsräknare
	movwf		d2
	BSF			setting,0

slutraknare
	DECFSZ		d3	
	goto		endIsr
	movlw		d3_value		;JA, Återställ d1 Tillägsräknare
	movwf		d3
	CLRF		setting

	CLRF		shadow
	BSF			shadow,relayBit
	MOVFW		shadow
	XORWF		relayPort, f
	



endIsr
        movf    pclath_temp,w     ; retrieve copy of PCLATH register
        movwf   PCLATH            ; restore pre-isr PCLATH register contents
        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_PROG       CODE

start
; remaining code goes here

	BANKSEL	PORTA		;Init Port A & B & C
	CLRF 	PORTA 
	BANKSEL	PORTB
	CLRF 	PORTB
	BANKSEL	PORTC
	CLRF 	PORTC  		

	BANKSEL	ANSEL
	CLRF 	ANSEL 		;digital I/O
	BANKSEL	ANSELH
	CLRF 	ANSELH 		;digital I/O

	BANKSEL	TRISA
	MOVLW 	b'00000000' ;Set RA<0-7> as Outputs
	MOVWF 	TRISA 	

	BANKSEL	TRISB
	MOVLW 	b'00000000' ;Set RB<0-7> as Outputs 
	MOVWF 	TRISB 

	BANKSEL	TRISC
	MOVLW 	b'00000000' ;Set RC Outputs and Inputs
	MOVWF 	TRISC 	

	BCF 	STATUS,RP0 	;Bank 0
	CLRWDT 				;Clear WDT and prescaler
	
	MOVLW	b'00110001'		;TMR1 on prescaler settings
	MOVWF	T1CON

	BANKSEL	PIE1
	BSF		PIE1,0			;TMR1 interrupt enabled

	BANKSEL	INTCON
	MOVLW	b'11000000'		;Global interrupt and TMR0 interrupt enabled
	MOVWF	INTCON 		

	movlw	d1_value	;Ladda TMR0s extraräknare med förbestämt värde, 
	movwf	d1			;definieras i början av koden.
	movlw	d2_value	;Ladda TMR0s extraräknare med förbestämt värde, 
	movwf	d2			;definieras i början av koden.
	movlw	d3_value	;Ladda TMR0s extraräknare med förbestämt värde, 
	movwf	d3			;definieras i början av koden.

	movlw	.1
	movwf	debug

	CLRF	setting

	BSF		relayPort, relayBit



MainLoop

        goto    MainLoop             ; loop forever






; initialize eeprom locations

EE      CODE    0x2100
        DE  0x00, 0x01, 0x02, 0x03

        END                       ; directive 'end of program'

EDIT: Så här är allt uträknat.

Interrupt sker var 524.288MilliSec.
Jag har en Register som räknar från 219 ner till noll, ett steg varje interruppt. En sån här nedräkning tar alltså ca 114.82 sekunder.
Sedan har jag ett register som räknar ner från 250 till noll. Ett steg för varje 114.82sec
Detta innebär att när detta register är på noll har gått har det gått 28705sekunder (ca 7.973timmar).
För de resterande 95sekunderna har jag då en räknare som räknar ner 181 interrupt. Alltså ca 94,89sekunder.

Efter detta (8timmar) Växlas utgången på PORTA,0 från hög till låg eller vice versa.
Allt nollställs och börjar om från början.


Så, nu ska jag sluta spamma med mina egna övningar. :)

MVH Peter
Användarvisningsbild
newbadboy
Inlägg: 2485
Blev medlem: 16 september 2006, 19:16:28
Ort: Landskrona
Kontakt:

Re: Enkel pic fråga gällande fördröjning

Inlägg av newbadboy »

Tack för alla bra förklaringar. jag inser mer och mer att detta är nog ngt som jag inte klarar mig utan.
Användarvisningsbild
Icecap
Inlägg: 26652
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Enkel pic fråga gällande fördröjning

Inlägg av Icecap »

Bra och korrekt insikt!
Skriv svar