Problema Pic16f887 lettura e stampa temperatura

di il
8 risposte

Problema Pic16f887 lettura e stampa temperatura

Salve a tutti!
Sto provando a realizzare un programma per il Pic 16f887 montato in una picboard per un progetto universitario:
Il pic è inizialmente in stato di sleep per poi risvegliarsi ogni 5 secondi, leggere il valore di temperatura, stamparlo nel formato a due cifre sulla porta seriale eusart e poi tornare in sleep.
Ho messo anche il lampeggio di un led ad ogni lettura.
Per contare 5 secondi ho utilizzato il timer1 e gestisco la lettura della temperatura (conversione adc inclusa) tramite interrupt.
Il problema è che stampa ogni 5 secondi con il relativo lampeggio, ma valori senza alcun senso.
Aiuto please!




;
; Descrizione software:
; - Microcontrollore in sleep
; - Uscita dallo sleep ogni 5 secondi (all'overflow del timr1)
; - Lettura e stampa temperatura su seriale EUSART
; - Accensione/spegnimento LED ad indicare stato sleep
;   

 

; Descrizione hardware:
; - scheda Cedar Pic Board (vedere schematico).
;   - MCU: PIC16F887 (clock interno 4 MHz)




; ***********************************************************
		
		list	 p=16f887       ; direttiva che definisce il tipo di processore
		#include <p16f887.inc>	; file che contiene le definizioni dei simboli (nomi registri, nomi bit dei registri, ecc).
		#include "macro.inc"  ; definizione di macro utili
				
		;**********************************************************************
; *** Configuration bits ***
; I bit di configurazione (impostazioni dell'hardware settate in fase di
; programmazione del dispostitivo) sono definiti
; tramite una direttiva nel codice.
; Impostazioni importanti:
; - Wathcdog timer disattivato (_WDT_OFF).
; - Low voltage programming disattivato (_LVP_OFF), altrimenti il pin RB3 (porta B)
;   non puo' essere utilizzato come I/O generico.
		
__CONFIG _CONFIG1, _INTRC_OSC_NOCLKOUT & _CP_OFF & _WDT_OFF & _BOR_OFF & _PWRTE_OFF & _LVP_OFF & _DEBUG_OFF & _CPD_OFF
	
	

		
tmr_5s	  EQU (.65536 - .20480) ;(setto prescaler per contare 5s)


		; variabili in RAM (shared RAM)
		UDATA_SHR
fsr_temp	RES		.1			;variabile per salvare fsr quando entro/esco da routine interrupt
temperature	RES		.2			;variabile per decine
tmp		RES	        .2			;variabile temporanea e per unita
w_temp		RES		.1			;variabile per salvare W quando entro/esco da routine interrupt
status_temp	RES		.1			;variabile per salvare contenuto registro STATUS quando entro/esco da routine interrupt
pclath_temp	RES		.1			;variabile per salvare contenuto registro PCLATH quando entro/esco da routine interrupt
cansleep	RES		.1

		; reset vector (quando viene premuto il pulsante di reset questa è la prima operazione che viene eseguita)
rst_vector	CODE	0x0000
		pagesel start
		goto start

;********************************************MAIN***************************************************************************	
		; programma principale
MAIN		CODE
start
		pagesel initHw
		call initHw       ; inizializzazione hardware
		
		 
		; abilita interrupt timer1
		setRegK PIE1, B'00000001'  
		; Abilita interrupt delle periferiche (tra cui timer1) 
		BANKSEL INTCON
		bsf	INTCON, PEIE
		
		PAGESEL	reload_timer1
		call	reload_timer1
		bsf	cansleep,0
		
main_loop
			; Dato che tutto il lavoro e' svolto dalla routine di interrupt,
			; il programma principale potrebbe mandare il microcontrollore
			; in modalita' sleep per essere risvegliato dal successivo
			; interrupt.
			; Utilizziamo percio' un bit che indica quando il programma puo'
			; andare in sleep, che sara' settato dall'interrupt quando opportuno.

waitSleep
		bcf	INTCON, GIE	; disabilita interrupt globalmente
									
		btfsc	cansleep, 0	; verifico possibilità di ingresso nello stato di sleep
		goto	goSleep
		bsf	INTCON, GIE
		goto	waitSleep
goSleep
		                    
		BANKSEL	PORTD
		bcf	PORTD,3	; spegne LED4 prima di sleep
		
		sleep		; la CPU si ferma!
		
		;(*******************************INTERRUPT********************************************)
			; a questo punto la CPU si e' risvegliata per via di un
			; interrupt, che nel nostro caso puo' essere solo il timer1.
			; Avendo riabilitato gli interrupt (bit GIE), viene subito
			; eseguita la routine di interrupt, quindi il programma
			; continua.
		;(*******************************INTERRUPT********************************************)	
		BANKSEL	PORTD				   
		bsf	PORTD,3			; accende LED4 dopo risveglio
		
		bsf	INTCON, GIE

		
		goto	main_loop		; ripete il loop principale del programma


			
;********************************************MAIN***************************************************************************		
			
			
			
			
reload_timer1
		; ricarica contatore timer1 per ricominciare conteggio.
		; In modalita' asincrona, occorre arrestare il timer prima
		; di aggiornare i due registri del contatore
		banksel	T1CON
		bcf	T1CON, TMR1ON	; arresta timer
		; le funzioni "low" e "high" forniscono il byte meno e piu'
		;  significativo di una costante maggiore di 8 bit
		banksel	TMR1L
		movlw	low  tmr_5s
		movwf	TMR1L
		movlw	high tmr_5s
		movwf	TMR1H
		banksel	PIR1
		bcf     PIR1, TXIF	
		banksel	T1CON
		bsf	T1CON, TMR1ON	; riattiva timer
		bsf	cansleep,0
		return

;************************************INIZIO ROUTINE INTERRUPT************************************
		
IRQ			CODE	0x0004
INTERRUPT
		; Salvataggio stato registri CPU (context saving).
		; A differenza di quasi tutte le altre architetture, il PIC non salva lo stato
		; della CPU automaticamente all'ingresso di un interrupt (e non lo ripristina
		; all'uscita). Questo perche' non esiste uno stack utilizzabile genericamente,
		; ma solo uno stack limitato al salvataggio ed al ripristino di PC.
		; In genere quindi, per assicurare che il programma principale funzioni sempre
		; correttamente anche in presenza di interrupt, occorre gestire queste due
		; fasi manualmente. I registri da salvare per il PIC16 sono W, STATUS e PCLATH.
		
		movwf	w_temp			; copia W in w_temp
		swapf	STATUS,w		; inverte i nibble di STATUS salvando il risultato in W.
						; Questo trucco permette di copiare STATUS senza alterarlo
						; (swapf e' una delle poche istruzioni che non alterano i bit di stato).
		movwf	status_temp
		movf	PCLATH,w		; copia il registro PCLATH in W (registro da salvare perché contiene i
						; bit più significativi del program counter, usati da GOTO e CALL,
						; e settati dalla direttiva pagesel).
		movwf	pclath_temp		; copia W (= PCLATH) in pclath_temp.
			
		movf FSR, w
		movwf fsr_temp			; altro registro usato dalla routine
						;  e quindi da salvare
		
		banksel PIR1			
		btfss PIR1, TMR1IF		; controllo se proprio il timer1 mi ha fatto entrare in interrupt
		goto $-1
		banksel PIE1			
		btfss PIE1, TMR1IE		
		goto $-1			
		banksel PIR1			
		bcf PIR1, TMR1IF
;*******************************************ADC************************************************************************************		

		
		PAGESEL	readAdc
		call	readAdc      ; chiama routine lettura ADC con canale 6
		PAGESEL	computeTemp
		call	computeTemp  ; calcola valore effettivo di temperatura
		PAGESEL	formatNumber
		call	formatNumber; formatta numero in 2 cifre decimali
		banksel	PIR1
		bcf	PIR1,ADIF
		PAGESEL	reload_timer1
		call	reload_timer1
		goto	irq_end  
readAdc
		; Legge valore analogico dal canale 6
		
		banksel ADCON0 
		bsf ADCON0,GO       ; inizia conversione
		btfsc ADCON0,GO     ; controllo go sia 0
		goto $-1
		banksel ADRESH
		movf ADRESH,w; copia valore campionato in W
		movwf tmp
		banksel ADCON0
		bcf ADCON0, ADON   ; disattiva modulo ADC
		return
computeTemp
		; routine di conversione da tensione a gradi centigradi
		; input:
		;   W: tensione campionata (0-255, corrispondente a 0-3.3 V)
		; output:
		;   W: risultato in gradi
		;
		; Dal datasheet del sensore di temperatura MCP9701A:
		;  T = (Vadc - V0) / Tc   [ dove V0 = 400 mV, Tc = 19.5 mV/C]
		; Convertendo da tensioni a valori binari, si ha:
		;  T = (Nadc - 31) / 1.51
		; che puo' essere approssimata in calcoli interi a 8 bit come:
		;  T = (Nadc - 31) * 2 / 3  [ approssimaz. 1.51 ~= 1.5 = 3/2 ]
		; Questa formula permette di calcolare temperature fino a 84 C
		;  senza incorrere nell'overflow della variabile a 8 bit
		;movwf tmp   ; questo è il valore della temperatura bufferizzato nell'ADC (non è ancora formattato per la stampa!)
		movlw .31
		subwf tmp, f  ; tmp = tmp - 31
		bcf STATUS, C
		rlf tmp, f    ; tmp = tmp * 2 (usando lo shift a sinistra)
		; divisione per 3, effettuata con semplice algoritmo di sottrazioni
		;  successive del valore 3, incrementando ogni volta il risultato,
		;  fino a che il minuendo non diventa negativo
		clrf temperature  ; valore iniziale del risultato = 0 
loop_div3
		movlw .3
		subwf tmp, w          ; w = tmp - 3
		btfss STATUS, C
		goto end_div3         ; se risultato negativo (C=0): fine divisione, se c'è il carry continuo
		movwf tmp             ; tmp = tmp - 3
		incf temperature, f   ; incrementa risultato di 1
		goto loop_div3        ; continua sottrazione
end_div3
		movf temperature,w
		return

		
formatNumber
		; calcolo delle 3 cifre decimali di un numero e scrittura
		;  delle stesse in codice ASCII su printBuff
		; input:
		;   W: valore da formattare
		;
		movwf tmp          ; salva temporaneamente il valore
		; divisione per 100
		clrf temperature          ; risultato della divisione (centinaia)
loop_div100
		movlw .100
		subwf tmp, w       ; w = tmp - 100
		btfss STATUS, C
		goto end_div100    ; se risultato negativo (C=0): fine divisione
		movwf tmp          ; tmp = tmp - 100
		incf temperature, f       ; incrementa risultato di 1
		goto loop_div100   ; continua sottrazione
end_div100
		; "temperature" contiene le centinaia, "tmp" le decine e unita'
		;   (resto della divisione)
		movlw '0'          ; il codice ASCII del carattere '0' sommato
		addwf temperature,w       ;  alla cifra fornisce il codice ASCII della
		;movwf printBuff    ;  cifra in questione
		; divisione per 10
		clrf temperature          ; risultato della divisione (decine)
loop_div10
		movlw .10
		subwf tmp, w       ; w = tmp - 10
		btfss STATUS, C
		goto serial_print     ; se risultato negativo (C=0): fine divisione
		movwf tmp          ; tmp = tmp - 10
		incf temperature, f       ; incrementa risultato di 1
		goto loop_div10    ; continua sottrazione
serial_print	
		; Trasmetto decine 
		movlw '0'
		addwf tmp,w ; w + tmp = w   ; il codice ASCII del carattere '0' sommato alla cifra fornisce il codice ASCII della cifra in questione
		banksel TXREG
		movwf TXREG 
		banksel PIR1
		btfss PIR1,TXIF 
		goto $-1		
		
		; Trasmetto unità 
		movlw '0'
		addwf temperature,w ; w + temperature = w   
		banksel TXREG
		movwf TXREG 
		banksel PIR1
		btfss PIR1,TXIF 
		goto $-1	
		
		; Trasmetto invio
		movlw .10      
		BANKSEL TXREG 
		movwf TXREG   ;scrivo il carattere invio
		banksel PIR1
		btfss PIR1,TXIF  
		goto $-1
		
		return
		
		
		

;************************************ADC*******************************************************************************************************************			
			
;************************************SERIALE************************************
		   
		; "tmp" contiene le decine, "temperature" le unita'
		;   (resto della divisione)

;************************************SERIALE************************************
		

irq_end		       
			movf	fsr_temp,w
			movwf	FSR
			movf	pclath_temp,w	; copia pclath_temp in W
			movwf	PCLATH		; copia W in PCLATH
			swapf	status_temp,w	; inverte i nibble di status_temp salvando il risultato in W
						; anche in questo caso serve a non alterare STATUS stesso
			movwf	STATUS		; copia W (che contiene lo STATUS originale ripristinato dopo 2 inversioni) in STATUS
						; per ripristinare W senza alterare STATUS appena ripristinato, si utilizza sempre swapf
			swapf	w_temp,f	; prima inversione di w_temp, risultato su se stesso
			swapf	w_temp,w	; seconda inversione di w_temp, risultato in W (W contiene il valore precedente all'interrupt)
			bsf	cansleep,0
						  
			retfie			; uscita da interrupt e ritorno al punto in cui il programma era stato interrotto
		
;************************************FIME INTERRUPT************************************
		
initHw		; inizializzazione hardware per scheda PIC Board - Studio

	
		; registro INTCON:
			; - tutti gli interrupt inzialmente disabilitati
			; (verranno abilitati nel programma principale, quando tutte
			;  le periferiche saranno correttamente inizializzate)
		clrf	INTCON

		

		
		
		;port A:
		; RA0-RA5: analog inputs
		; RA6-RA7: digital outputs (flash_ce, bus_switch)
		setRegK PORTA, B'01000000' ; flash_ce = 1
		setRegK ANSEL, B'11111111' ; set RE0-RE2 as analog too
		setRegK TRISA, B'00111111'
		
		;porta D:1..3settato come output (LED)
		setRegK TRISD, 0xF0
		setReg0 PORTD
		
		;ADC
		setRegK ADCON0, B'11011000' ; clock = RC, ch. 6, ADC off  
		setReg0 ADCON1 ; use vdd and vss as reference
		
		
		banksel ANSEL
		setRegK ANSEL, B'11111111'	    ;imposto i pin adc come analogici
		banksel PIR1	
		bcf	PIR1,ADIF	    ;azzero flag ADC	
		
		;portE:
		setReg0	TRISE	    ;abilito porta per il sensore
		
		; Timer1
		; Impostazioni:
		; - usa quarzo esterno (32768 Hz)
		; - modalita' asincrona (funziona con quarzo esterno anche durante sleep)
		; - prescaler = 1:8
		; - Avvio timer in stop
		; Con la frequenza del quarzo ed il prescaler a 8 si ha:
		; - singolo tick ~= 24.414 us
		; - periodo max = 5 s (contatore a 16 bit)
		; - 24.414us ? 1tick = 5 ? x -> x = 5/0,000244141 = 20480 tick -> 65536 - 20480 
		banksel	T1CON
		movlw	B'00111110';(abilito clock esterno ma non sincronizzo con input clock esterno)
		movwf	T1CON

		;EUSART
		; baud rate = 19200 (BRGH = 1, BRG16 = 0) ;(high speed, 8 bit baud rate)
		; TXEN = 1 (abilito trasmissione)
		; SPEN = 1 (abilito seriale)
		; SYNC = 0 (configuro per operazioni asincrone)
		
		banksel TXSTA
		bsf TXSTA,TXEN
		bsf TXSTA,SPEN
		bcf TXSTA,SYNC
		bsf TXSTA,BRGH
		
		banksel RCSTA
		bsf RCSTA,SPEN
		
		banksel BAUDCTL
		bcf BAUDCTL,BRG16
		
		setRegK SPBRG, .12
		return
		;fine codice	
	
	END		;direttiva di fine codice


8 Risposte

  • Re: Problema Pic16f887 lettura e stampa temperatura

    Ho letto molto velocemente ma mi pare ci sia un problema ...

    Nella formatNumber trasformi il valore in ASCII ma poi, quando trasmetti, trasformi nuovamente in ASCII aggiungendo '0' alle cifre.
    Ovviamente così hai caratteri sballati.
  • Re: Problema Pic16f887 lettura e stampa temperatura

    Grazie oregon per la celere risposta.
    Si effettivamente nella "formatNumber" convertivo il valore delle centinaia in ASCII ma questo non influiva poiché stampavo solo decine e unità.
    La stampa ad ogni modo è:
    46
    46
    46<0><e1>

    e atri caratteri strani.
    Chiaramente questi non sono valori di temperatura in gradi centigradi e inoltre non capisco da dove vengono fuori quei caratteri.
    Invio codice aggiornato:
    
    		
    		list	 p=16f887       ; direttiva che definisce il tipo di processore
    		#include <p16f887.inc>	; file che contiene le definizioni dei simboli (nomi registri, nomi bit dei registri, ecc).
    		#include "macro.inc"  ; definizione di macro utili
    				
    		;**********************************************************************
    ; *** Configuration bits ***
    ; I bit di configurazione (impostazioni dell'hardware settate in fase di
    ; programmazione del dispostitivo) sono definiti
    ; tramite una direttiva nel codice.
    ; Impostazioni importanti:
    ; - Wathcdog timer disattivato (_WDT_OFF).
    ; - Low voltage programming disattivato (_LVP_OFF), altrimenti il pin RB3 (porta B)
    ;   non puo' essere utilizzato come I/O generico.
    		
    __CONFIG _CONFIG1, _INTRC_OSC_NOCLKOUT & _CP_OFF & _WDT_OFF & _BOR_OFF & _PWRTE_OFF & _LVP_OFF & _DEBUG_OFF & _CPD_OFF
    	
    	
    
    		
    tmr_5s	  EQU (.65536 - .20480) ;(setto prescaler per contare 5s)
    
    
    		; variabili in RAM (shared RAM)
    		UDATA_SHR
    fsr_temp	RES		.1			;variabile per salvare fsr quando entro/esco da routine interrupt
    temperature	RES		.2			;variabile per decine
    tmp		RES	        .2			;variabile temporanea e per unita
    w_temp		RES		.1			;variabile per salvare W quando entro/esco da routine interrupt
    status_temp	RES		.1			;variabile per salvare contenuto registro STATUS quando entro/esco da routine interrupt
    pclath_temp	RES		.1			;variabile per salvare contenuto registro PCLATH quando entro/esco da routine interrupt
    cansleep	RES		.1
    
    		; reset vector (quando viene premuto il pulsante di reset questa è la prima operazione che viene eseguita)
    rst_vector	CODE	0x0000
    		pagesel start
    		goto start
    
    ;********************************************MAIN***************************************************************************	
    		; programma principale
    MAIN		CODE
    start
    		pagesel initHw
    		call initHw       ; inizializzazione hardware
    		
    		 
    		; abilita interrupt timer1
    		setRegK PIE1, B'00000001'  
    		; Abilita interrupt delle periferiche (tra cui timer1) 
    		BANKSEL INTCON
    		bsf	INTCON, PEIE
    		
    		PAGESEL	reload_timer1
    		call	reload_timer1
    		bsf	cansleep,0
    		
    main_loop
    			; Dato che tutto il lavoro e' svolto dalla routine di interrupt,
    			; il programma principale potrebbe mandare il microcontrollore
    			; in modalita' sleep per essere risvegliato dal successivo
    			; interrupt.
    			; Utilizziamo percio' un bit che indica quando il programma puo'
    			; andare in sleep, che sara' settato dall'interrupt quando opportuno.
    
    waitSleep
    		bcf	INTCON, GIE	; disabilita interrupt globalmente
    									
    		btfsc	cansleep, 0	; verifico possibilità di ingresso nello stato di sleep
    		goto	goSleep
    		bsf	INTCON, GIE
    		goto	waitSleep
    goSleep
    		                    
    		BANKSEL	PORTD
    		bcf	PORTD,3	; spegne LED4 prima di sleep
    		
    		sleep		; la CPU si ferma!
    		
    		;(*******************************INTERRUPT********************************************)
    			; a questo punto la CPU si e' risvegliata per via di un
    			; interrupt, che nel nostro caso puo' essere solo il timer1.
    			; Avendo riabilitato gli interrupt (bit GIE), viene subito
    			; eseguita la routine di interrupt, quindi il programma
    			; continua.
    		;(*******************************INTERRUPT********************************************)	
    		BANKSEL	PORTD				   
    		bsf	PORTD,3			; accende LED4 dopo risveglio
    		
    		bsf	INTCON, GIE
    
    		
    		goto	main_loop		; ripete il loop principale del programma
    
    
    			
    ;********************************************MAIN***************************************************************************		
    			
    			
    			
    			
    reload_timer1
    		; ricarica contatore timer1 per ricominciare conteggio.
    		; In modalita' asincrona, occorre arrestare il timer prima
    		; di aggiornare i due registri del contatore
    		banksel	T1CON
    		bcf	T1CON, TMR1ON	; arresta timer
    		; le funzioni "low" e "high" forniscono il byte meno e piu'
    		;  significativo di una costante maggiore di 8 bit
    		banksel	TMR1L
    		movlw	low  tmr_5s
    		movwf	TMR1L
    		movlw	high tmr_5s
    		movwf	TMR1H
    		banksel	PIR1
    		bcf     PIR1, TXIF	
    		banksel	T1CON
    		bsf	T1CON, TMR1ON	; riattiva timer
    		bsf	cansleep,0
    		return
    
    ;************************************INIZIO ROUTINE INTERRUPT************************************
    		
    IRQ			CODE	0x0004
    INTERRUPT
    		; Salvataggio stato registri CPU (context saving).
    		; A differenza di quasi tutte le altre architetture, il PIC non salva lo stato
    		; della CPU automaticamente all'ingresso di un interrupt (e non lo ripristina
    		; all'uscita). Questo perche' non esiste uno stack utilizzabile genericamente,
    		; ma solo uno stack limitato al salvataggio ed al ripristino di PC.
    		; In genere quindi, per assicurare che il programma principale funzioni sempre
    		; correttamente anche in presenza di interrupt, occorre gestire queste due
    		; fasi manualmente. I registri da salvare per il PIC16 sono W, STATUS e PCLATH.
    		
    		movwf	w_temp			; copia W in w_temp
    		swapf	STATUS,w		; inverte i nibble di STATUS salvando il risultato in W.
    						; Questo trucco permette di copiare STATUS senza alterarlo
    						; (swapf e' una delle poche istruzioni che non alterano i bit di stato).
    		movwf	status_temp
    		movf	PCLATH,w		; copia il registro PCLATH in W (registro da salvare perché contiene i
    						; bit più significativi del program counter, usati da GOTO e CALL,
    						; e settati dalla direttiva pagesel).
    		movwf	pclath_temp		; copia W (= PCLATH) in pclath_temp.
    			
    		movf FSR, w
    		movwf fsr_temp			; altro registro usato dalla routine
    						;  e quindi da salvare
    		
    		banksel PIR1			
    		btfss PIR1, TMR1IF		; controllo se proprio il timer1 mi ha fatto entrare in interrupt
    		goto $-1
    		banksel PIE1			
    		btfss PIE1, TMR1IE		
    		goto $-1			
    		banksel PIR1			
    		bcf PIR1, TMR1IF
    ;*******************************************ADC************************************************************************************		
    
    		
    		PAGESEL	readAdc
    		call	readAdc      ; chiama routine lettura ADC con canale 6
    		PAGESEL	computeTemp
    		call	computeTemp  ; calcola valore effettivo di temperatura
    		PAGESEL	formatNumber
    		call	formatNumber; formatta numero in 2 cifre decimali
    		banksel	PIR1
    		bcf	PIR1,ADIF
    		PAGESEL	reload_timer1
    		call	reload_timer1
    		goto	irq_end  
    readAdc
    		; Legge valore analogico dal canale 6
    		
    		banksel ADCON0 
    		bsf ADCON0,GO       ; inizia conversione
    		btfsc ADCON0,GO     ; controllo go sia 0
    		goto $-1
    		banksel ADRESH
    		movf ADRESH,w; copia valore campionato in W
    		movwf tmp
    		banksel ADCON0
    		bcf ADCON0, ADON   ; disattiva modulo ADC
    		return
    computeTemp
    		; routine di conversione da tensione a gradi centigradi
    		; input:
    		;   W: tensione campionata (0-255, corrispondente a 0-3.3 V)
    		; output:
    		;   W: risultato in gradi
    		;
    		; Dal datasheet del sensore di temperatura MCP9701A:
    		;  T = (Vadc - V0) / Tc   [ dove V0 = 400 mV, Tc = 19.5 mV/C]
    		; Convertendo da tensioni a valori binari, si ha:
    		;  T = (Nadc - 31) / 1.51
    		; che puo' essere approssimata in calcoli interi a 8 bit come:
    		;  T = (Nadc - 31) * 2 / 3  [ approssimaz. 1.51 ~= 1.5 = 3/2 ]
    		; Questa formula permette di calcolare temperature fino a 84 C
    		;  senza incorrere nell'overflow della variabile a 8 bit
    		;movwf tmp   ; questo è il valore della temperatura bufferizzato nell'ADC (non è ancora formattato per la stampa!)
    		movlw .31
    		subwf tmp, f  ; tmp = tmp - 31
    		bcf STATUS, C
    		rlf tmp, f    ; tmp = tmp * 2 (usando lo shift a sinistra)
    		; divisione per 3, effettuata con semplice algoritmo di sottrazioni
    		;  successive del valore 3, incrementando ogni volta il risultato,
    		;  fino a che il minuendo non diventa negativo
    		clrf temperature  ; valore iniziale del risultato = 0 
    loop_div3
    		movlw .3
    		subwf tmp, w          ; w = tmp - 3
    		btfss STATUS, C
    		goto end_div3         ; se risultato negativo (C=0): fine divisione, se c'è il carry continuo
    		movwf tmp             ; tmp = tmp - 3
    		incf temperature, f   ; incrementa risultato di 1
    		goto loop_div3        ; continua sottrazione
    end_div3
    		movf temperature,w
    		return
    
    		
    formatNumber
    		; calcolo delle 3 cifre decimali di un numero
    		; input:
    		;   W: valore da formattare
    		;
    		movwf tmp          ; salva temporaneamente il valore
    		; divisione per 100
    		clrf temperature          ; risultato della divisione (centinaia)
    loop_div100
    		movlw .100
    		subwf tmp, w       ; w = tmp - 100
    		btfss STATUS, C
    		goto end_div100    ; se risultato negativo (C=0): fine divisione
    		movwf tmp          ; tmp = tmp - 100
    		incf temperature, f       ; incrementa risultato di 1
    		goto loop_div100   ; continua sottrazione
    end_div100
    		
    		
    		clrf temperature          ; risultato della divisione (decine)
    loop_div10
    		movlw .10
    		subwf tmp, w       ; w = tmp - 10
    		btfss STATUS, C
    		goto serial_print     ; se risultato negativo (C=0): fine divisione
    		movwf tmp          ; tmp = tmp - 10
    		incf temperature, f       ; incrementa risultato di 1
    		goto loop_div10    ; continua sottrazione
    serial_print	
    		;scrittura in codice ASCII
    		; Trasmetto decine 
    		movlw '0'
    		addwf tmp,w ; w + tmp = w   ; il codice ASCII del carattere '0' sommato alla cifra fornisce il codice ASCII della cifra in questione
    		banksel TXREG
    		movwf TXREG 
    		banksel PIR1
    		btfss PIR1,TXIF 
    		goto $-1		
    		
    		; Trasmetto unità 
    		movlw '0'
    		addwf temperature,w ; w + temperature = w   
    		banksel TXREG
    		movwf TXREG 
    		banksel PIR1
    		btfss PIR1,TXIF 
    		goto $-1	
    		
    		; Trasmetto invio
    		movlw .10      
    		BANKSEL TXREG 
    		movwf TXREG   ;scrivo il carattere invio
    		banksel PIR1
    		btfss PIR1,TXIF  
    		goto $-1
    		
    		return
    		
    		
    		
    
    ;************************************ADC*******************************************************************************************************************			
    			
    ;************************************SERIALE************************************
    		   
    		; "tmp" contiene le decine, "temperature" le unita'
    		;   (resto della divisione)
    
    ;************************************SERIALE************************************
    		
    
    irq_end		       
    			movf	fsr_temp,w
    			movwf	FSR
    			movf	pclath_temp,w	; copia pclath_temp in W
    			movwf	PCLATH		; copia W in PCLATH
    			swapf	status_temp,w	; inverte i nibble di status_temp salvando il risultato in W
    						; anche in questo caso serve a non alterare STATUS stesso
    			movwf	STATUS		; copia W (che contiene lo STATUS originale ripristinato dopo 2 inversioni) in STATUS
    						; per ripristinare W senza alterare STATUS appena ripristinato, si utilizza sempre swapf
    			swapf	w_temp,f	; prima inversione di w_temp, risultato su se stesso
    			swapf	w_temp,w	; seconda inversione di w_temp, risultato in W (W contiene il valore precedente all'interrupt)
    			bsf	cansleep,0
    						  
    			retfie			; uscita da interrupt e ritorno al punto in cui il programma era stato interrotto
    		
    ;************************************FIME INTERRUPT************************************
    		
    initHw		; inizializzazione hardware per scheda PIC Board - Studio
    
    	
    		; registro INTCON:
    			; - tutti gli interrupt inzialmente disabilitati
    			; (verranno abilitati nel programma principale, quando tutte
    			;  le periferiche saranno correttamente inizializzate)
    		clrf	INTCON
    
    		
    
    		
    		
    		;port A:
    		; RA0-RA5: analog inputs
    		; RA6-RA7: digital outputs (flash_ce, bus_switch)
    		setRegK PORTA, B'01000000' ; flash_ce = 1
    		setRegK ANSEL, B'11111111' ; set RE0-RE2 as analog too
    		setRegK TRISA, B'00111111'
    		
    		;porta D:1..3settato come output (LED)
    		setRegK TRISD, 0xF0
    		setReg0 PORTD
    		
    		;ADC
    		setRegK ADCON0, B'11011000' ; clock = RC, ch. 6, ADC off  
    		setReg0 ADCON1 ; use vdd and vss as reference
    		
    		
    		banksel ANSEL
    		setRegK ANSEL, B'11111111'	    ;imposto i pin adc come analogici
    		banksel PIR1	
    		bcf	PIR1,ADIF	    ;azzero flag ADC	
    		
    		;portE:
    		setReg0	TRISE	    ;abilito porta per il sensore
    		
    		; Timer1
    		; Impostazioni:
    		; - usa quarzo esterno (32768 Hz)
    		; - modalita' asincrona (funziona con quarzo esterno anche durante sleep)
    		; - prescaler = 1:8
    		; - Avvio timer in stop
    		; Con la frequenza del quarzo ed il prescaler a 8 si ha:
    		; - singolo tick ~= 24.414 us
    		; - periodo max = 5 s (contatore a 16 bit)
    		; - 24.414us ? 1tick = 5 ? x -> x = 5/0,000244141 = 20480 tick -> 65536 - 20480 
    		banksel	T1CON
    		movlw	B'00111110';(abilito clock esterno ma non sincronizzo con input clock esterno)
    		movwf	T1CON
    
    		;EUSART
    		; baud rate = 19200 (BRGH = 1, BRG16 = 0) ;(high speed, 8 bit baud rate)
    		; TXEN = 1 (abilito trasmissione)
    		; SPEN = 1 (abilito seriale)
    		; SYNC = 0 (configuro per operazioni asincrone)
    		
    		banksel TXSTA
    		bsf TXSTA,TXEN
    		bsf TXSTA,SPEN
    		bcf TXSTA,SYNC
    		bsf TXSTA,BRGH
    		
    		banksel RCSTA
    		bsf RCSTA,SPEN
    		
    		banksel BAUDCTL
    		bcf BAUDCTL,BRG16
    		
    		setRegK SPBRG, .12
    		return
    		;fine codice	
    	
    	END		;direttiva di fine codice
    
    
    
    
  • Re: Problema Pic16f887 lettura e stampa temperatura

    Metti un valore costante e vedi se lo ottieni ... ad esempio scrivi
    
    formatNumber
           movlw .37
    
    e vedi se ottieni in output il 37 o altro. Per capire se il problema è prima o dopo la formatNumber
  • Re: Problema Pic16f887 lettura e stampa temperatura

    Si, ho messo .37 in input alla formatNumber (invece del valore convertito dall'adc) e ho ottenuto lo stesso valore ma sempre con quei simboli strani vicino.
  • Re: Problema Pic16f887 lettura e stampa temperatura

    Cosa visualizzi?
  • Re: Problema Pic16f887 lettura e stampa temperatura

    37
    37
    37<0><e1>....
  • Re: Problema Pic16f887 lettura e stampa temperatura

    Prova ad abbassare la velocità (PIC e PC) a 9600

    Sembrano disturbi dovuti ad ambiente rumoroso elettricamente o a cavi non schermati correttamente.
    Ad una velocità minore non dovresti avere problemi.
  • Re: Problema Pic16f887 lettura e stampa temperatura

    Ho abbassato il baud rate come mi hai consigliato a 9600 e infatti il problema dei valori "strani" non cè più!
    Ora rimane da capire perchè ottengo valori errati (46 in stampa)....
    Non riesco a capire dove sia l'errore...
Devi accedere o registrarti per scrivere nel forum
8 risposte