martes, 10 de mayo de 2022

Implementación de una Máquina de Estados Finita en un PIC

 

http://www.aquihayapuntes.com/indice-practicas-pic-en-c/implementacion-de-una-maquina-de-estados-finita-en-un-pic.html


Implementación de una Máquina de Estados Finita en un PIC

Máquina de Estados Implemetada en un PICEn este pequeño tutorial vamos a ver lo fácil que es crear una Máquina de Estados Finita e implementar el código resultante en un Microcontrolador. La teoría de lo que es una máquina de estados y como implementarla a través del DTE (Diagrama de Transiciones de Estados) ya se explico en este artículo, por lo que si no lo habéis leído todavía recomiendo su lectura antes de empezar a leer este. Para ayudarnos en el diseño de la Máquina de Estados y la posterior codificación en C nos vamos a ayudar de una herramienta gráfica concretamente Qfsm, un proyecto Multiplataforma de software libre realizado con Qt.

 

 

qfsn

 

Como ejemplo vamos hacer el del movimiento del robot visto en el primer artículo (así sirve de comparación). Por lo que el diagrama de estados será el mismo, lo que vamos a ver ahora es como crearlo con este IDE.

Creación del Diagrama de Estados


Para crear una nueva máquina de estados hacemos clic en File ->New

 

Nueva Máquina de Estados

 

Lo más importante en la ventana que nos aparece es lo que está dentro de los recuadros Moore y Mealy. En el recuadro Moore pondremos el número de salidas y el nombre de estas que tendrá el Autómata y en definitiva nuestro PIC. Las entradas las pondremos en el apartado para Mealy, las salidas aquí no hace falta ponerlas porque al final lo que vamos a implementar es un Autómata de Moore.

Una vez que tengamos creada la Máquina de Estados deberemos incluir los diferentes estados que tendrá el autómata, para ello hacemos clic en State-> New o pinchando directamente en el icono que hay en la barra de herramientas.

 

Nuevo Estado

 

En esta ventana pondremos: en la caja de texto identificada como Name el nombre con el que queremos identificar el estado (es solo una etiqueta) el estado se identifica realmente por el número en binario que hay en la caja de texto Code, (al crear el estado ya se asigna un número por defecto). En Moore Outpts pondremos la salida de Moore que queremos asociar al estado que acabamos de crear.

Una vez hecho esto el siguiente paso es unir los estados por medio de transiciones, para ello hacemos clic en Add Transition en la barra de herramientas, después hacemos clic en el estado donde queremos iniciar la transición y arrastramos la flecha al estado de destino.

Repetimos el proceso con cada uno de los estados y transiciones que tenga nuestro autómata.

En el caso de nuestro ejemplo (el movimiento del robot) quedaría así:

 

DTE movimiento robots

 

Una vez creado muestro diagrama de estados podemos chequearlo, para ello hacemos clic en Machine-> Integrity Check, nos aparecerá la siguiente ventana:

 

Chek Integridad Máquina de Estados

 

Donde sí nuestro autómata es correcto aparecerán con una aspa verde los diferentes chequeos realizados. Este tipo de test nos sirve para saber si nuestro autómata es determinista, es decir, que no tenga estados y condiciones ambiguas, el diseño lógico es responsabilidad nuestra y la aplicación no funcionará correctamente si está mal diseñado, realmente está es la única complicación que hay, todo lo demás es un proceso mecánico e igual para cualquier programa que queramos hacer.

 

Simulando el diagrama de Estados


Una vez creado el diagrama de estados podemos simularlo desde el propio IDE, para ello hacemos clic en Machine-> Simulate… o directamente desde el botón Simulate que hay en la barra de herramientas, nos aparecerá la siguiente ventana:

 

Simulación Máquina de Estados

 

La simulación empezará en el estado de inicio o reset, representándose por medio de un cuadrado de color rojo el estado en el que nos encontramos, a partir de aquí meteremos las entradas en la caja de texto que pone Inputs y podremos ver la evolución de los estados.

 

Creación del programa en C

 

Una vez comprobado que nuestra máquina de estados funciona correctamente exportaremos el código. El IDE permite la exportación directa a diferentes lenguajes de descripción hardware como: AHDL, VHDL, Verilog HDL, etc. pero no tiene la opción (de momento) de exportar el código a un lenguaje de alto nivel como el C que pueda ser compilado para un microcontrolador, pero no importa mucho ya que el hacer la portabilidad manualmente resulta fácil.

 

Exportar código

 

Para ello seleccionaremos exportar a AHDL que es un lenguaje de Descripción Hardware propietario de Altera usado para la programación de CPLDs y FPGAs, el por qué seleccionar AHDL y no otro es porque este tiene la ventaja de que su sintaxis es parecida al lenguaje C.  


El código AHDL generado por el IDE para nuestro ejemplo es el siguiente:

 

