Vai al contenuto
PLC Forum


Interfacciare Un Microcontrollore Con Un Sensore


MusicIsLife

Messaggi consigliati

Inserita: (modificato)

Provo a dare un'occhiata domani a lavoro.

Il PIC che vorrei usare è il 16F84a, dato che è maggiormente disponibile qui in azienda.

Se fosse possibile preferirei programmarlo in assembly piuttosto che in C.

Comunque ho trovato un file di una decodifica Manchester R5 per i telecomandi della Philips. Domani lo carico sul forum.

La decodifica che interessa a me, comunque, è quella che ha il bit "1" rappresentato da uno stato basso seguito da uno alto e il bit "0" viceversa. I primi due bit sono di start e sono rispettivamente un "1" ed uno "0".

Modificato: da MusicIsLife
Link al commento
Condividi su altri siti


Inserita: (modificato)

Metto qui la bozza della decodifica Manchester che sto implementando.

L'ho debuggata con MPLAB e non mi da errori sintattici. Lunedì provo a caricarla nel PIC.

Praticamente utilizzo 3 registri (KeyCode, KeyCode+1, KeyCode+2) per inserire i 18 bit dei dati in uscita dal sensore. I dati vengono letto dal pin RA0 di PORTA e poi, nello stato 5 della macchina a stati prendo i dati di questi registri e li mando in serie in uscita sul pin RB0 (e RB1 in versione invertita) in modo poi va visualizzare sull'oscilloscopio se la decodifica funziona.

;-----------------------------------------------------------------------------

PROCESSOR 16F84A

RADIX DEC

INCLUDE "P16F84A.INC"

__CONFIG 3FF5H

;per ora ho copiato questo valore di CONFIG, ma va controllato

;.................................................................

; DICHIARAZIONI DEL FILE REGISTER

;-----------------------------------------------------------------------------

TestCode equ 12h

IR_STATE equ 14h ;Registro associato alla IR state machine

BIT_TIMER equ 15h ;Bit timer

KeyCode equ 16h ;IR shift register

msDelayCounter equ 19h

FLAG equ 1Ah

TEMP equ 1Bh

HCONT equ 1Ch

LCONT equ 1Dh

TEMP1 equ 1Eh

EADR equ 1Fh

Contatore equ 20h

;-----------------------------------------------------------------------------

; COSTANTI

;-----------------------------------------------------------------------------

TIMER_UPDATE equ -50+3 ;Timer update value (2 dead cycles)

HALF_TIME equ 850/50 ;Number of timer counts per half bit

;Bisogna calcolare l'HALF_TIME in base al tempo di bit

;850 per il 38kHz

;.................................................................

IN equ 0

OFF equ 1

SUB equ 2

VOLD equ 3

VOLI equ 4

IR_END equ 7

TEST equ 6

;-----------------------------------------------------------------------------

;

; Reset vector

;

;-----------------------------------------------------------------------------

ORG 00h

goto Start

;:................................................................

Start

bsf STATUS,RP0 ;Entro nel banco 1

movlw b'00011111' ;Set PORTA come ingressi

movwf TRISA

movlw b'00000000' ;Set PORTB come uscite

movwf TRISB

;movlw b'11011111'

;movwf OPTION_REG

bcf STATUS,RP0 ;Torno al banco 0

movlw b'00000000' ;Tutti gli interrupts sono disabilitati

movwf INTCON

movlw IR_STATE_0 ;Inizializza la state machine per la decodifica Manchester

movwf IR_STATE

movwf TMR0 ;Inizializza TMR0

clrf KeyCode

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

MainLoop clrwdt

LOOP CALL STATE_MACHINE ;Chiamata alla state machine per la decodifica Manchester

CLRWDT

GOTO LOOP

;-----------------------------------------------------------------------------

;

; State machine for encoding MANCHESTER

;

;-----------------------------------------------------------------------------

STATE_MACHINE movf IR_STATE,W ;W=IR_STATE

movwf PCL ;Carica l'indirizzo di IR_STATE nel PC

;---------------------------------------STATE 0, WAIT FOR BEGIN OF START BIT--

IR_STATE_0 btfss PORTA,IN ;Se IN=0 esegue l'istruzione successiva (che fa uscire dalla subroutine)

