Diferencia entre revisiones de «C10 - Finite State Machine»

De Proyectos
Ir a la navegación Ir a la búsqueda
Línea 389: Línea 389:
*Siempre que S1 se mantenga en 1 nos quedamos en este estado
*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
*Si no hay ningún coche en las dos calles también nos mantenemos en este estado
*Para pasar al siguiente estado tiene que S2 tiene que valer 1
*Para pasar al siguiente estado S2 tiene que valer 1
<b>Estado2 - W1</b>
<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
*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
Línea 398: Línea 398:
*Siempre que S2 se mantenga en 1 nos quedamos en este estado
*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
*Si no hay ningún coche en las dos calles también nos mantenemos en este estado
*Para pasar al siguiente estado tiene que S1 tiene que valer 1
*Para pasar al siguiente estado S1 tiene que valer 1
<b>Estado4 - W2</b>
<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
*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
Línea 404: Línea 404:
*Cualquier input nos hace pasar al siguiente estado
*Cualquier input nos hace pasar al siguiente estado
<br>
<br>
En esta table muestro la relación de inputs con la transición de estados:<br>
{|border="1" cellpadding="5" cellspacing="0"
!Input || C1 || W1 || C2 || W2
|-
|00 || C1 || C2 || C2 || C1
|-
|01 || W1 || C2 || C2 || C1
|-
|10 || C1 || C2 || W2 || C1
|-
|11 || W1 || C2 || W2 || C1
|}
<br>
La primera columna (C1) se lee:
*Si el input es 00 (no hay coches en niguna calle) nos mantenemos en C1
*Para el input 01 (coche en C2 y no en C1) pasamos al estado W1
*Para el input 10 (coche en C1 y no en C2) nos mantenemos en C1
*Para el input 11 (coches en C1 y en C2) pasamos a estado W1


=== Programación estados ===
=== Programación estados ===

Revisión del 20:29 26 mar 2015

Introducción


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)

Que és? Cómo funciona?


  • 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:


velocidad=400n+1⇒n=SYSDIV2
Ej.
velocidad=400n+1=4004+1=80Mhz⇒ 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


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

  • 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


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
80Mhz⇒180Mhz=12.5ns 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
10ms=12ns*n⇒n=10ms12ns=800000

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


  • 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


  • 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


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

  • 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

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

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


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

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

Imagen STG

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

//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



Stepper Motor



Lab 10

Introducción


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


  • 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