Jump to content
PLC Forum


Sign in to follow this  
Lcucinelli

Gestione Pause Con Pic Basic Pro

Recommended Posts

Lcucinelli

Signori

ho iniziato da poco a compilare piccoli progetti con Pic basic pro quindi e' ovio il mio livello di conoscenza in materia, scusate anche la quantita' di info che vi spedisco ma non sono pratico di come funziona un forum .

Ho un problema con la gestione delle pause , non riesco a far gestire un ritado alla mia uscita secondo l'esempio A , mentre quello che riesco ad ottenere e' il B:

Uscita ritarda di 15sec

Esempio A

Ing ____-----__-------------------

Out ______________________--------

Sec ____:___:_:______:_____:____

0 3 5 15 20

Esempio B

Ing ____----__-------------------

Out ________________--------

Sec ____:__:_:_______:_____

0 3 5 15

Il problema e' che la pausa non si resetta se l'ingresso torna a 0 per cui se l'ingresso torna a 1 il conteggio non riparte da 0.

Il programma e' scritto in pic basic pro:

DEFINE OSC 4

SYMBOL IN_A = PORTB.0

SYMBOL OUT = PORTB.2

TEMP VAR BIT

FLAG var BIT

VALORE VAR WORD

on interrupt GOTO INT

OPTION_REG=%10000000 'OPTION_REG.7=0 ABILITA I PULL UP

TRISB=%11000011

INTCON=%11000000

PIE1=%00000100

PCON.3=1 'OSC INTERNO 4 MHZ

CMCON=7

T1CON=%00100100

T2CON=0

CCP1CON=%00001010

'0,5HZ 30KHZ

VALORE = 65535 'MODIFICARE DA 65535 A 1 PER VARIARE LA VELOCITà DI BLINKING (DIMINUIRE VALORE PER AUMENTARE VELOCITà BLINKING)

CCPR1L=VALORE.LOWBYTE

CCPR1H=VALORE.HIGHBYTE

INIZIO:

out = 1

pause 500

out=0

MAIN:

IF IN_a = 1 then

IF FLAG = 1 THEN GOTO SALTA

out=0

PAUSE 15000 'millisecondi di ritardo sulla porta A

FLAG = 1

ELSE

flag = 0

endif

SALTA:

IF IN_a = 1 THEN

PIE1.2=1

T1CON.0=1

ELSE

PIE1.2=0

T1CON.0=0

OUT=0

ENDIF

GOTO MAIN

''''''''''''''''''''''''''''''''''''''''''''''''''

DISABLE ' Disable interrupts in handler

INT:

PIR1.2=0

OUT = NOT OUT

RESUME ' Return to main program

ENABLE ' Enable interrupts after handler

end

Share this post


Link to post
Share on other sites

Lcucinelli

Salve a tutti

c'e qualche esperto che puo' darmi un indicazione sul mio problema ?

Forse non sono stato chiaro sul mio problema .

Pic usato 16f628a scritto in pic basic pro.

Sto' cecando di realizzare un hardware che dovrebbe con un Ingresso che cambia stato far blinkare un Uscita solo dopo 15 sec . ( on delay )

Qualcuno puo' aiutarmi ?

Alzo ingresso inizia la pausa di 15000ms dopo tale tempo l'uscita inizia a blinkare ,

in tali condizioni tutto funziona come dovrebbe .

wallbash.gif In condizioni diverse del tipo

Ingresso alto ( per esempio ) 5 secondi, torna basso per 5 secondi ,torna alto 5 secondi e inizia a blinkare , se si analizza il tempo impiegato dall' uscita per alzarsi da quando si e' alzata per l'ultima volta ingresso, noterete che sono passati solo 5 sec !! Ok

L'anomalia sta' che il conteggio inizia dal momento che si alza per la prima volta ingresso e non come dovrebbe essere dopo l'ultima volta alto.

Invece tutto funziona correttamente se l'ingresso si rialza dopo che sono trascorsi i 15 secondi dall'ultima volta che l'ingresso si e' alzato

Esempio.

ingresso alto per 5 secondi Basso per 11 sec, per cui ha gia superato di 1 secondo il tempo da me impostato . senzasperanza.gif

Il problema e' che non si resetta il contatore quando l'ingresso torna basso.