return ;Se IN=1 salta quest'istruzione e passa alla successiva perchè c'è il primo bit

movlw HALF_TIME/2-1 ;Calcola metà del tempo di bit e carica il valore in W

movwf BIT_TIMER ;BIT_TIMER=W

movlw IR_STATE_1 ;Aggiorna lo stato della macchina a stati [Next stop is state 1]

movwf IR_STATE

return

;---------------------------STATE 1, START BIT DETECTED, CHECK IF IT IS REAL--

IR_STATE_1 DECFSZ BIT_TIMER,1 ;Attende fino ad arrivare al centro del bit di start

RETURN ;Time's not up yet!

BTFSC PORTA,IN ;Is the input still low? [skip se il bit 4 di PORTA=0]

GOTO IR_ERROR_1 ;Nope! Exit with error

MOVLW HALF_TIME ;Set interval to the center of the [W=HALF_TIMER]

MOVWF BIT_TIMER ;first half of the next bit [bIT_TIMER=HALF_TIMER]

MOVLW b'01000000' ;Prepare the shift register

MOVWF KeyCode ;Copia 01000000 in KeyCode

CLRF KeyCode+1 ;Setta a 0 tutti i bit di KeyCode+1

CLRF KeyCode+2 ;Setta a 0 tutti i bit di KeyCode+2

MOVLW IR_STATE_2 ;Aggiorna lo stato della macchina a stati [Prepare for next stop]

MOVWF IR_STATE

RETURN

;-----------------------------------IR STATE 2, WAIT FOR FIRST HALF OF A BIT--

IR_STATE_2 DECFSZ BIT_TIMER,1 ;Wait until center of first half of bit

RETURN ;Keep waiting!

MOVLW IR_STATE_3 ;Salta a IR_STATE_3 se la prima metà del bit è alta

BTFSS PORTA,IN

MOVLW IR_STATE_4 ;Salta a IR_STATE_4 se la prima metà del bit è bassa

MOVWF IR_STATE

MOVLW HALF_TIME ;Azzera il bit-timer

MOVWF BIT_TIMER

RETURN

;---------------IR STATE 3, FIRST HALF WAS HIGH NOW IT MUST BE LOW FOR A "1"--

IR_STATE_3 DECFSZ BIT_TIMER,1 ;Wait until center of 2nd half of bit

RETURN ;Keep waiting!

BTFSC PORTA,IN ;Se la seconda metà del bit è =1, va alla label _ERROR

GOTO _ERROR

BSF STATUS,C ;A 1 was received, shift it in result

RLF KeyCode,F ;Inserisce il Carry nella posizione 0 di KeyCode

RLF KeyCode+1,F ;Shift di 1 bit a sinistra e ricopia in KeyCode+1

RLF KeyCode+2,F ;Shift di 1 bit a sinistra e ricopia in KeyCode+2

MOVLW HALF_TIME ;Azzera il bit-timer

MOVWF BIT_TIMER

MOVLW IR_STATE_2 ;In case we need some more bits

BTFSC STATUS,C ;We're done when Carry is 1

MOVLW IR_STATE_5 ;Carry is 1, received entire message

MOVWF IR_STATE

RETURN

_ERROR MOVLW IR_ERROR_0 ;Wait until input gets high before

MOVWF IR_STATE ;returning to state 0

RETURN

;---------------IR STATE 4, FIRST HALF WAS LOW NOW IT MUST BE HIGH FOR A "0"--

IR_STATE_4 DECFSZ BIT_TIMER,1 ;Wait until center of 2nd half of bit

RETURN ;Keep waiting!

BTFSS PORTA,IN ;Is input high now?

GOTO IR_ERROR_1 ;Nope! It's an error!

BCF STATUS,C ;A 0 was received, shift it in result

RLF KeyCode,F ;Shift di 1 bit a sinistra e ricopia in KeyCode

RLF KeyCode+1,F ;Shift di 1 bit a sinistra e ricopia in KeyCode+1

RLF KeyCode+2,F ;Shift di 1 bit a sinistra e ricopia in KeyCode+2

MOVLW HALF_TIME ;Restart bit timer

MOVWF BIT_TIMER

MOVLW IR_STATE_2 ;In case we need some more bits

