panic_error!

Programación de un PIC16F84

Años antes de que el primer Arduino viera la luz del día ya había gente trasteando con pequeños microcontroladores. Os dejo por aquí un pequeño código que he encontrado rebuscando en el baúl donde se programa un dado electrónico usando un pequeño microcontrolador PIC16F84.

Mientras conectamos un display de 7 segmentos al PORTB y lo usamos como salida, conectamos a PORTA un botón físico que será el que detenga el dado. Como los microcontroladores son deterministas, generar un número puramente aleatorio es difícil. El programa utiliza el tiempo humano para esta labor. Mientras mantienes pulsado el botón, el registro AUX2 incrementa a una velocidad de microsegundos del 1 al 6. Como es imposible que un humano suelte el botón exactamente en el mismo microsegundo cada vez, el número que queda en AUX2 cuando sueltas el botón parece totalmente aleatorio.

Aquí tenéis el código completo aunque hace tanto tiempo que no toco uno de estos que no sería capaz de encontrar ningún error en caso de haberlo.

        LIST    P=16F84
        RADIX   HEX
; definicion de las constantes a usar en el programa
W       EQU     0
F       EQU     1
UNO     EQU     06
DOS     EQU     5B
TRES    EQU     4F
CUATRO  EQU     66
CINCO   EQU     6D
SEIS    EQU     7D

; declaracion de los registros
TMROPT  EQU     0x01
; ###### de generacion del numero aleatorio ######
PC      EQU     0x02
Z       EQU     0x02
ESTADO  EQU     0x03
PUERTAA EQU     0x05
PUERTAB EQU     0x06
INTCON  EQU     0x0B
VECES   EQU     0x10
AUX     EQU     0x0E


; ###### de generacion del numero aleatorio ######
AUX2    EQU     0x15
DISP    EQU     0x12
        ORG     0
        goto    inicio
        ORG     4
        goto    inter
        ORG     5

; para empezar inicializamos los 'registros'con los valores correspondientes
inicio  bsf     ESTADO,5
        clrf    PUERTAB
        movlw   b'00000001'     
        movwf   PUERTAA
        movlw   b'00000110'
        movwf   TMROPT
        bcf     ESTADO,5
        movlw   b'10100000'
        movwf   INTCON                       
; ###### de generacion del numero aleatorio ######
        MOVLW   0x01
        MOVWF   AUX2
        movlw   0X64
        movwf   VECES
        movlw   0xB2
        movwf   TMROPT
; ###### de generacion del numero aleatorio ######
bucle   btfsc   PUERTAA,0
        goto    bucle

; ###### de generacion del numero aleatorio ######
        call    RANDOM
        call    DISPLAY
        movwf   PUERTAB
        movlw   b'10100000'     
        movwf   INTCON
        goto    bucle
; codigo de la interrupcion
inter   btfsc   PUERTAA,0
        goto    inter_
        movlw   b'10100000'
        movwf   INTCON
        movlw   0xB2
        movwf   TMROPT
        retfie
inter_  decfsz  VECES,1
        goto    salir
reinic  movlw   0x64
        movwf   VECES
; en este momento ha pasado un segundo asi que empezamos a
; mostrsr los numero del uno al seis por el display con un
; peque¤o retardo (dos bucles anidados de ff instrucciones)
nums    movlw   0x01
        movwf   AUX
; ********* mostramos el valor 1 **********
        movf    AUX,W
        call    Display1
        movwf   PUERTAB
        movlw   0xff
        movwf   DISP


bucle1  btfsc   PUERTAA,0
        goto    b_1
        movlw   b'10100000'
        movwf   INTCON
        movlw   0xB2
        movwf   TMROPT
        retfie
b_1     decfsz  DISP,1
        goto    bucle1
; metemos un segundo bucle para mostrar el valor un mayor tiempo
        movlw   0xff
        movwf   DISP            
bucle1_ btfsc   PUERTAA,0
        goto    b__1
        movlw   b'10100000'
        movwf   INTCON
        movlw   0xB2
        movwf   TMROPT
        retfie
b__1    decfsz  DISP,1
        goto    bucle1_
; ********* mostramos el valor 2 **********
        incf    AUX,F
        movf    AUX,W
        call    Display2
        movwf   PUERTAB
        movlw   0xff
        movwf   DISP
bucle2  btfsc   PUERTAA,0
        goto    b_2
        movlw   b'10100000'
        movwf   INTCON
        movlw   0xB2
        movwf   TMROPT
        retfie
b_2     decfsz  DISP,1
        goto    bucle2
; metemos un segundo bucle para mostrar el valor un mayor tiempo
        movlw   0xff
        movwf   DISP            
bucle2_ btfsc   PUERTAA,0
        goto    b__2
        movlw   b'10100000'
        movwf   INTCON
        movlw   0xB2
        movwf   TMROPT
        retfie