01.% This file was generated by                %
02.% Qfsm Version 0.52                    %
03.% (C) Stefan Duffner, Rainer Strobel        %
04. 
05.SUBDESIGN Ejemplo_robot
06.(clock, reset        :INPUT;
07.I1,I0    :INPUT;
08.:OUTPUT;
09.M1,M2    :OUTPUT;)
10. 
11.VARIABLE
12.fsm    :    MACHINE OF BITS(s0, s1)
13.WITH STATES (
14.Para = B"00",
15.Adel. = B"01",
16.Atras = B"10");
17.reset_async : NODE;
18._asyncM1, _asyncM2 : NODE;
19. 
20.BEGIN
21.reset_sync = DFF(reset,clock,VCC,VCC);
22.fsm.reset = reset_sync;
23. 
24.fsm.clk = clock;
25.M1 = DFF(M1_async,clock,VCC,VCC);
26.M2 = DFF(M2_async,clock,VCC,VCC);
27. 
28.CASE fsm IS
29.WHEN Para =>
30.IF (I1,I0) == B"10" THEN
31.END IF;
32.IF (I1,I0) == B"01" THEN
33.fsm = Adel.;
34.(_asyncM1, _asyncM2) = B"01";
35.END IF;
36.IF (I1,I0) == B"11" THEN
37.fsm = Atras;
38.(_asyncM1, _asyncM2) = B"10";
39.END IF;
40.IF (I1,I0) == B"00" THEN
41.END IF;
42.WHEN Adel. =>
43.IF (I1,I0) == B"00" THEN
44.END IF;
45.IF (I1,I0) == B"01" THEN
46.END IF;
47.IF (I1,I0) == B"10" THEN
48.fsm = Para;
49.(_asyncM1, _asyncM2) = B"00";
50.END IF;
51.IF (I1,I0) == B"11" THEN
52.fsm = Atras;
53.(_asyncM1, _asyncM2) = B"10";
54.END IF;
55.WHEN Atras =>
56.IF (I1,I0) == B"10" THEN
57.fsm = Para;
58.(_asyncM1, _asyncM2) = B"00";
59.END IF;
60.IF (I1,I0) == B"00" THEN
61.END IF;
62.IF (I1,I0) == B"11" THEN
63.END IF;
64.IF (I1,I0) == B"01" THEN
65.fsm = Adel.;
66.(_asyncM1, _asyncM2) = B"01";
67.END IF;
68.END CASE;
69.END;

 

Y el código resultante una vez portado a C para el compilador de CCS será el siguiente:

 

01.////////////////////////////////////////////////////////////////////////////
02.//                                                                        //
03.//Ejemplo de Autómata de MOORE. Implementado en un PIC                    //
04.//Basado en el código generado por Qsfm.                                   //
05.//                                                                        //
06.//WWW.AQUIHAYAPUNTES.COM                                                  //
07.//                                                                        //
08.////////////////////////////////////////////////////////////////////////////
09. 
10.#include <16F877.h>
11.#FUSES NOWDT, XT, NOPUT, PROTECT, NOBROWNOUT, NOLVP, NOCPD, NOWRT, NODEBUG
12.#use delay(clock=20000000)
13. 
14.//Definición de registros
15.#byte PORTA=0x05
16.#byte PORTB=0x06
17.#bit RB0=PORTB.0
18.#bit RB1=PORTB.1
19. 
20.//Definición de los tres estados posibles.
21.#DEFINE PARA 0
22.#DEFINE ADELANTE 1
23.#DEFINE ATRAS 2
24. 
25.//Función principal.
26.void main()
27.{
28.//Inicialización de registros.
29.set_tris_b (0x00);//RB0 como salida  
30.RB0=0;
31.RB1=0;
32. 
33.//Declaración de variables de la Máquina de estados.
34. 
35.int ESTADO=0;
36. 
37. 
38.while(true){
39. 
40.switch(ESTADO)         
41.{
42.case PARA:
43.{      
44.// if (PORTA==2);
45.if (PORTA==1){
46.ESTADO=ADELANTE;
47.RB0=1;
48.RB1=0;
49.}
50.if (PORTA==3){
51.ESTADO=ATRAS;
52.RB0=0;
53.RB1=1;
54.}
55.//if (PORTA==0);
56.break;
57.}
58. 
59.case ADELANTE:
60.{
61.//  if (PORTA==0);
62.//  if (PORTA==1);
63.if (PORTA==2){
64.ESTADO=PARA;
65.RB0=0;
66.RB1=0;  
67.}
68.if (PORTA==3){
69.ESTADO=ATRAS;
70.RB0=0;
71.RB1=1;  
72.}
73.break;
74.}   
75.case ATRAS:
76.{
77.if (PORTA==2){
78.ESTADO=PARA;
79.RB0=0;
80.RB1=0;  
81.}
82.// if (PORTA==0);
83.//  if (PORTA==3);    
84.if (PORTA==1){
85.ESTADO=ADELANTE;
86.RB0=1;
87.RB1=0;  
88.}
89.break;
90. 
91.}
92. 
93.defaultbreak;  
94.}
95.}       
96.}

La parte del código comentado son sentencias if que genera el IDE y que se pueden eliminar una vez optimizado el código.

Circuito final


Una vez compilado el código con CCS tendremos como siempre un .HEX que podremos programar en el PIC y probar en un circuito real o simularlo en Proteus.

 

Circuito en Proteus

 

Fuentes de Información

 

qfsm
Qt
CCS Custom Computer Services


En el foro tenéis el .DTE y .DNS del ejemplo y más ejemplos de usuarios del foro que han realizado su propia máquina de estados, como el proyecto de la lavadora del amigo UbunPIC.  

Como siempre espero vuestras sugerencias al respecto en el foro.

Os podéis descargar este artículo en versión .pdf desde aquí.

No hay comentarios:

Publicar un comentario