BTFSC STATUS,C ;We're done when Carry is 1

MOVLW IR_STATE_5 ;Carry is 1, received entire message

MOVWF IR_STATE

RETURN

;--------------------------IR STATE 5, MESSAGE RECEIVED, START PROCESSING IT--

IR_STATE_5 BCF STATUS,C ;Set CARRY=0

MOVLW b'00011000' ;W=24

MOVWF Contatore ;Contatore=W --> Contatore=24

OUTPUT RLF KeyCode,F ;Shift di 1 bit a sinistra di tutti i 3 registri

RLF KeyCode+1,F ;Considero il CARRY (dal KeyCode+2) per settare

RLF KeyCode+2,F ;il bit in uscita

BTFSC STATUS,C ;Se CARRY=0 salta l'istruzione successiva

GOTO SET_1

GOTO SET_0

SET_1 BSF PORTB,0 ;Set RB0=1

BCF PORTB,1 ;Set RB1=0 (Uscita invertita)

GOTO CONTINUE

SET_0 BCF PORTB,0 ;Set RB0=0

BSF PORTB,1 ;Set RB1=1 (Uscita invertita)

GOTO CONTINUE

CONTINUE ;BCF STATUS,C ;Set CARRY=0

DECFSZ Contatore,F ;Decrementa il contatore. Quando Contatore=0 skip istruzione successiva

GOTO OUTPUT

MOVLW IR_STATE_6 ;Aggiorna lo stato della macchina a stati

MOVWF IR_STATE

RETURN

;----------------------------------IR STATE 6, WAIT FOR INPUT TO RETURN HIGH--

IR_STATE_6

IR_ERROR_0 MOVLW IR_STATE_0 ;Reset state machine only if input is

BTFSC PORTA,IN ;high

MOVWF IR_STATE

RETURN

;-----------------------------------------------------------IR ERROR STATE 1--

IR_ERROR_1 MOVLW IR_STATE_0 ;Return to IR state 0

MOVWF IR_STATE

RETURN

;------------------------------------------------------------------------------

END

;--------------------------------FINE PROGRAMMA-------------------------

Mi era venuto un dubbio: quando termina quel programma? perchè a me sembra che sia un loop continuo dato che nel MainLoop c'è una GOTO che continua a ciclare la macchina a stati per la decodifica. Mi sbaglio o non terminerebbe mai?

Poi ho un'altra questione: ho un tempo di bit di 8uS. Come imposto l'HALF_TIME nelle costanti?

Modificato: da MusicIsLife
Link al commento
Condividi su altri siti

Un micro non termina mai il programma, gira sempre, a meno che tu non lo metta in "sleep mode" ma poi ti serve qualcosa per risvegliarlo.

In questo caso il loop controlla continuamente il pin di ingresso, se è 0 ripete il loop quando è 1 inizia la decodifica.

HALF_TIME equ 850/50 ;Number of timer counts per half bit

;Bisogna calcolare l'HALF_TIME in base al tempo di bit

;850 per il 38kHz

Ovviamente dipende dal quarzo che stai usando

Link al commento
Condividi su altri siti

Inserita: (modificato)

Grazie mille per le risposte Nikiki biggrin.gif

Allora le opzioni sono:

A)Quarzo da 4MHz

B)Quarzo da 10MHz

Nei due casi come si svolge il calcolo? huh.gif

Avevo poi la seguente questione:

IR_STATE_0 btfss PORTA,IN ;Se IN=0 esegue l'istruzione successiva (che fa uscire dalla subroutine)

return ;Se IN=1 salta quest'istruzione e passa alla successiva perchè c'è il primo bit

movlw HALF_TIME/2-1 ;Calcola metà del tempo di bit e carica il valore in W

movwf BIT_TIMER ;BIT_TIMER=W

movlw IR_STATE_1 ;Aggiorna lo stato della macchina a stati [Next stop is state 1]

movwf IR_STATE

return

Da quello che ho capito la macchina a stati così come è implementata sta sempre nel primo stato ciclando fino a quando non rileva una transizione che porta un "1" sul pin di ingresso? Perchè non ho capito bene la transizione iniziale per attivare la macchina a stati. Quando la macchina va in STATE_1 e smette di aspettare una transizione sul pin di ingresso?