b__2    decfsz  DISP,1
        goto    bucle2_
; ********* mostramos el valor 3 **********
        incf    AUX,F
        movf    AUX,W
        call    Display3
        movwf   PUERTAB
        movlw   0xff
        movwf   DISP
bucle3  btfsc   PUERTAA,0
        goto    b_3
        movlw   b'10100000'
        movwf   INTCON
        movlw   0xB2
        movwf   TMROPT
        retfie
b_3     decfsz  DISP,1
        goto    bucle3
; metemos un segundo bucle para mostrar el valor un mayor tiempo
        movlw   0xff
        movwf   DISP            
bucle3_ btfsc   PUERTAA,0
        goto    b__3
        movlw   b'10100000'
        movwf   INTCON
        movlw   0xB2
        movwf   TMROPT
        retfie
b__3    decfsz  DISP,1
        goto    bucle3_
; ********* mostramos el valor 4 **********
        incf    AUX,F
        movf    AUX,W
        call    Display4
        movwf   PUERTAB
        movlw   0xff
        movwf   DISP
bucle4  btfsc   PUERTAA,0
        goto    b_4
        movlw   b'10100000'
        movwf   INTCON
        movlw   0xB2
        movwf   TMROPT
        retfie
b_4     decfsz  DISP,1
        goto    bucle4
; metemos un segundo bucle para mostrar el valor un mayor tiempo
        movlw   0xff
        movwf   DISP            
bucle4_ btfsc   PUERTAA,0
        goto    b__4
        movlw   b'10100000'
        movwf   INTCON
        movlw   0xB2
        movwf   TMROPT
        retfie

b__4    decfsz  DISP,1
        goto    bucle4_
; ********* mostramos el valor 5 **********
        incf    AUX,F
        movf    AUX,W
        call    Display5
        movwf   PUERTAB
        movlw   0xff
        movwf   DISP
bucle5  btfsc   PUERTAA,0
        goto    b_5
        movlw   b'10100000'
        movwf   INTCON
        movlw   0xB2
        movwf   TMROPT
        retfie
b_5     decfsz  DISP,1
        goto    bucle5
; metemos un segundo bucle para mostrar el valor un mayor tiempo
        movlw   0xff
        movwf   DISP            
bucle5_ btfsc   PUERTAA,0
        goto    b__5
        movlw   b'10100000'
        movwf   INTCON
        movlw   0xB2
        movwf   TMROPT
        retfie
b__5    decfsz  DISP,1
        goto    bucle5_
; ********* mostramos el valor 6 **********
        incf    AUX,F
        movf    AUX,W
        call    Display6
        movwf   PUERTAB
        movlw   0xff
        movwf   DISP
bucle6  btfsc   PUERTAA,0
        goto    b_6
        movlw   b'10100000'
        movwf   INTCON
        movlw   0xB2
        movwf   TMROPT
        retfie
b_6     decfsz  DISP,1
        goto    bucle6
; metemos un segundo bucle para mostrar el valor un mayor tiempo
        movlw   0xff
        movwf   DISP            
bucle6_ btfsc   PUERTAA,0
        goto    b__6
        movlw   b'10100000'
        movwf   INTCON
        movlw   0xB2
        movwf   TMROPT
        retfie
b__6    decfsz  DISP,1
        goto    bucle6_
; una vez mostrados todos los numero del 1 al 6 repetimos la operacion
        goto    nums
salir   movlw   b'10100000'

        movwf   INTCON
        movlw   0xB2
        movwf   TMROPT
        retfie

; rutinas que nos dan el valor de los numeros en su "modo" display
Display1  retlw   UNO
Display2  retlw   DOS
Display3  retlw   TRES
Display4  retlw   CUATRO
Display5  retlw   CINCO
Display6  retlw   SEIS

; ###### de generacion del numero aleatorio ######
; rutina para generar el numero "aleatorio" (realmente es pseudoaleatorio)
; pues en el caso de que pulsaramos 2 veces el boton al mismo tiempo
; durante exactamente el mismo tiempo nos daria el mismo numero
; cuando en un algoritmo real de generacion de numero aleatorios esto
; seria realmente complicado
RANDOM  movlw   b'00000000'
        movwf   INTCON
RANDOM2 btfsc   PUERTAA,0
        goto    salirR
        movlw   b'00000110'
        subwf   AUX2,W
        btfsc   ESTADO,Z
        clrf    AUX2
        incf    AUX2,F
        goto    RANDOM2
salirR  movf    AUX2,W
        return

; ###### de generacion del numero aleatorio ######
; rutina que nos da el valor del "codigo" 7 segmentos para cada valor
; del dado
DISPLAY addwf   PC,F
        nop
        retlw   UNO
        retlw   DOS
        retlw   TRES
        retlw   CUATRO
        retlw   CINCO
        retlw   SEIS
        end


Abril 2003