;************************** Asignacion de pines *********************************************************************************
; ____________
; +5V -|1 \__/ 8|- GND
;LED y buzzer que indican escritura de datos en EEPROM -|2 7|- LED indicador de estado de GP2 (util en interrupciones)
; Datos conv A/D -|3 12F675 6|- Al puerto serie
; Int. Inicio -|4_________5|- Int. parada/transferir
;
;********************************************************************************************************************************
;
; Los registros utilizables son del 32 al 95 para este modelo de PIC
;
;-------------------------------------------------------------
; Define el PIC
;-------------------------------------------------------------
list p=12f675
#include P12F675.INC
__CONFIG _MCLRE_OFF & _CP_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _PWRTE_ON
errorlevel -302 ;prevents error code for this chipset
;-------------------------------------------------------------
; Declaracion de variables
;-------------------------------------------------------------
;
; NOTA: Lo que se agrego para que funcione el RS-232 usa las posiciones de memoria [32 ... 56], de modo que no hay que usarlas en el programa principal
;
RXBUFF equ d'00041' ; RX buffer, 8 bytes [20..27] (en hexadecimal)
PROC232 equ d'00042'
TXCNT equ d'00043'
TXVAR equ d'00044'
RXCNT equ d'00045'
RD_PTR equ d'00046'
WR_PTR equ d'00047'
RXCHAR equ d'00048'
FSRTMP equ d'00049'
PTRL equ d'00050'
PTRH equ d'00051'
TEMP equ d'00052'
; Banderas
RXFLAG equ d'0' ; 1 = RX en progreso (el numero es la posicion dentro del byte)
TXFLAG equ d'2' ; 1 = TX en progreso (idem arriba)
; Constantes
;******************************************************************
Tx_Pin equ d'1' ; Tx_Pin = GP1 (el numero significa que va a ser reemplazado como "bsf GPIO,X", donde X es el numero este)
Rx_Pin equ d'5' ; Rx_Pin = GP5 (para el momento en que se transfieran los datos el buzzer y led van a estar apagados, no se va a estar muestreando)
W_ISR equ h'5C' ; ISR 'W'
S_ISR equ h'5D' ; ISR 'STATUS'
P_ISR equ h'5E' ; ISR 'PCLATH'
F_ISR equ h'5F' ; ISR 'FSR'
;******************************************************************
conversion equ d'00057'
direccion equ d'00058'
CounterA equ d'00059'
CounterB equ d'00060'
CounterC equ d'00061'
reiniciar equ d'00062'
doblev equ d'00063'
dirleida equ d'00064'
datoleido equ d'00065'
contador equ d'00066'
aux equ d'00067'
;-------------------------------------------------------------
; Define donde empieza el programa y a donde dirigir las interrupciones
;-------------------------------------------------------------
resetear org 0 ;indica empezar el programa
goto calib ;I would guess that your code starting at address 0 (the reset vector) consists of more than four instructions - if an interrupt handler exists, you have to jump around it.
;va a configurar las cosas y despues a "principal"
org 4 ;indica a donde ir si hay una interrupcion
btfsc INTCON,2
goto INT_TMR0 ;si la interrupcion es por el TMR0 (usado para el RS232), va a esa interrupcion
btfsc INTCON,1
goto INT_GP2 ;si la interrupcion es por GP2, va a esa interrupcion
RETFIE
;-------------------------------------------------------------
; Subrutina de calibración del RC interno
;-------------------------------------------------------------
calib bsf STATUS,RP0 ;Bank 1
call 3FFh ;Get the cal value
movwf OSCCAL ;Calibrate
bcf STATUS,RP0
;-------------------------------------------------------------
; Configuración entradas y salidas (GP4 entrada analogica y GP2 entrada INT exterior)
;-------------------------------------------------------------
configurar CLRF STATUS
bcf STATUS,RP0 ;se pasa al banco 0
movlw b'00001101' ;[configura 1)"justificado a la izquierda" (todos los bit comprimidos hacia la izquierda del restultado), 2)Vref en Vdd ]
movwf ADCON0 ;[3)entrada analogica en GP4. 4)no empieza la conversion y esta operable (ultimos 2 bits) ]
clrf GPIO ;limpia las salidas
movlw b'00000111' ;[desactiva el comparador de tension y quedan libres GP1,GP2 y GP0]
movwf CMCON ;
bsf STATUS,RP0 ;se pasa al banco 1
movlw b'00011000' ;configura 1)toma el divisor de tiempo fosc/8. 2)configura GP4 como entrada analogica y las otras como digitales I/O
movwf ANSEL ;
movlw b'011100' ;Configura GP2, GP3, GP4 como entradas y GP0, GP1, GP5 como salidas.
movwf TRISIO
movlw b'11001000' ; Sin pull-ups y sin prescaler para TMR0
movwf OPTION_REG ; se genera la interrupcion con flanco ascendente de GP2
bcf STATUS,RP0 ;se pasa al banco 0
movlw b'10111000'
movwf INTCON ;configura habilitadas las interrupciones y GP2/INT externa (y TMR0), y las IOC
movlw b'00000100' ;habilita ioc en GP2
movwf IOC
call Init232 ;deja preparada la linea de salida de RS232
goto principal ;TERMINA DE INICIALIZAR REGISTROS Y COMIENZA EL PROGRAMA
;********************************************************************************
; Rutina de servicio de interrupción cuando llega un bit por el puerto serie
; Las interrupciones son generadas cada 104uS por TMR0 a 9600bps
; Las operaciones son por IOC (Interrupción por cambio de estado)
;********************************************************************************
INT_TMR0
bcf INTCON,2 ; limpia la bandera de interrupcion
ISR movwf W_ISR ; Guardar W-Reg
swapf STATUS,W ; No cambiar los bits de STATUS
movwf S_ISR ; Guardar STATUS reg
clrf STATUS ; Limpiar el registro STATUS
movf PCLATH,W ; Poner PCLATH
movwf P_ISR ; Guardar PCLATH
movf FSR,W ; Poner FSR
movwf F_ISR ; Guardar FSR
; Prueba con GP5 (Rx_Pin)
ISR_IOC btfss INTCON,GPIF ; IOC "bit de inicio" ¿Interrupción?
goto ISR_SET ; No, saltar
movf GPIO,W ; Si, leer GPIO
bcf INTCON,GPIF ; Limpiar la bandera de interrupción IOC
btfsc GPIO,Rx_Pin ; ¿Rx_Pin = 0? (bit de inicio)
goto ISR_XIT ; No, Polaridad equivocada, saltar
bsf PROC232,RXFLAG ; Indicar Rx en progreso
movlw d'10' ; (1 bit de inicio + 8 de datos + 1 de parada)
movwf RXCNT ; Inicializar el conteo de bits
bcf INTCON,T0IF ; Limpiar la bandera de interrupción de TMR0
movlw -d'52'+d'39'; 1/2 bit (52uS)
movwf TMR0
goto ISR_X ; GP3 = 0 (IOC) y salir
; Limpiar la bandera de interrupción de TMR0
; Preparar TMR0 para la siguiente interrupción.
ISR_SET bcf INTCON,T0IF ; Limpiar la bandera de interrupción de TMR0
movlw -d'104'+2 ; Establecer 104uS
addwf TMR0,f
; Poner el bit en la salida serial
ISR_TX
btfss PROC232,TXFLAG ; ¿TX en progreso?
goto ISR_RX ; No, saltar
movf TXCNT,W ; Obtener el conteo de bits
bnz ISR_TX0 ; No, saltar envíar el siguiente bit
movlw d'10' ; 10 bits (inicio + 8 datos + detener)
movwf TXCNT ; inicializar el contador de bits de Tx
goto ISR_TX1 ; Envíar el bit de inicio de transmisión
ISR_TX0
rrf TXVAR,f ; Cambiar lsb dentro de C
bsf TXVAR,7 ; Poner el bit 7 para el bit de parada
btfsc STATUS,C ; Salta si C = 0
bsf GPIO,Tx_Pin ; Pin Tx = 1
btfss STATUS,C ; Salta si C = 1
ISR_TX1
bcf GPIO,Tx_Pin ; Pin Tx = 0
decfsz TXCNT,f ; Se envío el último bit cambiado?
goto ISR_RX ; No, saltar
bcf PROC232,TXFLAG ; Si, indicar fin de transmisión
; Subrutina de recepción
ISR_RX
btfss PROC232,RXFLAG ; ¿RX en progreso?
goto ISR_XIT ; No, saltar, en caso de
movf WR_PTR,W ; Poner WR_PTR (RXBUFF + 00..07)
movwf FSR ; Establecer la inderección
bcf STATUS,C ; Limpiar Carry, si el dato es 0
btfsc GPIO,Rx_Pin ; ¿Rx_Pin = 0?
bsf STATUS,C ; No, poner Carry, dato = 1
rrf INDF,F ; rotar el bit del caracter
decfsz RXCNT,F ; ¿10 bits?
goto ISR_XIT ; No, saltar
rlf INDF,F ; Si, eliminar el bit de parada
; Aquí ya está lleno el buffer con el caracter RXBUFF[WR_PTR]
bcf PROC232,RXFLAG ; Limpiar la bandera (Rx en progreso)
; Si WR_PTR + 1 = RD_PTR el buffer esta lleno y salir, si no
; incrementar la variable WR_PTR para recibir el siguiente caracter.
incf WR_PTR,W ; W = WR_PTR + 1
andlw RXBUFF+h'07'; Esto funciona para 20..27
xorwf RD_PTR,W ; WR_PTR+1 = RD_PTR ¿lleno?
skpz ; Si, Ignorar el nuevo caracter
incf WR_PTR,F ; Si no, sumarlo al buffer
bcf WR_PTR,3 ; Mantener en el rango de 20..27
ISR_X
bsf STATUS,RP0 ; Banco 1
movlw 1<<Rx_Pin ; Mascara para Rx_Pin/GP3 IOC
xorwf IOC,F ; Invertir Rx_Pin/GP3 IOC
bcf STATUS,RP0 ; Banco 0
; Restaurar Contexto
ISR_XIT
movf F_ISR,W
movwf FSR ; Restaurar FSR
movf P_ISR,W
movwf PCLATH ; Restaurar PCLATH
swapf S_ISR,W
movwf STATUS ; Restaurar STATUS
swapf W_ISR,F
swapf W_ISR,W ; Restaurar W-reg
retfie ; Regresar de la interrupción
;-------------------------------------------------------------
; SUBRUTINA DE INTERRUPCION
;-------------------------------------------------------------
;NOTA: cuando se pone a 1 GP2, se produce una interrupcion. Si la misma dura mas de 0.5 sg, se transfieren los datos por RS232 a una pc. Si dura menos, se reinicia el programa.
INT_GP2 bcf INTCON,1 ;limpia la bandera de interrupcion de GP2
movwf doblev ;guarda el dato de w antes de la iterrupcion
bsf GPIO,0 ;indica que se acepto una interrupcion
call demora0.1
btfss GPIO,2
goto volver
call demora0.1
btfss GPIO,2
goto volver
call demora0.1
btfss GPIO,2
goto volver
call demora0.1
btfss GPIO,2
goto volver
call BAJAR_DATOS
goto volver
volver bcf GPIO,0
bsf reiniciar,0 ;marca que hay que reiniciar
bcf INTCON,INTF ;y borra la bandera de que ocurrio una interrupcion
movf doblev,w ;reestablece el valor de w antes de volver
RETFIE
;-------------------------------------------------------------
; SUBRUTINA DE TRANSFERENCIA DE DATOS A PC POR RS232
;-------------------------------------------------------------
BAJAR_DATOS call TITULO ;escribe el titulo de la transmision
movlw d'0' ;empieza a leer los datos de la EEPROM desde la direccion 0.
movwf dirleida
leerotro call LEER_DATO
movlw d'8' ;"contador" se resta cada vez que se envia un bit
movwf contador
movf datoleido,w ;carga el dato leido del puerto A/D
desarmar andlw b'00000001' ;se queda con el ultimo bit
movwf aux
movlw b'00000001'
subwf aux,1
btfss STATUS,C
goto mandar1 ;dio cero, o sea que ERA UN UNO
goto mandar0 ;dio negativo, o sea que ERA UN CERO
mandar call Put232
rrf datoleido,1
decfsz contador,1
goto desarmar ;si no se transmitieron todavia los 8 bits, continua desarmando y enviando los bits el byte que fue convertido
call enter ;si ya se transmitieron los 8 bits, "teclea un enter" y busca otro byte
incf dirleida,1
; movf direccion,w ;carga la direccion hasta la que se grabo, y la resta de la direccion actual transmitida. Cuando sean iguales se detiene el proceso.
movlw b'01111111'
subwf dirleida,w
btfsc STATUS,C ;corrobora si la resta dio resultado "negativo"
goto leerotro ;si dio negativo hay que seguir transmitiendo
retlw 0 ;si ya se llego al numero de datos tomados se detiene el proceso
mandar1 movlw d'49' ;carga el ASCII del uno
movwf TEMP
goto mandar
mandar0 movlw d'48' ;carga el ASCII del cero
movwf TEMP
goto mandar
;******************************************************************
; Subrutinas Put232 y Get232
;******************************************************************
Put232
btfsc PROC232,TXFLAG ; ¿TX en progreso?
goto Put232 ; Si, saltar y esperar
movwf TXVAR ; Rellenar caracter
bsf PROC232,TXFLAG ; Iniciar TX
return
Get232
movf RD_PTR,W
xorwf WR_PTR,W ; ¿RD_PTR = WR_PTR? (buffer vacio)
bz Get232 ; Si, hacer un bucle, y esperar un caracter
movf FSR,W ; Ponerlo y guardar FSR
movwf FSRTMP
movf RD_PTR,W
movwf FSR ; Poner la indirección
movf INDF,W ; Poner el caracter RXBUFF[RD_PTR]
movwf RXCHAR ; Guardarlo para después
movf FSRTMP,W
movwf FSR ; Restaurar FSR
incf RD_PTR,W ; Incrementar RD_PTR
andlw b'100111' ; Mantener en el rango de 20..27
movwf RD_PTR
movf RXCHAR,W ; Tomar el caracter recibido
return
;******************************************************************
; Subrutina Init232
;******************************************************************
Init232
movlw RXBUFF ; Poner la dirección del buffer circular Rx
movwf RD_PTR ; Iniciar el buffer circular RD_PTR
movwf WR_PTR ; "" "" "" WR_PTR
clrf PROC232 ; Limpiar el enclave RS232
clrf TXCNT ; Inicializar la variable TXCNT
bsf GPIO,Tx_Pin ; Poner Tx_Pin en estado desocupado
return
;******************************************************************
; Subrutina que genera un "Enter del teclado"
;******************************************************************
enter movlw d'13' ; Cargo un Cr (Carriage Return)
movwf TEMP
call Put232
movlw d'10' ; Cargo un Lf (Line Feed)
movwf TEMP
call Put232
return
;-------------------------------------------------------------
; Programa principal
;-------------------------------------------------------------
principal movlw d'0'
movwf GPIO ;apaga todos los leds
movwf direccion ;comienza a grabar datos desde la posición d'0' de la EEPROM
movwf reiniciar ;apaga la bandera que indica si hay que reiniciar el programa por una interrupcion de menos de 0.5sg
inicio btfss GPIO,3 ;pregunta para empezar conversion cada 30 segundos
goto nada
goto continuar
nada bcf reiniciar,0 ;mientras no esta activo el programa se borra la bandera de reiniciar
goto inicio
continuar btfsc reiniciar,0 ;si detecta que hay que reiniciar, reinicia
goto resetear
convertir call CONVERSORAD
bsf STATUS,RP0 ;pasa al banco 1 (donde se maneja la EEPROM)
movf conversion,w
movwf EEDATA ;y lo deja listo para grabar CONFIGURACION DE DATOS A GRABAR EN EEPROM
movf direccion,w ;tambien carga la direccion donde se va a grabar el dato
movwf EEADR
incf direccion,1 ;deja seteado donde se va a grabar el proximo dato
call ESCRIBIR_EEPROM
bsf GPIO,5 ;avisa que se grabo un dato
call demora0.1
bcf GPIO,5
call demora30
goto continuar ;vuelve a preguntar si hay que reiniciar y sigue juntando datos
;-------------------------------------------------------------
; SUBRUTINA QUE OBTIENE EL VALOR DEL CONVERSOR A/D (GP4)
;-------------------------------------------------------------
CONVERSORAD bsf ADCON0,1 ;comienza la conversion A/D
convierte btfsc ADCON0,1 ;espera a que convierta el dato
goto convierte
movf ADRESH,w ;pasa el resultado de la conversion a w
movwf conversion ;y luego a la variable conversion
retlw 0
;-------------------------------------------------------------
; SUBRUTINA DE ESCRITURA DE DATOS EN EEPROM (se deben haber cargado EEDATA y EEADR)
;-------------------------------------------------------------
ESCRIBIR_EEPROM bsf STATUS,RP0 ;Bank 1
bsf EECON1,WREN ;Enable write
bcf INTCON,GIE
movlw 0x55 ;Inicio de las intrucciones para EECON2
movwf EECON2
movlw 0xAA
movwf EECON2 ;Fin de las intrucciones para EECON2
bsf EECON1,WR ;Start the write
bcf EECON1,WREN ; disable Write
bsf INTCON,GIE ;habilita las interrupciones
bcf STATUS,RP0 ; Banco 0
retlw 0
;-------------------------------------------------------------
; SUBRUTINA DE LECTURA DE DATOS DE LA EEPROM (cargar en "dirleida" la direccion del dato a leer)
;-------------------------------------------------------------
LEER_DATO bsf STATUS,RP0 ;Bank 1
movf dirleida,w ;carga la direccion a leer
movwf EEADR ;Address to read
bsf EECON1,RD ;EE Read
movf EEDATA,W ;Move data to W
movwf datoleido
retlw 0
;-------------------------------------------------------------
; SUBRUTINA DE RETARDO DE 30 SEGUNDOS
;-------------------------------------------------------------
;demora30 movlw D'153'
; movwf CounterC
; movlw D'49'
; movwf CounterB
; movlw D'161'
; movwf CounterA
;loop1 decfsz CounterA,1
; goto loop1
; decfsz CounterB,1
; goto loop1
; decfsz CounterC,1
; goto loop1
; retlw 0
;PIC Time Delay = 2,00000200 s with Osc = 4000000 Hz
demora30 movlw D'11'
movwf CounterC
movlw D'38'
movwf CounterB
movlw D'93'
movwf CounterA
loop1 decfsz CounterA,1
goto loop1
decfsz CounterB,1
goto loop1
decfsz CounterC,1
goto loop1
retlw 0
;-------------------------------------------------------------
; SUBRUTINA DE RETARDO DE 0.1 SEGUNDOS
;-------------------------------------------------------------
demora0.1 movlw D'130'
movwf CounterB
movlw D'221'
movwf CounterA
loop2 decfsz CounterA,1
goto loop2
decfsz CounterB,1
goto loop2
retlw 0
;-------------------------------------------------------------
; SUBRUTINA DE TITULO DE LA TRANSMISION
;-------------------------------------------------------------
TITULO
movlw 'D' ; Un caractér (1 Byte)
movwf TEMP ; Lo muevo a TEMP
call Put232 ; Lo envío
movlw 'a'
movwf TEMP
call Put232
movlw 't'
movwf TEMP
call Put232
movlw 'o'
movwf TEMP
call Put232
movlw 's'
movwf TEMP
call Put232
movlw ':'
movwf TEMP
call Put232
call enter
call enter ; deja 2 espacios como margen
retlw 0
END