Modificato: da MusicIsLife
Link al commento
Condividi su altri siti

Prima di tutto verifica il tipo di PIC che hai, se è un PIC16F84A-04/P lo puoi cloccare solo fino a 4 MHz.

In questo firmware non è stato usato il timer0 (che sarebbe la cosa più logica) ma viene semplicemente caricato un valore in un registro e decrementato ad ogni ciclo fino ad arrivare a zero. Quindi la precisione del conteggio è influenzata dal numero di istruzioni eseguite.

Facendo un conto approssimativo (potrei aver sbagliato... gli ho dato uno sguardo veloce) esegue 16 istruzioni iniziali per il caricamento dei registri e successivamente 10 istruzioni per ogni loop (sto parlando dello stato 1).

Considerando che HALF_TIME viene dichiarato 850/50 (17) e che viene caricato diviso 2 -1 dal preprocessore, il valore iniziale di BIT_TIMER dovrebbe essere 7.

Quindi abbiamo 16 istruzioni + 7 loop da 10 istruzioni l'uno per un totale di 86 istruzioni.

Ogni istruzione viene eseguita in 4 cicli di clock, e a 32 KHz un ciclo dura 31,25 uS, quindi 31,25*4*86=10,750 mS. Possibile che in questo caso mezzo bit fosse 10,750 mS?

Potrei aver fatto errori di calcolo, sbagliato a contare le istruzioni con i relativi tempi di esecuzione, ma il metodo è questo.

Con 4 MHz un'istruzione dura esattamente 1 uS, solo le istruzioni di caricamento impiegano 16 uS, come fai a contare 4 uS del tuo mezzo bit?

Anche cloccando a 20 MHz non ci riesci lo stesso, devi per forza usare il timer.

Il metodo giusto è caricare il timer con il valore calcolato ed attendere l'interrupt dell'overflow. In questo modo non viene influenzato dalle istruzioni che ci sono in mezzo (il micro può fare tranquillamente altre cose) e l'incremento è dato solo dalla frequenza del quarzo/4 (più eventuali altre divisioni del prescaler).

Ma per curiosità... perchè non usare il C?

Link al commento
Condividi su altri siti

Inserita: (modificato)

Grazie per la risposta smile.gif

Allora, non uso il C per il semplice fatto che questo programmino l'avevo trovato all'incirca così poichè è stato utilizzato in azienda per dei sensori IR. Praticamente colui che mi ha mostrato il programma l'aveva preso da un sito internet che trattava la decodifica Manchester R5 per telecomandi Philips. Io ho quindi cercato di adattarlo alle mie esigenze togliendo le cose inutili e sistemando altre cose.

Il fatto è che il programma originale è scritto in assembly e, quindi, non posso riprogrammarlo in C.

Per il timer0 non saprei esattamente come implementarlo. Io mio problema è questo: arrivano 18 bit di dati + tempo di intervallo tra 1 stringa di bit e la successiva ogni 228uS dal sensore... fai conto che ogni bit è largo 8uS e, quindi, 18bitX8uS=144uS. Quindi la stringa di dati è di 144uS, mentre tra una stringa di bit (che iniziano con i 2 bit di start) e la successiva ci sono 228-144=84uS nei quali il segnale è portato a zero.

Sta di fatto che ho 2 alternative:

1)cerco di riprodurre FEDELMENTE in segnale ricevuto dal micro e decodificato mandandolo in uscita su un oscilloscopio. In questo caso dovrei, quindi, avere un segnale all'oscilloscopio simile a quello in ingresso del pic: 84uS di segnale a "0" tra una stringa di bit e l'altra e poi i miei 144uS di segnale decodificato, per un totale di 228uS.

2)Fregarmene delle temporizzazioni e lasciare che anche se passano ad esempio 20uS tra 1 bit e l'altro non mi cambi la cosa.

Ovviamente preferirei implementare la prima soluzione dato che avrei anche un confronto visivo tra ingresso del micro e uscita dal micro stesso.

Si può fare quest'opzione? Come posso fare in modo che la lettura sulla porta e la scrittura nei registri non dipendano dalle istruzioni necessarie x fare queste operazioni?

