Programació en pic-as del PIC 16F690

Referència Trucs Perifèrics   Recursos CITCEA
Tutorial Exemples Projectes   Inici

Generació de valors aleatoris

Per a la generació de números aleatoris podem fer servir la funció Random que dona resultats de 16 bits. En realitat, es tracta d'un generador de nombres pseudo-aleatoris, per tant comença amb un valor inicial (llavor) i va generant una seqüència a partir d'ella. El funcionament es basa en una rotació de LED cap a l'esquerra en la que, per la dreta, s'entra un bit que s'ha generat a partir dels bits de la llavor. El valor generat serà la llavor per a la següent vegada. El següent gràfic (on el símbol representa la funció o exclusiva) ens mostra com funciona. La funció o exclusiva dona 1 si els dos bits d'entrada són diferents i zero si són iguals.

Generació de nombres pseudo-aleatoris

En el programa següent generem, a cada cicle, un valor aleatori i en mostrem els quatre bits menys significatius als LED.

PROCESSOR 16F690
#include <xc.inc>
config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF
config CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF
Rand EQU 0x20  ; Dos bytes on guardarem el valor aleatori (2 bytes)
Auxrand EQU 0x22  ; Variable auxiliar per a Random (2 bytes)
Retard1 EQU 0x24  ; Variables de retard	
Retard2 EQU 0x25
Retard3 EQU 0x26
PSECT code, class=CODE, delta=2, abs
main:
  bsf RP0  ; Tria el banc 1
  movlw 11110000B  ; Posa les potes que corresponen als LED com a sortida
  movwf TRISC  ; la resta del port C com a entrada
  bcf RP0  ; Tria el banc 0
  movlw 01010101B  ; Agafa un valor concret
  movwf Rand  ; Ho posa com a llavor
  movwf Rand+1  ; Ho posa com a llavor
  clrf PORTC  ; Apaga els LED
Bucle:
  call Random  ; Genera un valor aleatori
  movf Rand,w  ; Llegeix el valor aleatori
  movwf PORTC  ; I ho posa als LED
  movlw 5  ; Retard d'1 s
  call Rets
  goto Bucle  ; Repetim-ho...
;
; Funció que genera valors aleatoris
;
Random:
  clrf Auxrand  ; Posa a zero les variables auxiliars
  clrf Auxrand+1  ; Posa a zero les variables auxiliars
                  ; Rand+1:  15 14 13 12 11 10  9  8
                  ; Rand:     7  6  5  4  3  2  1  0
  rlf Rand+1,w  ; Roda a l'esquerra i deixa el resultat a W
                ; Rand+1:  15 14 13 12 11 10  9  8
                ; W:       14 13 12 11 10  9  8  X
  xorwf Rand+1,w  ; Fa un xor amb l'original i deixa el resultat a W
  movwf Auxrand+1  ; El bit de l'esquerra serà la xor del 14 i el 15
  swapf Rand+1,f  ; Permuta els nibbles
                  ; Rand+1:  11 10  9  8 15 14 13 12
                  ; Rand:     7  6  5  4  3  2  1  0
  swapf Rand,w  ; Guarda els nibbles permutats a W
  movwf Auxrand  ; Auxrand:  3  2  1  0  7  6  5  4
  bcf CARRY  ; Entrarem un zero
  rlf Auxrand,f  ; Hem rodat a l'esquerra, ara el bit 3 és a C
  btfsc CARRY  ; Si C és zero no fem res
  bsf Auxrand,0  ; Si C és 1, activem el bit de la dreta
                 ; Auxrand:  2  1  0  7  6  5  4  3
                 ; Rand+1:  11 10  9  8 15 14 13 12
                 ; Rand:     7  6  5  4  3  2  1  0
  movf Auxrand,w  ; Copia Auxrand a W
  xorwf Rand+1,w  ; El bit de la dreta de W serà la xor de 3 i 12
  swapf Rand+1,f  ; Ho torna a deixar com estava
                  ; Rand+1:  15 14 13 12 11 10  9  8
                  ; Rand:     7  6  5  4  3  2  1  0
  andlw 00000001B  ; Posa w a zero excepte el bit de la dreta
  rlf Auxrand+1,f  ; Agafem el bit de l'esquerra i el posem a C
                   ; Aquest bit era la xor del 14 i el 15
  rlf Rand,f  ; Rodem Rand a l'esquerra entrant el bit que volem per la dreta
  xorwf Rand,f  ; Li fem una xor amb W que afecta només al bit de la dreta
  rlf Rand+1,f  ; Rodem Rand+1 a l'esquerra entrant el bit que ha sortit de Rand
  return
Rets:  ; Funció de retard de 0,2 W s
  movwf Retard3
Bucles:
  decfsz Retard1,f		
  goto Bucles		
  decfsz Retard2,f		
  goto Bucles		
  decfsz Retard3,f	
  goto Bucles
  return
END main