Questo accade perchè nel momento in cui uso la pausa 15000 il PIC non controlla se lo stato dell'ingresso è cambiato e quindi dopo 15sec ti attiva l'uscita indipendentemente da quante volte è cambiato lo stato dell'ingresso, nel momento in cui si attiva l'ingresso potrebbe anche essere attivo ma il PIC non lo sa.Sicuramente nel mio prog. che qualche cosa che non funzioana come dovrebbe sono disposta anche a modificarlo interamente se serve .

Vorrei pero' cercare di capire cosa non funziona e rimodificarlo utilizzando il compilatore pic basic pro .

Sono certo di un vostro aiuto

Ciao e grazie Luca

Share this post


Link to post
Share on other sites
kappa47

Non conosco il PIC Basic, ma credo ci sia una incongruenza nel tuo listato.

Ho numerato il tuo listato per farmi capire:

1) IF IN_a = 1 then

2) IF FLAG = 1 THEN GOTO SALTA

3) out=0

4) PAUSE 15000 'millisecondi di ritardo sulla porta A

5) FLAG = 1

6) ELSE

7) flag = 0

8) endif

L'istruzione "else" al punto 6 si riferisce al "if" del punto 2 (non del punto 1) e

quindi l'istruzione al punto 7 non viene mai eseguita.

Credo che tu voglia riferirla al punto 1, quindi devi mettere un "endif" tra il

punto 5 e il punto 6. Non credo che la modifica risolva il problema.

Una bozza del main potrebbe essere:

1) ingresso = 1 ?

2) se SI vai al punto 5 (aspetto che ingresso vada alto)

3) pausa 1 sec.

4) vai al punto 1

5) contatore = 15

6) pausa 1 sec.

7) ingresso = 1 ?

8) se NO vai al punto 1 (se tornato basso, riparto)

9) decremento contatore

10) contatore = 0 ?

11) se NO vai al punto 6 (tempo NON scaduto: torno a controllare ingresso)

12) output = 1

13) pausa 5 sec.

14) ingresso = 0 ?

15) se SI vai al punto 18

16) pausa 1 sec.

17) vai al punto 14

18) output = 0

19) vai al punto 1

Buon lavoro.

Share this post


Link to post
Share on other sites
Lcucinelli

Per iniziare grazie per aver risposta Kappa47 .

Ho capito perfettamente il tuo messaggio, il mio listato sicuramente presenta errori , sono un autodidatta che sta cercando di imparare .

Se ho capito bene il punto 5 dovrebbe essere il mio timer cioe 15 sec.

Ho un dubbio pero' su questo passaggio da te descritto , ti faccio un esempio :

se durante il conteggio da 1 a 15 il mio contatore si ferma per qualche problema tipo a 5 ( ingresso Basso ) e si rialza dopo 3 secondi , il contatore da dove riparte ?

Grazie di nuovo per il suggerimento ,seguiro il tuo consiglio.

Una bozza del main potrebbe essere:

1) ingresso = 1 ?

2) se SI vai al punto 5 (aspetto che ingresso vada alto)

3) pausa 1 sec.

4) vai al punto 1

5) contatore = 15

6) pausa 1 sec.

7) ingresso = 1 ?

8) se NO vai al punto 1 (se tornato basso, riparto)

9) decremento contatore

10) contatore = 0 ?

11) se NO vai al punto 6 (tempo NON scaduto: torno a controllare ingresso)

12) output = 1

13) pausa 5 sec.

14) ingresso = 0 ?

15) se SI vai al punto 18

16) pausa 1 sec.

17) vai al punto 14

18) output = 0

19) vai al punto 1

Share this post


Link to post
Share on other sites
kappa47

Tra il punto 6 e il punto 11 (compresi) hai un loop.

Da questo loop esci per due motivi:

primo: il contatore va a zero (quindi sono passati 15 sec.) e entri al punto 12