Modificato: da MusicIsLife
Link al commento
Condividi su altri siti

Usando il Timer0 del micro e l'interrupt.

Quando devi contare un tempo preciso, carichi il timer con un valore opportunamente calcolato, questo viene incrementato dal clock/4, e quando "trabocca", nel program counter viene caricato il valore del vettore di interrupt e viene settato il flag del timer.

Al vettore di interrupt ci metti un controllo per vedere cosa è successo (perchè il vettore di interrupt è unico per tutti gli eventi) e se trovi il flag del timer esegui quello che devi eseguire.

Comunque con un micro da 4 MHz ci stai un po' preciso, quindi anche l'ingresso ti conviene metterlo sotto interrupt, perchè il ciclo di istruzioni che si occupa di leggerlo potrebbe perdere troppo tempo prima che si accorga dell'arrivo del bit.

Oppure prendi un PIC che puoi cloccare a 20 MHz per avere un po' più di velocità di esecuzione.

Devi lavorarci un po... smile.gif

Link al commento
Condividi su altri siti

Inserita: (modificato)

Sto cercando di capirci qualcosa anche se mi rendo conto che parto svantaggiato dato che non ho quasi mai programmato un PIC.

Proviamo a ragionare: ho in ingresso una stringa di bit che variano ogni 8uS (tralasciando il tempo vuoto tra 1 stringa e la successiva). Se utilizzassi un quarzo da 4MHz ogni istruzione in assembler del programma verrebbe eseguita ogni 1uS. Ciò vorrebbe dire che il tempo massimo per decodificare un singolo bit in ingresso sarebbe di 8 istruzioni assembler. O__O

Ma non è possibile! Servono ben più di 8 istruzioni assembler per decodificare il bit in ingresso (anche tralasciando il fatto di copiarlo su un pin di uscita).

[Piccola parentesi: ho letto sul datasheet che il PIC16F84A accetta fino a quarzi di 20MHz se non erro wink.gif]

Poi una cosa che non ho capito è questa: mettiamo che io implemento il mio timer0 con un tempo adeguato affinchè vada in overflow nel tempo che mi interessa. Poi vado a leggere il bit nel registro che viene settato in caso di overflow e avvio una routine di interrupt (che dovrebbe fare cosa???). Il fatto è che questa routine di interrupt impiega del tempo per eseguirsi poichè anch'essa è composta da istruzioni che vengono eseguite in 1uS (o 2uS se impiegano 2 cicli macchina).

Quindi come faccio? blink.gif

Sono un pochino confuso!

Modificato: da MusicIsLife
Link al commento
Condividi su altri siti

devi solo testare il dato per vedere se è uno 0 o un 1 e copiarlo nel buffer di ricezione... 8 istruzioni potrebbero bastarti, magari evitando subroutine o salti inutili, ma come già detto saresti un po' nel preciso.

L'ideale sarebbe appunto cloccare più veloce, ma non è vero che tutti i PIC16F84 puoi cloccarli fino a 20 MHz. Verso la fine del datasheet trovi come identificare il codice, il suffisso -04/P significa che può funzionare fino a 4 MHz, o almeno questo è il limite che ti garantisce Microchip, personalmente l'ho cloccato anche più veloce e funziona, ma non so se arriverà a 20.

Link al commento
Condividi su altri siti

Alla fine ho utilizzato un altro PIC, il 16F886 che ha anche i moduli per la EUSART, I²C o SPI; perlomeno la comunicazione con l'esterno (che sia PC con installato un programma per leggere i dati oppure un altro micro per fare altre elaborazioni) risulta essere più semplice.

A titolo di test ho fatto in modo di girare i dati in ingresso (inseriti nei 3 registri KeyCode, KeyCode1, KeyCode2) in uscita, sul pin RA1 (e RA2 uscita invertita).

Il programma che ho realizzato (e che simulandolo sembra funzionante nel modo corretto) si basa su una routine di interrupt che gestisce l'arrivo dei fronti dei singoli bit, sia che siano di salita, sia che siano di discesa (i bit sono in arrivo dal mio sensore sul pin RB0).