Si provem el programa, hauríem d'obtenir una seqüència que pot semblar aleatòria però que és la mateixa cada cop que tornem a posar en marxa el microcontrolador. Això passa perquè aquesta funció el que fa és generar nombres pseudoaleatoris. Per aconseguir millors resultats, cal definir una llavor que sigui diferent cada vegada, així la seqüència serà diferent cada cop. El següent programa agafa com a llavor el valor de TMR0 que sempre està variant.

PROCESSOR 16F690
#include <xc.inc>
config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF
config CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF
Rand EQU 0x20  ; Dos bytes on guardarem el valor aleatori (2 bytes)
Auxrand EQU 0x22  ; Variable auxiliar per a Random (2 bytes)
Retard1 EQU 0x24  ; Variables de retard	
Retard2 EQU 0x25
Retard3 EQU 0x26
PSECT code, class=CODE, delta=2, abs
main:
  bsf RP0  ; Tria el banc 1
  movlw 11110000B  ; Posa les potes que corresponen als LED com a sortida
  movwf TRISC  ; la resta del port C com a entrada
  movlw 10000000B  ; Configuració de Timer0
                   ; Com a temporitzador basat en rellotge
                   ; 000 - Factor d'escala de 2
                   ; I resistències de pull-up desactivades (valor per defecte)
  movwf OPTION_REG  ; Ho guarda
  bcf RP0  ; Tria el banc 0
  movf TMR0,w  ; Agafa el valor de TMR0
  movwf Rand+1  ; Ho posa com a llavor
  swapf TMR0,w  ; Agafa el valor permutat de TMR0
  movwf Rand  ; Ho posa com a llavor
  clrf PORTC  ; Apaga els LED
Bucle:
  call Random  ; Genera un valor aleatori
  movf Rand,w  ; Llegeix el valor aleatori
  movwf PORTC  ; I ho posa als LED
  movlw 5  ; Retard d'1 s
  call Rets
  goto Bucle  ; Repetim-ho...
;
; Funció que genera valors aleatoris
;
Random:
  clrf Auxrand  ; Posa a zero les variables auxiliars
  clrf Auxrand+1  ; Posa a zero les variables auxiliars
                  ; Rand+1:  15 14 13 12 11 10  9  8
                  ; Rand:     7  6  5  4  3  2  1  0
  rlf Rand+1,w  ; Roda a l'esquerra i deixa el resultat a W
                ; Rand+1:  15 14 13 12 11 10  9  8
                ; W:       14 13 12 11 10  9  8  X
  xorwf Rand+1,w  ; Fa un xor amb l'original i deixa el resultat a W
  movwf Auxrand+1  ; El bit de l'esquerra serà la xor del 14 i el 15
  swapf Rand+1,f  ; Permuta els nibbles
                  ; Rand+1:  11 10  9  8 15 14 13 12
                  ; Rand:     7  6  5  4  3  2  1  0
  swapf Rand,w  ; Guarda els nibbles permutats a W
  movwf Auxrand  ; Auxrand:  3  2  1  0  7  6  5  4
  bcf CARRY  ; Entrarem un zero
  rlf Auxrand,f  ; Hem rodat a l'esquerra, ara el bit 3 és a C
  btfsc CARRY  ; Si C és zero no fem res
  bsf Auxrand,0  ; Si C és 1, activem el bit de la dreta
                 ; Auxrand:  2  1  0  7  6  5  4  3
                 ; Rand+1:  11 10  9  8 15 14 13 12
                 ; Rand:     7  6  5  4  3  2  1  0
  movf Auxrand,w  ; Copia Auxrand a W
  xorwf Rand+1,w  ; El bit de la dreta de W serà la xor de 3 i 12
  swapf Rand+1,f  ; Ho torna a deixar com estava
                  ; Rand+1:  15 14 13 12 11 10  9  8
                  ; Rand:     7  6  5  4  3  2  1  0
  andlw 00000001B  ; Posa w a zero excepte el bit de la dreta
  rlf Auxrand+1,f  ; Agafem el bit de l'esquerra i el posem a C
                   ; Aquest bit era la xor del 14 i el 15
  rlf Rand,f  ; Rodem Rand a l'esquerra entrant el bit que volem per la dreta
  xorwf Rand,f  ; Li fem una xor amb W que afecta només al bit de la dreta
  rlf Rand+1,f  ; Rodem Rand+1 a l'esquerra entrant el bit que ha sortit de Rand
  return
Rets:  ; Funció de retard de 0,2 W s
  movwf Retard3
Bucles:
  decfsz Retard1,f		
  goto Bucles		
  decfsz Retard2,f		
  goto Bucles		
  decfsz Retard3,f	
  goto Bucles
  return
END main

Aquest programa va bé si reprogramem el microcontrolador sense desconnectar-lo. Però si desconnectem el microcontrolador i el tornem a connectar és probable que la seqüència es repeteixi. El motiu és que el temps que triga en fer les instruccions prèvies és sempre el mateix o sigui que si l'apago i el torno a engegar, el valor de TMR0 que dóno és sempre igual. En el programa següent afegim un detall que li dona una aleatorietat pràcticament total ja que no es llegirà el valor de TMR0 fins que l'usuari hagi premut el polsador i després l'hagi deixat anar. Hem afegit un retard abans de mirar el polsador ja que el programador (que comparteix pota amb el polsador) pot interferir amb la lectura del polsador durant els primers microsegons.

