Referència | Trucs | Perifèrics | Recursos CITCEA | |
Tutorial | Exemples | Projectes | Inici |
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.
En el programa següent generem, a cada cicle, un valor aleatori i en mostrem els quatre bits menys significatius als LED.
#include <p16F690.inc> __config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
cblock 0x20 Rand:2 ; Dos bytes on guardarem el valor aleatori Auxrand:2 ; Variable auxiliar per a Random Retard1 ; Variables de retard Retard2 Retard3 endc
org 0 Inici bsf STATUS,RP0 ; Tria el banc 1 clrf TRISC ; Posa tots els bits del port C com a sortida bcf STATUS,RP0 ; Tria el banc 0 movlw b'01010101' ; 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 de 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 STATUS,C ; Entrarem un zero rlf Auxrand,f ; Hem rodat a l'esquerra, ara el bit 3 és a C btfsc STATUS,C ; 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 b'00000001' ; 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
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.
#include <p16F690.inc> __config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
cblock 0x20 Rand:2 ; Dos bytes on guardarem el valor aleatori Auxrand:2 ; Variable auxiliar per a Random Retard1 ; Variables de retard Retard2 Retard3 endc
org 0 Inici bsf STATUS,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 clrf TRISC ; Posa tots els bits del port C com a sortida movlw b'10000000' ; 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 STATUS,RP0 ; Tria el banc 0 clrf PORTC ; Apaga els LED movf TMR0,w ; Agafa el valor de TMR0 movwf Rand+1 ; I el posa com a byte més significatiu de la llavor swapf TMR0,w ; Agafa el valor permutat de TMR0 movwf Rand ; I el posa com a byte menys significatiu de la 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 de 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 STATUS,C ; Entrarem un zero rlf Auxrand,f ; Hem rodat a l'esquerra, ara el bit 3 és a C btfsc STATUS,C ; 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 b'00000001' ; 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
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.
#include <p16F690.inc> __config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
cblock 0x20 Rand:2 ; Dos bytes on guardarem el valor aleatori Auxrand:2 ; Variable auxiliar per a Random Retard1 ; Variables de retard Retard2 Retard3 endc
org 0 Inici bsf STATUS,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 clrf TRISC ; Posa tots els bits del port C com a sortida movlw b'10000000' ; 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 STATUS,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 ; I el posa com a byte més significatiu de la llavor swapf TMR0,w ; Agafa el valor permutat de TMR0 movwf Rand ; I el posa com a byte menys significatiu de la 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 de 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 STATUS,C ; Entrarem un zero rlf Auxrand,f ; Hem rodat a l'esquerra, ara el bit 3 és a C btfsc STATUS,C ; 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 b'00000001' ; 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
Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.