Praticamente appena arriva un fronte si avvia la routine di interrupt e vado a leggere che valore ho in ingresso; se esso è alto allora il bit deve essere un "1" (poichè con la mia codifica Manchester una transizione basso->alto sarebbe un "1" logico). Se invece dopo l'interrupt del fronte ciò che leggo è basso, allora il bit deve essere uno "0".

Il programma impiega circa 70uS per processare tutti i dati in uscita.

Se avete voglia provate a dare un'occhiata al programma che posto qui. Suggerimenti e commenti sono ben accetti... Grazie laugh.gif

;-----------------------------------------------------------------------------

PROCESSOR 16F886

RADIX DEC

INCLUDE "P16F886.INC"

__CONFIG _CONFIG1, _DEBUG_OFF & _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_OFF & _WDT_OFF & _HS_OSC

__CONFIG _CONFIG2, _WRT_OFF & _BOR40V

;-----------------------------------------------------------------------------

; DICHIARAZIONI DEL FILE REGISTER

;-----------------------------------------------------------------------------

KeyCode equ 20h ;3 shift register per i dati in uscita

KeyCode1 equ 21h

KeyCode2 equ 22h

Contatore equ 28h

;-----------------------------------------------------------------------------

; Reset vector

;-----------------------------------------------------------------------------

ORG 00h

goto Start

;-----------------------------------------------------------------------------

; Routine di interrupt

;-----------------------------------------------------------------------------

ORG 04h

CALL IR_STATE_0

nop

nop

nop

nop

nop

movf PORTB,W

BCF INTCON,RBIF

RETFIE

;-----------------------------------------------------------------------------

Start

banksel TRISA

movlw b'00000000' ;Set PORTA come uscite

movwf TRISA

movlw b'11111111' ;Set PORTB come ingressi

movwf TRISB

movlw b'11111111' ;RBPU=1 & INTEDG=1 & TOCS=1 & T0SE=1 & PSA=1 & 1:128 prescaler

movwf OPTION_REG

movlw b'00000001' ;Abilita gli interrupt per i pin di PORTB

movwf IOCB

movlw b'10101000' ;Abilitati interrupt T0IE (Timer interrupt), RBIF (interrupt sugli ingressi del PORTB), RBIE

movwf INTCON

banksel ANSEL

clrf ANSEL

clrf ANSELH

banksel TMR0

movlw b'11001110'

movwf TMR0 ;Inizializza TMR0 a 206

clrf PORTA ;Azzera tutti i bit di PORTA

clrf PORTB ;Azzera tutti i bit di PORTB

MOVLW b'01000000' ;Prepare the shift register

MOVWF KeyCode ;Copia 01000000 in KeyCode

CLRF KeyCode1 ;Setta a 0 tutti i bit di KeyCode1

CLRF KeyCode2 ;Setta a 0 tutti i bit di KeyCode2

CLRWDT

;--------------------------LOOP PRINCIPALE-----------------------------------

Int BTFSS INTCON,RBIF ;Verifica l'interrupt sul fronte di salita di RB1

nop

goto Int

;altrimenti cicla nuovamente in modo periodico

;-----------------------IR_STATE_0 [inizializzazione]-----------------------------------------

IR_STATE_0

BTFSS PORTB,0 ;Legge l'ingresso su RB0. Se RB0=0 va in IR_STATE_1

GOTO IR_STATE_1

GOTO IR_STATE_2 ;Se RB0=1 va in IR_STATE_2

;-----------------------IR_STATE_1 [setta il bit a "0"]---------------------------------------

IR_STATE_1

BCF STATUS,C ;Set C=0

RLF KeyCode,F ;Shift di 1 bit a sinistra e ricopia in KeyCode

RLF KeyCode1,F ;Shift di 1 bit a sinistra e ricopia in KeyCode1

RLF KeyCode2,F ;Shift di 1 bit a sinistra e ricopia in KeyCode2

BCF INTCON,RBIF ;Resetta il flag di interrupt su RB0

BTFSC STATUS,C ;Se C=1 ho finito di ricevere ed eseguo l'istruzione successiva

GOTO IR_STATE_3

RETURN

;---------------------IR_STATE_2 [setta in bit ad "1"]-------------------------

IR_STATE_2

BSF STATUS,C ;Set C=1

RLF KeyCode,F ;Shift di 1 bit a sinistra e ricopia in KeyCode

