LIST P=16f84a
   INCLUDE "p16C5x.inc"
  __FUSES _CP_OFF&_WDT_OFF&_LP_OSC

 ;Este programa realiza un contador decimal con un pulsador y un display de 7
 ;segmentos, el valor del conteo se guarda en la memoria serial 24LC01
 ;definición de bits
 status  equ    3h        ;registro de estados
 ptoa    equ    5h        ;
 ptob    equ    6h        ;
 addr    equ    0dh       ;posición de memoria que se lee o escribe
 datao   equ    0eh       ;registro para escribir datos en la memoria
 slave   equ    0fh       ;dirección del dispositivo en el bus I2C (1010xxx0)
 txbuf   equ    10h       ;buffer de transmision
 count   equ    11h       ;contador de bits
 eeprom  equ    12h       ;buffer de bits
 rxbuf   equ    13h       ;buffer de recepción
 loops   equ    15h       ;se utilizan en retardos
 loops2  equ    16h       ;
 di      equ    7         ;bit de entrada desde eeprom
 do      equ    6         ;bit de salida para eeprom
 sdata   equ    6         ;linea de datos seriales (pin RB6)
 sclk    equ    7         ;reloj serial (pin RB7)
 conta   equ    17h       ;lleva el conteo de pulsaciones
 conta2  equ    18h
 trisa   equ    85h       ;registro de configuración del puerto A
 trisb   equ    86h       ;registro de configuración del puerto B
 z       equ    02h       ;bandera de cero del registro de estados
 w       equ    00h       ;indica que el resultado se guarda en W
 c       equ    00h       ;bandera de carry
         org    00h       ;Vector de reset
         goto   INICIO
         org    03h

 WAIT                     ;subrutina de retardo en milisegundos
 top2    movlw  .110      ;el numero de milisegundos llega
         movwf  loops2    ;cargado en el registro loops
 top     nop
         nop
         nop
         nop
         nop
         nop
         decfsz  loops2   ;pregunta si termino 1 ms
         goto    top
         decfsz  loops    ;pregunta si termina el retardo
         goto    top2
         retlw   0

 retardo movlw   .100     ;retardo de 100 milisegundos
         movwf   loops
         call    WAIT
         retlw   0

 BSTART   ;Esta rutina genera el start bit para la comunicacion serial
          movlw   b’00111111'
          tris    ptob           ;programar datos y reloj como salidas
          bcf     ptob,sclk      ;linea de reloj en nivel bajo
          bsf     ptob,sdata     ;se asegura línea de datos en alto
          nop
          bsf     ptob,sclk      ;línea de reloj en alto
          nop
          nop                    ;ajuste de tiempo
          nop
          nop
          nop
          bcf     ptob,sdata     ;se baja la línea de datos
          nop                    ;mientras el reloj está alto
          nop
          nop                    ;ajuste de tiempo
          nop
          nop
          bcf     ptob,sclk      ;se baja la línea de reloj
          nop                    ;para terminar el pulso
          nop
          retlw    0

 BSTOP    ;Esta rutina genera el stop bit para la comunicación serial
          movlw    b’00111111'   ;
          tris     ptob          ;programa reloj y datos como salidas
          bcf      ptob,sdata    ;asegura línea de datos en bajo
          nop
          nop
          nop
          bsf      ptob,sclk     ;línea de reloj en nivel alto
          nop
          nop
          nop
          bsf      ptob,sdata    ;la línea de datos pasa a nivel alto
          nop                    ;mientras el reloj está alto
          nop
          bcf      ptob,sclk     ;la línea de reloj baja nuevamente
          nop                    ;para completar el pulso
          nop
          nop
          retlw    0

 BITOUT   ;Esta rutina toma el bit que se debe transmitir y lo saca al puerto
          movlw    b’00111111'   ;además genera el pulso de reloj
          tris     ptob          ;programa reloj y datos como salidas
          bsf      ptob,sdata    ;asume que el bit es alto
          btfss    eeprom,do     ;pregunta estado del bit a transmitir
          bcf      ptob,sdata    ;si el bit es bajo pone la salida en bajo
 clkout   nop
          nop
          bsf      ptob,sclk     ;sube el nivel de la línea de reloj
          nop                    ;para formar el pulso
          nop
          nop
          nop
          bcf      ptob,sclk     ;termina pulso de reloj
          retlw    0

 BITIN    ;Esta rutina lee un bit de la memoria y lo pone en un registro
          bsf      eeprom,di     ;asume que el bit es de nivel alto
          movlw    b’01111111'   ;programa pin de datos como entrada
          tris     ptob
          bsf      ptob,sclk     ;sube la linea del reloj
          nop                    ;
          nop
          nop
          nop
          nop      
          nop      
          nop      
          nop                    ;
          btfss    ptob,sdata    ;pregunta por el estado del pin de datos
          bcf      eeprom,di     ;si es bajo lo pone en ese nivel
          bcf      ptob,sclk     ;si es alto lo deja como se asumió antes
          retlw    0             ;

 TX       ;Esta rutina se encarga de transmitir un byte hacia la memoria
          movlw    .8
          movwf    count         ;el número de bits es 8
 TXLP     bcf      eeprom,do     ;asume que el bit a enviar es bajo
          btfsc    txbuf,7       ;consulta el estado real del bit
          bsf      eeprom,do     ;si era alto lo deja con dicho nivel
          call     BITOUT        ;saca el bit por el puerto
          rlf      txbuf,1       ;rota el byte que se está transmitiendo
          decfsz   count         ;pregunta si ya pasaron los 8 bits
          goto     TXLP          ;si no ha terminado sigue transmitiendo
          call     BITIN         ;espera el reconocimiento enviado por la
          retlw    0             ;memoria (ACK)

 RX       ;Esta rutina recibe un byte y lo entrega en el registro rxbuf
          clrf     rxbuf         ;borra el buffer de entrada
          movlw    .8            ;indica que recibe 8 bits
          movwf    count
          bcf      status,0      ;Borra el carry
 RXLP     rlf      rxbuf, F      ;rota a la izquierda
          call     BITIN         ;lee un bit
          btfsc    eeprom,di
          bsf      rxbuf,0       ;si es necesario pone el bit en uno
          decfsz   count         ;pregunta si completo 8 bits
          goto     RXLP          ;sino, recibe otro bit
          bsf      eeprom,do     ;envia el ACK de asentimiento
          call     BITOUT        ;para terminar
          retlw    0

 LEER     ;Esta rutina recibe la dirección que se
          ;desea LEER y devuelve el dato que tiene grabado
          call     BSTART        ;genera el start bit
          nop                    ;
          nop                    ;
          bcf      slave,0       ;selecciona la memoria
          movf     slave,w       ;y selecciona modo de escritura
          movwf    txbuf         ;
          call     TX            ;envía esos datos a la memoria
          movf     addr,w        ;
          movwf    txbuf         ;envía la posicion de memoria a ser leida
          call     TX            ;
          nop                    ;ahora se selecciona nuevamente la memoria
          nop                    ;y se le indica modo de lectura
          call     BSTART        ; genera start bit
          nop
          nop
          bsf      slave,0       ;indica que se va a LEER
          movf     slave,w       ;selecciona el dispositivo
          movwf    txbuf         ;
          call     TX            ;envia esa información a la memoria
          nop
          call     RX            ;la memoria entrega el byte de esa dirección
          bsf      eeprom,do     ;envia el ACK de reconocimiento
          call     BITOUT
          call     BSTOP         ;se envia el stop bit para finalizar comunicación
          retlw    0

 ESCRIB   ;Esta rutina escribe un dato en la posición
          ;de memoria que se le indique en el registro addr
          call     BSTART        ;genera el start bit
          nop                    ;
          nop                    ;
          bcf      slave,0       ;selecciona la memoria
          movf     slave,w       ;y selecciona modo de escritura
          movwf    txbuf         ;
          call     TX            ;envía esos datos a la memoria
          movf     addr,w        ;
          movwf    txbuf         ;envía la posición de memoria a ser grabada
          call     TX            ;ahora se selecciona nuevamente la memoria
          nop                    ;y se le indica modo de lectura
          nop
          movf     datao,w       ;toma el dato que va a ser grabado
          movwf    txbuf         ;y lo envía
          call     TX
          call     BSTOP
          movlw    .10           ;retardo de 10 ms al escribir
          movwf    oops          ;cada dato
          call     WAIT
          retlw    0

 INICIO    bsf       status,5       ;se ubica en el segundo banco de RAM
           movlw     0f0h           ;se carga el registro W con 0f
           movwf     trisa          ;se programa el puerto A como salidas
           movlw     07fh           ;se carga el registro W con 00
           movwf     trisb          ;se programa el puerto B como entradas
           bcf       status,5       ;se ubica en el primer banco de memoria RAM
           movlw  b’10100000'         ;La dirección A0, A1, y A2 de la memoria
           movwf  slave               ;en el bus I2C es 000
           clrf      addr           ;cuando se enciende el sistema se verifica que
           call      LEER           ;el dato guardado en memoria esté entre 0 y 9
           movlw     0ah            ;la prueba se hace porque la primera vez que
           subwf     rxbuf,w        ;se encienda el sistema se puede tener un
           btfss     status,c       ;número fuera del rango
           goto      ciclo          ;para las ocasiones posteriores no importa
 ini2      clrf      conta          ;inicia contador en cero
           clrf      datao
           call      ESCRIB         ;inicia dato de memoria en 0
 ciclo     call      LEER           ;LEER memoria, devuelve dato en W
           movf      rxbuf,w        ;pasa el valor de W al puerto A (display)
           movwf     conta
           movwf     ptoa
           call      retardo        ;retardo esperando que suelten la tecla
 pulsa     btfsc     ptob,0         ;pregunta si el pulsador está oprimido
           goto      pulsa          ;si no lo está continúa revisándolo
           call      retardo        ;si está oprimido retarda 100 milisegundos
           btfsc     ptob,0         ;para comprobar
           goto      pulsa          ;si no lo está vuelve a revisar
           incf      conta          ;si lo confirma incrementa el contador
           movf      conta,w        ;carga el registro W con el valor del conteo
           movwf     datao          ;el dato del conteo lo guarda en memoria
           call      ESCRIB         ;para recuperarlo en caso de un apagón
           movf      conta,w
           xorlw     0ah            ;hace operación xor para ver si es igual a 0ah
           btfss     status,z       ;prueba si el contador llegó a 0ah (diez)
           goto      ciclo          ;si no es igual se incrementa normalmente
           goto      ini2           ;
           end ;
;======================================================================
;          Fusibles de programación
;          Osc XT
;          Watchdog OFF
;          Code protect OFF
;          Power-Up-Timer ON
;          Micro. PIC16F84
;======================================================================