Professional Documents
Culture Documents
;
; Termometro.asm - firmware for the digital thermomether using LM35DZ and PIC16F818
; Version 1.0, 07/14/2007
;
; Copyright (C) 2007 Waldeck Schutzer <waldeck@dm.ufscar.br>
;
; This program is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License
; as published by the Free Software Foundation; either version 2
; of the License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
; USA.
;
; --------------------------------------------------------------------------------------
;
; Firmware para o termometro digital usando LM35DZ e PIC16F818
; Verso 1.0, 14/07/2007
;
; Copyright (C) 2007 Waldeck Schutzer <waldeck@dm.ufscar.br>
;
; Desenvolvido com Piklab 0.14.2, http://piklab.sourceforge.net
; e compilador assembler GNUPIC 0.13.4 beta, http://www.gnupic.org
;
; Este programa software livre; voc pode redistriu-lo e/ou
; modific-lo sob os termos da Licena Pblica Geral GNU, conforme
; publicada pela Fundao do Software Livre; seja a verso 2
; da licena, ou ( sua escolha) qualquer verso posterior.
;
; Este programa distribudo no intuito de que ele possa ser
; til, mas SEM NENHUMA GARANTIA; sem mesmo a garantia implcita
; de MERCANTIBILIDADE ou ADEQUAO A UMA FINALIDADE ESPECFICA. Veja
; a Licena Plica Geral GNU para mais detalhes.
;
; Voc deve ter recebido uma cpia da Licena Plica Geral GNU juntamente
; com este programa; caso contrrio, escreva para a Fundao do Software
; Livre, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
; EUA.
list P=16F818
radix dec
include <p16f818.inc>
__config _WDT_OFF & _PWRTE_OFF & _INTRC_IO & _MCLR_ON & _BODEN_ON & _LVP_OFF &
_CPD_OFF & _WRT_ENABLE_OFF & _DEBUG_OFF & _CCP1_RB2 & _CP_OFF
#define Timer1Div 1000 ; Divide a freq do Timer1, obtendo 250Hz. Essa a freqncia
#define Timer1Value (65536-Timer1Div) ; de atualizaes do display (bastante confortvel)
#define eAtraso 10 ; Atraso entre visualizaes sucessivas (em dcimos de seg.)
#define DebConst 5 ; Valor de recarga do contador debouncer
#define InitConst (3*72) ; Valor de recarga do contador de inicializao
#define aInterConst 3 ; Valor de recarga do timer de visualizao alternativa
;
#define DS0_ON PORTA,4 ; Habilitao para displays
#define DS1_ON PORTA,6
#define DS2_ON PORTA,7
;
; ------------------------------------------------------------------------------
; Ajustes de calibrao
;
ifdef BREAD_BOARD
; Verso 1 (proto-board)
#define TensaoRef 1600 ; em milivolts, Vdd=5.00V
#define AjusteOff 0 ; ajuste
else
; Verso 2 (circuito impresso)
#define TensaoRef 918 ; em milivolts
#define AjustePer (1+0/100) ; ajuste percentual
#define AjusteAms 0 ; ajuste de deslocamento amostragem
endif
#define Multiplicador ((AjustePer*TensaoRef*100+512)/1023+AjusteAms) ; fator amostra-
>temperatura
#define AjusteTempPer (100+0) ; ajuste percentual da temperatura
#define AjusteTempOff 0 ; deslocamento em milesimos de graus
Celsius
;
; Esta macro realiza multiplicao rpida em preciso dupla de h:l por uma constante,
; uilizando B2:B1:B0 como area de trabalho.
Mult24k macro u,h,l,k
local step, i
step set 0
i set k
movf l,W ; Salva u:h:l em B2:B1:B0
movwf B0
movf h,W
movwf B1
movf u,W
movwf B2
while i!=0
if (i&1)==1
if step==0
movf B0,W ; Primeira vez: move B2:B1:B0 para u:h:l
movwf l
movf B1,W
movwf h
movf B2,W
movwf u
else
movf B0,W ; Demais vezes: soma B2:B1:B0 em u:h:l
addwf l,F
movlw 1
btfsc _carry
addwf h,F
btfsc _carry
incf u,F
movf B1,W
addwf h,F
btfsc _carry
incf u,F
movf B2,W
addwf u,F
endif
step set step+1
endif
bcf _carry ; Faz B2:B1:B0 = 2 * B2:B1:B0
rlf B0,F
rlf B1,F
rlf B2,F
i set i>>1
endw
endm
;
; Macro para comparar dois inteiros em preciso dupla sem sinal
Comp16U macro Xhi,Xlo,Yhi,Ylo
movf Xhi,W
subwf Yhi,W ; subtract Y-X
btfss _zero ; Are they equal ?
goto $+3 ; No, they are not
movf Xlo,W ; yes, they are equal, compare lo
subwf Ylo,W ; subtract Y-X
; results:
; if X=Y then now Z=1.
; if Y<X then now C=0.
; if X<=Y then now C=1.
endm
;
; Macro usada pelo algoritmo de diviso
; -------------------------------------
; Este mtodo similar ao de diviso realizada com lpis e papel.
divMac macro
bcf _carry
rlf D0,F ; Desloca o dividendo para a esquerda,
rlf D1,F
rlf D2,F
rlf C0,F ; e para dentro do resto c.
movf B0,W ; Faz W=c-b
subwf C0,W
btfsc _carry ; O carry ser igual a 1 se c>=b
movwf C0 ; Nesse caso c=c-b
rlf A0,F ; Deslocamos o carry para dentro do quociente
rlf A1,F
rlf A2,F
endm
cblock 0xa0
W_T1a ; backup do registro W durante a interrupcao T1 (tambm no banco0)
;
; Armazena as leituras mais recentes de temperatura a fim de calcular a temperatura mdia
;
CurTemp ; indice indicando a temperatura atual (0:max-1)
Temps00L ; Tabela de leituras de temperaturas (em nmero de amostras)
Temps00H
Temps01L
Temps01H
Temps02L
Temps02H
Temps03L
Temps03H
Temps04L
Temps04H
Temps05L
Temps05H
Temps06L
Temps06H
Temps07L
Temps07H
Temps08L
Temps08H
Temps09L
Temps09H
TempsTopL
TempsTopH
;
TopOfBank1 ; Marca o topo do banco1 da RAM: no usar!
endc
;
; Alerta o programador para estouro do banco1
if TopOfBank0>0xc0
error "Estouro do banco1 da RAM"
endif
; ---------------------------------------------------------------------
; Ponto de incio de execuo
;
ORG 0
nop
movlw high Inicializa
movwf PCLATH ; Inicializa o PCLATH. Necessrio pois usamos jump-
table
goto Inicializa
; ---------------------------------------------------------------------
; Ponto de entrada de interrupes
org 4
movwf W_T1 ; Salva o status do processo durante a interrupcao (bancoX)
swapf STATUS,W ; Salva status do processo em W (movf estraga o flag Z!)
clrf STATUS ; Volta ao banco0, independentemente do banco selecionado
movwf STATUS_T1 ; Guarda o status do processo na varivel STATUS_T1
; --------------------------------------------------------------------
; Recarga do Timer1. Como estamos no incio da rotina de interrupo,
; passaram-se poucos ciclos desde que o Timer1 estourou de 0xFFFF para
; 0x0000. Por causa disso, TMR1H deve estar zerado e TMR1L contm
; algum valor baixo (pois a contagem no pra). Nessas condies, no
; h problema em recarregar TMR1H com outro valor, mas escrever no
; TMR1L pode causar erros de temporizao. Por exemplo, escrever nesse
; registrador causa a perda de 2 ciclos na contagem. Para procurar
; manter a preciso, vamos contabilizar os dois ciclos perdidos somando
; 2 ao valor da recarga, e vamos tambm somar ao registrador TMR1L
; ao invs de escrever nele diretamente.
; -------------------------------------------------------
; Usa a presente interrupcao para atualizar o display.
; Isto eh feito alternando-se para o proximo digito,
; pois somente um pde ser exibido por vez. Primeiro
; apagamos todos os digitos. Depois de identificarmos
; qual estava aceso, habilitamos o proximo digito.
; Por fim, lemos a posicao de memoria contendo aquele
; digito, o transformamos em codificacao 7-segmentos
; e o acendemos atravez da porta B.
;
AtualizaDisplay
clrf PORTB ; apaga o display durante a atualizao
btfsc DS0_ON
goto HabilitaDS1
btfsc DS1_ON
goto HabilitaDS2
HabilitaDS0
bcf DS1_ON
bcf DS2_ON
bsf DS0_ON ; habilita display 0
movf DS0,W
addlw 0
btfss _zero
call bcd27
btfsc LED0_ON ; Vai acender o led 0?
iorlw 1
goto AcendeDisplay
HabilitaDS1
bcf DS0_ON
bcf DS2_ON
bsf DS1_ON ; habilita display 1
movf DS1,W
call bcd27
btfsc LED1_ON ; Vai acender o led 1?
iorlw 1
goto AcendeDisplay
HabilitaDS2
bcf DS0_ON
bcf DS1_ON
bsf DS2_ON ; habilita display 2
movf DS2,W
call bcd27
AcendeDisplay
movwf PORTB ; acende o digito habilitado
; -------------------------------------
; Faz o tratamento debounce da chave
movf DebCounter,F
btfss _zero ; Contador debouncer chegou a zero?
goto DecDebouncer ; Ainda no, salta o processamento de chave
; -------------------------------------
; Converte o numero em W para codificao 7-segmentos
bcd27
andlw 0fh ; garante que o digito esteja entre 0 e 15
addwf PCL,F ; salta para dentro da tabela
; gfedcbaL ; L = LED externo
retlw B'01111110' ; 0
retlw B'00001100' ; 1
retlw B'10110110' ; 2
retlw B'10011110' ; 3
retlw B'11001100' ; 4
retlw B'11011010' ; 5
retlw B'11111010' ; 6
retlw B'00001110' ; 7
retlw B'11111110' ; 8
retlw B'11011110' ; 9
retlw B'11101110' ; A
retlw B'11111000' ; b
retlw B'01110010' ; C
retlw B'10111100' ; d
retlw B'11110010' ; E
retlw B'11100010' ; F
; ------------------------------------------------------------------
; Faz a inicializao do hardware, atribuindo valores para os
; vrios registradores de controle da CPU e dos perifricos,
; zera o banco 0 da RAM, e inicia o timer TMR1
;
Inicializa
;
; Configurao do oscilador, do clock do sistema e da fonte
; de clock para o TMR1
banksel OSCCON
movlw B'01110000' ; Oscilador interno, freqncia de 8Mhz
movwf OSCCON
banksel T1CON
movlw B'00110000' ; Timer1, clock interno, f/8
movwf T1CON
;
; Configurao do registro de controle de interrupes
movlw B'01000000' ; habilita interrupes de perifricos
movwf INTCON
;
; Pe as portas A e B em nivel lgico zero
clrf PORTB
clrf PORTA
;
; Determina quais perifricos podem gerar interrupes
banksel PIE1
movlw B'00000001' ; Habilita interrupcao TMR1
movwf PIE1 ; PIE1 controla interrupes dos perifricos
;
; Configura os bits das portas A e B
movlw B'00101111' ; RA3 Vref+, RA2 Vref-, RA4,RA6 e RA7 sao saidas
movwf TRISA
movlw B'00000000' ; all inputs
movwf TRISB
;
; Determina quais portas de entrada so digitais e quais so analgicas
movlw B'11000101' ; Entradas analogicas RA0 e RA1, Vref+, Vref-, I/O RA4, f/2
movwf ADCON1
banksel PORTA
clrf PORTB
clrf PORTA
; -----------------------------------------------------
; Inicializacao da RAM - zera os blocos 0 e 1
bcf STATUS,IRP ; Seleciona bancos 0-1
; -----------------------------------------------------
; Aguarda a estabilizao dos perifricos
movlw 250
call Delay_ms
; -----------------------------------------------------
; Inicializa e liga o TMR1
movlw high Timer1Value
movwf TMR1H
movlw low Timer1Value
movwf TMR1L ; RECARREGA CONTADOR DO TMR1
bsf T1CON,TMR1ON ; liga tmr1
;
; Inicializa a EEPROM, caso necessrio
movlw EESig ; A EEPROM est assinada?
call EERead
sublw low EESignature
btfss _zero
call EEInit ; Inicializa a EEPROM, se no estiver assinada
movlw EESigh
call EERead
sublw high EESignature
btfss _zero
call EEInit ; Inicializa a EEPROM, se no estiver assinada
;
call EEReadTemps ; Recupera as temperaturas registradas na EEPROM
; --------------------------------------------------------------------------------
;
; Mdulo principal - Permanece em loop realizando as
; sucessivas tarefas do termmetro. Exibe o resultado.
;
; --------------------------------------------------------------------------------
;
MainLoop
call FazMedida ; Faz a conversao A/D em A1:A0
call ArmazenaTemp ; Poe A1:A0 na tabela
MainMostraMin
movf TempMin,W ; Vamos exibir a temperatura mnima
movwf A0
movf TempMinh,W
movwf A1
bsf LED0_ON
bcf LED1_ON
goto MainMostra
MainMostraMax
movf TempMax,W ; Vamos exibir a temperatura mxima
movwf A0
movf TempMaxh,W
movwf A1
bcf LED0_ON
bsf LED1_ON
goto MainMostra
MainMostraNormal
clrf LEDS
bcf MostraMax
bcf MostraMin
MainMostra
call ComputeTemp ; Transforma a medida em temperatura em A2:A1:A0
MainMostraCelsius
movlw 50 ; Soma 0.05 ao resultado para arredondar
call Soma248 ; A2:A1:A0 = A2:A1:A0 + 50
call BinDec ; Converte de binrio para decimal
call MostraTemp ; Copia a temperatura para a cache do display
; ----------------------------------------------------------------
; Inicializa as temperaturas mnima e mxima e troca a escala
; de exibio entre Celsius e Farenheit
; --------------------------------
; Assume que A1:A0 tem uma temperatura inicial
;
ApagaTudo
movf A0,W
movwf TempMin
movwf TempMax
movf A1,W
movwf TempMinh
movwf TempMaxh
call EEWriteTemps
movlw EEConfBits
call EERead
xorlw (1<<EEEscala)
movwf eData
movlw EEConfBits
call EEWrite
bcf Init_ON
bcf MostraMax
bcf MostraMin
clrf LEDS
return
; ----------------------------------------------------------------
; Atraso de milisegundos
; ----------------------
; Entrada: W=nmero de milisegundos
;
Delay_ms
movwf TEMPO1
Delay_ms_loop
movlw 1+10*(250-3+8)/15 ; Atraso de 250 microsegundos
call Delay_us
movlw 1+10*(250-3+8)/15 ; Atraso de 250 microsegundos
call Delay_us
movlw 1+10*(250-3+8)/15 ; Atraso de 250 microsegundos
call Delay_us
movlw 1+10*(250-3+8)/15 ; Atraso de 250 microsegundos
call Delay_us
decfsz TEMPO1,F
goto Delay_ms_loop
return ; RETORNA
;
; Atraso de segundos
; Entrada: W=nmero de segundos do atraso
Delay_ss
movwf TEMPO0
Delay_ss_loop
movlw 250 ; 250 ms
call Delay_ms
movlw 250 ; 250 ms
call Delay_ms
movlw 250 ; 250 ms
call Delay_ms
movlw 250 ; 250 ms
call Delay_ms
decfsz TEMPO0,F
goto Delay_ss_loop
return
; Atraso de microsegundos
; -----------------------
; Entrada: W=n, o nmero de repeties do lao interno.
; Com clock de 8MHz, o perodo de uma instruo simples de 500ns
; (pois o clock internamente divido por 4). Instrues de saltos
; tomam 1.0us. O tempo total desta rotina dado por:
; 3.0 + 1.5*(n-1) microsegundos. Para um atraso de t microsegundos,
; devemos escolher n do seguinte modo: n>=1+(t-3)/1.5, onde
; 3us <= t <= 385us (n<=256).
;
Delay_us
movwf TEMPO2 ; 0.5us
nop ; 0.5us
decfsz TEMPO2,F ; n*0.5us
goto $-1 ; (n-1)*1.0us + 0.5us
return ; 1.0us
; Total: 3.0 + 1.5*(n-1) us
; ---------------------------------------------------------------
; Copia a temperatura em D4:D3 para a cache do display DS0-DS2
; As interrupes so desabilitadas durante esta operao
;
MostraTemp
bcf INTCON,GIE ; Desabilita interrupes
movf D4,W
movwf DS0
movf D3,W
movwf DS1
movf D2,W
movwf DS2
bsf INTCON,GIE ; Habilita interrupes
return
; ---------------------------------------------------------------
; Usa o conversor A/D para medir a temperatura (voltagem) do LM35DZ
; Retorna o resultado em nmero de amostras em A1:A0
FazMedida
banksel ADCON0
movlw B'00000001' ; Seleciona clock f/4, canal 0=AN0, ativa o modulo A/D
movwf ADCON0
bcf PIR1,ADIF ; Desabilita interrupcao do conversor A/D
movlw 1+10*(40-3+8)/15 ; Aguarda 40us para carga do capacitor (11.5us min.)
call Delay_us ; permitindo a carga do capacitor interno C_hold
bsf ADCON0,GO ; Inicia a conversao A/D
EsperaMedida
; Monitora o bit GO, aguardando termino da conversao
btfsc ADCON0,GO ; Chegou ao final da conversao
goto EsperaMedida ; Ainda nao, continua esperando
nop
movf ADRESH,W
movwf A1
banksel ADRESL
movf ADRESL,W
banksel A0
movwf A0
bcf PIR1,ADIF ; Limpa interrupcao do conversor A/D
bcf ADCON0,ADON ; Desliga o modulo A/D, poupando energia
return
; ------------------------------------------------------------
; Armazena a temperatura atual (medida em amostras) em uma
; tabela.
; Entrada: A1:A0
;
ArmazenaTemp
bcf STATUS,IRP ; Seleciona bancos 0-1
movlw CurTemp ; Carrega o endereo de CurTemp em W
movwf FSR ; e de W para o registrador de endereamento indireto
movf INDF,W ; Este o valor atual de CurTemp
incf FSR,F ; Avana para o primeiro elemento da tabela (entrada 0)
addwf FSR,F ; Acessa o elemento da tabela Temps apontado
addwf FSR,F ; por CurTemp (dois bytes por elemento)
movf A0,W
movwf INDF ; Armazena na proxima entrada da tabela
incf FSR,F
movf A1,W
movwf INDF
movlw CurTemp
movwf FSR
incf INDF,F ; Incrementa o ndice CurTemp
movlw TempsSize ; Nmero de elementos na tabela
subwf INDF,W
btfsc _zero
clrf INDF ; Quando chegar ao final da tabela, volta ao incio
return
; ------------------------------------------------------------
; Calcula a media das temperaturas armazenadas (medidas em amostras).
; O resultado sera armazenado em A1:A0.
; Resultados intermediarios em A2:A1:A0, B0
;
MediaTemp
bcf STATUS,IRP ; seleciona bancos 0-1
movlw Temps00L ; Carrega o endereo de Temps00L em W
movwf FSR
movlw TempsSize
movwf B0
clrf A0 ; Soma as temperaturas em A2:A1:A0
clrf A1
clrf A2
CalcMedia
movf INDF,W ; Carrega LSB da temperatura
incf FSR,F
call Soma248 ; Soma o LSB
movf INDF,W ; Carrega o MSB da temperatura
incf FSR,F
addwf A1,F ; soma o MSB
btfsc _carry
incf A2,F ; contabiliza o carry
decfsz B0,F
goto CalcMedia
movlw TempsSize/2 ; Soma isto a A2:A1:A0 a fim de que a diviso abaixo
call Soma248 ; possa ser arredondada para o inteiro mais prximo.
movlw TempsSize
movwf B0
goto Divisao248 ; Divide pelo nmero de elementos da tabela!!!
; A temperatura mdia deve agora estar em A2:A1:A0, mas A2 deve ser 0
; ------------------------------------------------------------
; Converte a medida do conversor A/D em temperatura Celsius
; ----------
; Entrada: 0:A1:A0 = amostragem do conversor A/D
; Sada: A2:A1:A0 = temperatura em milesimos de grau Celsius
;
; Teoria
; ------
; A tensao, medida em milivolts, informada pelo LM35DZ pode
; ser imediatamente interpretada como temperatura. Por
; exemplo, uma tenso de 245 mV equivale a 24.5 graus
; Celsius. Assim cada incremento de 10mV equivale a um grau.
;
; Por outro lado, se a tensao de referncia de 901.639344mV
; via ponte consistindo de um resistor de 10k em srie com
; um de 2k2, o primeiro ligado Vdd e o segundo a Vss, e
; a tomada central ligada a Vref+. Alem disso, o
; conversor opera com 10 bits, logo cada bit da amostra
; vale 901.639344mV/1023 = 0.881367883mV
;
; NOTA: a tenso de referncia obtida desse modo depende
; fortemente da estabilidade da tenso de alimentao e
; da tolerncia dos resistores. Esta pode ser melhorada
; usando-se uma referncia mais estvel como um diodo
; zener. No meu caso, a tenso medida efetiva foi de
; aproximadamente 885mV
;
; Desse modo, para converter as amostras em temperatura
; basta multiplica-las por 88. O resultado eh medido em
; milsimos de grau Celsius. Por exemplo, se a amostra
; eh igual a 278, ento:
; 278 * 88 = 24464x10^(-2)mV = 24.4 graus Celsius
;
; Como o resultado deve caber em 16 bits, o topo da
; escala ser 65.5 graus. Em valor de amostragem isto eh
; 65536/88 ~ 744. Para um termometro residencial, esta
; escala deve ser mais do que suficiene. Enquanto
; escrevo isto, meu novo termometro marca confortveis
; 26.5 graus.
;
; Para uma medida precisa, tome a medida exata da tenso
; de referncia presente no seu circuito e modifique o
; valor da varivel TensaoRef. O valor deve ser inteiro
; e medido em milivolts. Para compensar erros de truncamento,
; voc pode modificar a varivel AjusteOff para
; um dos valores -1, 0 ou 1. Aps qualquer ajuste, compare
; a leitura do termmetro com a tenso apresentada pelo
; LM35DZ e faa novos ajustes caso seja necessrio.
; Ateno: use os valores abaixo apenas como referncia. Voc
; deve ajust-los para o seu circuto em particular.
ComputeTemp
clrf A2
Mult24k A2,A1,A0,Multiplicador
;
; Se necessrio, aplica deslocamento de temperatura
if AjusteTempOff>0
movlw low AjusteTempOff
call Soma248
movlw high AjusteTempOff
call Soma248H
endif
if AjusteTempOff<0
movlw low AjusteTempOff
call Soma248
movlw high AjusteTempOff
call Soma248H
movlw 0xff
addwf A2,F
endif
;
; Se necessrio, aplica ajuste percentual
if AjusteTempPer!=100
Mult24k A2,A1,A0,AjusteTempPer
movlw 100
call Divisao248
endif
return
; ------------------------------------------------------------
; Registra Maximas e Minimas na EEPROM
; Temperatura a ser registrada em A1:A0
; ----------
MaxMin
; if A1:A0 > TempMax, then TempMax = A1:A0
; Comp16U macro Xhi,Xlo,Yhi,Ylo
; if X=Y then now Z=1.
; if Y<X then now C=0.
; if X<=Y then now C=1.
Comp16U A1,A0,TempMaxh,TempMax
btfsc _carry
goto MaxMin_TestMin
MaxMin_SetMax
movf A0,W ; Armazena nova temperatura mxima
movwf TempMax
movf A1,W
movwf TempMaxh
call EEWriteTemps ; Registra na EEPROM
return
MaxMin_TestMin
; if TempMin > A1:A0 then TempMin = A1:A0
; Comp16U macro Xhi,Xlo,Yhi,Ylo
; if X=Y then now Z=1.
; if Y<X then now C=0.
; if X<=Y then now C=1.
Comp16U TempMinh,TempMin,A1,A0
btfsc _carry
return
MaxMin_SetMin
movf A0,W ; Armazena nova temperatura mnima
movwf TempMin
movf A1,W
movwf TempMinh
call EEWriteTemps ; Registra na EEPROM
return
; -----------------------------------------------
; Converte um numero de binario para decimal.
; -------------------------
; Entrada: A2:A1:A0
; Saida: D4:D0 (um dgito por byte) -- valor mximo 99999
; Usa B3:B2:B1:B0
;
; Descrio:
; Sejam A_15,...,A_0 os bits de A1:A0. Para convertermos o nmero em A1:A0
; para decimal basta avaliarmos o polinmio
; 2^15 A_15 + 2^14 A_14 + ... + 2 A_1 + A_0
; s que usando aritmtica decimal. Isto parece complicado, mas usando o
; dispositivo prtico de Briot-Ruffini, pode ser feito de modo bastante
; eficiente:
; 2(... 2(2 A_15 + A_14) + A_13) + ... ) + A_0
;
BinDec
movlw 24 ; Inicializa o contador de dgitos binrios
movwf B3
BinDecAjuste
bcf _carry ; Alinha o nmero B1:B0 esquerda,
rlf B0,f ; permitindo a entrada dos bits mais significativos
rlf B1,f ; para dentro do carry C.
rlf B2,f
btfsc _carry ; Efetivamente, estamos evitando considerar
goto BinDecLoop ; os zeros esquerda em B2:B1:B0
decfsz B3,f
goto BinDecAjuste
return
BinDecLoop
rlf D0,f ; Este bloco multiplica D0 por 2.
movf D0,W ; Se o resultado for maior do que 10
addlw -10 ; ento subtrai 10
btfsc _carry ; e soma um no prximo digito (antes que
movwf D0 ; este seja multiplicado por 2).
; --------------------------------------------------------
; Soma no-sinalizada de um nmero de 24 bits com outro
; de 8 bits.
; Entrada: A2:A1:A0 = primeiro termo
; W = segundo termo
; Sada: A2:A1:A0 = soma, C=1 se houve estouro
; Obs: o valor em W destrudo
Soma248
addwf A0,F
movlw 1
btfsc _carry
addwf A1,F
btfsc _carry
addwf A2,F
return
; --------------------------------------------------------
; Diviso no-sinalizada de um nmero 24bits por outro
; de 8 bits.
; Entrada: A2:A1:A0=dividendo
; B0=divisor
; Sada: A2:A1:A0=quociente
; C0=resto
; Usa: D3:D2:D1:D0 - rea de trabalho
Divisao248
;
movf A0,W ; Copia A2:A1:A0 para a rea de trabalho D2:D1:D0
movwf D0
movf A1,W
movwf D1
movf A2,W
movwf D2
; -----------------------------------------------
; Le uma posicao da EEPROM
; ------------------------
; Entrada: W = posio da EEPROM
; Sada: W = valor armazenado naquela posio
;
EERead banksel EECON1
btfsc EECON1,WR ; Aguarda a concluso de uma operao de escrita
goto $-1 ; anterior.
banksel EEADR
movwf EEADR
banksel EECON1
bcf EECON1,EEPGD
bsf EECON1,RD
banksel EEDATA
nop ; just in case
movf EEDATA,W
banksel A0
return
; -----------------------------------------------
; Escreve uma posicao da EEPROM
; -----------------------------
; Entrada: W = posio da EEPROM, eData = dado a gravar
;
EEWrite banksel EECON1
btfsc EECON1,WR ; Aguarda a concluso de uma operao de escrita
goto $-1 ; anterior.
banksel EEADR
movwf EEADR ; Especifica o endereo a gravar
banksel eData
movf eData,W
banksel EEDATA
movwf EEDATA
banksel EECON1
bcf EECON1,EEPGD
bsf EECON1,WREN ; Liga a habilitao de escrita
bcf INTCON,GIE ; Desabilita as interrupes
movlw 0x55 ; para dar o comando de gravao
movwf EECON2
movlw 0xAA
movwf EECON2
bsf EECON1,WR
bsf INTCON,GIE ; Habilita as interrupes
bcf EECON1,WREN ; Desabilita a escrita, sem interromper a escrita
atual
banksel A0
return
; -----------------------------------------------
; Inicializa a EEPROM
; -------------------
; Assume que as temperaturas mxima e mnima j foram determinadas.
;
EEInit call EEWriteTemps ; Registra as temperaturas
clrf eData
movlw EEConfBits ; Bits de configurao
call EEWrite
movlw low EESignature
movwf eData ; Assina a EEPROM
movlw EESig
call EEWrite
movlw high EESignature
movwf eData
movlw EESigh
call EEWrite
return
; -----------------------------------------------
; Escala de exibio da temperatura
; Saida: Z=1 Celsius, Z=0 Farenheit
; -------------------
EEReadScale
movlw EEConfBits
call EERead
andlw (1<<EEEscala)
return
; -----------------------------------------------
; Grava as temperaturas na EEPROM
; -------------------
;
EEWriteTemps
banksel TempMin
movf TempMin,W ; Registra a Temperatura Mnima
movwf eData
movlw EETempMin
call EEWrite
movf TempMinh,W
movwf eData
movlw EETempMinh
call EEWrite
return
; -----------------------------------------------
; Grava as temperaturas na EEPROM
; -------------------
;
EEReadTemps
movlw EETempMin
call EERead
movwf TempMin
movlw EETempMinh
call EERead
movwf TempMinh
movlw EETempMax
call EERead
movwf TempMax
movlw EETempMaxh
call EERead
movwf TempMaxh
return
; ------------------------------------------------------------
;
dt "termometro.asm 14/07/2007 R1.0, "
dt "(c) Waldeck Schutzer 2007, "
dt "waldeck@dm.ufscar.br"
EndOfProg
if EndOfProg>1023
error "Programa muito grande!"
endif
end