RLF KeyCode1,F ;Shift di 1 bit a sinistra e ricopia in KeyCode1

RLF KeyCode2,F ;Shift di 1 bit a sinistra e ricopia in KeyCode2

BCF INTCON,RBIF ;Resetta il flag di interrupt su RB0

BTFSC STATUS,C ;Se C=1 ho finito di ricevere ed eseguo l'istruzione successiva

GOTO IR_STATE_3

RETURN

;----------------------IR_STATE_3 [Processo il segnale presente nei 3 registri KeyCode]----

IR_STATE_3 nop

nop

nop

nop

nop

movf PORTB,W

BCF INTCON,RBIF ;Resetta il flag di interrupt su RB0

MOVLW b'00011000' ;W=24

MOVWF Contatore ;Contatore=W --> Contatore=24

OUTPUT BCF STATUS,C ;Set CARRY=0

RLF KeyCode,F ;Shift di 1 bit a sinistra di tutti i 3 registri

RLF KeyCode1,F ;Considero il CARRY (dal KeyCode+2) per settare

RLF KeyCode2,F ;il bit in uscita

BTFSC STATUS,C ;Se CARRY=0 salta l'istruzione successiva

GOTO SET_1

GOTO SET_0

SET_1 BSF PORTA,1 ;Set RA1=1

BCF PORTA,2 ;Set RA2=0 (Uscita invertita)

GOTO CONTINUE

SET_0 BCF PORTA,1 ;Set RA1=0

BSF PORTA,2 ;Set RA2=1 (Uscita invertita)

GOTO CONTINUE

CONTINUE DECFSZ Contatore,F ;Decrementa il contatore. Quando Contatore=0 skip istruzione successiva

GOTO OUTPUT

movlw b'10101000' ;Abilitati interrupt T0IE (Timer interrupt), RBIF (interrupt sugli ingressi del PORTB), RBIE

movwf INTCON

MOVLW b'01000000' ;Prepare the shift register

MOVWF KeyCode ;Copia 01000000 in KeyCode

clrf KeyCode1 ;Azzera KeyCode1

clrf KeyCode2 ;Azzera KeyCode2

GOTO Int ;Finito il ciclo riprende da capo

;-----------------------------------------------------------------------------

END

Modificato: da MusicIsLife
Link al commento
Condividi su altri siti

Secondo me ci sono degli errori.

Questo è vero se il fronte di salita avviene in un preciso momento. Nel manchester ci sono dei fronti che non indicano l'1 logico... ad esempio se ci sono una sequenza di zeri, hai lo stesso dei fronti di salita, ma non c'è nessun 1 logico.

Conoscendo la durata di un bit, devi misurare il tempo che passa dallo start, e vedere il fronte nel centro del bit.

DEVI USARE IL TIMER!!! biggrin.gif il tempo è fondamentale!

Inoltre quando usi l'interrupt, come prima cosa ti devi preoccupare di salvare i registri che sporcherai durante la routine di interrupt, per poterli ripristinare prima del RETFIE.

Link al commento
Condividi su altri siti

Il fatto è che io mi metto in ascolto solamente dei fronti di salita o discesa a metà bit.

In questo modo, andando a leggere nell'immediato successivo del fronte centrale, se trovo un fronte basso è come se il bit fosse a "0", se invece fosse alto è come se fosse ad "1".

Ho provato e la decodifica sembra funzionare.

L'unico problema, forse, è se per caso il programma inizia a leggere quando la trasmissione è già in atto. Se per caso il pic inizia a leggere a metà treno di dati esce un casino assurdo poichè il contatore è tarato a 24 (3 registri da 8 bit l'uno)... e conta fino a 0, ovvero fino a quando TUTTI i bit sono stati mandati in uscita dai 3 registri sul pin RA1.

Per quando riguarda i registri da salvare prima di entrare nella routine di interrupt hai perfettamente ragione. Però non mi sembrano critici dato che, praticamente, i registri KeyCodex vengono sempre sovrascritti.

Link al commento
Condividi su altri siti

  • 2 weeks later...

Ma se non conti il tempo con precisione come fai a sapere se sei a metà bit?