secondo: il tuo ingresso torna basso (test sul punto 7) (ti ricordo che sei entrato

nel loop con l'ingresso alto) torni all'inizio (punto 8).

Come detto al post precedente, questo vuole essere una traccia di partenza.

Ha sicuramente dei difetti del tipo debouncing sull'ingresso, campionamento piuttosto basso (1 sec), ecc.

Se il tuo ingresso varia tra alto e basso con una frequenza maggiore di 1 sec. il programma non funziona.

Puoi ovviare facendo pausa di 0,5 sec. e caricare il contatore con 30.

Non preoccuparti degli errori: ti assicuro che ne faccio anch'io.

Ciao.

Share this post


Link to post
Share on other sites
mf2hd

Ciao, a occhio c'è sicuramente un errore sull' istruzione PAUSE che tende a prendere il controllo del flusso sino a che non ha terminato il suo conteggio.

Quando usi l' interrupt devi impostare i ritardi PAUSE (millisec) o PAUSEUS (microsec) in questo modo:

invece di

PAUSE 500

trasformala in uno o più cicli FOR..TO..NEXT

nel tuo esempio 500=$1F4 perciò un byte non ti basta (max 255=$FF)

I VAR BYTE

T VAR BYTE

FOR I=1 TO 5

FOR T=1 TO 100

PAUSE 1

NEXT T

NEXT I

Così l' interrupt sul timer viene "intercettato" essendo il PAUSE molto breve,

Lo stesso vale per le istruzioni simili DELAYMS e DELAYUS del Proton picbasic.

P.S. Non ho controllato se il resto del tuo programma è corretto, così come la confgurazione per i timer (prescaler,ecc.).

Ti metto un po' di passaggi e pezzi del codice con interrupt ho usato recentemente su un 16F628, forse ti può essere utile...o forse no smile.gif

Mi serviva un interrupt timer a cadenza di un 1 secondo.

Il 16F628 usa 4 clock per istruzione, come suppongo la maggior parte dei suoi fratelli.

Con un clock di 4MHz (1/4000000=0.25usec) il timer TMR0 viene incrementato ogni 0.25us*4=1us.

Dato che TMR0 e' da un byte, per riazzerarsi ha bisogno di 256 incrementi, perciò ogni "giro" corriponde a 1us*256=256us.

Usando il prescaler impostato a 64 (OPTION_REG=$05) l' interrupt scatta ogni 256us*64=16.384ms.

Per avere un secondo (circa) si dovranno aspettare 61 interrupt : 61*16.384ms=999.424ms.

L' errore, se non ho contato male, porta a circa 2s all' ora di cui, a seconda dell' applicazione, bisogna eventualmente tenerne conto.

Se si usa il clock interno è probabile che l' errore sia maggiore di quello citato, perche' e' meno preciso di un quarzo esterno.

Con gli ultimi modelli di PIC la % di errore sul clock interno dichiarata e' molto contenuta, anche se personalmente ho riscontrato un po' di problemi con le comunicazioni seriali su pins non dedicati.

Percio', se possibile, quarzo o risuonatore...e c'e' un intoppo in meno.smile.gif

Il codice e' con sole istruzioni in picbasic, volendo si possono inserire delle routine in assembler.

Per questo tipo di metodo, che pero' richiede anche MPASM e forse la versione PRO del compilatore, vedi gli esempi sul sito del produttore oppure le famose routine di Darrel Taylor (link)).

---Programma tipo---

(Inserire le dichiarazioni varibili, clock, micro, condizioni iniziali, ecc.)

Conta VAR BYTE (variabile per conteggio interrupt)

Conta=0 (condizione iniziale per variabile contatore)

OPTION_REG=$5 (prescaler = 64)

ON INTERRUPT GOTO InterRoutine (l' interrupt salta al propria sub)

INTCON=$A0 (abilita l' interrupt TMR0)

Main:

(qui si mette il programma: attenzione all' uso di PAUSE)

GOTO Main

(qui si possono mettere eventuali SubRoutine chiamate dal programma: sempre attenzione all' uso di PAUSE)

SubRoutine1:

...

RETURN

SubRoutine2:

...

RETURN

ecc.

DISABLE (qui comincia la routine dell' interrupt)

InterRoutine:

Conta=Conta+1 (incrementa contatore ad ogni interrupt/prescaler)

IF Conta<61 THEN Salta (verifica se raggiunto 1s circa)

Conta=0 (azzera la var usata per conteggio di raggiunto 1s circa)

(qui si mette la parte di programma che e' strettamente legata all' interrupt)

(es. l' incremento di variabili Secondi e Minuti)

Secondi=Secondi+1

IF Secondi=60 THEN

Secondi=0

Minuti=Minuti+1

ENDIF

(ecc.)

Salta:

INTCON.2=0 (riabilita interrupt su TMR0)

RESUME

ENABLE

END

Share this post


Link to post
Share on other sites
Lcucinelli

Signori grazie per le info , cerchero di farle fruttare ... sicuramente ci risentiamo per il momento grazie mille rolleyes.gif

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...