Indice |
Introduzione
Ciao a tutti.
Eccomi ancora una volta a parlarvi del pic 16F1705 e delle sue straordinarie capacità, questa volta nelle vesti di decodificatore di toni dtmf. Desidero proporvelo, poiché i nostri progetti, senza l’ausilio di decoder dedicati del tipo MT8870, potranno essere più snelli e più semplici. Oltretutto vista l’enorme flessibilità del pic in questione, potremo se lo desideriamo, impostare delle frequenze fuori standard, al fine di ottenere dei toni dtmf personalizzati, naturalmente tutto ciò in abbinamento all’encoder dtmf che vi ho già proposto in passato.
Il raggiungimento di questo risultato è stato possibile grazie al concentrato di tecnologia presente all’interno del pic 16F1705. In particolare mi riferisco al blocco DAC, ADC ed alla RAM interna, non di grandi dimensioni è vero, ma sufficiente al nostro scopo. La tecnica da me utilizzata per la decodifica dei segnali, è nota come “Autocorrelazione dei segnali periodici”, di cui per la verità non sapevo assolutamente nulla, e che avrei continuato ad ignorare se non fosse stato per il mio amico "Daniels118", che mi ha parlato per la prima volta di questa tecnica e che ringrazio per i suggerimenti.
Autocorrelazione
In estrema sintesi, l’autocorrelazione consiste nel sommare ad un segnale periodico quanto si voglia complesso, se stesso, però ritardato di un certo tempo “t”. Accade che, fra tutti i segnali presenti all’ingresso del sommatore, uno sarà annullato, cioè quello il cui ritardo “t” corrisponde al suo semiperiodo. Solo in questo caso infatti i due segnali diretto e ritardato, si presenteranno all’ingresso del sommatore in opposizione di fase, cioè sfasati tra loro di 180°, per cui si elideranno a vicenda e non saranno più presenti all’uscita del sommatore, mentre tutti gli altri saranno presenti. Col disegnino che segue spero di essere più esplicito.
In poche parole, con tale tecnica è possibile implementare nel pic un filtro notch, cioè un filtro escludi banda, ossia un filtro che non si lascia attraversare dal segnale sinusoidale per il quale è stato progettato. Ciò accade comunemente con l’elettronica analogica, ne abbiamo visti in tutte le salse, dai semplici circuiti LC, ai più sofisticati circuiti con amplificatori operazionali.
Implementare un filtro notch digitale è abbastanza semplice, occorre solo creare una linea di ritardo pari a mezza lunghezza d’onda del segnale ricercato, ed eseguire la somma del segnale diretto e del segnale ritardato. La linea di ritardo ovviamente è costituita da un certo numero di locazioni di memoria RAM, dove si va a scrivere il segnale campionato presente all’ingresso del ADC, e dopo un certo tempo “t” programmabile, si va a rileggerlo per sommarlo al segnale diretto. Accade che, la frequenza il cui semiperiodo è impostato sulla linea di ritardo sarà annullata, azzerata; così come descritto pocanzi.
Decodifica
Immaginiamo adesso di avere due filtri notch digitali in serie, e di poter modificare ed impostare a nostro piacimento, la loro frequenza di funzionamento. Immaginiamo inoltre, di avere all’ingresso di tali filtri, la coppia di toni dtmf relativa al numero “1”, ossia le due frequenze di 1209 Hz e 697 Hz. Vedi tabella.
Come avrete certamente intuito, se i due filtri sono programmati per funzionare uno a 1209 Hz e l’altro a 697 Hz, all’uscita del secondo filtro non troveremo alcun segnale, troveremo cioè zero. Infatti, il primo filtro annullerà il tono a 1209 Hz lasciando passare l’altro, che sarà annullato a sua volta dal secondo filtro, all’uscita del quale non ci sarà più niente.
Supponiamo adesso di non sapere quale sia il tono dtmf all’ingresso dei filtri, per scoprirlo basterà impostare sui filtri notch, una dopo l’altra a rotazione, tutte le sedici coppie di frequenze possibili a noi note, vedi tabella. Ebbene, solo in un caso l’uscita dei filtri sarà zero, e quando ciò accadrà avremo anche trovato le due frequenze che compongono il tono dtmf, e di conseguenza il codice dtmf associato ad esse.
Per tutte le altre coppie, il segnale d’uscita dei filtri sarà diverso da zero, infatti può accadere che un filtro blocchi e non lasci passare una delle due frequenze, ma l’altra passerà, e se non sarà bloccata dal successivo filtro ce la ritroveremo all’uscita, e di conseguenza sapremo che non è quello il tono dtmf che stiamo cercando.
Funzionamento
Per cominciare il segnale d’ingresso viene digitalizzato con una frequenza di campionamento di circa 29,4 Khz, e se il segnale campionato supera il valore prefissato come tensione di soglia, viene memorizzato sulla RAM del pic. La soglia altro non è che una sorta di circuito squelc, indispensabile per evitare di memorizzare il fruscio di fondo del ricevitore.
Questa operazione viene ripetuta fino a memorizzare 240 campioni, per un tempo totale di 8 mS circa, campioni più che sufficienti per consentire le successive operazioni, che naturalmente richiederanno un certo tempo di elaborazione. Questo significa come vedremo più avanti, che già un segnale dtmf dalla durata di appena 25 mS sarà riconosciuto e decodificato correttamente.
A seguire sul segnale così memorizzato, eseguiremo il primo filtraggio, e sarà quindi riletto dalla RAM da due punti differenti. Il primo punto è quello iniziale che chiamiamo segnale diretto, il secondo punto che si trova più avanti che chiamiamo segnale ritardato, dista dal precedente esattamente di un certo numero di locazioni, per un tempo complessivo pari a mezz’onda. I due segnali quindi sono sommati tra loro ed il risultato salvato su un secondo blocco di RAM.
Tali operazioni naturalmente vanno eseguite dalla prima all’ultima cella di memoria, per tutte le 240 locazioni e sempre con lo stesso ritardo; quindi con le coppie n0+n8; n1+n9; n2+n10 e cosi via. Adesso occorre ripetere la stessa procedura adottata per il primo blocco di RAM, anche sul secondo blocco. Supponendo che i ritardi impostati siano quelli giusti, una frequenza sarà annullata dal primo filtro e l’altra dal secondo, ed all’uscita del secondo blocco ci ritroveremo zero.
Se così sarà, vuol dire che quelle sono le due frequenze che componevano il tono dtmf che abbiamo quindi individuato. Se così invece non sarà, ripeteremo per sedici volte le operazioni di filtraggio, cambiando di volta in volta i ritardi introdotti in modo appropriato, fino a quando almeno per una di tali operazioni il risultato sarà zero, e quando ciò accadrà sapremo anche che quello è il tono riconosciuto e decodificato.
Questa tecnica non è tra le più sofisticate, ma il software di volta in volta, adegua automaticamente i valori delle tensioni di soglia, all’ampiezza del segnale in ingresso all’ADC, ed alle ampiezze in uscita dai due filtri. Tali adeguamenti ricavati dal valore di picco di tutti i campioni memorizzati, consentono una corretta decodifica dei toni dtmf nel cento per cento dei casi, e per una vasta gamma di valori di tensione in ingresso.
Per la precisione, ci tengo a specificare che nella realtà, dato che si lavora sulle ampiezze dei segnali, all’uscita dei filtri non sempre otterremo proprio zero, ma sicuramente il segnale decodificato avrà la minore ampiezza rispetto a tutti gli altri quindici dtmf. Vedi figura che segue.
Essendo la frequenza di clock del pic pari a 32 MHz, le operazioni di riconoscimento del dtmf sono eseguite in pochissimi mS, ed effettuando delle prove con un generatore di segnali dtmf esterno, ho potuto verificare che i toni sono decodificati correttamente, anche quando la loro durata è pari a 25 ms con una pausa di intertono di 50 mS. Ciò significa che in un secondo, il circuito che vi propongo può decodificare correttamente una raffica di 13 DTMF circa.
Lo schema elettrico come visibile dalla figura che segue, è veramente ridotto all’osso. Troviamo il solo pic, che oltre ad occuparsi della decodifica dei toni deve pilotare anche il display, e se aggiungiamo altro software, sarà possibile realizzare ad esempio una chiave dtmf senza l’ausilio di decodificatori dedicati, o tutto ciò che la nostra fantasia può immaginare.
Il primo potenziometro collegato al display serve a regolarne il contrasto. Il secondo, bisogna regolarlo fino a leggere sul suo pin centrale evidenziato dal pallino rosso, una tensione di circa 1,3V, questo sarà il valor medio di tutti i campioni memorizzati. Al centro tra le due resistenze da 15K, deve essere presente una tensione di 2,5V, che sarà la tensione di riferimento massima per il convertitore ADC del pic.
Nel circuito non ci sono altri punti di taratura, Per le mie prove ho sempre prelevato il segnale dalla presa dell’altoparlante esterno del mio ricevitore VHF, con un livello del segnale di circa 1,5V; anche se ho verificato che regolando il volume, per livelli di tensione compresi tra 0.6 e 2 Vpp, la decodifica è sempre stata perfetta.
A seguire troverete il File.asm, che ho corredato di varie note e che vi invito ad approfondire, perché permette d’implementare funzioni che altrimenti con altri linguaggi non sarebbero assolutamente possibili.
Buon lavoro e buon divertimento.
Saluti….it9dpx
Francesco Mira. #135
;************************* ; DTMF DECODER 02 07 2016 ; REGISTRO SU RAM DEL PIC PER 8MS CIRCA ; RILEGGO SEGNALE SENZA INTERRUPT ELIMINO TONO BASSO E RISCRIVO ; RILEGGO SEGNALE SENZA INTERRUPT ELIMINO TONO ALTO E RISCRIVO ; RILEGGO SEGNALE PRIVO DI TONI ; provo con tute le combinazioni di ritardi ; buon compromesso per tutti i toni ; ESEGUO (A+B)/2 ; A FINE ELABORAZIONE INVIO NUMERO DI TONO AD RC0 RA2 RA4 RA5 ; FUNZIONA BENE ENTRO UN'AMPIA ESCURSIONE DI VPP D'INGRESSO ; impulso out di interrupt se tono è valido ; una sola passata di tutte le combinazioni ; 32 ms per la decodifica 24 ms per l'interrupt ; DECODIFICA CONTINUAMENTE ; controllo dello squelc ; INVIO DATI DECODIFICATI AL DISPLAY CON LATC,1 ; RC0 = OUT D6 ; RC1 = N.C. ; RC2 = OUT D4 ; RC3 = ING. B.F. ; RC4 = OUT RS ; RC5 = OUT CK (EN) ; RA0 = ICSP ; RA1 = V.REF ADC ICSP ; RA2 = OUT D7 ; RA3 = ICSP ; RA4 = OUT D5 ; RA5 = N.C. ;************************* PROCESSOR 16F1704 RADIX DEC INCLUDE "P16F1704.INC" ERRORLEVEL -302 ERRORLEVEL -305 CBLOCK 70H ; ORG 0170H ; 130H INC_PASSO TEMP_PASSO PASSO_A PASSO_B RIT : 2 PASSATA CONTATORE VALORE_VPP VALORE_MIN VALORE_MAX LIVEL_TONO NUMER_TONO REGTEMP CONT16CHR ENDC __CONFIG H'8007', H'3FA4' __CONFIG H'8008', H'1FFF' #define RS PORTC,4 #define CK PORTC,5 ORG 00H GOTO VIA ;----INTERRUPT--------- ORG 04 ; NOP ; NOP ; NOP NOP MOVLB 0 MOVLW 124 MOVWF TMR0 BTFSC PASSATA,5 GOTO PROSSIMO CALL SQUELC GOTO FINE_INT PROSSIMO BTFSC PASSATA,0 GOTO PROSSIMO_1 CALL REGISTRA_BUFFER_1 GOTO FINE_INT PROSSIMO_1 BTFSC PASSATA,6 GOTO PROSSIMO_2 CALL RILEGGI GOTO FINE_INT PROSSIMO_2 BTFSC PASSATA,7 GOTO PROSSIMO_3 CALL FINE_TONO GOTO FINE_INT PROSSIMO_3 CLRF PASSATA FINE_INT BCF INTCON,2 RETFIE ;----FINE INTERRUPT------- VIA MOVLB 1 MOVLW B'00000011' MOVWF TRISA MOVLW B'00001000' MOVWF TRISC MOVLB 3 MOVLW B'00001000' MOVWF ANSELC CLRF ANSELA MOVLB 0 MOVLW 135 MOVWF TMR0 MOVLW B'00000000' MOVWF PORTC MOVLW B'00000000' MOVWF LATA MOVLB 2 CLRF CM1CON0 CLRF CM2CON0 ; MOVLW B'10000000' ; MOVWF DAC1CON0 MOVLB 10 ; MOVLW B'10010010' CLRF OPA1CON CLRF OPA2CON MOVLB 30 CLRF CLC1CON CLRF CLC2CON CLRF CLC3CON MOVLB 1 MOVLW B'00011101' MOVWF ADCON0 MOVLW B'01100010' MOVWF ADCON1 MOVLW B'00000000' MOVWF ADCON2 MOVLW B'11110000' ;26mS MOVWF OSCCON CLRF OPTION_REG ;,7 ;pull-up ;------------------- ; MOVLB 3 ; MOVLW B'00001000' ;MOVLW B'00010000' ; MOVWF ANSELC ;MOVWF ANSELA ;---------------- CLRF INC_PASSO CLRF PASSATA CALL INIZ_LCD MOVLB 1 MOVLW B'10100000' MOVWF INTCON ;----------------------- ATTESA ; goto prova NOP NOP NOP NOP NOP GOTO ATTESA REGISTRA_BUFFER_1 ;----------------------------------- ;-----scrivo un byte nella ram------ ;inizializzo ram BTFSC PASSATA,3 GOTO FINIZIALIZ_FINE CALL INIZIALIZZO_RAM_1 MOVLW .2 MOVWF RIT+1 MOVLW .224 MOVWF RIT+0 FINIZIALIZ_FINE ;avvio nuova ADC MOVLB 1 BSF ADCON0,ADGO ;ADC terminata ? BTFSC ADCON0,ADGO GOTO $-1 MOVFW ADRESH ;scrivo dato ; MOVLW .33 ;TOGLIERE DOPO MOVWF INDF0 MOVLB .31 INCF FSR0L_SHAD BTFSC STATUS,Z INCF FSR0H_SHAD DECFSZ RIT+0 RETURN DECFSZ RIT+1 RETURN ;fine memoria BSF PASSATA,0 ;fine_registrazione BCF PASSATA,3 ;bit inizializzazione MOVLW .255 ;prepara alla decodifica MOVWF LIVEL_TONO RETURN ;----fine scrittura------ ;------------------------ SPOSTA_BUFFER_2A1 ;inizializzo ram CALL INIZIALIZZO_RAM_1 CALL INIZIALIZZO_RAM_2A INIZ_FATTA MOVFW INDF1 MOVWF INDF0 MOVLB .31 INCF FSR1L BTFSC STATUS,Z INCF FSR1H INCF FSR0L BTFSC STATUS,Z INCF FSR0H DECFSZ CONTATORE GOTO INIZ_FATTA BCF PASSATA,3 ;bit inizializzazione RETURN ;--------------------------- INIZIALIZZO_RAM_1 MOVLW .240 MOVWF CONTATORE ;fine memoria ;inizio indirizzamento indicizzato MOVLB .31 MOVLW 0X00 MOVWF FSR0L MOVWF FSR0L_SHAD MOVLW 0X20 MOVWF FSR0H_SHAD MOVWF FSR0H BSF PASSATA,3 RETURN ;------------------------ ;--------------------------- INIZIALIZZO_RAM_2 MOVLW .240 MOVWF CONTATORE ;fine memoria INIZIALIZZO_RAM_2A ;inizio indirizzamento indicizzato MOVLB .31 MOVLW 0XF0 MOVWF FSR1L MOVWF FSR1L_SHAD MOVLW 0X20 MOVWF FSR1H_SHAD MOVWF FSR1H BSF PASSATA,3 RETURN ;------------------------ ;------------------------ INIZIALIZZO_RAM_3 MOVLB .31 MOVFW PASSO_A ;MOVLW .10 ;valore del salto MOVWF FSR1L MOVWF FSR1L_SHAD MOVLW 0X20 MOVWF FSR1H_SHAD MOVWF FSR1H RETURN ;------------------------ ;------------------------ INIZIALIZZO_RAM_4 MOVLB .31 MOVFW PASSO_B ;MOVLW .18 ;valore del salto MOVWF FSR1L MOVWF FSR1L_SHAD MOVLW 0X20 MOVWF FSR1H_SHAD MOVWF FSR1H RETURN ;------------------------ PROVA_SALTI INCF INC_PASSO MOVFW INC_PASSO ANDLW .3 CALL SALTO_A MOVWF PASSO_A RRF INC_PASSO,W MOVWF TEMP_PASSO RRF TEMP_PASSO,W ANDLW .3 CALL SALTO_B MOVWF PASSO_B RETURN SALTO_A ADDWF PCL RETLW .12 RETLW .11 RETLW .10 RETLW .9 SALTO_B ADDWF PCL RETLW .21 RETLW .19 RETLW .17 RETLW .16 ;------------------------ TABELLA CLRF PCLATH ADDWF PCL RETLW "1" RETLW "2" RETLW "3" RETLW "A" RETLW "4" RETLW "5" RETLW "6" RETLW "B" RETLW "7" RETLW "8" RETLW "9" RETLW "C" RETLW "*" RETLW "0" RETLW "#" RETLW "D" ;--------------- ELIMINA_TONO_BASSO ;inizializzo ram CALL INIZIALIZZO_RAM_1 CALL INIZIALIZZO_RAM_4 GOTO NO_INIZIALIZZ ELIMINA_TONO_ALTO ;inizializzo ram CALL INIZIALIZZO_RAM_1 CALL INIZIALIZZO_RAM_3 NO_INIZIALIZZ MOVFW INDF1 ; leggo dato da ram con salto ADDWF INDF0 ; sommo dato alla ram RRF INDF0 ; diviso due annullo tono DECFSZ CONTATORE GOTO INCREMENTA_MEM RETURN INCREMENTA_MEM MOVLB .31 INCF FSR1L BTFSC STATUS,Z INCF FSR1H INCF FSR0L BTFSC STATUS,Z INCF FSR0H GOTO NO_INIZIALIZZ ;RETURN ;---fine lettura 2 byte------- ;----------------------------- ;////////////////////////// ;////////////////////////// RILEGGI ;-----leggo tono alto dalla ram------ ;inizializzo ram BTFSC PASSATA,3 GOTO NO_INIZIALIZ CALL SPOSTA_BUFFER_2A1 CALL ELIMINA_TONO_BASSO CALL ELIMINA_TONO_ALTO CALL INIZIALIZZO_RAM_1 MOVLW .200 MOVWF CONTATORE ;fine memoria NO_INIZIALIZ MOVFW INDF0 ; leggo dato da ram MOVLB 2 MOVWF DAC1CON1 ;invio all'adc ;---salvo apiezza tono decodificato--- TROVA_TONO BTFSC PASSATA,4 GOTO DECRE_AMP BSF PASSATA,4 MOVWF VALORE_MAX ;1^ dato di riferimento MOVWF VALORE_MIN ;1^ dato di riferimento GOTO INCRE_FSR DECRE_AMP MOVFW INDF0 ; leggo dato da ram SUBWF VALORE_MIN,W BTFSS STATUS,C ; è> o è< ? GOTO INCRE_AMP ;è> MOVFW INDF0 ; leggo dato da ram MOVWF VALORE_MIN ;è< GOTO INCRE_AMP INCRE_AMP MOVFW INDF0 ; leggo dato da ram SUBWF VALORE_MAX,W BTFSC STATUS,C ; è> o è< ? GOTO INCRE_FSR ;è< MOVFW INDF0 ; leggo dato da ram MOVWF VALORE_MAX ;è> GOTO INCRE_FSR INCRE_FSR ;--fine controllo ampiezza---- DECFSZ CONTATORE GOTO INCREMENTA_2 BCF PASSATA,4 ;nuovo tono MOVFW VALORE_MIN ;calcolo Vpp SUBWF VALORE_MAX,W MOVWF VALORE_VPP ;salvo Vpp SUBWF LIVEL_TONO,W BTFSS STATUS,C GOTO AMP_MAGG MOVFW VALORE_VPP MOVWF LIVEL_TONO ;salvo la minore Vpp MOVFW INC_PASSO ANDLW .15 MOVWF NUMER_TONO ;salvo num. del tono AMP_MAGG CALL PROVA_SALTI MOVFW INC_PASSO ANDLW .15 ;passaggio per lo zero BTFSS STATUS,Z GOTO ANCORA_TONO ;---controllo tono valido--- MOVFW LIVEL_TONO SUBLW .16 BTFSS STATUS,C GOTO NO_TONO_VALIDO ; MOVLB 0 ; MOVLW B'00000000' ; MOVWF LATA CALL TX_LED ;CALL TX_TONO ; BSF PORTC,1 ;invio impulso ; CALL RITARDO ; BCF PORTC,1 ;invio impulso BSF PASSATA,6 NO_TONO_VALIDO BCF PASSATA,0 ;nuova_registrazione BCF PASSATA,3 ;nuova_registrazione RETURN GOTO $-1 ;fine ricerca tono ;---fine controllo tono valido--- MOVLW .255 ;prepara alla decodifica MOVWF LIVEL_TONO ANCORA_TONO BCF PASSATA,3 ;bit inizializzazione GOTO RILEGGI INCREMENTA_2 MOVLB .31 INCF FSR0L BTFSC STATUS,Z INCF FSR0H GOTO RILEGGI ;^^^^^^^^^^^^^^^^^^^^^^^^ ;^^^^^^^^^^^^^^^^^^^^^^^^ RITARDO movlw .127 movwf RIT+0 movlw .255 movwf RIT+1 decfsz RIT+1 goto $-1 decfsz RIT+0 goto $-3 RETURN ; fine pausa ;*************************** TX_LED MOVLB 2 MOVFW NUMER_TONO ANDLW .15 CALL TABELLA call TXDATO INCF CONT16CHR BTFSS CONT16CHR,4 ; 16 CARATTERI INVIATI? RETURN MOVLW 80H CALL TXCMD CLRF CONT16CHR RETURN ;--------------------------------- ;***controllo livello di squelc*** SQUELC ;avvio nuova ADC MOVLB 1 BSF ADCON0,ADGO ;ADC terminata ? BTFSC ADCON0,ADGO GOTO $-1 MOVFW ADRESH SALVA_RIF_AMP BTFSC PASSATA,4 GOTO MINORE_AMP BSF PASSATA,4 MOVWF VALORE_MAX ;1^ dato di riferimento MOVWF VALORE_MIN ;1^ dato di riferimento MOVLW .50 ;tempo d'ascolto MOVWF CONTATORE MOVLW .16 ;livello di squelc MOVWF LIVEL_TONO GOTO FINE_CONTROLLO MINORE_AMP MOVFW ADRESH ; leggo dato da adc SUBWF VALORE_MIN,W BTFSS STATUS,C ; è> o è< ? GOTO MAGGIORE_AMP ;è> MOVFW ADRESH ; leggo dato da adc MOVWF VALORE_MIN ;è< GOTO MAGGIORE_AMP MAGGIORE_AMP MOVFW ADRESH ; leggo dato da adc SUBWF VALORE_MAX,W BTFSC STATUS,C ; è> o è< ? GOTO FINE_CONTROLLO ;è< MOVFW ADRESH ; leggo dato da adc MOVWF VALORE_MAX ;è> GOTO FINE_CONTROLLO FINE_CONTROLLO DECFSZ CONTATORE RETURN BCF PASSATA,4 ;prepara per nuovo controllo MOVFW VALORE_MIN ;calcolo Vpp SUBWF VALORE_MAX,W ;nuova Vpp SUBWF LIVEL_TONO,W ;livello di squelc BTFSS STATUS,C GOTO SEGNALE_PRESENTE RETURN ;assenza di segnale SEGNALE_PRESENTE BSF PASSATA,5 ;presenza di segnale RETURN ;***fine controllo livello di squelc*** ;--------------------------------- ;***controllo livello di squelc*** FINE_TONO ;avvio nuova ADC MOVLB 1 BSF ADCON0,ADGO ;ADC terminata ? BTFSC ADCON0,ADGO GOTO $-1 MOVFW ADRESH SALVA_RIF_AMP1 BTFSC PASSATA,1 GOTO MINORE_AMP1 BSF PASSATA,1 MOVWF VALORE_MAX ;1^ dato di riferimento MOVWF VALORE_MIN ;1^ dato di riferimento MOVLW .50 ;tempo d'ascolto MOVWF CONTATORE MOVLW .16 ;livello di squelc MOVWF LIVEL_TONO GOTO FINE_CONTROLLO1 MINORE_AMP1 MOVFW ADRESH ; leggo dato da adc SUBWF VALORE_MIN,W BTFSS STATUS,C ; è> o è< ? GOTO MAGGIORE_AMP1 ;è> MOVFW ADRESH ; leggo dato da adc MOVWF VALORE_MIN ;è< GOTO MAGGIORE_AMP1 MAGGIORE_AMP1 MOVFW ADRESH ; leggo dato da adc SUBWF VALORE_MAX,W BTFSC STATUS,C ; è> o è< ? GOTO FINE_CONTROLLO1 ;è< MOVFW ADRESH ; leggo dato da adc MOVWF VALORE_MAX ;è> GOTO FINE_CONTROLLO1 FINE_CONTROLLO1 DECFSZ CONTATORE RETURN BCF PASSATA,1 ;prepara per nuovo controllo MOVFW VALORE_MIN ;calcolo Vpp SUBWF VALORE_MAX,W ;nuova Vpp SUBWF LIVEL_TONO,W ;livello di squelc BTFSC STATUS,C GOTO SEGNALE_ASSENTE RETURN ;presenza di segnale SEGNALE_ASSENTE BSF PASSATA,7 ;assenza di segnale RETURN ;***fine controllo livello di squelc*** ;------------------------------ ;......INIZ_LCD................. INIZ_LCD MOVLB 2 bcf RS bcf CK movlw .250 ;Wait 30 ms call msDelay ; MOVLW 30H ;Set LCD command mode BCF LATA,2 ;D7 Send a reset sequence to LCD BCF LATC,0 ;D6 Send a reset sequence to LCD BSF LATC,1 ;D5 Send a reset sequence to LCD BSF LATC,2 ;D4 Send a reset sequence to LCD CALL CARICA CALL CARICA CALL CARICA ; MOVLW 20H ;Set LCD command mode BCF LATA,2 ;D7 Set LCD command mode BCF LATC,0 ;D6 Set LCD command mode BSF LATC,1 ;D5 Set LCD command mode BCF LATC,2 ;D4 Set LCD command mode CALL CARICA movlw 28H ;Set 4 bit TX, 2 RIGHE call TXCMD movlw 06H ;Entry mode set, increment, no shift call TXCMD movlw 0FH ;Display ON, Curson ON, Blink ON call TXCMD movlw 01H ;Clear display call TXCMD movlw .17 ;Wait 2 ms call msDelay ;............................ ripetizione ; BSF LATC,1 MOVLW H'CA' ;DD RAM 18° CIFRA CALL TXCMD MOVLW "I" call TXDATO MOVLW "T" call TXDATO MOVLW "9" call TXDATO MOVLW "D" call TXDATO MOVLW "P" call TXDATO MOVLW "X" call TXDATO MOVLW H'80' ;DD RAM 1° CIFRA CALL TXCMD ; BCF LATC,1 ATTENDI CALL PAUSA ; goto ripetizione return ;.............................. TXNUM ADDLW 30H TXDATO bsf RS call TXBYTE return TXCMD bcf RS call TXBYTE return TXBYTE movwf REGTEMP ;Save value to send ;tx 4 bits alti BCF LATA,2 ;D7 BCF LATC,0 ;D6 BCF LATC,1 ;D5 BCF LATC,2 ;D4 BTFSC REGTEMP,7 BSF LATA,2 ;D7 BTFSC REGTEMP,6 BSF LATC,0 ;D6 BTFSC REGTEMP,5 BSF LATC,1 ;D5 BTFSC REGTEMP,4 BSF LATC,2 ;D4 nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop bsf CK ; clock fase 2 nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop bcf CK ;tx 4 bits bassi BCF LATA,2 ;D7 BCF LATC,0 ;D6 BCF LATC,1 ;D5 BCF LATC,2 ;D4 BTFSC REGTEMP,3 BSF LATA,2 ;D7 BTFSC REGTEMP,2 BSF LATC,0 ;D6 BTFSC REGTEMP,1 BSF LATC,1 ;D5 BTFSC REGTEMP,0 BSF LATC,2 ;D4 nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop bsf CK ; clock fase 2 nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop bcf CK movlw .16 ;Wait 2ms call msDelay RETURN CARICA movlw .10 ;Wait 1ms call msDelay bsf CK ;Enables LCD movlw .10 ;Wait 1ms call msDelay bcf CK ;Disables LCD movlw .10 ;Wait 1ms call msDelay return ;------------------------ msDelay movwf RIT+1 clrf RIT+0 RITLOOP nop decfsz RIT+0,F goto RITLOOP nop decfsz RIT+1,F goto RITLOOP return ;----------------------------- PAUSA movlw .250 ;Wait 250 ms call msDelay movlw .250 ;Wait 250 ms call msDelay RETURN ;------ 2° RIGA ------ MOVLW H'80' ;DD RAM 18° CIFRA CALL TXCMD ;----------------------------- NOP NOP RETURN ;----------------------- END