Anche se il tuo codice è relativamente semplice, è opportuno che tu tratti nel modo giusto gli interrupt, onde evitare imprevisti. E' una questione di principio. Anche nei pochi esempi nel datasheet mostra come fare.

Link al commento
Condividi su altri siti

Semplicemente attendo fino al primo fronte di salita. Questo vuol dire che ho beccato il primo bit di start che è un 1. Per sapere se il bit che leggo è 1 o 0 leggo il valore dell'ingresso subito dopo il fronte che è appena arrivato; se esso è alto il valore è "1", se esso è basso il valore è "0".

Comunque praticamente gestisco quell'interrupt con la sua routine utilizzando gli INTERRUPT-ON-CHANGE presenti sui pin del PORTB.

Link al commento
Condividi su altri siti

  • 4 weeks later...

Allora, fino ad ora sembra funzionare tutto bene. Ho simulato il programma e funziona anche la teorica parte di programmazione del sensore.

L'unico fatto è che ultimamente ho notato problemi all'uscita del PIC quando sono in modalità di lettura (ovvero la modalità di default, quando l'accelerometro trasmette segnali al pic e il pic effettua la decodifica Manchester).

Mi spiego meglio: a volte fornisco alimentazione al circuito e il segnale in uscita del PIC è esattamente quello che mi aspetto. A volte, invece, alimento l'intero circuito e in uscita ho un bel "0" costante. Altre volte, invece, alimento l'intero circuito e per qualche secondo ho in uscita dal pic uno "0"; dopo un pò, invece, inizia a comparire il segnale che mi aspetterei.

Pensavo fosse un problema di oscillazione del quarzo; per questo motivo, ora, ho spostato la parte del pic su millefori in modo da effettuare collegamenti più "stabili" e più corti. Utilizzo un quarzo da 20MHz e ho collegato i 2 condensatori da 18pF il più vicino possibile al quarzo e al pic.

Mi sembra che il problema sia proprio il quarzo perchè con l'oscilloscopio a volte vedo delle sinusoidi sul pin CLKIN mentre sul CLKOUT un valore costante di tensione. A volte, invece, vedo su entrambi i pin delle sinusoidi. Qual è il segnale corretto che devo visualissare sui 2 pin sui quali è connesso il quarzo?

Secondo voi qual è il problema?

Il programma, comunque, l'ho debuggato interamente: è perfettamente funzionante a livello di simulatore al pc. La cosa strana è che prima funzionava tutto... poi, un pò alla volta, ho visto che alcune volte non funzionava... Ultimamente, invece, sono più le volte che non funziona. . xD

Modificato: da MusicIsLife
Link al commento
Condividi su altri siti

mi sembra strano che su un pin ci sia l'oscillazione e sull'altro no... come farebbe ad oscillare?... il quarzo non oscilla di sua iniziativa.

Di solito si vede l'onda su entrambi i pin, ma su uno ha un'ampiezza minore.

Se il Pic ha difficoltà ad oscillare potresti provare a fare un'oscillatore esterno...

Il PIC lo alimenti a 5 Volt?

Il pin di reset è collegato?

Io continuo a pensare che questo è sbagliato, o ti sei spiegato male, oppure la decodifica così non può funzionare.

l'1 logico non ce l'hai su "qualsiasi" fronte di salita... ma solo su quelli che accadono in un particolare momento!

E quì ritiro in ballo il famoso timer, indispensabile per capire quel momento.

smile.gif

Link al commento
Condividi su altri siti

Ho sistemato i collegamenti e cambiato PIC. Non chiedetemi perchè ma il 16F886 non riuscivo a farlo oscillare a 20MHz neppure cambiando tutte e due le capacità.

Ho usato un 16F628A e con quello oscilla senza problemi.

Inoltre il pin dell MCLR è collegato con una resistenza a +5V e il PIC è alimentato a 5V.

Nella configuration map ho ovviamente impostato HS come oscillatore esterno.

Misteri dell'elettronica ph34r.gif

Link al commento
Condividi su altri siti

Crea un account o accedi per commentare

Devi essere un utente per poter lasciare un commento

Crea un account

Registrati per un nuovo account nella nostra comunità. è facile!

Registra un nuovo account

Accedi

Hai già un account? Accedi qui.

Accedi ora
×
×
  • Crea nuovo/a...