Diferencia entre revisiones de «C10 - Finite State Machine»
Sin resumen de edición |
|||
| (No se muestran 61 ediciones intermedias del mismo usuario) | |||
| Línea 1: | Línea 1: | ||
= Introducción = | = Introducción = | ||
<br> | <br> | ||
El microcontrolador cuenta | El microcontrolador cuenta con dos fuentes para el oscilador: | ||
*Interna | *Interna | ||
**El oscilador interno del uC TM4C va a 16Mhz con una presicón de | **El oscilador interno del uC TM4C va a 16Mhz con una presicón de ±1% <math>\Rightarrow</math> poco preciso | ||
**Consume poca corriente | **Consume poca corriente | ||
*Externa | *Externa | ||
**Se puede | **Se puede configurar el cristal a <b>diferentes velocidades</b> según las necesidades | ||
**Son mucho mas | **Son mucho mas <b>preciso</b> que el interno | ||
**Consumen más corriente y espacio en el PCB | **<b>Consumen más corriente</b> y espacio en el PCB | ||
<br> | <br> | ||
= Phase-Lock-Loop (PLL) = | = Phase-Lock-Loop (PLL) = | ||
== Que és? Cómo funciona? == | == Que és? Cómo funciona? == | ||
<br> | <br> | ||
*Permite seleccionar un cristal externo | *Permite seleccionar un <b>cristal externo</b> | ||
*Permite seleccionar la velocidad del procesador | *Permite seleccionar la <b>velocidad del cristal</b> y por tanto del procesador | ||
*Permite seleccionar la <b>velocidad del bus del sistema</b> | |||
*Para poder llevar a cabo estas dos operaciones necesitamos manipular dos registros | *Para poder llevar a cabo estas dos operaciones necesitamos manipular dos registros | ||
**SYSCTL_RCC_R | **SYSCTL_RCC_R | ||
| Línea 29: | Línea 31: | ||
**Este campo se compone de 7 bits - del bit 28 al bit 22 | **Este campo se compone de 7 bits - del bit 28 al bit 22 | ||
**Configura la velocidad del bus del sistema | **Configura la velocidad del bus del sistema | ||
**La fórmula para calcular es: | **La fórmula para calcular es: | ||
<br> | |||
<math>velocidad = \frac{400}{n+1} \Rightarrow n = SYSDIV2</math><br> | <math>velocidad = \frac{400}{n+1} \Rightarrow n = SYSDIV2</math><br> | ||
Hay que tener en cuenta que a <math>\uparrow</math> el número n <math>\Rightarrow</math> <math>\downarrow</math> velocidad del reloj<br> | Ej.<br> | ||
<math>velocidad = \frac{400}{n+1} = \frac{400}{4+1} = 80Mhz \Rightarrow</math> En el campo <b>SYSDIV2</b> pondremos el valor <b>4</b><br> | |||
(Hay que tener en cuenta que a <math>\uparrow</math> el número n <math>\Rightarrow</math> <math>\downarrow</math> velocidad del reloj)<br> | |||
<br> | <br> | ||
Codificación velocidad cristal en hexadecimal:<br> | Codificación velocidad cristal en hexadecimal:<br> | ||
[[File: edx-xtal.png || 500px]]<br> | [[File: edx-xtal.png || 500px]]<br> | ||
<br> | <br> | ||
Notas: | |||
*No se si está bien explicada la función del PLL de ajustar la velocidad del reloj/bus. En las prácticas se ve como ponen a 80Mhz "algo". Yo creia que era el cristal, pero viendo la tabla de arriba el cristal como máximo puede ir a 25Mhz. | |||
*El campo <b>SYSDIV2</b> parece ser el encargado de configurar la velocidad del bus y vemos que lo puedes poner a 80Mhz, por lo tanto lo que creo que cambian en las prácticas es la velocidad de bus, no la cristal en si. | |||
*También tendria que mirar que es el reloj del bus y como afecta a la velocidad de proceso del uC | |||
== Usar PLL == | == Usar PLL == | ||
| Línea 51: | Línea 60: | ||
*Paso 2: Seleccionar la velocidad del cristal a través del campo <b>XTAL</b> | *Paso 2: Seleccionar la velocidad del cristal a través del campo <b>XTAL</b> | ||
**Los bits de <b>OSCSRC2</b> se hacen clear para seleccionar el main oscillator como oscillator clock source | **Los bits de <b>OSCSRC2</b> se hacen clear para seleccionar el main oscillator como oscillator clock source | ||
*Paso 3: Hacer clear al <b>PWRDN2</b> (bit 13) para activar el PLL | |||
*Paso 4: Configurar y activar el divisor del reloj usando el campo <b>SYSDIV2</b> | |||
**Explicado en el apartado anterior la fórmula para calcular el bus del reloj a través del <b>SYSDIV2</b> | |||
*Paso 5: Esperar a que el PLL se estabilize | |||
**Cuando el <b>PLLRIS</b> (bit 6) del <b<SYSCTL_RIS_R</b> sea high estará estabilizado | |||
*Paso 6: Hacer clear al bit <b>BYPASS2</b> para conectar el PLL | |||
<br> | |||
void PLL_Init(void){ | |||
// 0) Use RCC2 | |||
SYSCTL_RCC2_R |= 0x80000000; // USERCC2 | |||
// 1) bypass PLL while initializing | |||
SYSCTL_RCC2_R |= 0x00000800; // BYPASS2, PLL bypass | |||
// 2) select the crystal value and oscillator source | |||
SYSCTL_RCC_R = (SYSCTL_RCC_R &~0x000007C0) // clear XTAL field, bits 10-6 | |||
+ 0x00000540; // 10101, configure for 16 MHz crystal | |||
SYSCTL_RCC2_R &= ~0x00000070; // configure for main oscillator source | |||
// 3) activate PLL by clearing PWRDN | |||
SYSCTL_RCC2_R &= ~0x00002000; | |||
// 4) set the desired system divider | |||
SYSCTL_RCC2_R |= 0x40000000; // use 400 MHz PLL | |||
SYSCTL_RCC2_R = (SYSCTL_RCC2_R&~ 0x1FC00000) // clear system clock divider | |||
+ (4<<22); // configure for 80 MHz clock | |||
// 5) wait for the PLL to lock by polling PLLLRIS | |||
while((SYSCTL_RIS_R&0x00000040)==0){}; // wait for PLLRIS bit | |||
// 6) enable use of PLL by clearing BYPASS | |||
SYSCTL_RCC2_R &= ~0x00000800; | |||
} | |||
<br> | |||
= Accurate Time Delays Using SysTick = | |||
<br> | |||
El temporizador SysTick funciona de la siguiente manera: | |||
*Se coloca el numero de ciclos de reloj que se quieren dejar pasar (hacer el delay) en el registro <b>RELOAD</b> | |||
*Cada ciclo de reloj se resta un bit al número introducido en <b>RELOAD</b> | |||
*Cuando se pasa del numero 1 al numero 0 el bit 16 del registro <b>CTRL</b> se pone en 1. Esto nos indica que el contador ha llegado a su fin | |||
<br> | |||
Delay<br> | |||
*Por lo visto como funciona el SysTick timer podemos utilizarlo para crear una función delay precisa | |||
*Cada iteración de Systick tarda 1 ciclo de reloj | |||
Ej: Si el bus del sistema va a 80Mhz<br> | |||
<math>80Mhz \Rightarrow \frac {1}{80Mhz} = 12.5 ns</math> por operación<br> | |||
<br> | |||
*Sabiendo lo que tarda cada iteración podemos calcular cuantas iteraciones son necesarias para tener un delay de Xms | |||
Ej: Si queremos calcular un delay de 10ms. n es el número que pondremos en el registro <b>RELOAD</b><br> | |||
<math>10ms = 12ns * n \Rightarrow n = \frac {10ms}{12ns} = 800000</math><br> | |||
<br> | |||
Ej código: | |||
#define NVIC_ST_CTRL_R (*((volatile unsigned long *)0xE000E010)) //Registro CTRL | |||
#define NVIC_ST_RELOAD_R (*((volatile unsigned long *)0xE000E014)) //Registro RELOAD | |||
#define NVIC_ST_CURRENT_R (*((volatile unsigned long *)0xE000E018)) //Registro CURRENT | |||
void SysTick_Init(void){ | |||
NVIC_ST_CTRL_R = 0; // disable SysTick during setup | |||
NVIC_ST_CTRL_R = 0x00000005; // enable SysTick with core clock | |||
} | |||
// The delay parameter is in units of the 80 MHz core clock. (12.5 ns) | |||
void SysTick_Wait(unsigned long delay){ | |||
NVIC_ST_RELOAD_R = delay-1; // se resta 1 a delay porque la cuenta la haria de 8000000 a 0 que son 800001 veces | |||
NVIC_ST_CURRENT_R = 0; // any value written to CURRENT clears | |||
while((NVIC_ST_CTRL_R&0x00010000)==0){ // esperamos a que el bit 16 de CTRL pase a 1 | |||
} | |||
} | |||
<br> | |||
*Como el SysTick timer solo admite un numero de 24 bits, por lo tanto como máximo se puede hacer un delay de 200ms | |||
*Para poder hacer un delay más grande se puede usar un bucle que vaya llamando a SysTick cada Xms | |||
*En el ejemplo de abajo se ve como se crea un bucle que llama las veces que queramos a la función SysTick_Wait10ms que tarda 10ms en acabarse. Por lo tanto si queremos un delay de 100ms tenemos que llamar a la función 10 veces<br> | |||
// 800000*12.5ns equals 10ms | |||
void SysTick_Wait10ms(unsigned long delay){ | |||
unsigned long i; | |||
for(i=0; i<delay; i++){ | |||
SysTick_Wait(800000); // wait 10ms | |||
} | |||
} | |||
<br> | |||
En la siguiente imagen se puede ver una máquina de estados finita de las dos funciones:<br> | |||
[[File: edx-fsm-systick-delay.png|400px]]<br> | |||
<br> | |||
= Structures = | |||
<br> | |||
*Un <b>struct</b> en C es un "array" de variables de diferentes tipos | |||
Ej: crearé un struct jugador | |||
struct Player{ | |||
unsigned int xPos; | |||
unsigned int yPos; | |||
unsigned short points; | |||
} | |||
struct Player Player1; | |||
void main(void){ | |||
Player1.xPos = 3; | |||
Player1.yPos = 2; | |||
Player1.points = 0; | |||
} | |||
*Este código declara un struct Player con 3 variables. Dos variables son del tipo int y la otra es de tipo short | |||
*Luego declaramos un struct, Player1 | |||
*En el main lo que hacemos es acceder a cada variable que hay en el struct. Utilizamos el punto | |||
*Con <b>typedef</b> podemos crear nuevos tipos de variables (como int, long, ... ) | |||
Ej: crearé un nuevo tipo de variable que será un struct de Player | |||
struct Player{ | |||
unsigned int xPos; | |||
unsigned int yPos; | |||
unsigned short points; | |||
} | |||
typedef Player Ptype; | |||
Ptype Player1; | |||
void main(void){ | |||
//Código | |||
} | |||
Al declarar un tipo Ptype cada vez que quiera crear un struct Player no tendré que poner | |||
struct Player Player1; | |||
Poniendo solo | |||
Ptype Player1; | |||
Ya estoy declarando una variable de tipo struct Player<br> | |||
<br> | |||
= Finite State Machine with Indexed Structures = | |||
<br> | |||
*FSM se puede llamar a un sistema lógico que tiene inputs y outpus | |||
*Este sistema lógico tiene estados que cambian según los inputs y producen outpus | |||
<br> | |||
Una FMS contiene 5 cosas: | |||
*Conjunto de inputs | |||
*Conjunto de outputs | |||
*Conjunto de estados que hay en el sistema | |||
*State Transition: Nos dice que causa que el sistema pasa de un estado a otro. Se puede representar mediante | |||
**Gráfico | |||
**Matriz numérica | |||
*Output determination: Que condiciones genera los outpus | |||
<br> | |||
Tipos de FSM | |||
*Moore FSM | |||
**NextState = f(current_State, Input) <math>\Rightarrow</math> NextState va en función del current_State y de los inputs | |||
**Output = g(current_State) <math>\Rightarrow</math> Output va en función del current_State | |||
*Mealey FSM | |||
**NexStet igual que en Moore | |||
**Output = h(current_State, Input) <math>\Rightarrow</math> Output va en función del current_State y de los inputs | |||
<br> | |||
== Ej. Máquina cuenta 1s == | |||
<br> | |||
Tenemos un sistema que lee por un puerto bits (0 o 1). El sistema cuenta cuantos bits 1 ha leido y por un output escribe 1 si el número de 1s es impar y 0 si es par<br> | |||
<br> | |||
=== Definición FSM === | |||
*Input - 1 bit que puede ser 0 o 1 | |||
*Output - 1 bit que puede ser 0 o 1 | |||
*States - 2 estados | |||
**nº de 1 par | |||
**nº de 1 impar | |||
*State Transition Graphic | |||
**Los círculos expresan los estados y las flechas expresan las transiciones | |||
**En el estado par | |||
***Si recibimos un 0 nos quedamos en el estado porque el número de 1 no ha cambiado | |||
***Si recibimos un 1 pasamos al estado impar | |||
**En el estado impar | |||
**Si recibimos un 0 nos quedamos en el estado porque el número de 1 no ha cambiado | |||
**Si recibimos un 1 pasamos al estado par | |||
[[File: edx-odd-stg.png | 300px]]<br> | |||
*Output | |||
**Como estamos haciendo una FSM de Moore cada estado tiene un output | |||
**Los outputs son los números azules del gráfico | |||
**Cuando estamos en el estado par ponemos un 0 en el output | |||
**Cuando estamos en el estado impar ponemos un 1 en el output | |||
<br> | |||
=== Programación estados === | |||
Código que plasma el STG que vemos mas arriba en un struct.<br> | |||
<br> | |||
//Construimos el "contenedor" de cada estado | |||
struct State{ | |||
unsigned char out; //Aqui va la salida que tendrá cada estado (los numero azules del dibujo) | |||
unsigned long wait; //Entre cada estado esperaremos un tiempo para que pueda leer la entrada | |||
unsigned char next[2]; //En cada estado almacenamos los posibles estados siguientes | |||
} | |||
typedef struct State SType; | |||
#define Even 0 //Lo hago para que sean más claros los estados | |||
#define Odd 1 | |||
//Creamos los estados y los inicializamos | |||
//En primer el estado el output sera 0, en el segundo estado sera 1 | |||
//El tiempo que esperaremos para cambiar de estado sera de 100ms en los dos estados | |||
//En el primer estado si obtenemos un 0 nos mantenemos en el y si obtenemos un 1 cambiamos a Odd | |||
//En el segundo estado si obtenemos un 0 nos mantenemos en el y si obtenemos un 1 cambiamos a Even | |||
Stype fsm[2]={ | |||
{0,100,{Even, Odd}}, | |||
{1,100,{Odd, Even}} | |||
}; | |||
<br> | |||
=== Programación controlador FSM === | |||
El controlador de la máquina de estados finita es le encargado de leer las entradas, escribir las salidas y cambiar entre los diferentes estados.<br> | |||
Este controlador se programa en el main y se sigue este esquema: | |||
*Escribo el output | |||
*Espero | |||
*Leo input | |||
*Cambio de estado según el input y el estado en el que estoy | |||
<br> | |||
Nota:<br> | |||
No entiendo porqué no se hace así: | |||
*Leo input | |||
*Cambio estado según input y estado actual | |||
*Escribo output | |||
*Espero | |||
<br> | |||
El código de este ejemplo quedaria:<br> | |||
unsigend char cState; | |||
void main(void){ | |||
unsigned char input; | |||
//Inicializar puertos | |||
//Inicializar SysTick para función delay | |||
cState = Even; | |||
while(1){ | |||
GPIO_PORT... = Fsm[cState].out; //Escribimos el output del estado actual | |||
delay(); //Esperamos | |||
input = GPIO_PORT...; //Leemos input | |||
cState = Fsm[cState].next[input]; //Cambiamos de estado según el input. Si el input | |||
//es 0 vamos al estado Even y si el input es 1 vamos al estado Odd | |||
//y también según el estado en el que estamos (la variable | |||
//cState es la que nos indica en que estado estamos) | |||
} | |||
} | |||
== Ej. Semaforos == | |||
<br> | |||
El siguiente ejemplo es sobre un cruce que tiene dos semáforos para controlar el tráfico. Hay dos sensores que detectan si hay coches en la calle 1 o en la calle 2. Dependiendo de donde hayan los coches se pone el semáforo en rojo o verde.<br> | |||
<br> | |||
[[File: Edx-fsm-semaforo.png | 300px]]<br> | |||
<br> | |||
=== Definicion FSM === | |||
Imagen STG<br> | |||
<br> | |||
La tabla muestra la misma información que el gráfico. Es un resumen de la funcionalidad de la máquina de estados<br> | |||
{| class="wikitable" | |||
! colspan="9" style="text-align: center;" | | |||
! colspan="4" style="text-align: center; font-weight: bold;" | Input | |||
|- | |||
| colspan="2" style="text-align: center; font-weight: bold;" | Estados | |||
| style="text-align: center;" | | |||
| colspan="6" style="text-align: center; font-weight: bold;" | Output | |||
| style="text-align: center; font-weight: bold;" | S2S1 | |||
| style="text-align: center; font-weight: bold;" | S2S1 | |||
| style="text-align: center; font-weight: bold;" | S2S1 | |||
| style="text-align: center; font-weight: bold;" | S2S1 | |||
|- | |||
| style="text-align: center; font-weight: bold;" | Descripción | |||
| style="text-align: center; font-weight: bold;" | Nombres | |||
| style="text-align: center; font-weight: bold;" | Tiempo | |||
| style="text-align: center; font-weight: bold;" | V1 | |||
| style="text-align: center; font-weight: bold;" | A1 | |||
| style="text-align: center; font-weight: bold;" | R1 | |||
| style="text-align: center; font-weight: bold;" | V2 | |||
| style="text-align: center; font-weight: bold;" | A2 | |||
| style="text-align: center; font-weight: bold;" | R2 | |||
| style="text-align: center; font-weight: bold;" | 00 | |||
| style="text-align: center; font-weight: bold;" | 01 | |||
| style="text-align: center; font-weight: bold;" | 10 | |||
| style="text-align: center; font-weight: bold;" | 11 | |||
|- | |||
| Calle 1 verde. Calle 2 rojo | |||
| style="text-align: center;" | C1 | |||
| style="text-align: center;" | 30 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | C1 | |||
| style="text-align: center;" | C1 | |||
| style="text-align: center;" | W1 | |||
| style="text-align: center;" | W1 | |||
|- | |||
| Calle 1 amarillo. Calle 2 rojo | |||
| style="text-align: center;" | W1 | |||
| style="text-align: center;" | 5 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | C2 | |||
| style="text-align: center;" | C2 | |||
| style="text-align: center;" | C2 | |||
| style="text-align: center;" | C2 | |||
|- | |||
| Calle 1 rojo. Calle 2 verde | |||
| style="text-align: center;" | C2 | |||
| style="text-align: center;" | 30 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | C2 | |||
| style="text-align: center;" | W2 | |||
| style="text-align: center;" | C2 | |||
| style="text-align: center;" | W2 | |||
|- | |||
| Calle 1 rojo. Calle 2 amarillo | |||
| style="text-align: center;" | W2 | |||
| style="text-align: center;" | 5 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | C1 | |||
| style="text-align: center;" | C1 | |||
| style="text-align: center;" | C1 | |||
| style="text-align: center;" | C1 | |||
|} | |||
Inputs: | |||
*Coche calle 1 - S1 | |||
*Coche calle 2 - S2 | |||
Outputs: | |||
*V1 A1 R1 <math>\Rightarrow</math> semáforo calle 1 que cuenta con verde, amarillo y rojo | |||
*V2 A2 R2 | |||
<br> | |||
<b>Estado1 - C1</b> | |||
*Verde en calle 1 y rojo en calle 2, por lo tanto las salidas son | |||
V1 A1 R1 V2 A2 R2 | |||
1 0 0 0 0 1 | |||
*Siempre que S1 se mantenga en 1 nos quedamos en este estado | |||
*Si no hay ningún coche en las dos calles también nos mantenemos en este estado | |||
*Para pasar al siguiente estado S2 tiene que valer 1 | |||
<b>Estado2 - W1</b> | |||
*Es un estado de transición entre el verde y el rojo. Hemos de pasar por el amarillo y el estado tiene una duración máxima de 5ms | |||
*La salida es 010001 <math>\Rightarrow</math> Activamos A1 porque vamos a cambiar de V1 a R1 | |||
*Cualquier input nos hace pasar al siguiente estado | |||
<b>Estado3 - C2</b> | |||
*Rojo calle 1 y verde calle 2 <math>\Rightarrow</math> 001100 | |||
*Siempre que S2 se mantenga en 1 nos quedamos en este estado | |||
*Si no hay ningún coche en las dos calles también nos mantenemos en este estado | |||
*Para pasar al siguiente estado S1 tiene que valer 1 | |||
<b>Estado4 - W2</b> | |||
*Es un estado de transición entre el verde y el rojo. Hemos de pasar por el amarillo y el estado tiene una duración máxima de 5ms | |||
*La salida es 001010 <math>\Rightarrow</math> Activamos A2 porque vamos a cambiar de V2 a R2 | |||
*Cualquier input nos hace pasar al siguiente estado | |||
<br> | |||
=== Programación estados === | |||
//Contenedor de cada estado | |||
struct State{ | |||
unsigned long out; | |||
unsigned long wait; | |||
unsigned long next[4]; | |||
}; | |||
typedef struct State SType; | |||
#define C1 0 //Estado con el sensor de la calle 1 activo | |||
#define W1 1 //Estado de transición de C1 a C2 | |||
#define C2 2 //Estado con el sensor de la calle 2 activo | |||
#define W2 3 //Estado de transición de C2 a C1 | |||
//Definición estados | |||
Stype fsm[4]={ | |||
{0x21, 3000, {C1,W1,C1,W1}}, | |||
{0x11, 500, {C2,C2,C2,C2}}, | |||
{0x0C, 3000, {C2,C2,W2,W2}}, | |||
{0x0A, 500, {C1,C1,C1,C1}} | |||
}; | |||
<br> | |||
=== Programación controlador FSM === | |||
<br> | |||
El código del controlador de la fsm es igual al del ejemplo anterior:<br> | |||
S = goN; //Colocamos el primer estado | |||
while(1){ | |||
LIGHT = FSM[S].Out; //Escribimos la salida | |||
SysTick_Wait10ms(FSM[S].Time); //Esperamos | |||
Input = SENSOR; //Leemos | |||
S = FSM[S].Next[Input]; //Pasamos al siguiente estado según los inputs leidos | |||
} | |||
<br> | |||
= Stepper Motor = | |||
<br> | |||
<br> | |||
= Lab 10 = | |||
== Introducción == | |||
<br> | |||
Diseñar un sistema que controle dos semáforos para tráfico y un semáforo para peatones.<br> | |||
Cada semáforo de tráfico tendrá un sensor para detectar si hay coches y el semáforo de peatones tiene otro sensor para detectar peatones.<br> | |||
El semáforo de coches tiene verde, amarillo y rojo. El semáforo de peatones tiene verde y rojo. Para pasar de verde a rojo el verde parpadea y luego pasa a rojo.<br> | |||
Cuando un semáforo está en verde los demás semáforos tienen que estar en rojo, no pueden estar en amarillo ni parpadeando.<br> | |||
<br> | |||
[[File: Edx-fsm-lab10.png | 300px]]<br> | |||
<br> | |||
Nomenclaturas: | |||
*C1 será la calle 1 | |||
*C2 será la calle 2 | |||
*P1 será el paso de peatones | |||
*W1 será le estado de transición del verde de C1 al amarillo de C1 despúes al rojo de C1 | |||
*W2 lo mismo pero de C2 | |||
*Las salidas serán: | |||
**V1 A1 R1 <math>\Rightarrow</math> los colores del semáforo de C1 | |||
**V2 A2 R2 <math>\Rightarrow</math> los colores del semáforo de C2 | |||
**VP1 RP1 <math>\Rightarrow</math> los colores del semáforo de peatones | |||
== Condiciones == | |||
<br> | |||
*Cambio de verde a rojo máximo 5 segundos | |||
*Si los tres sensores están activos se pasa de un estado a otro sin parar | |||
*De 9 a 30 estados es una buena implementación | |||
*Tener 3 inputs implica 8 next state link | |||
*Data Structure stored in ROM | |||
*No pueden haber conditional branching | |||
*Tiempo en cada estado (tiempo en que permanece en verde o rojo un semaforo) entre medio segundo y un segundo | |||
*Flash de no pasar para peaton 2Hz y ejecutarlo dos veces | |||
*Si coche llega a C2 y verde es C1 se espera que acabe C1 y luego empieza C2 | |||
*Si solo un sensor está activo en menos de 5 segundos se tiene que pasar a ese semáforo | |||
*Siempre que haya solo un sensor activo se mantiene en ese estado el tiempo que este ese sensor activo | |||
<br> | |||
== Definición FSM == | |||
<br> | |||
{| cellpadding="4" border="1" cellspacing="0" | |||
! colspan="3" style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | | |||
! colspan="10" style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | Output | |||
! colspan="8" style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | Input | |||
|- | |||
| colspan="2" style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | Estados | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | | |||
| colspan="3" style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | West | |||
| colspan="3" style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | South | |||
| colspan="2" style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | Walk | |||
| colspan="2" style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | Salida Hex | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | WaSoWe | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | WaSoWe | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | WaSoWe | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | WaSoWe | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | WaSoWe | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | WaSoWe | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | WaSoWe | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | WaSoWe | |||
|- | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | Descrpción | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | Nombre | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | Tiempo | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | R | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | A | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | V | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | R | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | A | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | V | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | V | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | R | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | Hex | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | Hex | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | 0 0 0 | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | 0 0 1 | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | 0 1 0 | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | 0 1 1 | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | 1 0 0 | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | 1 0 1 | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | 1 1 0 | |||
| style="text-align: center; font-weight: bold; background:rgb(210,210,210);" | 1 1 1 | |||
|- | |||
| West verde. South rojo. Walk rojo | |||
| style="text-align: center;" | goWest | |||
| style="text-align: center;" | 30 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0x0C | |||
| style="text-align: center;" | 0x02 | |||
| style="text-align: center;" | goWest | |||
| style="text-align: center;" | goWest | |||
| style="text-align: center;" | waWest | |||
| style="text-align: center;" | waWest | |||
| style="text-align: center;" | waWest | |||
| style="text-align: center;" | waWest | |||
| style="text-align: center;" | waWest | |||
| style="text-align: center;" | waWest | |||
|- | |||
| West amarillo. South rojo. Walk rojo | |||
| style="text-align: center;" | waWest | |||
| style="text-align: center;" | 5 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0x14 | |||
| style="text-align: center;" | 0x02 | |||
| style="text-align: center;" | goWest | |||
| style="text-align: center;" | goWest | |||
| style="text-align: center;" | goSouth | |||
| style="text-align: center;" | goSouth | |||
| style="text-align: center;" | goWalk | |||
| style="text-align: center;" | goWalk | |||
| style="text-align: center;" | goWalk | |||
| style="text-align: center;" | goSouth | |||
|- | |||
| West rojo. South verde. Walk rojo | |||
| style="text-align: center;" | goSouth | |||
| style="text-align: center;" | 30 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0x21 | |||
| style="text-align: center;" | 0x02 | |||
| style="text-align: center;" | goSouth | |||
| style="text-align: center;" | waSouth | |||
| style="text-align: center;" | goSouth | |||
| style="text-align: center;" | waSouth | |||
| style="text-align: center;" | waSouth | |||
| style="text-align: center;" | waSouth | |||
| style="text-align: center;" | waSouth | |||
| style="text-align: center;" | waSouth | |||
|- | |||
| West rojo. South amarillo. Walk rojo | |||
| style="text-align: center;" | waSouth | |||
| style="text-align: center;" | 5 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0x22 | |||
| style="text-align: center;" | 0x02 | |||
| style="text-align: center;" | goSouth | |||
| style="text-align: center;" | goWest | |||
| style="text-align: center;" | goSouth | |||
| style="text-align: center;" | goWest | |||
| style="text-align: center;" | goWalk | |||
| style="text-align: center;" | goWalk | |||
| style="text-align: center;" | goWalk | |||
| style="text-align: center;" | goWalk | |||
|- | |||
| West rojo. South rojo. Walk verde | |||
| style="text-align: center;" | goWalk | |||
| style="text-align: center;" | 30 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0x24 | |||
| style="text-align: center;" | 0x08 | |||
| style="text-align: center;" | goWalk | |||
| style="text-align: center;" | dontWalk | |||
| style="text-align: center;" | dontWalk | |||
| style="text-align: center;" | dontWalk | |||
| style="text-align: center;" | goWalk | |||
| style="text-align: center;" | dontWalk | |||
| style="text-align: center;" | dontWalk | |||
| style="text-align: center;" | dontWalk | |||
|- | |||
| West rojo. South rojo. Walk rojo | |||
| style="text-align: center;" | dontWalk | |||
| style="text-align: center;" | 5 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0x24 | |||
| style="text-align: center;" | 0x02 | |||
| style="text-align: center;" | walkOff | |||
| style="text-align: center;" | walkOff | |||
| style="text-align: center;" | walkOff | |||
| style="text-align: center;" | walkOff | |||
| style="text-align: center;" | walkOff | |||
| style="text-align: center;" | walkOff | |||
| style="text-align: center;" | walkOff | |||
| style="text-align: center;" | walkOff | |||
|- | |||
| West rojo. South rojo. Walk apagado | |||
| style="text-align: center;" | walkOff | |||
| style="text-align: center;" | 5 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0x24 | |||
| style="text-align: center;" | 0x00 | |||
| style="text-align: center;" | dontWalk2 | |||
| style="text-align: center;" | dontWalk2 | |||
| style="text-align: center;" | dontWalk2 | |||
| style="text-align: center;" | dontWalk2 | |||
| style="text-align: center;" | dontWalk2 | |||
| style="text-align: center;" | dontWalk2 | |||
| style="text-align: center;" | dontWalk2 | |||
| style="text-align: center;" | dontWalk2 | |||
|- | |||
| West rojo. South rojo. Walk rojo | |||
| style="text-align: center;" | dontWalk2 | |||
| style="text-align: center;" | 5 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0x24 | |||
| style="text-align: center;" | 0x02 | |||
| style="text-align: center;" | walkOff2 | |||
| style="text-align: center;" | walkOff2 | |||
| style="text-align: center;" | walkOff2 | |||
| style="text-align: center;" | walkOff2 | |||
| style="text-align: center;" | walkOff2 | |||
| style="text-align: center;" | walkOff2 | |||
| style="text-align: center;" | walkOff2 | |||
| style="text-align: center;" | walkOff2 | |||
|- | |||
| West rojo. South rojo. Walk apagado | |||
| style="text-align: center;" | walkOff2 | |||
| style="text-align: center;" | 5 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 1 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0 | |||
| style="text-align: center;" | 0x24 | |||
| style="text-align: center;" | 0x00 | |||
| style="text-align: center;" | goWalk | |||
| style="text-align: center;" | goWest | |||
| style="text-align: center;" | goSouth | |||
| style="text-align: center;" | goSouth | |||
| style="text-align: center;" | goWalk | |||
| style="text-align: center;" | goWalk | |||
| style="text-align: center;" | goWalk | |||
| style="text-align: center;" | goWest | |||
|} | |||
<br> | <br> | ||
Revisión actual - 14:46 27 mar 2015
Introducción
[editar]
El microcontrolador cuenta con dos fuentes para el oscilador:
- Interna
- El oscilador interno del uC TM4C va a 16Mhz con una presicón de ±1% poco preciso
- Consume poca corriente
- Externa
- Se puede configurar el cristal a diferentes velocidades según las necesidades
- Son mucho mas preciso que el interno
- Consumen más corriente y espacio en el PCB
Phase-Lock-Loop (PLL)
[editar]Que és? Cómo funciona?
[editar]
- Permite seleccionar un cristal externo
- Permite seleccionar la velocidad del cristal y por tanto del procesador
- Permite seleccionar la velocidad del bus del sistema
- Para poder llevar a cabo estas dos operaciones necesitamos manipular dos registros
- SYSCTL_RCC_R
- SYSCTL_RCC2_R
En la siguiente imagen se ven los registros que van asociados al PLL
![]()
Los datos que nos interesan:
- En el registro SYSCTL_RCC_R el campo XTAL
- Este se compone de 5 bits - del bit 10 al bit 6
- El campo XTAL configura la velocidad del cristal. En la tabla de abajo se ven la codificacion de la velocidad en hexadecimal
- En el registro SYSCTL_RCC2_R el campo SYSDIV2
- Este campo se compone de 7 bits - del bit 28 al bit 22
- Configura la velocidad del bus del sistema
- La fórmula para calcular es:
Ej.
En el campo SYSDIV2 pondremos el valor 4
(Hay que tener en cuenta que a el número n velocidad del reloj)
Codificación velocidad cristal en hexadecimal:
![]()
Notas:
- No se si está bien explicada la función del PLL de ajustar la velocidad del reloj/bus. En las prácticas se ve como ponen a 80Mhz "algo". Yo creia que era el cristal, pero viendo la tabla de arriba el cristal como máximo puede ir a 25Mhz.
- El campo SYSDIV2 parece ser el encargado de configurar la velocidad del bus y vemos que lo puedes poner a 80Mhz, por lo tanto lo que creo que cambian en las prácticas es la velocidad de bus, no la cristal en si.
- También tendria que mirar que es el reloj del bus y como afecta a la velocidad de proceso del uC
Usar PLL
[editar]
Hay dos formas de activar PLL:
- A través de una libreria
- La mejor solucion porque es mas estable
- El código se puede portar más fácil a otro micro
- Accediendo directamente a los registros
Accediendo manualmente
[editar]- Paso 0: Usar RCC2 porque provee más opciones
- Paso 1: Poner bit 11 de BYPASS2 a 1
- PLL esta bypassed y no hay system clock divider
- Paso 2: Seleccionar la velocidad del cristal a través del campo XTAL
- Los bits de OSCSRC2 se hacen clear para seleccionar el main oscillator como oscillator clock source
- Paso 3: Hacer clear al PWRDN2 (bit 13) para activar el PLL
- Paso 4: Configurar y activar el divisor del reloj usando el campo SYSDIV2
- Explicado en el apartado anterior la fórmula para calcular el bus del reloj a través del SYSDIV2
- Paso 5: Esperar a que el PLL se estabilize
- Cuando el PLLRIS (bit 6) del <b<SYSCTL_RIS_R sea high estará estabilizado
- Paso 6: Hacer clear al bit BYPASS2 para conectar el PLL
void PLL_Init(void){
// 0) Use RCC2
SYSCTL_RCC2_R |= 0x80000000; // USERCC2
// 1) bypass PLL while initializing
SYSCTL_RCC2_R |= 0x00000800; // BYPASS2, PLL bypass
// 2) select the crystal value and oscillator source
SYSCTL_RCC_R = (SYSCTL_RCC_R &~0x000007C0) // clear XTAL field, bits 10-6
+ 0x00000540; // 10101, configure for 16 MHz crystal
SYSCTL_RCC2_R &= ~0x00000070; // configure for main oscillator source
// 3) activate PLL by clearing PWRDN
SYSCTL_RCC2_R &= ~0x00002000;
// 4) set the desired system divider
SYSCTL_RCC2_R |= 0x40000000; // use 400 MHz PLL
SYSCTL_RCC2_R = (SYSCTL_RCC2_R&~ 0x1FC00000) // clear system clock divider
+ (4<<22); // configure for 80 MHz clock
// 5) wait for the PLL to lock by polling PLLLRIS
while((SYSCTL_RIS_R&0x00000040)==0){}; // wait for PLLRIS bit
// 6) enable use of PLL by clearing BYPASS
SYSCTL_RCC2_R &= ~0x00000800;
}
Accurate Time Delays Using SysTick
[editar]
El temporizador SysTick funciona de la siguiente manera:
- Se coloca el numero de ciclos de reloj que se quieren dejar pasar (hacer el delay) en el registro RELOAD
- Cada ciclo de reloj se resta un bit al número introducido en RELOAD
- Cuando se pasa del numero 1 al numero 0 el bit 16 del registro CTRL se pone en 1. Esto nos indica que el contador ha llegado a su fin
Delay
- Por lo visto como funciona el SysTick timer podemos utilizarlo para crear una función delay precisa
- Cada iteración de Systick tarda 1 ciclo de reloj
Ej: Si el bus del sistema va a 80Mhz
por operación
- Sabiendo lo que tarda cada iteración podemos calcular cuantas iteraciones son necesarias para tener un delay de Xms
Ej: Si queremos calcular un delay de 10ms. n es el número que pondremos en el registro RELOAD
Ej código:
#define NVIC_ST_CTRL_R (*((volatile unsigned long *)0xE000E010)) //Registro CTRL
#define NVIC_ST_RELOAD_R (*((volatile unsigned long *)0xE000E014)) //Registro RELOAD
#define NVIC_ST_CURRENT_R (*((volatile unsigned long *)0xE000E018)) //Registro CURRENT
void SysTick_Init(void){
NVIC_ST_CTRL_R = 0; // disable SysTick during setup
NVIC_ST_CTRL_R = 0x00000005; // enable SysTick with core clock
}
// The delay parameter is in units of the 80 MHz core clock. (12.5 ns)
void SysTick_Wait(unsigned long delay){
NVIC_ST_RELOAD_R = delay-1; // se resta 1 a delay porque la cuenta la haria de 8000000 a 0 que son 800001 veces
NVIC_ST_CURRENT_R = 0; // any value written to CURRENT clears
while((NVIC_ST_CTRL_R&0x00010000)==0){ // esperamos a que el bit 16 de CTRL pase a 1
}
}
- Como el SysTick timer solo admite un numero de 24 bits, por lo tanto como máximo se puede hacer un delay de 200ms
- Para poder hacer un delay más grande se puede usar un bucle que vaya llamando a SysTick cada Xms
- En el ejemplo de abajo se ve como se crea un bucle que llama las veces que queramos a la función SysTick_Wait10ms que tarda 10ms en acabarse. Por lo tanto si queremos un delay de 100ms tenemos que llamar a la función 10 veces
// 800000*12.5ns equals 10ms
void SysTick_Wait10ms(unsigned long delay){
unsigned long i;
for(i=0; i<delay; i++){
SysTick_Wait(800000); // wait 10ms
}
}
En la siguiente imagen se puede ver una máquina de estados finita de las dos funciones:
![]()
Structures
[editar]
- Un struct en C es un "array" de variables de diferentes tipos
Ej: crearé un struct jugador
struct Player{
unsigned int xPos;
unsigned int yPos;
unsigned short points;
}
struct Player Player1;
void main(void){
Player1.xPos = 3;
Player1.yPos = 2;
Player1.points = 0;
}
- Este código declara un struct Player con 3 variables. Dos variables son del tipo int y la otra es de tipo short
- Luego declaramos un struct, Player1
- En el main lo que hacemos es acceder a cada variable que hay en el struct. Utilizamos el punto
- Con typedef podemos crear nuevos tipos de variables (como int, long, ... )
Ej: crearé un nuevo tipo de variable que será un struct de Player
struct Player{
unsigned int xPos;
unsigned int yPos;
unsigned short points;
}
typedef Player Ptype;
Ptype Player1;
void main(void){
//Código
}
Al declarar un tipo Ptype cada vez que quiera crear un struct Player no tendré que poner
struct Player Player1;
Poniendo solo
Ptype Player1;
Ya estoy declarando una variable de tipo struct Player
Finite State Machine with Indexed Structures
[editar]
- FSM se puede llamar a un sistema lógico que tiene inputs y outpus
- Este sistema lógico tiene estados que cambian según los inputs y producen outpus
Una FMS contiene 5 cosas:
- Conjunto de inputs
- Conjunto de outputs
- Conjunto de estados que hay en el sistema
- State Transition: Nos dice que causa que el sistema pasa de un estado a otro. Se puede representar mediante
- Gráfico
- Matriz numérica
- Output determination: Que condiciones genera los outpus
Tipos de FSM
- Moore FSM
- NextState = f(current_State, Input) NextState va en función del current_State y de los inputs
- Output = g(current_State) Output va en función del current_State
- Mealey FSM
- NexStet igual que en Moore
- Output = h(current_State, Input) Output va en función del current_State y de los inputs
Ej. Máquina cuenta 1s
[editar]
Tenemos un sistema que lee por un puerto bits (0 o 1). El sistema cuenta cuantos bits 1 ha leido y por un output escribe 1 si el número de 1s es impar y 0 si es par
Definición FSM
[editar]- Input - 1 bit que puede ser 0 o 1
- Output - 1 bit que puede ser 0 o 1
- States - 2 estados
- nº de 1 par
- nº de 1 impar
- State Transition Graphic
- Los círculos expresan los estados y las flechas expresan las transiciones
- En el estado par
- Si recibimos un 0 nos quedamos en el estado porque el número de 1 no ha cambiado
- Si recibimos un 1 pasamos al estado impar
- En el estado impar
- Si recibimos un 0 nos quedamos en el estado porque el número de 1 no ha cambiado
- Si recibimos un 1 pasamos al estado par
- Output
- Como estamos haciendo una FSM de Moore cada estado tiene un output
- Los outputs son los números azules del gráfico
- Cuando estamos en el estado par ponemos un 0 en el output
- Cuando estamos en el estado impar ponemos un 1 en el output
Programación estados
[editar]Código que plasma el STG que vemos mas arriba en un struct.
//Construimos el "contenedor" de cada estado
struct State{
unsigned char out; //Aqui va la salida que tendrá cada estado (los numero azules del dibujo)
unsigned long wait; //Entre cada estado esperaremos un tiempo para que pueda leer la entrada
unsigned char next[2]; //En cada estado almacenamos los posibles estados siguientes
}
typedef struct State SType;
#define Even 0 //Lo hago para que sean más claros los estados
#define Odd 1
//Creamos los estados y los inicializamos
//En primer el estado el output sera 0, en el segundo estado sera 1
//El tiempo que esperaremos para cambiar de estado sera de 100ms en los dos estados
//En el primer estado si obtenemos un 0 nos mantenemos en el y si obtenemos un 1 cambiamos a Odd
//En el segundo estado si obtenemos un 0 nos mantenemos en el y si obtenemos un 1 cambiamos a Even
Stype fsm[2]={
{0,100,{Even, Odd}},
{1,100,{Odd, Even}}
};
Programación controlador FSM
[editar]El controlador de la máquina de estados finita es le encargado de leer las entradas, escribir las salidas y cambiar entre los diferentes estados.
Este controlador se programa en el main y se sigue este esquema:
- Escribo el output
- Espero
- Leo input
- Cambio de estado según el input y el estado en el que estoy
Nota:
No entiendo porqué no se hace así:
- Leo input
- Cambio estado según input y estado actual
- Escribo output
- Espero
El código de este ejemplo quedaria:
unsigend char cState;
void main(void){
unsigned char input;
//Inicializar puertos
//Inicializar SysTick para función delay
cState = Even;
while(1){
GPIO_PORT... = Fsm[cState].out; //Escribimos el output del estado actual
delay(); //Esperamos
input = GPIO_PORT...; //Leemos input
cState = Fsm[cState].next[input]; //Cambiamos de estado según el input. Si el input
//es 0 vamos al estado Even y si el input es 1 vamos al estado Odd
//y también según el estado en el que estamos (la variable
//cState es la que nos indica en que estado estamos)
}
}
Ej. Semaforos
[editar]
El siguiente ejemplo es sobre un cruce que tiene dos semáforos para controlar el tráfico. Hay dos sensores que detectan si hay coches en la calle 1 o en la calle 2. Dependiendo de donde hayan los coches se pone el semáforo en rojo o verde.
![]()
Definicion FSM
[editar]Imagen STG
La tabla muestra la misma información que el gráfico. Es un resumen de la funcionalidad de la máquina de estados
| Input | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Estados | Output | S2S1 | S2S1 | S2S1 | S2S1 | |||||||
| Descripción | Nombres | Tiempo | V1 | A1 | R1 | V2 | A2 | R2 | 00 | 01 | 10 | 11 |
| Calle 1 verde. Calle 2 rojo | C1 | 30 | 1 | 0 | 0 | 0 | 0 | 1 | C1 | C1 | W1 | W1 |
| Calle 1 amarillo. Calle 2 rojo | W1 | 5 | 0 | 1 | 0 | 0 | 0 | 1 | C2 | C2 | C2 | C2 |
| Calle 1 rojo. Calle 2 verde | C2 | 30 | 0 | 0 | 1 | 1 | 0 | 0 | C2 | W2 | C2 | W2 |
| Calle 1 rojo. Calle 2 amarillo | W2 | 5 | 0 | 0 | 1 | 0 | 1 | 0 | C1 | C1 | C1 | C1 |
Inputs:
- Coche calle 1 - S1
- Coche calle 2 - S2
Outputs:
- V1 A1 R1 semáforo calle 1 que cuenta con verde, amarillo y rojo
- V2 A2 R2
Estado1 - C1
- Verde en calle 1 y rojo en calle 2, por lo tanto las salidas son
V1 A1 R1 V2 A2 R2 1 0 0 0 0 1
- Siempre que S1 se mantenga en 1 nos quedamos en este estado
- Si no hay ningún coche en las dos calles también nos mantenemos en este estado
- Para pasar al siguiente estado S2 tiene que valer 1
Estado2 - W1
- Es un estado de transición entre el verde y el rojo. Hemos de pasar por el amarillo y el estado tiene una duración máxima de 5ms
- La salida es 010001 Activamos A1 porque vamos a cambiar de V1 a R1
- Cualquier input nos hace pasar al siguiente estado
Estado3 - C2
- Rojo calle 1 y verde calle 2 001100
- Siempre que S2 se mantenga en 1 nos quedamos en este estado
- Si no hay ningún coche en las dos calles también nos mantenemos en este estado
- Para pasar al siguiente estado S1 tiene que valer 1
Estado4 - W2
- Es un estado de transición entre el verde y el rojo. Hemos de pasar por el amarillo y el estado tiene una duración máxima de 5ms
- La salida es 001010 Activamos A2 porque vamos a cambiar de V2 a R2
- Cualquier input nos hace pasar al siguiente estado
Programación estados
[editar]//Contenedor de cada estado
struct State{
unsigned long out;
unsigned long wait;
unsigned long next[4];
};
typedef struct State SType;
#define C1 0 //Estado con el sensor de la calle 1 activo
#define W1 1 //Estado de transición de C1 a C2
#define C2 2 //Estado con el sensor de la calle 2 activo
#define W2 3 //Estado de transición de C2 a C1
//Definición estados
Stype fsm[4]={
{0x21, 3000, {C1,W1,C1,W1}},
{0x11, 500, {C2,C2,C2,C2}},
{0x0C, 3000, {C2,C2,W2,W2}},
{0x0A, 500, {C1,C1,C1,C1}}
};
Programación controlador FSM
[editar]
El código del controlador de la fsm es igual al del ejemplo anterior:
S = goN; //Colocamos el primer estado
while(1){
LIGHT = FSM[S].Out; //Escribimos la salida
SysTick_Wait10ms(FSM[S].Time); //Esperamos
Input = SENSOR; //Leemos
S = FSM[S].Next[Input]; //Pasamos al siguiente estado según los inputs leidos
}
Stepper Motor
[editar]
Lab 10
[editar]Introducción
[editar]
Diseñar un sistema que controle dos semáforos para tráfico y un semáforo para peatones.
Cada semáforo de tráfico tendrá un sensor para detectar si hay coches y el semáforo de peatones tiene otro sensor para detectar peatones.
El semáforo de coches tiene verde, amarillo y rojo. El semáforo de peatones tiene verde y rojo. Para pasar de verde a rojo el verde parpadea y luego pasa a rojo.
Cuando un semáforo está en verde los demás semáforos tienen que estar en rojo, no pueden estar en amarillo ni parpadeando.
![]()
Nomenclaturas:
- C1 será la calle 1
- C2 será la calle 2
- P1 será el paso de peatones
- W1 será le estado de transición del verde de C1 al amarillo de C1 despúes al rojo de C1
- W2 lo mismo pero de C2
- Las salidas serán:
- V1 A1 R1 los colores del semáforo de C1
- V2 A2 R2 los colores del semáforo de C2
- VP1 RP1 los colores del semáforo de peatones
Condiciones
[editar]
- Cambio de verde a rojo máximo 5 segundos
- Si los tres sensores están activos se pasa de un estado a otro sin parar
- De 9 a 30 estados es una buena implementación
- Tener 3 inputs implica 8 next state link
- Data Structure stored in ROM
- No pueden haber conditional branching
- Tiempo en cada estado (tiempo en que permanece en verde o rojo un semaforo) entre medio segundo y un segundo
- Flash de no pasar para peaton 2Hz y ejecutarlo dos veces
- Si coche llega a C2 y verde es C1 se espera que acabe C1 y luego empieza C2
- Si solo un sensor está activo en menos de 5 segundos se tiene que pasar a ese semáforo
- Siempre que haya solo un sensor activo se mantiene en ese estado el tiempo que este ese sensor activo
Definición FSM
[editar]
| Output | Input | |||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Estados | West | South | Walk | Salida Hex | WaSoWe | WaSoWe | WaSoWe | WaSoWe | WaSoWe | WaSoWe | WaSoWe | WaSoWe | ||||||||
| Descrpción | Nombre | Tiempo | R | A | V | R | A | V | V | R | Hex | Hex | 0 0 0 | 0 0 1 | 0 1 0 | 0 1 1 | 1 0 0 | 1 0 1 | 1 1 0 | 1 1 1 |
| West verde. South rojo. Walk rojo | goWest | 30 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 0x0C | 0x02 | goWest | goWest | waWest | waWest | waWest | waWest | waWest | waWest |
| West amarillo. South rojo. Walk rojo | waWest | 5 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 0x14 | 0x02 | goWest | goWest | goSouth | goSouth | goWalk | goWalk | goWalk | goSouth |
| West rojo. South verde. Walk rojo | goSouth | 30 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0x21 | 0x02 | goSouth | waSouth | goSouth | waSouth | waSouth | waSouth | waSouth | waSouth |
| West rojo. South amarillo. Walk rojo | waSouth | 5 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0x22 | 0x02 | goSouth | goWest | goSouth | goWest | goWalk | goWalk | goWalk | goWalk |
| West rojo. South rojo. Walk verde | goWalk | 30 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0x24 | 0x08 | goWalk | dontWalk | dontWalk | dontWalk | goWalk | dontWalk | dontWalk | dontWalk |
| West rojo. South rojo. Walk rojo | dontWalk | 5 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0x24 | 0x02 | walkOff | walkOff | walkOff | walkOff | walkOff | walkOff | walkOff | walkOff |
| West rojo. South rojo. Walk apagado | walkOff | 5 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0x24 | 0x00 | dontWalk2 | dontWalk2 | dontWalk2 | dontWalk2 | dontWalk2 | dontWalk2 | dontWalk2 | dontWalk2 |
| West rojo. South rojo. Walk rojo | dontWalk2 | 5 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0x24 | 0x02 | walkOff2 | walkOff2 | walkOff2 | walkOff2 | walkOff2 | walkOff2 | walkOff2 | walkOff2 |
| West rojo. South rojo. Walk apagado | walkOff2 | 5 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0x24 | 0x00 | goWalk | goWest | goSouth | goSouth | goWalk | goWalk | goWalk | goWest |