PROCESSOR 16F690
#include <xc.inc>
config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF
config CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF
Rand EQU 0x20  ; Dos bytes on guardarem el valor aleatori (2 bytes)
Auxrand EQU 0x22  ; Variable auxiliar per a Random (2 bytes)
Retard1 EQU 0x24  ; Variables de retard	
Retard2 EQU 0x25
Retard3 EQU 0x26
PSECT code, class=CODE, delta=2, abs
main:
  bsf RP0  ; Tria el banc 1
  movlw 0xFF  ; Posa l'acumulador a FFh (tot uns)
  movwf TRISA  ; Posa tots els bits del port A com a entrada
  movlw 11110000B  ; Posa les potes que corresponen als LED com a sortida
  movwf TRISC  ; la resta del port C com a entrada
  movlw 10000000B  ; Configuració de Timer0
                   ; Com a temporitzador basat en rellotge
                   ; 000 - Factor d'escala de 2
                   ; I resistències de pull-up desactivades (valor per defecte)
  movwf OPTION_REG  ; Ho guarda
  bcf RP0  ; Tria el banc 0
  clrf PORTC  ; Apaga els LED
  movlw 10  ; Retard de 2 s
  call Rets
  btfsc PORTA,3  ; Mira si està desactivada l'entrada A3
                 ; Si està desactivada, no fa la instrucció següent
                 ; Fa la instrucció si l'entrada està activada
  goto $-1  ; Si no està premut, espera
  btfss PORTA,3  ; Mira si està activada l'entrada A3
                 ; Si està activada, no fa la instrucció següent
                 ; Fa la instrucció si l'entrada està desactivada
  goto $-1  ; Si està premut, espera
  movf TMR0,w  ; Agafa el valor de TMR0
  movwf Rand+1  ; Ho posa com a llavor
  swapf TMR0,w  ; Agafa el valor permutat de TMR0
  movwf Rand  ; Ho posa com a llavor
Bucle:
  call Random  ; Genera un valor aleatori
  movf Rand,w  ; Llegeix el valor aleatori
  movwf PORTC  ; I ho posa als LED
  movlw 5  ; Retard d'1 s
  call Rets
  goto Bucle  ; Repetim-ho...
;
; Funció que genera valors aleatoris
;
Random:
  clrf Auxrand  ; Posa a zero les variables auxiliars
  clrf Auxrand+1  ; Posa a zero les variables auxiliars
                  ; Rand+1:  15 14 13 12 11 10  9  8
                  ; Rand:     7  6  5  4  3  2  1  0
  rlf Rand+1,w  ; Roda a l'esquerra i deixa el resultat a W
                ; Rand+1:  15 14 13 12 11 10  9  8
                ; W:       14 13 12 11 10  9  8  X
  xorwf Rand+1,w  ; Fa un xor amb l'original i deixa el resultat a W
  movwf Auxrand+1  ; El bit de l'esquerra serà la xor del 14 i el 15
  swapf Rand+1,f  ; Permuta els nibbles
                  ; Rand+1:  11 10  9  8 15 14 13 12
                  ; Rand:     7  6  5  4  3  2  1  0
  swapf Rand,w  ; Guarda els nibbles permutats a W
  movwf Auxrand  ; Auxrand:  3  2  1  0  7  6  5  4
  bcf CARRY  ; Entrarem un zero
  rlf Auxrand,f  ; Hem rodat a l'esquerra, ara el bit 3 és a C
  btfsc CARRY  ; Si C és zero no fem res
  bsf Auxrand,0  ; Si C és 1, activem el bit de la dreta
                 ; Auxrand:  2  1  0  7  6  5  4  3
                 ; Rand+1:  11 10  9  8 15 14 13 12
                 ; Rand:     7  6  5  4  3  2  1  0
  movf Auxrand,w  ; Copia Auxrand a W
  xorwf Rand+1,w  ; El bit de la dreta de W serà la xor de 3 i 12
  swapf Rand+1,f  ; Ho torna a deixar com estava
                  ; Rand+1:  15 14 13 12 11 10  9  8
                  ; Rand:     7  6  5  4  3  2  1  0
  andlw 00000001B  ; Posa w a zero excepte el bit de la dreta
  rlf Auxrand+1,f  ; Agafem el bit de l'esquerra i el posem a C
                   ; Aquest bit era la xor del 14 i el 15
  rlf Rand,f  ; Rodem Rand a l'esquerra entrant el bit que volem per la dreta
  xorwf Rand,f  ; Li fem una xor amb W que afecta només al bit de la dreta
  rlf Rand+1,f  ; Rodem Rand+1 a l'esquerra entrant el bit que ha sortit de Rand
  return
Rets:  ; Funció de retard de 0,2 W s
  movwf Retard3
Bucles:
  decfsz Retard1,f		
  goto Bucles		
  decfsz Retard2,f		
  goto Bucles		
  decfsz Retard3,f	
  goto Bucles
  return
END main

 

 

Llicència de Creative Commons
Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.