sistema de control basat en màquines...

108
Sistema de Control Basat en Màquines d’Estat AUTOR: Enric Dalmau Malet DIRECTOR: Ernest Gil Dolcet DATA: setembre / 2002

Upload: others

Post on 13-Jul-2020

1 views

Category:

Documents


0 download

TRANSCRIPT

Sistema de Control Basat en Màquines d’Estat

AUTOR: Enric Dalmau Malet

DIRECTOR: Ernest Gil Dolcet

DATA: setembre / 2002

Índex

Índex

AGRAÏMENTS ............................................................................................................................................. VI

1 INTRODUCCIÓ...................................................................................................................................... 1

1.1 OBJECTE DEL PROJECTE ................................................................................................................... 1

1.2 ANTECEDENTS.................................................................................................................................. 1

1.3 POSSIBLES SOLUCIONS I SOLUCIÓ ADOPTADA ................................................................................. 1

1.4 DESCRIPCIÓ GENERAL...................................................................................................................... 2

1.4.1 Compilació de Màquines d’Estat ............................................................................................... 2

1.4.2 Monitorització de Màquines d’Estat .......................................................................................... 2

1.5 POSSIBLES APLICACIONS.................................................................................................................. 3

2 MICROCONTROLADORS DE LA FAMÍLIA 8051.......................................................................... 4

2.1 EL MICROCONTROLADOR BASE DE LA FAMÍLIA 8051 ...................................................................... 4

2.2 EL MICROCONTROLADOR 8052........................................................................................................ 5

2.3 INTERFÍCIE DE COMUNICACIÓ SÈRIE ................................................................................................ 5

2.4 INTERRUPCIONS................................................................................................................................ 6

2.4.1 Taula de Vectors ........................................................................................................................ 6

2.4.2 Execució d’una Interrupció........................................................................................................ 6

2.4.3 Tipus d’Interrupcions................................................................................................................. 6

3 EINES DE DESENVOLUPAMENT ..................................................................................................... 7

3.1 EMULADOR DCSEMU....................................................................................................................... 7

3.1.1 Mapa de Memòria utilitzat per l’Emulador DCSemu ................................................................ 8

3.1.2 Modificació de la Targeta Emuladora........................................................................................ 9

3.1.3 Hardware de la Targeta.............................................................................................................. 9

4 BLOC I: COMPILACIÓ DE MÀQUINES D’ESTAT ...................................................................... 11

4.1 PROCEDIMENT DE COMPILACIÓ...................................................................................................... 11

4.2 EDICIÓ DE MÀQUINES D’ESTAT...................................................................................................... 11

4.2.1 Especificacions de les Màquines d’Estat ................................................................................. 11

i

Índex

4.2.1.1 Variables........................................................................................................................... 12

4.2.1.2 Limitacions dels Diagrames ............................................................................................. 13

4.2.1.3 Format dels Diagrames .................................................................................................... 13

4.2.2 Taules d’Estructures ................................................................................................................ 14

4.2.2.1 Transicions ....................................................................................................................... 14

4.2.2.2 Operacions........................................................................................................................ 15

4.2.2.3 Estats ................................................................................................................................ 16

4.2.2.4 Diagrames d’estat............................................................................................................. 17

4.2.2.5 Projectes de Màquines d’Estat ......................................................................................... 18

4.2.2.6 Variables........................................................................................................................... 19

4.2.3 Entorn Gràfic ........................................................................................................................... 23

4.3 COMPILACIÓ DE MÀQUINES D’ESTAT............................................................................................. 25

4.3 COMPILACIÓ DE MÀQUINES D’ESTAT............................................................................................. 26

4.3.1 Flux d’Execució....................................................................................................................... 26

4.3.1.1 Flux d’Execució: Variables .............................................................................................. 26

4.3.1.2 Tractament dels Temporitzadors ...................................................................................... 28

4.3.2 Mapejat de Variables ............................................................................................................... 30

4.3.2.1 Adreçament de Variables en l’Execució ........................................................................... 30

4.3.2.2 Mapejat de Variables en Temps d’Execució..................................................................... 33

4.3.3 Expressions de les Transicions ................................................................................................ 35

4.3.3.1 Estructura Enllaçada de Dades........................................................................................ 35

4.3.3.2 Tractament de les Variables ............................................................................................. 36

4.3.3.3 Memòria Intermèdia ......................................................................................................... 37

4.3.3.4 Procediment de Resolució ................................................................................................ 37

4.3.3.5 Codificació de les Instruccions......................................................................................... 37

4.3.4 Disposició del Codi Assemblador............................................................................................ 38

4.3.4.1 Codi Inicial ....................................................................................................................... 39

4.3.4.2 Codi Cíclic ........................................................................................................................ 39

4.3.4.3 Diagrama de Flux del Cicle d’Execució........................................................................... 40

4.3.4.4 Codi de Tractament dels Temporitzadors......................................................................... 40

ii

Índex

4.3.5 Conversió a Llenguatge Assemblador ..................................................................................... 42

4.3.5.1 Etiquetes de Variables ...................................................................................................... 42

4.3.5.2 Tractament d’Imatges....................................................................................................... 43

4.3.5.3 Evolució dels Diagrames d’Estat ..................................................................................... 44

4.3.5.4 Expressions ....................................................................................................................... 45

4.3.5.5 Operacions de Forçat ....................................................................................................... 47

4.3.5.6 Operacions Combinacionals ............................................................................................ 48

4.3.5.7 Operacions Biestables ...................................................................................................... 49

4.3.5.8 Temporitzadors ................................................................................................................. 50

4.3.6 Codi ‘C’ Resultant ................................................................................................................... 52

5 BLOC II: MONITORITZACIÓ DE MÀQUINES D’ESTAT .......................................................... 53

5.1 OBJECTIU ....................................................................................................................................... 54

5.2 CARACTERÍSTIQUES DEL SISTEMA DE MONITORITZACIÓ................................................................ 54

5.2.1 Característiques de les Màquines d’Estat................................................................................. 54

5.2.2 Tipus de Dades a Enviar .......................................................................................................... 55

5.2.3 Interacció amb el Sistema de Control ...................................................................................... 56

5.3 UTILITZACIÓ DEL PORT SÈRIE ........................................................................................................ 56

5.3.1 Treball amb Interrupcions o per Enquesta ............................................................................... 57

5.3.2 Mode de treball del port sèrie .................................................................................................. 57

5.3.3 Software pel Microcontrolador ................................................................................................ 57

5.3.3.1 Organització de la RAM Interna ...................................................................................... 58

5.3.4 Software pel PC ....................................................................................................................... 59

5.4 PROTOCOL DE COMUNICACIONS..................................................................................................... 60

5.4.1 Format de les Trames............................................................................................................... 61

5.4.2 Tipus de Trames....................................................................................................................... 62

5.4.2.1 Informació Inicial de Diagrames i Estats......................................................................... 62

5.4.2.2 Dades d’Actualització....................................................................................................... 63

5.4.3 Protocol de Comunicacions en la Interacció............................................................................ 64

5.5 TRACTAMENT DE DADES EN EL MICROCONTROLADOR.................................................................. 65

iii

Índex

5.5.1 Obtenció de Dades ................................................................................................................... 65

5.5.1.1 Informació Inicial de Diagrames i Estats......................................................................... 65

5.5.1.2 Dades d’Actualització....................................................................................................... 66

5.5.2 Modificació de Variables......................................................................................................... 68

5.6 TRACTAMENT DE DADES EN EL PC................................................................................................. 69

5.7 INTERFÍCIE AMB L’USUARI ............................................................................................................. 69

5.8 CODI RESULTANT........................................................................................................................... 71

6 CONCLUSIONS.................................................................................................................................... 73

7 ANNEXES.............................................................................................................................................. 74

7.1 ANNEX A.1: LLISTAT DELS FITXERS CREATS EN EL BLOC I EN LLENGUATGE ‘C' .......................... 74

7.1.1 Fitxer General de Capçalera: “def&typ.h”............................................................................... 74

7.1.2 Fitxer de Capçalera de l’Edició: “edicio.h” ............................................................................. 75

7.1.3 Fitxer de Capçalera de la Compilació: “compi.h”.................................................................... 77

7.1.4 Fitxer de Capçalera del Tractament de les Expressions: “prim.h”........................................... 78

7.1.5 Fitxer Principal: “proj.c”.......................................................................................................... 79

7.1.6 Fitxer d’Edició de Diagrames: “diags.c” ................................................................................. 84

7.1.7 Fitxer d’Edició d’Estats: “estats.c” .......................................................................................... 92

7.1.8 Fitxer d’Edició de variables: “vars.c” .................................................................................... 100

7.1.9 Fitxer d’Edició de Menús: “menus.c”.................................................................................... 114

7.1.10 Fitxer d’Edició Referent als Llistats d’Elements de Màquines d’Estat: “mostra.c”........... 119

7.1.11 Fitxer de Compilació Inicial: “com_ini.c” ......................................................................... 126

7.1.12 Fitxer de Compilació del Flux d’Execució: “com_flux.c” ................................................. 132

7.1.13 Fitxer de Compilació d’Expressions: “com_exp.c” ........................................................... 143

7.1.14 Fitxer de Compilació de Temporitzadors: “com_temp.c” .................................................. 146

7.1.15 Fitxer Base del Tractament de les Expressions: “predef.c”................................................ 149

7.1.16 Fitxer de Tractament de les Operacions de les Expressions: “operacio.c”......................... 152

7.1.17 Fitxer de Tractament d’Expressions: “tractame.c”............................................................. 157

7.1.18 Fitxer de Tractament de Diverses Funcions: “funcions.c” ................................................. 161

7.2 ANNEX A.2: LLISTATS DE FITXERS OBTINGUTS D’UNA COMPILACIÓ D’EXEMPLE ....................... 167

iv

Índex

7.2.1 Fitxer de Capçalera Obtingut: “prova.h” ............................................................................... 167

7.2.2 Fitxer de Tractament de les Màquines d’Estat Obtingut: “prova.asm”.................................. 170

7.3 ANNEX B.1: LLISTAT DELS FITXERS CREATS EN EL BLOC II EN LLENGUATGE ‘C' ....................... 181

7.3.1 Fitxer de Capçalera de la Monitorització: “capsal.h” ............................................................ 181

7.3.2 Fitxer Principal de la Monitorització: “projek.c”................................................................... 183

7.3.3 Fitxer de Tractament de Comunicacions a Través del Port Sèrie: “sericom.c” ..................... 185

7.3.4 Fitxer de Tractament de Dades d’Estructures: “estruk.c” ...................................................... 192

7.3.5 Fitxer de Tractament d’Elements Visuals: “menus2.c” ......................................................... 200

7.3.6 Fitxer de Tractament de Diverses Funcions: “funcion2.c” .................................................... 208

7.4 ANNEX B.2: LLISTAT DELS FITXERS CREATS EN EL BLOC II EN LLENGUATGE ASSEMBLADOR.... 211

7.4.1 Fitxer de Capçalera del Tractament de les Comunicacions: “RS232prj.h” ........................... 211

7.4.2 Fitxer de Tractament de Comunicacions per la Monitorització: “RS232prj.asm”................. 211

7.5 ANNEX C: SOFTWARE GENERAT................................................................................................... 234

BIBLIOGRAFIA........................................................................................................................................ 243

v

Agraïments

Agraïments

Des d’aquí, vull enviar els meus agraïments a totes aquelles persones que de forma directa o indirecta han participat en la realització d’aquest projecte.

En primer lloc, vull agrair a l’Ernest Gil, director d’aquest projecte, tot el temps i tota l’ajuda que m’ha donat en tot moment, aquest projecte s’ha realitzat gràcies a ell.

En segon lloc, no puc deixar d’anomenar al Pere, la col·laboració del qual ha estat molt important. També agraeixo als meus companys Àlex, Ros i David, els seus consells i la seva ajuda en els dos últims anys en la universitat.

Tampoc puc oblidar-me de la gent que tinc més a prop, que m’han recolzat en tot moment i han seguit amb entusiasme l’evolució del meu treball. Ells són: la Susana, els meus pares Josep Mª i Conxita, i els meus amics.

vi

Introducció

MEMÒRIA

1 Introducció

1.1 Objecte del Projecte

El que es pretén en aquest projecte, bàsicament, és crear un sistema de control basat en màquines d’estat. Aquest procés de creació consta de diverses fases: definició, compilació, monitorització i depuració de les màquines d’estat. Es pretén que totes aquestes fases estiguin dirigides mitjançant un ordinador personal.

El projecte es divideix en dues parts ben diferenciades. En la primera es crea un programa en llenguatge ‘C’ capaç de crear i editar màquines d’estat amb les dades introduïdes per l’usuari, traduint-les després a llenguatge assemblador. Aquest primer bloc s’anomena ‘Compilació de Màquines d’Estat’.

La segona part del projecte parteix del codi assemblador anteriorment creat i disposat en un microcontrolador. En aquest cas es creen unes rutines en ‘C’ i unes altres en codi assemblador de forma que comunicant-se a través del port sèrie, es monitoritza l’evolució de les màquines d’estats introduïdes anteriorment en el microcontrolador. Aquesta monitorització permet depurar de forma senzilla el funcionament del sistema de control basat en màquines d’estat. Aquest segon bloc s’anomena ‘Monitorització de Màquines d’Estat’.

1.2 Antecedents

La creació de sistemes de control basats en màquines d’estat sempre ha estat una feina tediosa, sobretot a l’hora de traduir aquests sistemes a llenguatge assemblador compilable per executar-se en un µcontrolador. D’altra banda, la depuració dels sistemes de control també resulta una tasca dificultosa, ja que encara que s’emuli el funcionament del µcontrolador, el valor de les variables i l’evolució dels diagrames és difícil d’observar enmig de la memòria.

Per tant, la realització d’aquest projecte ha vingut motivada, en primer lloc, per l’interès en reduir el temps destinat a traduir el disseny de diagrames d’estat en paper a llenguatge assemblador; i en segon lloc, per permetre una depuració còmode i senzilla de sistemes de control basats en màquines d’estat.

1.3 Possibles Solucions i Solució Adoptada

L’elecció del llenguatge de programació és molt important. En principi, diferents llenguatges de programació podrien haver-se utilitzat, com per exemple: 'Pascal' o 'Basic'. No obstant, s’ha cregut que el llenguatge ‘C’ és el més oportú. De fet, llenguatges com el ‘Pascal’ o el ‘Basic’, es caracteritzen per no oferir massa rapidesa ni eficàcia, al menys, quan es necessita treballar amb un temps crític o amb aplicacions que exigeixen molt al sistema.

El llenguatge de programació ‘C’ és ideal per a les necessitats d’aquest projecte, disposa d’operacions típiques de qualsevol microprocessador, i de tipus de dades i estructures que són força generals i flexibles. El ‘C’ és elegant, compacte i ràpid.

1

Introducció

D’altra banda, calia escollir el microcontrolador a utilitzar. Entre d’altres microcontroladors destaquen: el 68000 de Motorola, el 80C196 de Intel, el 8051 de Philips o el PIC 16C84 de Motorola. Tot i les diferents opcions, s’ha optat pel 8051 degut a la gran difusió que ha tingut aquest microcontrolador, fet que implica que el preu sigui força reduït. Del 8051 i la seva família de microcontroladors cal destacar-ne la bona resposta en aplicacions de control en temps real. A més, ha sigut un factor important el fet que el departament de Sistemes Informàtics en Temps Real i Comunicacions (SITRC) tingui oberta una línia d’investigació en aquest sentit.

1.4 Descripció General

El present projecte es divideix en dos grans blocs que es descriuen a continuació:

1.4.1 Compilació de Màquines d’Estat

Aquest primer bloc és l’encarregat de crear i editar màquines d’estat a partir de la informació introduïda per l’usuari, traduint tota aquesta informació a llenguatge assemblador corresponent a la família de microcontroladors 8051. La realització d’aquest primer bloc també es divideix en dues parts ben diferents.

La primera és la corresponent a l’edició de tota la informació dels diagrames d’estats, on s’emmagatzema tota la informació que es vulgui de tants projectes com es vulgui (cada projecte consta d’un o més diagrames i de diferents variables) en el disc dur i en forma de fitxers binaris.

La segona part és la compilació pròpiament dita, que obté la informació d’un projecte determinat que es troba en disc i la tradueix a llenguatge assemblador corresponent a la família del 8051.

Aquest primer bloc ha estat impulsat pel grup de recerca: “Línia de Sistemes de Temps Real i Control Distribuït” del Departament d’Enginyeria Electrònica, Elèctrica i Automàtica (DEEEA). Per tant, tot i que el treball ha estat completament personal, les directrius han estat marcades pel departament, i més directament, pel director del departament i d’aquest projecte, el Sr. Ernest Gil Dolcet.

1.4.2 Monitorització de Màquines d’Estat

Aquest segon bloc es basa en allò realitzat en el primer, tot i que ara tant el treball com les directrius són absolutament personals.

El que es pretén en aquest bloc és monitoritzar l’evolució dels diferents diagrames que conformen la màquina d’estat, així com l’estat de les variables que hi intervenen, permetent a l’usuari depurar el sistema de control basat en màquines d’estat. Això es fa mitjançant comunicació sèrie, ja que tant el PC com el microcontrolador en disposen. A més, per tal de comunicar-se adequadament, es crea un protocol de comunicacions propi que permet una comunicació idònia entre microcontrolador i PC.

La monitorització també inclou una interacció amb les variables del microcontrolador, ja que la comunicació sèrie permet modificar des del programa de monitorització en ‘C’ les diferents variables que continguin informació d’entrada del microcontrolador. Aquesta característica afegeix una prestació molt important al programa creat, ja que permet introduir al sistema de control les condicions d’entrada desitjades per tal de depurar de millor forma el seu funcionament.

2

Introducció

1.5 Possibles Aplicacions

Aquest projecte és eminentment pràctic i pot ser utilitzat per a diverses aplicacions, totes elles relacionades amb les màquines d’estat i la família de microcontroladors 8051. A continuació es mostra una sèrie de possibles aplicacions d’aquest projecte o de parts d’aquest projecte:

• Realització d’un sistema de control basat en màquines d’estat per controlar una planta automàtica a través d’un microcontrolador de la família del 8051. Aquesta aplicació aprofitaria totes les possibilitats de què disposa aquest projecte.

• Creació, edició i emmagatzemament de dades de màquines d’estat. Aquí, només s’aprofitaria la primera part del primer bloc del projecte.

• Monitorització i depuració de sistemes de control basats en màquines d’estat i funcionant en un microcontrolador de la família del 8051.

Qualsevol aplicació que manipuli màquines d’estat, pot beneficiar-se d’aquest projecte, ja sigui del projecte sencer, o bé d’alguna o algunes de les seves parts.

3

Microcontroladors de la Família 8051

2 Microcontroladors de la Família 8051

El microcontrolador 8051 ha estat utilitzat en una gran quantitat de projectes en els últims anys. Es tracta d’un dels microcontroladors més usats a nivell mundial i té una enorme difusió.

El microcontrolador 8051 va sorgir a començaments dels anys 80 a mans de Intel. A partir d’aquí van sorgir una sèrie de versions que van culminar amb el 8052, microcontrolador utilitzat per a la realització d’aquest projecte. De totes aquestes versions, el 8051 és el microcontrolador base.

2.1 El Microcontrolador Base de la Família 8051

El 8051 és el microcontrolador base de la família que té el mateix nom. Aquest microcontrolador disposa de ROM interna i té com a principals característiques les que es mostren a continuació:

• 128 bytes de RAM interna que admeten adreçament directe i indirecte de byte; a més, una zona de 16 by és accessible bit a bit.

• 4 Kby de ROM interna.

• CPU de 8 bits interns i externs.

• 4 ports de 8 bits d’entrada/sortida.

• 2 comptadors/temporitzadors interns.

MEMÒRIA DE PROGRAMA MEMÒRIA DE DADES

IO

• Port s

1

• 5 font

• Mapa

• Mapa

Figura 2.1. Organització dels espais de memòria del 805

4

èrie.

s d’interrupció amb 2 nivells de prioritat.

de memòria de programa de fins a 64Kby.

de memòria de dades de fins a 64Kby.

Microcontroladors de la Família 8051

5

Com a particularitat s’observa la distinció que es fa en l’adreçament a un espai de memòria de programa i un espai de memòria de dades. En la figura de la pàgina anterior es mostra com s’organitzen els espais de memòria del 8051.

2.2 El Microcontrolador 8052

Aquest microcontrolador és l’últim i més evolucionat de la família 8051. Es caracteritza per posseir un tercer temporitzador i 128 bytes més de ram interna. A continuació es mostra una figura que presenta la organització dels espais de memòria del 8052.

MEMÒRIA DE PROGRAMA MEMÒRIA DE DADES

O

I

Els 128 bytes suplementaris de RAM interna de què disposa el 8052 únicament són accessibles mitjançant adreçament indirecte mitjançant els registres: R0, R1 o SP.

Figura 2.2. Organització dels espais de memòria del 8052

2.3 Interfície de Comunicació Sèrie

La interfície de comunicació sèrie és accessible físicament gràcies a la funció secundària de dues línies del port P3. La línia P3.0 fa la funció del terminal de recepció RXD i la línia P3.1 fa la funció del terminal de transmissió TXD.

El port sèrie dels microcontroladors de la família del 8051 funciona en mode “full duplex”, és a dir, que és capaç de transmetre i rebre informació simultàniament. A més, posseeix un “buffer” de recepció que permet la recepció d’un byte abans de la lectura de l’anterior. Els registres de recepció i transmissió són ambdós accessibles en la mateixa adreça de la RAM interna, designada pel símbol SBUF. Una escriptura en aquesta adreça accedeix al registre de transmissió, mentre que una lectura permet extreure la dada del registre de recepció.

El control del port sèrie es realitza mitjançant el registre SCON, que permet fer funcionar el port sèrie en 4 modes:

• Mode 0: Registre de desplaçament. En aquest mode el port sèrie funciona com un registre de desplaçament de 8 bits. El rellotge funciona amb una freqüència 12 vegades inferior a la de l’oscil·lador del microcontrolador.

Microcontroladors de la Família 8051

6

• Mode 1: El port sèrie funciona com una UART de 8 bits amb un bit d’inici i un bit de parada. La velocitat de comunicació és variable.

• Mode 2: Aquest mode fa que el port sèrie es comporti com una UART de 9 bits amb un bit d’inici i un bit de parada. La velocitat de comunicació pot ser 32 o 64 vegades inferior a la de l’oscil·lador del microcontrolador.

• Mode 3: Aquest últim mode és quasi idèntic a l’anterior, amb la diferència que la velocitat de comunicació és variable.

2.4 Interrupcions

El 8051 bàsic disposa de cinc fonts d’interrupció, mentre que la versió 8052 en disposa de 6. Totes aquestes fonts d’interrupció són “emmascarables”, és a dir, es poden habilitar i deshabilitar per software. Després de la inicialització, totes les interrupcions estan inhibides. El registre IE serveix per habilitar o deshabilitar individualment les fonts d’interrupció. El mecanisme d’interrupció posseeix vectors de direcció fixa. Aquestes adreces estan situades en la part baixa de la memòria de programa (o codi).

2.4.1 Taula de Vectors

La primera instrucció que s’executa després d’una inicialització (Reset=1) és la que es troba en la direcció 0000H de la memòria de programa. Es reserven tres bytes per aquesta primera instrucció, nombre de bytes suficient per executar una instrucció de salt de tipus ‘LJMP’.

Per aquest motiu, les adreces reservades a les subrutines que han d’atendre a les diferents interrupcions del programa principal se situen a partir de la direcció 0003H, amb una separació de vuit bytes entre cada rutina d’atenció a la interrupció.

2.4.2 Execució d’una Interrupció

Quan el processador accepta una petició d’interrupció, s’executa un salt automàtic a la rutina de servei corresponent. Però abans d’efectuar el salt, el processador emmagatzema automàticament a la pila l’adreça de la instrucció que s’estava a punt d’executar. Després posa a 1 un indicador intern que assenyala que s’està executant una interrupció i, finalment es realitza el salt. És necessari que una rutina de servei a una interrupció acabi amb la instrucció ‘RETI’. Aquesta instrucció ho retorna tot a l’estat anterior d’executar-se la rutina.

2.4.3 Tipus d’Interrupcions

Com s’ha dit abans, existeixen 5 (o 6 en el 8052) fonts diferents d’interrupció. Aquestes fonts poden dividir-se en:

• Interrupcions externes ‘INT0’ i ‘INT1’: que utilitzen dues línies del port P3.

• Interrupcions dels timers 0 i 1 (i 2 en el 8052): provocades pels desbordament del comptador corresponent.

• Interrupció del port sèrie: que pot ser provocada per la recepció d’un byte o per la indicació de que un byte està preparat per ser enviat.

Eines de Desenvolupament

7

3 Eines de Desenvolupament

La realització d’aquest projecte requereix la utilització de diferents eines de desenvolupament de tipus software. La majoria d’elles tracten el desenvolupament i depuració de programes en llenguatge assemblador.

Les eines utilitzades referents al codi assemblador són les següents:

• Editor de text: Microsoft WordPad de Windows 98. S’utilitza per introduir el codi en llenguatge assemblador.

• Programa Assemblador: X8051 de la firma 2500 AD Software. Serveix per assemblar el codi assemblador anterior per traduir-lo a codi objecte.

• Programa enllaçador: LINK1. Crea el fitxer executable en el µC a partir d’un o més fitxers en codi objecte.

• Programa enllaçador: LINK2. Aquest enllaçador és més limitat i genera un fitxer en codi Intel Hex, que s’utilitza per simular l’aplicació.

• Programa simulador: 8051 microcontroller debugger/simulator. Permet que el microprocessador de l’ordinador simuli l’execució del programa realitzat pel µcontrolador.

• Programa emulador: DCSemu, versió 1.0. Es tracta d’un Emulador de Sistemes de Control Distribuït. Tot i el potencial del programa, en aquest projecte només s'utilitza per emular una targeta individual basada en el µcontrolador 80C52 o compatible.

A banda d’aquestes eines, se n’ha utilitzat una altra per tal de programar i depurar els programes en llenguatge ‘C'. Aquesta eina de programació és: Borland C++, Versió 4.5. Aquest programa s’utilitza per realitzar els codis corresponents en els dos blocs del projecte.

A continuació es detalla el funcionament i la informació d’una de les eines de desenvolupament utilitzada, l’emulador DCSemu. Aquesta eina és molt important ja que no és una eina massa comú i permet depurar els programes en llenguatge assemblador realitzats.

3.1 Emulador DCSemu

L’objectiu d’aquest emulador és el de permetre l’emulació de Sistemes de Control Distribuït (SCD) basats en el bus RDbus i en el µcontrolador 80C52 o compatible. Això inclou el control de l’execució i l’accés a les variables internes del µcontrolador de cada node. El SCD es connecta a l’ordinador mitjançant una connexió RS232. De fet, només s’hi connecta l’estació “Master”. Aquesta connexió estableix l’interfície amb l’usuari, ja que en l’ordinador s’executa el software que permet interaccionar amb la placa emuladora de forma amigable.

Aquest programa permet l’emulació d’un sol node, que és el cas d’aquest projecte. I aquest únic node ha de ser el “Master”. Realment, el node utilitzat és una placa emuladora i avaluadora a la vegada, que disposa d’un hardware addicional per poder funcionar. Per tant, s’utilitza el microcontrolador i es fa treballar en temps real, de forma que si els

Eines de Desenvolupament

8

programes funcionen correctament en aquesta targeta, tenen un alt índex de probabilitat que funcioni correctament en l’aplicació per a la qual s’ha dissenyat el programa.

En qualsevol cas, el software de l’aplicació que realitza l’usuari per tal de ser executat en un node ha d’haver estat linkat amb una sèrie de llibreries que ofereixen els serveis de gestió local de comunicacions RS232 i RS485 i de les comandes de depuració. En aquest projecte, com que en cap cas s’utilitza més d’un node, no és necessària la inclusió de la llibreria referent al bus RDbus, ja que aquest bus no s’utilitza.

D’altra banda, cal dir que el cristall utilitzat és el del µcontrolador i la seva freqüència d’oscil·lació és de 12 MHz, valor que cal tenir en compte a l’hora d’utilitzar els timers. Aquesta freqüència d’oscil·lació suposa un cicle de màquina de 1 µs.

3.1.1 Mapa de Memòria utilitzat per l’Emulador DCSemu

És important veure la organització i ocupació del mapa de memòria, ja que les aplicacions que es realitzin en el projecte hauran de compartir aquesta memòria.

La següent taula mostra un resum del mapa de memòria que utilitzen les diferents llibreries necessàries per executar una aplicació en un sol node.

Tipus Mida Descripció Codi

0000h-7EFFh

~32 Kby LLIURE

Dades (iRAM) 00h-16h 17h-1Fh 20h-29h

2Ah-2Ch 2Dh-2Eh 2Fh-7Fh 80h-9Fh

A0h-FFh

23 by 9 by

10 by 3 by 2 by

81 by 32 by 96 by

LLIURE (RAM local) Reservat pel debugger LLIURE (RAM adreçable bit a bit) Reservat per la base de temps Reservat per la gestió del RS232 LLIURE LLIURE (RAM d’accés indirecte) Pila

Dades (xRAM) 0000h-00FFh 0100h-0167h 0168h-018Ch 018Dh-019Fh 01A0h-03FFh 0400h-04FFh 0500h-FEFFh FF00h-FFFFh

256 by 37 by 19 by 96 by

607 by 256 by

~64 Kby 256 by

LLIURE Reservat per la llibreria RS232xs Reservat per la llibreria RS232dlc Reservat per la llibreria DEBUG_M LLIURE Reservat per la UART externa: RS232 (Xip SCC2691) LLIURE Reservat pel debugger (EMUreg)

Taula 3.1. Resum del mapa de memòria amb el sistema DCSemu

Les zones de memòria de dades i de programa descrites com a lliure són les que poden utilitzar les aplicacions que es creïn en aquest projecte.

Eines de Desenvolupament

9

3.1.2 Modificació de la Targeta Emuladora

Tal i com s’ha dit en la introducció, el segon bloc del projecte pretén obtenir informació del microcontrolador a través del port sèrie.

La tarja emuladora de que es disposa està dissenyada per treballar amb dos ports de comunicacions: d’una banda, la comunicació RS232 usa la UART SCC2691AC1N24 o compatible, que està mapejada en memòria externa de dades i està connectada al µcontrolador com a interrupció externa; d’altra banda, la comunicació RS485, treballa amb la UART interna del propi µcontrolador. No obstant, com que la comunicació RS485 s’utilitza per connectar diferents targetes, i en aquest projecte només se n’utilitza una, s’aprofita l’interfície sèrie interna del µcontrolador per comunicar el µC amb l’ordinador i poder monitoritzar així el sistema de control basat en màquines d’estat.

Per tant, el que s’ha fet és anul·lar la comunicació RS485, substituint el xip corresponent, per un petit circuit que captura els senyals corresponents a la recepció de dades (RxD) i a la transmissió de dades (TxD) del µcontrolador. Aquests senyals es porten a un connector RS232 del tipus DB9 a través del xip ST232CN. D’aquesta forma, el port sèrie del µC ja és completament accessible. Això s’observa en el diagrama de la figura següent.

A més del xip esmentat, s’han utilitzat 4 condensadors de tàntal de 2,2 µ i 35V.

PLACA EMULADORA

9 8

ST232CN

16 1

TxD

RxD

2

3

RS232

DB9

TxD

RxD

Figura 3.1. Diagrama de connexions per capturar senyals del port sèrie del µC

3.1.3 Hardware de la Targeta

La targeta utilitzada es comunica amb el microcontrolador a través de registres i portes triestat. Hi ha 2 registres, corresponents a sortides, i 3 portes triestat, corresponents a entrades. Cada registre i porta triestat és de tipus byte, és a dir, té 8 bits i per tant 8 variables.

Eines de Desenvolupament

10

µC8051

Reg. Porta triestatReg. Porta triestat Porta triestat

8 88 8 8

WR WR RD RD RD

ENTRADESSORTIDES

Figura 3.2. Comunicació del µcontrolador amb la targeta

Això permet delimitar el nombre màxim de variables reals que s’utilitzen en el projecte quan es treballa amb el microcontrolador. El nombre màxim d’entrades és de 24 i el de sortides és de 16. És a dir, que l’espai de memòria necessari és de 3 i 2 bytes respectivament, ja que cada variable ocupa un bit.

Bloc II: Monitorització de Màquines d’Estat

53

INFORMACIÓ CONFIDENCIAL

Per més informació, adreçar-se a: [email protected]

5 Bloc II: Monitorització de Màquines d’Estat

La monitorització de màquines d’estat constitueix el segon bloc d’aquest projecte i parteix de la base realitzada en el primer bloc. Això significa que el programa de monitorització que es realitzi estarà preparat per realitzar el seguiment de màquines d’estat construïdes en el primer bloc.

Bloc II: Monitorització de Màquines d’Estat

54

Una propietat important de la monitorització és que és interactiva, és a dir, que es poden modificar les variables des del programa de monitorització resident en el PC.

Per establir la comunicació s’utilitza la interfície de comunicació sèrie. I el protocol de comunicacions utilitzat s’ha creat especialment per a aquest sistema de monitorització.

5.1 Objectiu

L’objectiu bàsic de la monitorització de les màquines d’estat és el de depurar les màquines d’estat que constitueixen un sistema de control. Aquest seguiment del sistema de control es realitza mitjançant la interfície de comunicació sèrie entre el microcontrolador i un ordinador personal, de forma que aquest rebi la informació de la màquina d’estat que s’estigui executant en el microcontrolador. Aquesta informació permet mostrar per pantalla l’estat de totes les variables, així com l’estat actiu de cada diagrama.

El sistema de monitorització, a més d’obtenir informació, també permet interactuar amb el sistema de control basat en màquines d’estat. De fet, es permet modificar l’estat de les variables que intervenen en el sistema de control. L’objectiu d’aquesta interacció és permetre a l’usuari establir les condicions d’entrada desitjades per tal de comprovar i depurar el funcionament del sistema de control.

5.2 Característiques del Sistema de Monitorització

El seguiment de l’evolució del sistema de control depèn completament de la informació present en el microcontrolador. Per tant, cal veure quines són les característiques de les màquines d’estat que conformen el sistema de control.

5.2.1 Característiques de les Màquines d’Estat

Les característiques de les màquines d’estat són les que s’han especificat en el primer bloc del projecte. Allí s’han llistat unes especificacions generals per l’edició i unes altres més restrictives pel microcontrolador destí de la compilació. Aquestes especificacions més restrictives són les que es tenen en compte en aquest segon bloc, la monitorització de les màquines d’estat.

Les restriccions dels diagrames d’estat són les següents:

• Nombre màxim de 16 diagrames per projecte.

• Nombre màxim de 16 estats per diagrama.

• Nombre màxim de 16 transicions i operacions per estat.

I les restriccions de les variables es mostren en les següents taules:

Bloc II: Monitorització de Màquines d’Estat

55

Entr.(b) Sort.(b) Tempor.(b) Forç.(b) Marq.(b) Est. actius(By) Nº vars. 24 16 16 16 64 16

Taula 5.1. Nombre màxim de variables d’una màquina d’estat

En la taula anterior, entre parèntesis, es defineix l’espai que ocupen les variables: ‘b’ significa que les variables són de tipus bit; ‘By’ significa que les variables són de tipus byte.

Entrades Sortides Temporitzadors Forçats Marques Est. actius Nº bytes 3 2 2 2 8 16

Taula 5.2. Nombre de bytes reservat per cada tipus de variables

La informació de totes aquestes variables es troba en la memòria interna del µcontrolador. En el cas de les entrades i sortides, el que s’envia realment són les imatges d’aquestes. Això és així perquè és molt més còmode accedir-hi que no pas accedir a la memòria externa. No obstant, per a la interacció amb les variables d’entrada, no té cap sentit modificar les seves imatges, pel que és necessari actuar en la memòria externa corresponent.

D’altra banda, la informació dels temporitzadors també s’obté de les seves imatges perquè l’accés és molt més senzill, ja que es troben tots els bits junts. Per tant, tot i que els temporitzadors ocupen un total de 18 bytes, pel sistema de monitorització només són necessaris els dos bytes corresponents a les imatges.

Pel que fa als forçats, cada variable informa de cada diagrama, si està forçat. Per tant, el nombre de variables de forçat coincideix amb el nombre de diagrames. Aquestes variables es mostren encara que el diagrama corresponent no resulti afectat per cap operació de forçat del sistema de control.

5.2.2 Tipus de Dades a Enviar

Tota les dades referents a l’estat de les variables i dels diagrames s’obtenen del µcontrolador a través del port sèrie. No obstant, una informació interessant que no pot transmetre el µcontrolador és el nom de les variables que conformen la màquina d’estat. Per aconseguir aquesta informació s’obté el nom de les variables des d’un fitxer de variables (amb extensió “.var”) creat amb el programa del primer bloc del projecte. La obtenció del nom de les variables només és necessari realitzar-la una vegada i abans d’establir la comunicació.

La informació necessària per realitzar el programa de monitorització es divideix en tres grups diferents de dades:

4. Informació inicial de variables: noms d’aquestes.

5. Informació inicial de diagrames i estats: nombre i número de cadascun d’ells.

6. Dades d’actualització: estat actiu de cada diagrama i estat de les variables.

La informació del primer grup, com s’ha dit abans, s’obté directament d’un fitxer de variables en començar el programa i abans d’establir la comunicació.

Bloc II: Monitorització de Màquines d’Estat

56

La informació restant, dels grups 2 i 3, s’obté del µcontrolador a través del port sèrie. La diferència es troba en que la informació del grup 2, al ser inicial, només cal rebre-la una vegada, de la mateixa manera que la informació del grup 1. Per tant, es rep a l’inici de la comunicació.

Les dades del tercer grup cal actualitzar-les constantment, ja que la màquina d’estat que es pretén monitoritzar està en constant evolució en el µcontrolador. Per tant, l’actualització de les dades es realitza de forma contínua.

La comunicació està governada per l’ordinador personal, qui s’encarrega de demanar la informació necessària al µC en tot moment. El sistema de comunicacions permet una monitorització en temps real de l’evolució del sistema de control en el µcontrolador.

5.2.3 Interacció amb el Sistema de Control

La interacció amb el sistema de control es realitza a través de les variables. El PC, per ordre de l’usuari, envia una petita trama al microcontrolador amb la informació de la variable a modificar. Quan el µcontrolador rep una trama d’aquest tipus l’únic que fa és modificar l’estat de la variable en qüestió.

Es poden modificar totes les variables, amb l’excepció dels temporitzadors, ja que aquests poden modificar-se a través de les seves variables activadores. D’altra banda, després de modificar una variable, no s’assegura que aquesta es mantingui modificada, ja que les operacions de forçat i combinacionals, en cada cicle d’execució del sistema de control, assignen el valor 1 o 0 a les variables subjectes a aquests tipus d’operacions. Per exemple, si l’usuari intenta modificar la variable de forçat d’un diagrama que està subjecte a una operació de forçat en algun estat, aquesta variable tornarà a l’estat anterior automàticament. Per tant, no serveix de res intentar modificar aquelles variables subjectes a alguna operació de forçat o combinacional.

5.3 Utilització del Port Sèrie

Per treballar amb el port sèrie cal definir un software que agafi, enviï, rebi i interpreti la informació . Evidentment, cal un software pel microcontrolador i un altre pel PC. Però aquests dos softwares s’han de comunicar, pel que han de partir d’una filosofia de comunicacions comú.

Les comunicacions a través del port sèrie, ja fa molt de temps que es realitzen. De fet, en els últims anys s’ha realitzat una gran quantitat de programes que permeten establir comunicacions pel port sèrie, tant pels PC’s, com pels µcontroladors. Tot aquest software acostuma a ser programable i independent del protocol de comunicacions utilitzat. De fet, una bona part d’aquest software circula per Internet i es pot utilitzar lliurement. Per tant, com que el propòsit d’aquest projecte no és el de dissenyar un software programador del port sèrie, s’han utilitzat dos programes ja creats per tal d’establir les comunicacions. El software encarregat de programar i utilitzar el port sèrie en el µcontrolador ha estat proporcionat pel director d’aquest projecte, el Sr. Ernest Gil i Dolcet. I pel que fa al software corresponent al PC i programat en llenguatge ‘C’, s’ha obtingut d’Internet de forma completament gratuïta.

Bloc II: Monitorització de Màquines d’Estat

57

5.3.1 Treball amb Interrupcions o per Enquesta

En primer lloc cal veure si la transmissió de caràcters s’ha de realitzar amb l’ajuda d’interrupcions, o bé per enquesta. Si es fa per interrupcions, cada vegada que s’envia un caràcter i es deixa el registre de desplaçament de la transmissió preparat per enviar un altre caràcter es genera una interrupció. A més, quan es rep un caràcter pel port de comunicacions també es genera una interrupció. En canvi, treballant per enquesta, es necessita que el software constantment comprovi l’estat del registre de desplaçament de transmissió i el de recepció. A continuació es descriuen alguns avantatges i desavantatges dels dos mètodes:

• Ús d’interrupcions:

Els avantatges d’utilitzar interrupcions són que es tracta d’un mètode més eficient, i que no es perd temps de CPU, ja que els caràcters poden esperar en la cua i l’aplicació pot continuar sense haver d’esperar.

Pel que fa als inconvenients: en la rutina de servei a la interrupció s’utilitza més codi, i a altes velocitats de transmissió pot causar problemes en màquines poc potents o sota certes circumstàncies.

• Per enquesta:

Els avantatges de treballar per enquesta són l’escurçament de la rutina de servei a la interrupció i la simplificació del codi en alguns llocs.

Els desavantatges són que mentre l’aplicació està enviant caràcters, no pot fer res més i no s’usa el buffer de sortida; i que aquest mètode té un pitjor “throughput”.

Finalment, s’opta per treballar amb interrupcions pel millor “throughput”, bàsicament.

5.3.2 Mode de treball del port sèrie

Per treballar amb el port sèrie, abans cal inicialitzar-lo definint així el mode de treball. En aquest projecte, el mode de treball del port sèrie consta de les següents característiques:

• Nombre de bits de dades: 8 bits.

• Tipus de control de paritat: sense control de paritat.

• Bits de control: un bit d’inici i un bit de parada.

• Velocitat de transmissió/recepció: aquesta velocitat ve marcada pel µcontrolador, ja que no pot aconseguir velocitats tan altes com el PC. De fet, la velocitat del µcontrolador depèn del cristall utilitzat, i com que el cristall utilitzat és de 12MHz, la freqüència màxima aconseguida en concordança amb el PC és de 9600 bits/s o baudis.

Aquestes característiques de treball impliquen que en el µcontrolador el port sèrie ha de treballar en el Mode 1, mode explicat en el capítol corresponent als microcontroladors.

5.3.3 Software pel Microcontrolador

El software utilitzat per programar i utilitzar el port sèrie en el µcontrolador s’ha obtingut en format de codi objecte, es tracta del fitxer “RS232i.obj”. Això significa que

Bloc II: Monitorització de Màquines d’Estat

58

està preparat per ser compilat mitjançant un programa enllaçador. A més, es disposa del fitxer de capçalera corresponent “RS232i.h”, on es declaren les funcions, variables i constants necessàries per utilitzar el programa.

Aquest software disposa d’una sèrie de funcions i variables que permeten programar i utilitzar el port. Les funcions utilitzades es mostren i descriuen a continuació:

• RS232i_open: Funció encarregada d’obrir i inicialitzar el port en el Mode 1. A l’ACC se li passa el paràmetre que permet programar la velocitat de les comunicacions.

• RS232i_Tsend: Funció encarregada d’enviar la informació disposada en el buffer de transmissió.

• V_RS232i: Rutina d’atenció a la interrupció del port sèrie (provocada per RI o per TI)

• V_RS232i_R: Rutina a definir, cridada per V_RS232i en el cas que la interrupció hagi estat provocada per RI.

Pel que fa a les variables utilitzades, són les següents:

• RS232i_Tbuf: Adreça inicial del buffer de transmissió.

• RS232i_Rbuf: Adreça inicial del buffer de recepció.

• RS232i_ctrl: Adreça inicial dels registres de control.

• RS232i_Tn: Longitud de trama per enviar (1er registre de control).

• RS232i_Tcnt: Comptador de bytes enviats (2n registre de control).

• RS232i_Rcnt: Comptador de bytes rebuts (3r registre de control).

D’altra banda, la constant RS232i_Rlen, defineix la longitud del buffer de recepció.

5.3.3.1 Organització de la RAM Interna

Definir la utilització de la RAM interna equival a reservar zones de memòria per les funcions pròpies de l’aplicació que s’està projectant. L’assignació dels 256 bytes de RAM interna (es recorda que es treballa amb el 80C52) s’ha de realitzar en funció d’altres aplicacions que la utilitzin. En el cas d’aquest projecte, tal i com s’explica en el segon apartat de la memòria, el funcionament de l’aplicació en la placa emuladora necessita una sèrie de llibreries que utilitzen part de la memòria interna. Per tant, cal assignar-la en funció del mapa de memòria utilitzat per les llibreries.

A continuació es mostra una taula que presenta com s’ha organitzat tota la RAM interna del µcontrolador. S’hi ha inclòs la memòria utilitzada per l’aplicació del primer bloc del projecte, la utilitzada pel software de manipulació del port sèrie i la memòria utilitzada per les llibreries del programa emulador DCSemu.

DADES (iRAM) MIDA DESCRIPCIÓ 00h-16h: 23 by: Zona de RAM local:

00h-07h 08h-08h 09h-16h

8 by 1 by

14 by

Banc 0 de registres (R0...R7). Variables locals intermèdies (tipus bit). Lliure.

Bloc II: Monitorització de Màquines d’Estat

59

17h-1Fh 9 by Reservat pel debugger. 20h-29h 10 by Lliure (RAM adreçable bit a bit). 2ªh-2Ch 3 by Reservat per la base de temps. 2Dh-2Eh 2 by Reservat per la gestió del RS232. 2Fh-7Fh: 81 by: Zona de variables globals:

2Fh-31h 32h-33h 34h-3Bh 3Ch-4Bh 4Ch-4Dh 4Eh-5Dh 5Eh-5Fh 60h-61h 62h-7Ch 7Dh-7Fh

3 by 2 by 8 by

16 by 2 by

16 by 2 by 2 by

27 by 3 by

Imatges de les entrades (tipus bit). Imatges de les sortides (tipus bit). Marques (tipus bit). Estats actius (tipus byte). Imatges dels temporitzadors (tipus bit). Temporitzadors (tipus byte). Comptadors dels temporitzadors (tipus nibble). Forçats (tipus bit). Lliure. Registres de control del port sèrie (tipus byte).

80h-9Fh: 32 by: Zona de RAM d’accés indirecte: 80h-8Fh 90h-9Fh

16 by 16 by

Buffer de transmissió. Buffer de recepció.

A0h-FFh 96 by Pila. Taula 5.3. Resum de la organització de la memòria interna del µC

En la taula anterior s’han utilitzat els colors per distingir la utilització del mapa de memòria de dades interna. De color blau es mostra la zona de memòria utilitzada pel sistema de control basat en màquines d’estat (aplicació del primer bloc del projecte) i de color vermell la utilitzada pel tractament del port de comunicacions. De color negre es presenta la resta de memòria. En negreta s’observen les zones que s’han desglossat en zones més petites. I per últim, la zona corresponent al Banc 0 de registres s’ha escrit en cursiva per diferenciar que es tracta d’una zona utilitzada per diferents aplicacions.

Es pot apreciar que els buffers de comunicacions ja tenen una mida establerta de 16 bytes cadascun. Això és així perquè es considera que un valor més gran significaria una ocupació de memòria interna innecessària, tenint en compte la informació que cal enviar. D’altra banda, el µcontrolador disposa de la suficient memòria com per admetre aquests buffers. A més, la zona utilitzada, només és accessible de forma indirecta, i als buffers només s’hi accedeix indirectament mitjançant registres.

El mapa de memòria no està completament ocupat. En la taula s’observa que tota la zona de memòria adreçable bit a bit i 27 bytes de memòria adreçable byte a byte no s’utilitzen. Tampoc s’utilitzen 14 bytes de memòria local. Tot i això, és possible que l’aplicació que es creï per enviar i rebre les trames necessiti algun byte més.

5.3.4 Software pel PC

El software utilitzat pel PC s’ha obtingut en format de codi en llenguatge ‘C’. El fitxer en qüestió s’anomena “rs232.c” i disposa de la capçalera corresponent, el fitxer “rs232.h”.

Aquest software disposa d’una sèrie de funcions i variables que permeten programar i utilitzar el port. Les funcions més importants es mostren i descriuen a continuació:

• rs_inthndlr( ): Rutina d’atenció a la interrupció.

Bloc II: Monitorització de Màquines d’Estat

60

• rs_initport( ): Funció que inicialitza el port: defineix els paràmetres, instal·la el vector d’interrupció i activa les interrupcions. També es defineixen els buffers de transmissió i recepció.

• rs_sndbyt( ): Funció que envia un byte al port.

• rs_sndstr( ): Funció que envia una cadena de bytes al port.

• rs_getbyt( ): Funció que obté un byte del buffer de recepció.

• rs_getstr( ): Funció que obté una cadena de bytes del buffer de recepció.

• rs_inrcvd( ): Funció que retorna el nombre de bytes rebuts que encara no s’han obtingut del buffer.

• rs_clrout( ): Funció que esborra el contingut del buffer de sortida o transmissió.

• rs_clrin( ): Funció que esborra el contingut del buffer d’entrada o recepció.

• rs_modctrl( ): Funció que controla o retorna l’estat de les línies de control del módem.

• rs_close( ): Tanca el port que abans s’ha obert amb la funció ‘rs_initport( )’.

Hi ha d’altres funcions però no s’utilitzen en aquest projecte. De totes formes, la resta de funcions es descriuen en el llistat del fitxer.

5.4 Protocol de Comunicacions

Per comunicar el µcontrolador amb el PC s’ha d’establir un protocol de comunicacions, és a dir, un llenguatge que tots dos entenguin. El protocol de comunicacions que s’utilitza per a comunicar PC i µcontrolador en aquest projecte no és un protocol estàndard, i no ho és perquè el µcontrolador necessita utilitzar el mínim espai possible de memòria i el mínim de recursos de la CPU. La millor forma de minimitzar-ho és utilitzant un protocol de comunicacions fet a mida.

La mida dels buffers del port sèrie no permet admetre trames massa llargues. D’altra banda, el protocol ha de permetre diferenciar trames diferents de forma senzilla. No obstant, el nombre de caràcters de control (que no són de dades) ha de ser mínim, ja que no aporten informació i en enviar trames curtes, el percentatge de bytes de dades respecte els bytes totals de la trama ha de ser el més gran possible.

Tenint en compte tot això, s’ha dissenyat un protocol de tipus ARR (“Automatic Repeat Request”), és a dir, que després que el µcontrolador enviï cada trama al PC, el µcontrolador espera una resposta de confirmació o d’error de comunicació per part del PC. Llavors, depenent de la resposta s’envia la mateixa informació o la següent.

El protocol està governat pel PC, i el seu funcionament es mostra en la figura de la pàgina següent. En ella s’observa que la comunicació l’inicia el PC enviant el caràcter de control de comunicacions ‘ENQ’ (05h). A partir d’allí, el µcontrolador va enviant totes les trames a mida que va rebent les confirmacions per cada trama. Quan s’envien les 7 trames, el µ s’espera i és l’ordinador l’encarregat d’enviar un caràcter de sincronització ‘SYN’ (16h) per reiniciar la comunicació. S’observa que aquesta reiniciació de la comunicació no comença per la primera trama, ja que la informació inicial és constant i no cal tornar-la a enviar. Per tant, el caràcter de sincronització provoca que el µC comenci a enviar a partir de la quarta trama.

Bloc II: Monitorització de Màquines d’Estat

61

PC µControlador

TRAMA N

ENQ N = 0

ACK N ++

NAK

SI

NO

N < 7?

SI

NO

FINAL

SYN N = 4

I

N

T

E

R

F

Í

C

I

E

S

È

R

I

E

Trama OK?

Última Trama ?

SI

Figura 5.1. Diagrama de flux de la comunicació sèrie

5.4.1 Format de les Trames

Pel que fa a les trames, aquestes tenen el següent format:

SOH Tipus

de trama

CHK- SUM EOT

DADES (8 o 9 bytes)

Figura 5.2. Format de la trama

Per tal de facilitar la comunicació, la longitud de les trames no és variable. No obstant, per raons pràctiques es defineixen dos longituds de trama. Una per les trames d’inici, i una altra per les trames d’actualització que s’envien contínuament. La invariabilitat de la mida de les trames evita la presència d’un byte indicador de la longitud de la trama. El valor de longitud de dades escollit és de 8 bytes per les trames d’inici i de 9 bytes per les trames d’actualització. Aquests dos valors són suficients per enviar tota la informació en poques trames, i encaixa perfectament en el buffer de transmissió tenint en compte el nombre de caràcters de control necessaris, que són quatre.

Bloc II: Monitorització de Màquines d’Estat

En la trama es defineixen una sèrie de caràcters de control que permeten que la comunicació sigui correcta i controlable. Aquests caràcters de control es defineixen a continuació:

• SOH (01 hex): Inici de trama

• Tipus de trama: Indica el tipus de trama, i per tant, de dades

• CHKSUM: caràcter que conté la suma dels 8 bytes de dades. Quan es rep una trama es recalcula la suma per observar si hi ha alguna diferència. Si els dos caràcters són iguals, vol dir que la trama s’ha rebut correctament.

• EOT (04 hex): caràcter indicador de final de trama.

5.4.2 Tipus de Trames

5.4.2.1 Informació Inicial de Diagrames i Estats

La informació inicial que s’ha d’enviar és la referent al nombre de diagrames i estats, i al número de cadascun d’ells. Per enviar aquesta informació, s’envia un bit per cada estat possible. Tenint en compte que 16 és el nombre màxim de diagrames i d’estats per diagrama, calen 256 bits. Això té l’avantatge que el nombre de bits a enviar és fix. No obstant, té l’inconvenient que encara que el nombre de diagrames i estats sigui molt petit, s’envia la mateixa informació, i per tant, es desaprofita la comunicació. No obstant, aquesta informació només s’envia la primera vegada, pel que no es considera que el rendiment de la comunicació sigui tant important.

Els 256 bits d’informació necessaris, suposen que cal enviar 2 bytes d’informació per cada diagrama. Cada bit indica si un estat està definit o no. Això permet enviar la informació dels 16 estats possibles. No obstant, com que en cada trama es disposa de 8 bytes de dades, calen 4 trames per enviar tota la informació.

1 2 3 4 5 6 7 8 9 10 11 12 0 1

10 10 10 1012 12 12 12

10 10 10 10

10 10 10 10 12 12 12 12

10 10 10 12 12 12 13 14 15

10 11

8 9 0 1 8 9 0 1 8 9 0 1 8 9

2 3 11 2 3 11 2 3 11 2 3 11 4 5 13 4 5 13 4 5 13 4 5 13

SOH DC1

6 7 14 15 6 7 14 15 6 7 14 15 6 7 14 15

CHK- SUM EOT

0 1 8 9 0 1 8 9 0 1 8 9 0 1 8 9 2 3 11 2 3 11 2 3 11 2 3 11 4 5 12 13 4 5 12 13 4 5 12 13 4 5 12 13

SOH DC2

6 7 14 15 6 7 14 15 6 7 14 15 6 7 14 15

CHK- SUM EOT

0 1 8 9 0 1 8 9 0 1 8 9 0 1 8 9 2 3 11 2 3 11 2 3 11 2 3 11 4 5 13 4 5 13 4 5 13 4 5 13

SOH DC3 6 7 14 15 6 7 14 15 6 7 14 15 6 7 14 15

CHK- SUM EOT

0 1 8 9 0 1 8 9 0 1 8 9 0 1 8 9 2 3 10 11 2 3 11 2 3 11 2 3 11 4 5 12 13 4 5 13 4 5 13 4 5 13

SOH DC4 6 7 14 15 6 7 14 15 6 7 14 15 6 7 14 15

CHK- SUM EOT

D12 D D D

D8 D9 D D

D4 D5 D6 D7

D0 D1 D2 D3

Figura 5.3. Trames d’inicialització dels diagrames d’estat

62

Bloc II: Monitorització de Màquines d’Estat

63

Cadascuna d’aquestes trames disposa d’un caràcter identificatiu del tipus de trama. Aquests caràcters identificatius són els següents:

• DC1 (11 hex): Trama inicial amb informació dels diagrames 0, 1, 2 i 3.

• DC2 (12 hex): Trama inicial amb informació dels diagrames 4, 5, 6 i 7.

• DC3 (13 hex): Trama inicial amb informació dels diagrames 8, 9, 10 i 11.

• DC4 (14 hex): Trama inicial amb informació dels diagrames 12, 13, 14 i 15.

5.4.2.2 Dades d’Actualització

Les dades d’actualització són les que permeten al sistema de control estar informat de l’evolució dels diagrames i de les variables. L’evolució dels diagrames s’indica amb els estats actius de cada diagrama. I com que només poden haver-hi 16 estats en cada diagrama, un nibble (4 bits) és suficient per a cadascun. Com que hi ha 16 diagrames, són necessaris 8 bytes per transmetre tots els estats actius. Això permet enviar aquestes dades en una sola trama, ja que les trames amb dades d’actualització s’ha determinat que siguin de 9 bytes de dades. Per tant, l’últim byte no afegeix informació, i es determina que ha de valer 0 (caràcter ‘NULL’).

D’altra banda, cal enviar les dades referents a les variables pròpiament dites (entrades, sortides, temporitzadors, forçats i marques,). En aquest cas la informació de cada variable ocupa un sol bit. Cal veure, doncs, com agrupar la informació. Hi ha diverses opcions, d’entre les que destaquen: enviar la informació de les variables definides, o bé, enviar tota la memòria reservada per les variables. La primera opció té l’inconvenient de la dificultat per seleccionar les variables definides. La segona opció té l’inconvenient d’enviar sempre el màxim de informació. Però com que la mida de les trames és constant, s’adequa molt millor al format de les trames la segona opció. Per tant, s’envia tota la memòria reservada per les variables a enviar.

Sumant la quantitat de bytes que ocupen les diferents variables, s’obté una suma de 17 bytes. Aquest valor permet dividir la informació en 9 i 8 bytes, de forma que dues trames són suficients per enviar tota la informació referent a aquestes dades.

La primera trama la constitueixen les entrades, sortides, temporitzadors i forçats, ja que sumen 9 bytes. La segona trama conté íntegrament la informació referent a les marques. S’observa que en el cas de la trama corresponent a les marques, un byte queda lliure, aquest es defineix amb el caràcter zero de la mateixa forma que l’últim caràcter de la trama d’estats actius. Pel que fa als caràcters que defineixen el tipus de trama, són els següents:

• SO (0E hex): Trama amb les dades de les variables d’entrada, les de sortida, els temporitzadors i els forçats.

• SI (0F hex): Trama amb les dades de les variables de marca.

• DLE (10 hex): Trama amb les dades dels estats actius dels 16 diagrames.

Bloc II: Monitorització de Màquines d’Estat

1 2 3 4 5 6 7 8 9 10 11 12 13

0 1 10 11 3 10 2 3 10 11 3 10 12 13 5 12 4 5 12 13 5 12

Estats Actius

trades rtides Temporitz. rçats 8 9 16 17 0 1 8 9 0 1 8 9 0 1 8 9

2 3 18 19 2 11 2 11 4 5 21 22 4 13 4 13 SOH SO 6 7 14 15 23 24 6 7 14 15 6 7 14 15 6 7 14 15

CHK- SUM EOT

0 1 8 9 16 17 24 25 32 33 40 41 48 49 56 57 2 3 10 11 18 19 26 27 34 35 42 43 50 51 58 59 4 5 12 13 20 21 28 29 36 37 44 45 52 53 60 61 SOH SI 6 7 14 15 22 23 30 31 38 39 46 47 54 55 62 63

0 CHK- SUM EOT

SD0 SD2 SD4 SD6 SD8 SD10 SD12 SD14 SOH DLE

SD1 SD3 SD5 SD7 SD9 SD11 SD13 SD15 0 CHK-

SUM EOT

Marques

En So Fo

Figura 5.4. Trames d’actualització de diagrames d’estat i de variables

En total, hi ha definits set tipus diferents de trames: quatre d’inicialització (de 8 bytes de dades) i 3 d’actualització (de 9 bytes de dades). El segon byte de cada trama és el que indica el tipus de dades que conté la trama.

5.4.3 Protocol de Comunicacions en la Interacció

El protocol utilitzat en la interacció amb el sistema de control, no és tan complex ni elaborat, ja que la informació a tractar és molt més reduïda i puntual. No obstant, aquest protocol conviu amb l’altre i cal tenir-ho present.

El protocol actua de la forma indicada en el següent diagrama de flux:

PC µControlador

SOH

Modifica variable

FINAL

EOT

Dades

B U F F E R

I N T E R F Í C I E

S È R I E

ó

El PC és l’en enviar al µco

Figura 5.5. Protocol de comunicacions en la interacci

64

únic que intervé activament en aquest protocol, i la seva acció consisteix ntrolador la informació necessària per modificar l’estat d’una variable

Bloc II: Monitorització de Màquines d’Estat

65

seleccionada per l’usuari a través d’un cursor. Quan el µC rep el caràcter d’inici de trama, no tracta cap més byte fins que no rep el caràcter de final de trama, moment en el que es crida a la rutina que inverteix el valor de la variable indicada en la trama rebuda.

La informació enviada pel PC ha de tenir una estructura definida per tal que el µcontrolador pugui identificar-la, llegir-la i actuar en conseqüència de forma adequada. El format de la trama enviada és el següent:

1 2 3 4

SOH Tipus

de variable

Número de

variable EOT

Figura 5.6. Format de la trama

El primer i l’últim byte de la trama són idèntics que els utilitzats en el protocol principal. Els altres dos bytes sí que són diferents i s’expliquen a continuació:

• Tipus de variable: aquest caràcter identifica el tipus de variable a modificar. Els següents caràcters són els que identifiquen a cada tipus de variable:

‘I’: indica que la variable a modificar és de tipus entrada (“Input”).

‘O’: indica que la variable a modificar és de tipus sortida (“Output”).

‘F’: indica que la variable a modificar és de tipus forçat (“Forced”).

‘M’: indica que la variable a modificar és de tipus marca (“Mark”).

• Número de variable: aquest caràcter determina el número de variable, ja que les variables, tal i com s’ha explicat en el primer bloc, estan disposades de forma ordenada. Per no confondre aquest número amb un caràcter de control, se li suma el valor en ASCII del ‘0’.

Es pot pensar amb la possibilitat d’afegir un caràcter de ‘checksum’ a la trama. Però com que aquesta només conté 2 bytes de dades, es considera que la inclusió d’un altre byte és innecessària.

5.5 Tractament de Dades en El Microcontrolador

5.5.1 Obtenció de Dades

En els apartats anteriors s’ha explicat quin és el tipus d’informació que s’obté però no com es realitza aquesta obtenció. Com s’ha dit anteriorment, la informació de les variables (entrades, sortides, temporitzadors, forçats, marques i estats actius) s’obté de la memòria interna de dades del µcontrolador, però la informació inicial dels estats dels diagrames, s’obté d’una altra manera. A continuació s’explica com s’obtenen les diferents dades.

5.5.1.1 Informació Inicial de Diagrames i Estats

La informació referent als estats definits dels diagrames definits no s’emmagatzema enlloc. No obstant, en el programa del primer bloc, existeixen una sèrie d’etiquetes que

Bloc II: Monitorització de Màquines d’Estat

66

depenent de si estan definides o no, permeten conèixer l’existència dels estats i diagrames definits. El millor mètode per accedir a aquesta informació és mitjançant la utilització de directives. Concretament, el programa assemblador utilitzat en el projecte, el “X8051 Cross Assembler” de la firma 2500 A. D. Software Inc, disposa d’una sèrie de directives d’assemblatge condicional que permeten assemblar les sentències següents a la directiva fins que es trobi una directiva ‘.ELSE’ o ‘.ENDIF’ si la condició de la directiva es compleix. La condició que encaixa perfectament amb les necessitats descrites és la que permet assemblar codi depenent de si una etiqueta determinada està definida en el programa. La directiva s’anomena ‘.IFDEF’.

Amb la directiva anterior, es comprova si cada diagrama està definit. Això es fa comprovant si està definida l’etiqueta ‘SDX’, on X és el número de diagrama, per cada diagrama. Es recorda que aquesta etiqueta emmagatzema la posició en la memòria interna on es troba guardat el número de l’estat actiu corresponent.

Per a tots els diagrames definits, amb la mateixa directiva es comprova si cada estat del diagrama està definit. Això es comprova amb les etiquetes del tipus ‘DXXSYYT00’, on:

• XX és el número de diagrama

• YY és el número d’estat

Aquestes etiquetes indiquen l’inici de la transició 0 de l’estat YY del diagrama XX. Per cada etiqueta, si està definida indica que l’estat YY està definit, ja que té com a mínim una transició.

La directiva ‘.IFDEF’ s’utilitza per cada diagrama i per cada estat. Això suposa la presència de 16 directives pels diagrama i 256 pels estats. Per tant, el llistat del programa en llenguatge assemblador és realment llarg. Però les directives condicionals, permetent que el codi resultant de l’assemblat només contingui les instruccions requerides, pel que el codi es redueix moltíssim. La mida del codi depèn únicament de la quantitat d’estats definits.

A més de les directives, són necessàries les instruccions que permetin emmagatzemar la informació dels estats definits. Aquestes instruccions són totes del tipus ‘orl’ (operació lògica OR), de forma que cada estat definit activa un bit. Per exemple, per a l’estat 0 del diagrama 7, caldria el següent codi:

.IFDEF SD7 .IFDEF D07S00T00 orl A,#01h

Codi 5.1. Codi assemblador que activa el primer bit de l’ACC si l’estat 0 del diagrama 7 està definit

La constant, que val 1, fa la OR amb l’ACC, de forma que si l’estat 0 està definit, el primer bit de l’ACC s’activa a 1.

Com que són necessaris dos bytes per a cada diagrama, s’utilitzen els registres ACC i B com a bases per activar els bits corresponents als estats actius. Llavors es copien els dos bytes amb la informació del diagrama al lloc corresponent de la trama a enviar.

5.5.1.2 Dades d’Actualització

Les dades variables, que mostren l’estat en cada moment dels diagrames i les variables, sí que estan emmagatzemades, pel que és més senzill poder accedir-hi. A més, si

Bloc II: Monitorització de Màquines d’Estat

67

es té en compte que cada tipus de variables té una etiqueta que en defineix l’adreça inicial, l’accés és immediat. Per tant, només cal col·locar byte a byte la informació de les variables en la trama. Per exemple, en el cas de les variables d’entrada, com que ocupen 3 bytes, cal fer el següent:

mov R0,#Iadr mov B,#3 envia_I: mov A,@R0 mov @R1,A inc R0 inc R1 djnz B,envia_I

Codi 5.2. Codi assemblador que carrega la trama amb el valor de les imatges de les variables d’entrada

En la primera línia es copia l’adreça inicial de les variables al registre R0, per tal de fer-hi accessos indirectes.

En la segona línia s’inicialitza el comptador a 3, que és el nombre de bytes a copiar.

La tercera línia copia els bytes a l’ACC.

La quarta línia copia els bytes a la trama mitjançant el registre R1.

La cinquena i sisena línia incrementen els registres per apuntar a les següents posicions.

Finalment, la setena i última línia decrementa el comptador continua el bucle fins que el comptador val 0.

En el cas dels estats actius, tot i que cada variable ocupa un byte, el tractament és molt similar. La diferència radica en que aquest byte que ocupa cada variable es redueix a un nibble. Aquesta reducció es fa amb les següents instruccions en assemblador:

envia_SD_1: mov A,@R0 inc R0 swap A orl A,@R0 mov @R1,A

Codi 5.3. Codi assemblador que carrega l’ACC amb l’estat actiu de dos diagrames consecutius

La primera i l’última instrucció són idèntiques als casos de les altres variables. La primera carrega a l’ACC l’estat actiu d’un primer diagrama.

La segona instrucció es posiciona a un byte d’un segon diagrama.

La tercera instrucció intercanvia els nibbles per col·locar l’estat actiu d’un primer diagrama en el nibble alt de l’ACC.

La quarta instrucció copia l’estat actiu del següent diagrama al nibble baix de l’ACC. Obtenint els estats actius de dos diagrames en l’ACC.

I finalment, l’última instrucció carrega la trama amb els dos estats actius continguts en l’ACC.

Bloc II: Monitorització de Màquines d’Estat

68

5.5.2 Modificació de Variables

El µcontrolador, a petició de l’usuari, modifica l’estat de les variables indicades per les trames que envia el PC. Aquest procés de modificació és completament asíncron, ja que només es realitza quan l’usuari ho demana.

Tal i com s’ha remarcat amb anterioritat, les úniques variables que no es modifiquen en la memòria interna són les entrades, ja que en cada cicle les imatges que es troben en la memòria interna s’actualitzen per les entrades reals disposades en la memòria externa. Per tant, cal actualitzar les entrades en la memòria externa.

El tractament per modificar les variables s’efectua just després de rebre una trama pel port sèrie i es diferencia el canvi de les variables en memòria interna, del canvi de les entrades, que es fa en memòria externa.

• Modificació en memòria interna

La modificació de les variables en la memòria interna s’inicia carregant en un registre d’adreçament indirecte l’adreça inicial del tipus de variable a modificar. Després, amb l’ús de registres del µcontrolador, s’aconsegueix modificar la variable desitjada. A grans trets, el que es fa és obtenir el número de byte i de bit de la variable a modificar. Amb aquests valors s’aconsegueix crear una màscara per conèixer l’estat de la variable a modificar. Depenent del seu valor, per tal d’invertir-la, s’activa o es desactiva utilitzant la mateixa màscara. Finalment es modifica i es carrega el nou valor en memòria.

En l’annex, hi ha llistat el codi assemblador corresponent, on s’inclouen els comentaris pertinents per tal d’entendre perfectament l’ús de les diferents instruccions.

• Modificació en memòria externa

Les variables d’entrada cal modificar-les de diferent manera per dos motius: pel fet de modificar-les en la memòria externa; i perquè les variables no estan situades consecutivament en memòria, sinó que s’agrupen en bytes. A més, les adreces d’aquests bytes poden existir o no depenent del nombre de variables.

El tractament de la memòria externa només pot realitzar-se mitjançant el registre de 16 bits DPTR, que s’ha de carregar amb una de les tres adreces externes d’entrades possibles. Per saber si aquestes adreces estan definides, s’utilitzen les directives condicionals que permeten assemblar un fragment de codi depenent de si una etiqueta determinada està definida o no.

El número de byte on es troba l’entrada a modificar, determina l’adreça externa d’entrades a carregar en el DPTR. Després, el tractament d’inversió de la variable és idèntic que en el cas del tractament de la memòria interna. Finalment, el byte de variables convenientment tractat es carrega a l’adreça apuntada pel DPTR.

Bloc II: Monitorització de Màquines d’Estat

5.6 Tractament de Dades en el PC

Tota la informació obtinguda pel PC cal emmagatzemar-la en memòria. Amb aquest propòsit es crea una estructura de la següent forma:

typedef struct { char ndiags; u_char DIAG_EST[16][16]; u_char INFO_DIAG[16][2];

t

char VI[128][8]; char VO[128][8]; char VM[128][8]; char VT[128][8]; char VF[16][8]; } s_gen;

Codi 5.4. Codi ‘C' que defineix l’estru

La informació d’aquesta estructura, aa continuació:

• La matriu ‘DIAG_EST’ conté unaestat. Si el caràcter val 1, significaestà definit.

• La matriu ‘INFO_DIAG’ està dispfila es correspon a un dels 16 diaindica quin és l’estat actiu del dianombre d’estats del diagrama. Laes rep pel port sèrie, sinó que es ca

• La resta de matrius emmagatzemcorrespon a una variable. I per a cel nom de la variable; la última pactivada o no. Una variable no escaràcter nul.

5.7 Interfície amb l’Usuari

La interfície entre l’usuari i les dadeen ‘C’ amb el programa Borland C++.

En iniciar el programa es demana el nobtenir el nom de les variables a mostrargràfic. Després d’obtenir la informació delgràfic i es mostra la informació dels diagAquesta informació es refresca contínuamen

La interfície gràfica permet a l’usuad’un cursor, que té les coordenades defAquesta estructura també conté un camp qucursor, ja que cada columna es correspon am

Informació dels diagrames d’esta

s

Informació de les variable

69

ctura de dades del monitoritzador

nomenada ‘s_gen’ (“struct” general), es detalla

posició de tipus caràcter sense signe per cada que l’estat està definit; si val 0, vol dir que no

osada en forma de 16 files i 2 columnes. Cada grames. I pel que fa a les columnes: la primera grama corresponent a la fila; la segona conté el informació corresponent al nombre d’estats no lcula a partir de la matriu ‘DIAG_EST’.

en la informació de les variables. Cada fila es ada variable, les 7 primeres posicions contenen osició val 1 o 0 depenent de sí la variable està tà definida si el primer caràcter del nom és un

s del sistema de monitorització s’ha programat

om del fitxer d’extensió “.var” que cal obrir per . Aquesta petició es realitza en un entorn no fitxer de forma correcta, s’inicialitza l’entorn rames d’estat i de les variables per pantalla. t a traves del port sèrie.

ri invertir l’estat de les variables amb l’ajuda inides en una estructura anomenada ‘s_bar’. e defineix el número de columna on es troba el b un tipus de variable diferent.

Bloc II: Monitorització de Màquines d’Estat

70

El moviment del cursor i altres opcions s’assenyalen en un menú d’opcions que se situa en la part inferior de la pantalla. Allí s’indiquen les tecles que cal pitjar per desplaçar el cursor per sobre de les variables. Aquestes tecles són les corresponents al cursor del teclat numèric. La modificació de l’estat d’una variable es realitza prement la tecla de retorn (‘INTRO’) quan el cursor està seleccionant la variable a invertir.

D’altra banda, el menú disposa de la opció de parar i continuar l’actualització per pantalla, això es fa amb la barra espaiadora. No obstant, aquest pausa en el refresc només és de tipus visual, ja que la comunicació segueix el seu curs.

Finalment, la tecla ‘ESC’ permet sortir del programa en qualsevol moment, aturant d’aquesta manera la comunicació entre ordinador personal i µcontrolador.

La pantalla de l’entorn gràfic està dividida en dues parts iguals. En la de l’esquerra es representen els diagrames amb els estats actius corresponents i en la de la dreta es mostren les diferents variables seguides del seu valor actual.

Cada diagrama es representa en forma d’el·lipse, dins de la qual hi ha tantes petites el·lipses com estats té el diagrama. Aquests són equidistants entre ells i estan disposats de forma correlativa ocupant tot el perímetre interior de l’el·lipse del diagrama. La informació més important dels diagrames es correspon al número de l’estat actiu. Per tant, per diferenciar l’estat actiu dels altres estats, aquest s’escriu de color verd i la resta de color vermell. Això permet identificar de forma molt ràpida i visual l’estat actiu. No obstant, per clarificar encara més la informació, en el centre de les el·lipses de diagrama, s’escriu al costat del número de diagrama, l’estat actiu actual.

La mida de totes les el·lipses de diagrama és idèntica i inversament proporcional al nombre de diagrames existents. Això suposa en millor aprofitament de l’espai de pantalla per representar els diferents diagrames.

La representació gràfica dels diferents estats realment no és una informació massa important perquè la disposició dels diagrames es quasi impossible que es correspongui amb un possible diagrama previ que hagi fet a mà l’usuari. Però sí que es tracta d’una informació molt visual i agraïda, ja que permet diferenciar visualment uns diagrames d’uns altres molt ràpidament, així com l’evolució d’aquests.

La presentació de dades de les variables és molt senzilla. L’única característica especial consisteix en escriure els uns (estat actiu de la variable) de color verd i els zeros (estat inactiu de la variable) de color vermell. D’aquesta forma s’aprecia ràpidament qualsevol canvi.

La figura de la pàgina següent mostra un exemple de sistema de control basat en màquines d’estat representat amb el PC havent obtingut la informació del µcontrolador a través del port sèrie. S’hi pot observar que el sistema presenta dos dels casos límit: màxim nombre de diagrames, i màxim nombre d’estats en el diagrama nº 1.

Observant ara les variables, s’aprecia que les variables modificables es troben en la part superior de la pantalla. En la part inferior de la dreta es mostren els temporitzadors, que només són modificables a través de les seves variables activadores.

Bloc II: Monitorització de Màquines d’Estat

En l’apaµcontrolador ipantalla de moprograma a undisposa d’espales variables dtipus de variabforçats sempre

5.8 Codi Re

Tot el qAquest codi col’ordinador; d’de codi del µco

El codi r8 fitxers, dos dsèrie. Es tracta

• “rs23

• “rs23

Figura 5.7. Interfície gràfica del sistema de monitorització

71

rtat 5.2.1 s’ha especificat el nombre màxim de variables que té el per a qualsevol tipus de variable l’espai reservat per les variables en la nitorització és molt gran. Això s’ha fet així per una possible adaptació del µcontrolador amb més memòria, i per tant, amb més variables. La pantalla i per a 50 variables d’entrada, sortida i marca, aproximadament. Pel que fa a e forçat i de temporització, l’espai queda reduït a la meitat. ja que aquests les no acostumen a ser massa nombrosos. De fet, el nombre màxim de

serà igual al de diagrames, en aquest cas 16.

sultant

ue s’ha vist en els apartats d’aquest bloc es plasma en el codi resultant. nsta de dues parts: d’una banda, el codi en llenguatge ‘C’ que resideix a

altra banda, el codi en llenguatge assemblador que resideix en la memòria ntrolador.

esultant en ‘C’ del sistema de monitorització de màquines d’estat consta de els quals són els obtinguts d’Internet per tal d’inicialitzar i utilitzar el port

dels dos fitxers següents:

2.h”: Fitxer de capçalera del software del port de comunicacions sèrie.

2.c”: Fitxer que conté les diferents funcions de tractament del port sèrie.

Bloc II: Monitorització de Màquines d’Estat

72

A continuació es mostra una llista dels altres sis fitxers amb una breu explicació del seu propòsit:

• “capsal.h”: Fitxer de capçalera del programa de monitorització i depuració. En ell s’inclou el següent:

“Includes” de totes les llibreries de ‘C’ necessàries.

Definicions de constants

Definicions de tipus de variables

Declaracions de totes les funcions del programa

• “projek.c”: Fitxer principal on es troba el ‘main()’ de l’aplicació.

• “estruk.c”: Fitxer on es troben les funcions que manipulen les estructures creades. Una de les estructures s’utilitza per emmagatzemar les dades referents a variables i a diagrames d’estat.

• “sericom.c”: Fitxer on es troben les funcions que mitjançant el fitxer “rs232.c” manipulen el port sèrie.

• “menus2.c”: S’hi defineixen les funcions que creen pantalles d’interfície amb l’usuari i tracten amb l’entorn gràfic.

• “funcion2.c”: Fitxer que conté diverses funcions que no tenen cap similitud entre elles.

D’aquests vuit fitxers, els que s’han creat en aquest projecte - els sis últims - es llisten en l’annex B.1, llistats que contenen comentaris explicatius de totes i cadascuna de les funcions i variables creades. Els dos fitxers d’interfície amb el port sèrie no es llisten en l’annex perquè només s’utilitzen com a eina i no són elements del projecte en sí.

D’altra banda, el codi resultant en llenguatge assemblador es troba en dos fitxers:

• “RS232prj.h”: Fitxer de capçalera del tractament del port sèrie per part del monitoritzador.

• “RS232prj.asm”: Fitxer que conté totes les rutines de tractament del sistema monitoritzador.

Els llistats d’aquests dos fitxers es troben en l’annex B.2, llistats que també disposen de comentaris.

Conclusions

6 Conclusions

73

La realització d’aquest projecte permet afirmar que la fase de disseny d’un sistema de qualsevol tipus és l’etapa més important. Aquesta afirmació s’extreu tant del procés d’elaboració del projecte, com del contingut d’aquest.

L’elaboració d’aquest projecte va partir de la idea de construir un programa compilador que permetés introduir diagrames d’estat de forma senzilla a un ordinador, i després els traduís a codi assemblador. L’objectiu era automatitzar i agilitzar enormement el tediós procés de realitzar aquestes tasques manualment per a cada sistema basat en màquines d’estat. I a partir d’aquella idea inicial es va tenir que pensar en el disseny del compilador.

El disseny del compilador ha presentat diferents punts en els que calia dissenyar elements importants i ha estat clau l’anàlisi que s’ha fet en cadascun d’aquests punts. El disseny de l’emmagatzemament de les dades de les màquines d’estat ha estat un factor clau per poder desenvolupar satisfactòriament la resta del projecte. Un mal disseny hagués representat una pèrdua de temps molt important, o fins i tot, la obtenció d’un programa defectuós. Per aconseguir un bon disseny, s’han analitzat diferents possibilitats, i comparant-les entre elles s’ha arribat a la conclusió de que la utilització de taules d’estructures era la millor solució.

Un altre punt important ha estat la resolució de la compilació de les expressions de les transicions d’estat. El disseny d’aquesta resolució ha estat una tasca francament complicada i ha estat resolta amb la col·laboració d’altres companys de la universitat Rovira i Virgili (URV) que realitzaven projectes finals de carrera amb aquest punt en comú.

El bloc referent al sistema de monitorització i depuració de les màquines d’estat, també ha tingut una fase clau, el disseny del protocol de comunicacions. Un mal disseny del protocol no hagués permès comunicar el microcontrolador amb l’ordinador.

D’altra banda, l’objectiu del propi projecte pretén facilitar el disseny d’altres projectes que es basin en diagrames d’estat. Aquí es veu clarament la importància de la fase de disseny.

Amb tot això, es vol fer veure que un bon disseny permet que la resta del camí per realitzar un projecte sigui una tasca molt menys dificultosa. De fet, acostuma a ser molt més profitós el temps de disseny que el temps d’elaboració.

Una altra conclusió que s’extreu d’aquest projecte és que els microcontroladors de la família del 8051 presenten un molt bon comportament en aplicacions de control en temps real. A més, disposen d’un mapa de memòria molt senzill d’utilitzar gràcies a la divisió de la memòria en memòria de dades i memòria de codi o programa. Això permet una perfecta i clara manipulació de dades.

Per finalitzar, assenyalar que el llenguatge ‘C' ha estat una sòlida base per crear els programes d’aquest projecte. Els seus tipus de dades i estructures han permès manipular dades de tots tipus de forma prou senzilla. També es vol destacar que aquest llenguatge de programació ha permès utilitzar el port sèrie adequant la comunicació a les necessitats del projecte. Aquesta adequació ha comportat un rendiment òptim.

Annexes

74

7 Annexes

7.1 Annex A.1: Llistat dels Fitxers Creats en el Bloc I en Llenguatge ‘C'

INFORMACIÓ CONFIDENCIAL

Per més informació, adreçar-se a: [email protected]

Annexes

167

7.2 Annex A.2: Llistats de Fitxers Obtinguts d’una Compilació d’Exemple

S0 I1·T1

M1

S2

F/D2:2

D1

S1 S3 M2·I3

P·I3

P·!M2 O2 O3 M3 M4 O2+I2

!M2·I1

!M2·M1

S0I2

D2

S1 F/D4:1R O5

S2P

S O5

M2

I2+D1:3

S0 D2:2O4

D3

S1

M2

S2!M2·I2

M4

I4·D2:1

S0 D3:1

D4

S1 O1

D3:2

Figura 7.1. Exemple de màquines d’estat

7.2.1 Fitxer de Capçalera Obtingut: “prova.h” ;#######################( include )######################## ;### ### ;### Capçalera de l'aplicacio: MAQUINES D'ESTAT ### ;### ### ;########################################################## ;*********************************************************** ; UBICACIO DE VARS. EN MEMORIA EXTERNA // INTERNA ;----------------------------------------------------------- ;Entrades: ;--------- ;I1 Adreça Ext.(hex): 0 // Adreça Int.(hex): 2F Bit: 0 ;I2 Adreça Ext.(hex): 0 // Adreça Int.(hex): 2F Bit: 1 ;I3 Adreça Ext.(hex): 0 // Adreça Int.(hex): 2F Bit: 2 ;I4 Adreça Ext.(hex): 0 // Adreça Int.(hex): 2F Bit: 3 ;P Adreça Ext.(hex): 0 // Adreça Int.(hex): 2F Bit: 4 ;M Adreça Ext.(hex): 0 // Adreça Int.(hex): 2F Bit: 5 ;Sortides: ;--------- ;O1 Adreça Ext.(hex): 3 // Adreça Int.(hex): 32 Bit: 0 ;O2 Adreça Ext.(hex): 3 // Adreça Int.(hex): 32 Bit: 1 ;O3 Adreça Ext.(hex): 3 // Adreça Int.(hex): 32 Bit: 2 ;O4 Adreça Ext.(hex): 3 // Adreça Int.(hex): 32 Bit: 3 ;O5 Adreça Ext.(hex): 3 // Adreça Int.(hex): 32 Bit: 4 ;Marques: ;---------

Annexes

168

;M1 Adreça(hex): 34 Bit: 0 ;M2 Adreça(hex): 34 Bit: 1 ;M3 Adreça(hex): 34 Bit: 2 ;M4 Adreça(hex): 34 Bit: 3 ;Estats actius: Diagrames forçats: ;-------------- ------------------ ;SD1 Adreça(hex): 3D FD02 Adreça(hex): 60 Bit: 2 ;SD2 Adreça(hex): 3E FD04 Adreça(hex): 60 Bit: 4 ;SD3 Adreça(hex): 3F ;SD4 Adreça(hex): 40 ;Temporitzadors: ;--------------- ;T1 Adreça de la imatge(hex): 4C Bit: 0 ;Variable activadora: I1 Adreça descomptador(hex): 4E ;Base de temps: 1.0 s Valor de temporitzacio: 10 ;Comptadors pels temporitzadors: ;------------------------------- ;C1 Adreça(hex): 5E Nibble: baix ;C2 Adreça(hex): 5E Nibble: alt ;C3 Adreça(hex): 5F Nibble: baix ;************************************************** ; DEFINICIO D'ETIQUETES ;-------------------------------------------------- ; ADRECES INICIALS DE VARS. EN MEM. INTERNA ;-------------------------------------------------- Iadr: .EQU 2Fh Oadr: .EQU 32h Madr: .EQU 34h Sadr: .EQU 3Ch Tadr: .EQU 4Ch Fadr: .EQU 60h MEMadr: .EQU 8h ; ADRECES DE BYTES DE VARIABLES D'E/S EN MEM. EXTERNA ;------------------------------------------------------ XIadr0: .EQU 0h XOadr0: .EQU 3h ; ADRECES DE BYTES I BITS DE VARIABLES EN MEM. INTERNA ;------------------------------------------------------- I1_by: .EQU Iadr+0 I1_bit: .EQU 0 I2_by: .EQU Iadr+0 I2_bit: .EQU 1 I3_by: .EQU Iadr+0 I3_bit: .EQU 2 I4_by: .EQU Iadr+0 I4_bit: .EQU 3 P_by: .EQU Iadr+0

Annexes

169

P_bit: .EQU 4 M_by: .EQU Iadr+0 M_bit: .EQU 5 O1_by: .EQU Oadr+0 O1_bit: .EQU 0 O2_by: .EQU Oadr+0 O2_bit: .EQU 1 O3_by: .EQU Oadr+0 O3_bit: .EQU 2 O4_by: .EQU Oadr+0 O4_bit: .EQU 3 O5_by: .EQU Oadr+0 O5_bit: .EQU 4 M1_by: .EQU Madr+0 M1_bit: .EQU 0 M2_by: .EQU Madr+0 M2_bit: .EQU 1 M3_by: .EQU Madr+0 M3_bit: .EQU 2 M4_by: .EQU Madr+0 M4_bit: .EQU 3 SD1: .EQU Sadr+1 SD2: .EQU Sadr+2 SD3: .EQU Sadr+3 SD4: .EQU Sadr+4 FD02_by: .EQU Fadr+0 FD02_bit: .EQU 2 FD04_by: .EQU Fadr+0 FD04_bit: .EQU 4 ; ETIQUETES DE MEMORIA INTERMEDIA: P-W ;-------------------------------------------------- _P_bit: .EQU 0 _Q_bit: .EQU 1 _R_bit: .EQU 2 _S_bit: .EQU 3 _T_bit: .EQU 4 _U_bit: .EQU 5 _V_bit: .EQU 6 _W_bit: .EQU 7 ; ETIQUETES PER TEMPORITZADORS (Mem. Interna) ;---------------------------------------------------- T1_by: .EQU Tadr+0

Annexes

170

T1_bit: .EQU 0 _T1VA_by: .EQU I1_by _T1VA_bit: .EQU I1_bit T1val_act: .EQU Tadr+2 T_C1_2: .EQU Tadr+18 T_C3: .EQU Tadr+19 .END

Codi 7.19. Codi en assemblador del fitxer “prova.h”

7.2.2 Fitxer de Tractament de les Màquines d’Estat Obtingut: “prova.asm” ;#######################( include )####################### ;### ### ;### Aplicacio: MAQUINES D'ESTAT ### ;### ### ;######################################################### ;************************************************** ; INICIALITZACIONS ;-------------------------------------------------- APP_INI: mov SD1,#01h mov SD2,#00h mov SD3,#00h mov SD4,#00h mov Madr+0,#00h mov Fadr+0,#00h mov Fadr+1,#00h mov T_C1_2,#AAh mov T_C3,#0Ah ret ;************************************************** ; FLUX DEL PROGRAMA: MAQUINA D'ESTATS ;-------------------------------------------------- ;-------------------------------------------------- APP_FLUX: push A push PSW push 00h push DPL push DPH push MEMadr call PAE call PAT call DIAG01 call DIAG02 call DIAG03 call DIAG04 call FORSATS

Annexes

171

call OPS_COMB call OPS_BIES call FUNCIONS call PAA pop MEMadr pop DPH pop DPL pop 00h pop PSW pop A FI_A_F: ret ;************************************************** ; PAE-Realitza imatges de les entrades ;-------------------------------------------------- PAE: mov DPTR,#XIadr0 movx A,@DPTR mov Iadr+0,A FI_PAE: ret ;************************************************** ; PAT-Realitza imatges dels temporitzadors ;-------------------------------------------------- PAT: mov A,T1val_act mov C,A.7 mov A,T1_by mov A.T1_bit,C mov T1_by,A FI_PAT: ret ;************************************************** ; EVOLUCIO DIAGRAMA 1 ;-------------------------------------------------- DIAG01: mov A,Fadr+0 jb A.1,FIDIAG01 mov A,SD1 rl A mov DPTR,#D01AD0 jmp @A+DPTR D01AD0: ajmp D01S00T00 ajmp D01S01T00 ajmp D01S02T00 ajmp D01S03T00 D01S00T00: call ED01S00T00 jnc FIDIAG01 mov SD1,#1 ajmp FIDIAG01

Annexes

172

D01S01T00: call ED01S01T00 jnc FIDIAG01 mov SD1,#2 ajmp FIDIAG01 D01S02T00: call ED01S02T00 jnc D01S02T01 mov SD1,#0 ajmp FIDIAG01 D01S02T01: call ED01S02T01 jnc D01S02T02 mov SD1,#1 ajmp FIDIAG01 D01S02T02: call ED01S02T02 jnc D01S02T03 mov SD1,#2 ajmp FIDIAG01 D01S02T03: call ED01S02T03 jnc FIDIAG01 mov SD1,#3 ajmp FIDIAG01 D01S03T00: call ED01S03T00 jnc FIDIAG01 mov SD1,#0 FIDIAG01: ret ;************************************************** ; EVOLUCIO DIAGRAMA 2 ;-------------------------------------------------- DIAG02: mov A,Fadr+0 jb A.2,FIDIAG02 mov A,SD2 rl A mov DPTR,#D02AD0 jmp @A+DPTR D02AD0: ajmp D02S00T00 ajmp D02S01T00 ajmp D02S02T00 D02S00T00: call ED02S00T00 jnc FIDIAG02 mov SD2,#1 ajmp FIDIAG02 D02S01T00: call ED02S01T00 jnc FIDIAG02 mov SD2,#2 ajmp FIDIAG02 D02S02T00: call ED02S02T00

Annexes

173

jnc FIDIAG02 mov SD2,#0 FIDIAG02: ret ;************************************************** ; EVOLUCIO DIAGRAMA 3 ;-------------------------------------------------- DIAG03: mov A,Fadr+0 jb A.3,FIDIAG03 mov A,SD3 rl A mov DPTR,#D03AD0 jmp @A+DPTR D03AD0: ajmp D03S00T00 ajmp D03S01T00 ajmp D03S02T00 D03S00T00: call ED03S00T00 jnc FIDIAG03 mov SD3,#1 ajmp FIDIAG03 D03S01T00: call ED03S01T00 jnc FIDIAG03 mov SD3,#2 ajmp FIDIAG03 D03S02T00: call ED03S02T00 jnc D03S02T01 mov SD3,#1 ajmp FIDIAG03 D03S02T01: call ED03S02T01 jnc FIDIAG03 mov SD3,#0 FIDIAG03: ret ;************************************************** ; EVOLUCIO DIAGRAMA 4 ;-------------------------------------------------- DIAG04: mov A,Fadr+0 jb A.4,FIDIAG04 mov A,SD4 rl A mov DPTR,#D04AD0 jmp @A+DPTR D04AD0: ajmp D04S00T00 ajmp D04S01T00 D04S00T00: call ED04S00T00 jnc FIDIAG04 mov SD4,#1 ajmp FIDIAG04

Annexes

174

mov A,M2_by

D04S01T00: call ED04S01T00 jnc FIDIAG04 mov SD4,#0 FIDIAG04: ret ;************************************************** ; ANALISI EXPRESSIONS DIAGRAMA 1 ;-------------------------------------------------- ED01S00T00: mov A,I1_by mov C,A.I1_bit mov A,T1_by anl C,A.T1_bit ret ED01S01T00: mov A,O2_by mov C,A.O2_bit mov A,I2_by orl C,A.I2_bit ret ED01S02T00: mov A,P_by mov C,A.P_bit mov A,M2_by cpl A.M2_bit anl C,A.M2_bit ret ED01S02T01:

cpl A.M2_bit mov C,A.M2_bit mov A,I1_by anl C,A.I1_bit ret ED01S02T02: mov A,M2_by cpl A.M2_bit mov C,A.M2_bit mov A,M1_by anl C,A.M1_bit ret ED01S02T03: mov A,M2_by mov C,A.M2_bit mov A,I3_by anl C,A.I3_bit ret ED01S03T00: mov A,P_by

Annexes

175

mov C,A.P_bit mov A,I3_by anl C,A.I3_bit ret ;************************************************** ; ANALISI EXPRESSIONS DIAGRAMA 2 ;-------------------------------------------------- ED02S00T00: mov A,I2_by mov C,A.I2_bit ret ED02S01T00: mov A,P_by mov C,A.P_bit ret ED02S02T00: mov A,I2_by mov C,A.I2_bit mov A,SD1 cjne A,#3,1 setb C ret ;************************************************** ; ANALISI EXPRESSIONS DIAGRAMA 3 ;-------------------------------------------------- ED03S00T00: mov A,SD2 cjne A,#2,3 setb C sjmp 1 clr C ret ED03S01T00: mov A,M2_by mov C,A.M2_bit ret ED03S02T00: mov A,M2_by cpl A.M2_bit mov C,A.M2_bit mov A,I2_by anl C,A.I2_bit ret ED03S02T01: mov A,I4_by mov C,A.I4_bit mov A,SD2 cjne A,#1,2 sjmp 1 clr C

Annexes

176

ret ;************************************************** ; ANALISI EXPRESSIONS DIAGRAMA 4 ;-------------------------------------------------- ED04S00T00: mov A,SD3 cjne A,#1,3 setb C sjmp 1 clr C ret ED04S01T00: mov A,SD3 cjne A,#2,3 setb C sjmp 1 clr C ret ;************************************************** ; OPERACIONS DE FORÇAT ;-------------------------------------------------- FORSATS: FD02: mov A,FD02_by mov R0,SD1 cjne R0,#2,FD02_0 mov SD2,#2 FD02_1: setb A.FD02_bit sjmp FIFD02 FD02_0: clr A.FD02_bit FIFD02: mov FD02_by,A FD04: mov A,FD04_by mov R0,SD2 cjne R0,#2,FD04_0 mov SD4,#1 FD04_1: setb A.FD04_bit sjmp FIFD04 FD04_0: clr A.FD04_bit FIFD04: mov FD04_by,A FI_FORS: ret ;************************************************** ; OPERACIONS COMBINACIONALS ;-------------------------------------------------- OPS_COMB: OC00: mov A,M1_by mov R0,SD1 cjne R0,#1,OC00_0 OC00_1: setb A.M1_bit sjmp FIOC00 OC00_0: clr A.M1_bit

Annexes

177

FIOC00: mov M1_by,A OC01: mov A,O2_by mov R0,SD1 cjne R0,#3,OC01_0 OC01_1: setb A.O2_bit sjmp FIOC01 OC01_0: clr A.O2_bit FIOC01: mov O2_by,A OC02: mov A,O3_by mov R0,SD1 cjne R0,#3,OC02_0 OC02_1: setb A.O3_bit sjmp FIOC02 OC02_0: clr A.O3_bit FIOC02: mov O3_by,A OC03: mov A,M3_by mov R0,SD1 cjne R0,#3,OC03_0 OC03_1: setb A.M3_bit sjmp FIOC03 OC03_0: clr A.M3_bit FIOC03: mov M3_by,A OC04: mov A,M4_by mov R0,SD3 cjne R0,#1,OC04_02 sjmp OC04_1 OC04_02: mov R0,SD1 cjne R0,#3,OC04_0 OC04_1: setb A.M4_bit sjmp FIOC04 OC04_0: clr A.M4_bit FIOC04: mov M4_by,A OC05: mov A,M2_by mov R0,SD2 cjne R0,#0,OC05_0 OC05_1: setb A.M2_bit sjmp FIOC05 OC05_0: clr A.M2_bit FIOC05: mov M2_by,A OC06: mov A,O4_by mov R0,SD3 cjne R0,#2,OC06_0 OC06_1: setb A.O4_bit sjmp FIOC06 OC06_0: clr A.O4_bit FIOC06: mov O4_by,A OC07: mov A,O1_by mov R0,SD4 cjne R0,#1,OC07_0 OC07_1: setb A.O1_bit

Annexes

178

sjmp FIOC07 OC07_0: clr A.O1_bit FIOC07: mov O1_by,A FI_OPS_C: ret ;************************************************** ; OPERACIONS BIESTABLES ;-------------------------------------------------- OPS_BIES: OBS00: mov A,SD2 cjne A,#1,FIOBS00 mov A,O5_by setb A.O5_bit mov O5_by,A FIOBS00: OBR00: mov A,SD2 cjne A,#2,FIOBR00 mov A,O5_by clr A.O5_bit mov O5_by,A FIOBR00: FI_OPS_B: ret ;************************************************** ; FUNCIONS DIVERSES ;-------------------------------------------------- FUNCIONS: FI_FUNC: ret ;************************************************** ; PAA-Realitza imatges de les entrades ;-------------------------------------------------- PAA: mov DPTR,#XOadr0 mov A,Oadr+0 movx @DPTR,A FI_PAA: ret ;************************************************** ; TRACTAMENT TEMPORITZADORS ;-------------------------------------------------- ; ETIQUETES PER TEMPORITZADORS (Mem. de CODI) ;---------------------------------------------------- T1val: .BYTE 0Ah T1code: .BYTE 01h ; RUTINES PELS TEMPORITZADORS ;-------------------------------------------------- T_HANDLER:

Annexes

179

; Tractament de C1 (cada 0,1 s) ;-------------------------------------------------- T_01s: push A push PSW push DPL push DPH call T_INICI_00 mov A,T_C1_2 anl A,#0Fh djnz A,T_01s_seg call T_1s mov A,#0Ah T_01s_seg: anl T_C1_2,#F0h orl T_C1_2,A pop DPH pop DPL pop PSW pop A ret ; Tractament de C2 (cada 1 s) ;-------------------------------------------------- T_1s: call T_INICI_01 mov A,T_C1_2 anl A,#F0h swap A djnz A,T_1s_seg call T_10s mov A,#0Ah T_1s_seg: swap A anl T_C1_2,#0Fh orl T_C1_2,A ret ; Tractament de C3 (cada 10 s) ;-------------------------------------------------- T_10s: call T_INICI_02 mov A,T_C3 anl A,#0Fh djnz A,T_10s_seg call T_INICI_03 mov A,#0Ah T_10s_seg: anl T_C3,#F0h orl T_C3,A ret ;------------------------------------------------------- ; Temporitzadors de codi de base de temps = 00 ;------------------------------------------------------- T_INICI_00: T_FI_00: ret

Annexes

180

; Temporitzadors de codi de base de temps = 01 ;------------------------------------------------------- T_INICI_01: T1_inici: mov A,_T1VA_by jb A._T1VA_bit,T1_act T1_no_act: mov T1val_act,#00h sjmp T1_fi T1_act: mov A,T1val_act jz T1_ini jb A.7,T1_fi djnz T1val_act,T1_fi mov T1val_act,#80h sjmp T1_fi T1_ini: mov DPTR,#T1val clr a movc A,@A+DPTR mov T1val_act,A T1_fi: T_FI_01: ret ; Temporitzadors de codi de base de temps = 02 ;------------------------------------------------------- T_INICI_02: T_FI_02: ret ; Temporitzadors de codi de base de temps = 03 ;------------------------------------------------------- T_INICI_03: T_FI_03: ret .END

Codi 7.20. Codi en assemblador del fitxer “prova.asm”

Annexes

181

7.3 Annex B.1: Llistat dels Fitxers Creats en el Bloc II en Llenguatge ‘C'

7.3.1 Fitxer de Capçalera de la Monitorització: “capsal.h” /******************************************************************* -------------------------------------------------------------------- Fitxer de capçalera del programa -------------------------------------------------------------------- *******************************************************************/ /* INCLUDES ------------------------------------------------------------------*/ #include <stdio.h> #include <bios.h> #include <conio.h> #include <dos.h> #include <string.h> #include <graphics.h> #include <stdlib.h> #include <math.h> #include <dir.h> /* DEFINES ------------------------------------------------------------------*/ // Tecles especials #define ESC 27 #define INTRO 13 #define SPC 32 // Caràcters utilitzats en el protocol de comunicacions #define SOH 1 // inici de capçalera #define EOT 4 // fi de trama #define ENQ 5 // petició de comunicació #define ACK 6 // caràcter de confirmació #define NAK 21 // caràcter de no confirmació #define SYN 22 // petició de noves trames #define SO 14 /* trama de tipus 'vars. d'entrada, sortida i tempors. */ #define SI 15 // trama de tipus 'vars. de marca' #define DLE 16 // trama de tipus 'estats actius' #define DC1 17 // trama de tipus 'definició de diags 0-3' #define DC2 18 // trama de tipus 'definició de diags 4-7' #define DC3 19 // trama de tipus 'definició de diags 8-11' #define DC4 20 // trama de tipus 'definició de diags 12-15' // Semàfors #define S_D0_3 1 // indica definició dels diags. 0-3 #define S_D4_7 2 // indica definició dels diags. 4-7 #define S_D8_11 4 // indica definició dels diags. 8-11 #define S_D12_15 8 // indica definició dels diags. 12-15 #define S_DIAGS 15 // indica diags. acabats d’inicialitzar #define S_INI 16 /* indica que ja s'ha mostrat la info. inicial */ #define S_VAR 32 // indica que s'ha rebut trama de vars #define S_EA 64 // indica que s'ha rebut info. d’est. act. #define S_VPRIM 128 // indica que cal escriure noms de les vars.

Annexes

182

// Colors #define NEGRE 0 #define BLAUMARI 1 #define GRIS 7 #define VERD 10 #define BLAU 11 #define VERMELL 12 #define LILA 13 #define GROC 14 #define BLANC 15 // Valors de control de comunicacions #define DTR 0x01 // Data Terminal Ready #define RTS 0x02 // Ready To Send #define COM1PORT 0x0000 // Punter a la posició del port COM1 #define COM2PORT 0x0002 // Punter a la posició del port COM2 #define DATA_READY 0x100 /* TYPEDEFS ------------------------------------------------------------------*/ typedef unsigned char u_char; typedef unsigned int u_int; typedef struct // estructura d’informació de màquines d'estat { char ndiags; u_char DIAG_EST[16][16]; /* cada posició indica si un estat existeix o no (val 1 o 0) */ u_char INFO_DIAG[16][2]; /* columna 1=Est. actiu; columna 2=Nombre d'estats */ char VI[128][8]; /* 7 primers caràcters=nom de la variable l’últim caràcter indica el valor de la var. */ char VO[128][8]; char VM[128][8]; char VT[127][8]; char VF[16][8]; } s_gen; typedef struct /* estructura de coordenades de barra utilitzades per crear el cursor */ { int left, up, right, down; // coordenades de la barra cursor char col; // num. de columna (tipus de vars.).Col. 1 => entrades } s_bar; /* DECLARACIO DE FUNCIONS DEL PROGRAMA ------------------------------------------------------------------*/ // Funcions del fitxer: "menus.c" void ini_grafics(void), hola(void), mostra_vars(void), escriu_nom(char, char, int, int), u_o_zero(char, int, int), mostra_estats(char, int, int, int, int), estats_actius(void), menu_info(void),

Annexes

183

crea_elipses(void), mini_elipses(char,int,int,int,int), adeu_no_graf(void), adeu_graf(void), changetextstyle(int, int, int); //Funcions del fitxer: "sericom.c" int rep_car(void); char ini_port(void), ini_comunicacions(void), obtenir_info_serie(int), get_diags_i_estats(int), actualitzar_info_serie(int), obte_4_diags(char); u_char qrecte (char *, char); int inicialitza(char), end_it(void); void contesta_error(char), envia_SYN(void), envia_mod_var(char, int), tanca_port(void); //Funcions del fitxer: "estruk.c" void clr_struct_diags(void), clr_struct_vars(void), calcula_info(void), obte_forsats(void), amunt(void), avall(void), esquerra(void), dreta(void), ini_s_bar(void), modifica_vars(void), restaura_var(char); char manipula_vars(void), pos_buida(void), ini_vars(void), get_file_vars(char *), get_nom_vars(char *), ia_fvar(char *s); int busca_ultim(void); //Funcions del fitxer: "funcions.c" void lc(void), mes_ext(char *, char *), clr_ln(char nl), p_error(char);

Codi 7.21. Codi en ‘C’ del fitxer “capsal.h”

7.3.2 Fitxer Principal de la Monitorització: “projek.c” /******************************************************************* -------------------------------------------------------------------- Fitxer on es defineix la funcio principal 'main()' -------------------------------------------------------------------- *******************************************************************/

Annexes

184

#include "capsal.h" /* DECLARACIO DE VARIABLES GLOBALS ------------------------------------------------------------------*/ u_char semafor=0; // var. amb bits utilitzats com a semàfors /* PROGRAMA PRINCIPAL ------------------------------------------------------------------- - En ell s'executa el bucle principal on es visualitza la informació d'una màquina d'estats en execució directament del microcontrolador */ main() { char error=0, // control d'error sortir=0; // control per sortir del programa int tip, conta=0; // tipus de trama rebuda hola(); // pantalla de presentació error=ini_vars(); // obté la info. de variables des d’un fitxer if (!error) // si no hi ha error error=ini_port(); // s'inicialitza el port if (error) // si s'ha comès algun error { p_error(error); // missatge d'error tanca_port(); // per assegurar-se, es tanca el port adeu_no_graf(); // mostra pantalla de sortida } else // si no s'ha comès cap error { ini_grafics(); // s'inicialitzen els gràfics do // s'inicia el bucle { if (rep_car()==SOH) // si es rep char d'inici de trama { conta=0; tip=rep_car(); // es llegeix quin tipus de trama és error=obtenir_info_serie(tip); // s’obté la trama contesta_error(error); // respon trama rebuda segons error } else // si es rep un altre caràcter o no es rep res { conta++; // s’incrementa comptador d’espera if (conta==10000) contesta_error(100); /* si el comptador arriba al màxim, es contesta reenviant la resposta */ } if ((semafor & S_DIAGS)==S_DIAGS) /* si s'han rebut els 16 diagrames */ { calcula_info(); // calcula la informació dels diagrames obte_forsats(); // es defineixen els forsats menu_info(); // es dibuixen els diagrames existents semafor=semafor | S_INI; /* activa semàfor de diags. ja inicialitzats */ semafor=semafor - S_DIAGS; /* es desactiva el semàfor de diags. acabats de rebre */ }

Annexes

185

if (kbhit()) // si s'ha pitjat una tecla sortir=manipula_vars(); // es tracta el cursor de vars. if (semafor & S_INI) // si diags. ja inicialitzats { if (semafor & S_VAR) // si s'ha rebut la info. de vars { mostra_vars(); // s'actualitza la info. de vars semafor=semafor - S_VAR; // desactiva semàfor de vars } if (semafor & S_EA) // si s'han rebut els estats actius { estats_actius(); // s'actualitza info. d'est. actius semafor=semafor - S_EA; // desactiva semàfor d’est.act. envia_SYN(); // envia senyal per rebre més trames } } } while (!sortir); // mentre l'usuari no vulgui sortir if (error) // si hi ha hagut algun error { closegraph(); gotoxy(2,10); printf("Error of comunication number %d. Press any key to exit...",error); getch(); } end_it(); // es tanca tot i es mostra pantalla de sortida } return 0; }

Codi 7.22. Codi en ‘C’ del fitxer “projek.c”

7.3.3 Fitxer de Tractament de Comunicacions a Través del Port Sèrie: “sericom.c” /******************************************************************* -------------------------------------------------------------------- Fitxer on es troben les funcions que manipulen el port sèrie utilitzant les funcions del fitxer "rs232.c" -------------------------------------------------------------------- *******************************************************************/ #include "capsal.h" #include "rs232.h" #define BUF_SIZ 1024U /* definició de la mida dels buffers utilitzats en la comunicació sèrie */ /* DECLARACIO DE VARIABLES GLOBALS ------------------------------------------------------------------*/ extern s_gen G; extern u_char semafor; char *in_buf, *out_buf; // punters globals dels buffers char buf1[BUF_SIZ], buf2[BUF_SIZ]; // declaració de buffers /* DEFINICIO DE FUNCIONS ------------------------------------------------------------------*/ /******************************************************************

Annexes

186

- Funció encarregada de inicialitzar el port sèrie utilitzat, les variables i la comunicació amb el microcontrolador - Retorna l'error comès */ char ini_port() { int port_ok; // var. de retorn de la inicialització del port in_buf = buf1; // inicialitza el punter del buffer d'entrada out_buf = buf2; // inicialitza el punter del buffer de sortida port_ok = inicialitza(RS_PORT1); // inicialitza el port 1 if (!port_ok) // si s'ha retornat un error return 6; // retorna error=6 ctrlbrk(end_it); /* es modifica la rutina de control/break per assegurar que el port i l'entorn gràfic es tanquin bé */ return (ini_comunicacions()); /* s’inicien comunicacions i es retorna codi d’error corresponent */ } /******************************************************************* - Funció encarregada d’iniciar les comunicacions amb el microcontrolador - Retorna l'error comès */ char ini_comunicacions() { int conta; // comptador d'espera semafor=0; rs_clrout(); rs_clrin(); clr_struct_diags(); rs_sndbyt(ENQ); // envia senyal d'inici de comunicacions for (conta=1000; !rs_inrcvd() && conta; conta--) /* espera fins a 10 s mentre no es rebi res */ delay(10); // (10 s = 10 ms*1000) if (!conta) return 7; // si passen 10 s, es retorna error=7 return 0; // si s'arriba aquí => no hi ha error } /******************************************************************* - Funció que s'encarrega de rebre un caràcter del port - Retorna el caràcter rebut o 0 si no es rep res */ int rep_car() { if (rs_inrcvd()) // si s’ha rebut algun caràcter del port return (rs_getbyt()); // es llegeix i es retorna else return(0); // sinó, es retorna 0 } /******************************************************************* - Funció que s'encarrega d'obtenir una trama del port - Retorna l'error comès o 0 si no hi ha error - Paràmetres: tipus: tipus de trama */ char obtenir_info_serie(int tipus) { char error; // control d'error

Annexes

187

if (tipus>=DC1 && tipus<=DC4) /* si és una trama inicial de diags. i estats */ error=get_diags_i_estats(tipus); // obté diags. i estats else if (tipus>=SO && tipus<=DLE) /* si és una trama d’actualització de variables i diagrames */ { error=actualitzar_info_serie(tipus); // es refresquen les dades if (!error) // si l’actualització no presenta errors if (tipus==SI) semafor=semafor | S_VAR; /* s'activa el bit que indica que cal refrescar la informació de variables */ if (tipus==DLE) semafor=semafor | S_EA; /* s'activa el bit que indica que cal refrescar la informació de diagrames */ } else error=1; // si tipus de trama vàlid => error=2 return (error); } /******************************************************************* - Funció que s'encarrega d'obtenir la informació inicial que determina el de diagrames que hi ha i el nombre d'estats de cada diagrama - Retorna l'error comès o 0 si no hi ha error - Paràmetres: tipu: tipus de trama */ char get_diags_i_estats(int tipu) { char i, // var. aux. que indica el num. de conjunt de 4 diags. error; // control d'error i=(tipu-DC1); // calcula el número de conjunt de 4 diagrames error=obte_4_diags(i*4); // obté info. inicial dels 4 diags. if (!error) semafor=semafor | (1 << i); // activa bit corresponent return (error); // retorna l'error comès } /******************************************************************* - Funció que s'encarrega d'obtenir la informació inicial que determina el nombre de diagrames que hi ha i el nombre d'estats de cada diagrama. La informació de cada diagrama ocupa 16 bits (2 bytes). Cada bit indica, segons la posició, si l'estat està definit o no - Retorna l'error comès o 0 si no hi ha error - Paràmetres: ini: tipus de trama */ char obte_4_diags(char ini) { char in_lin[BUF_SIZ], // buffer per rebre una trama numdiag, numest, // número de diagrama, número d'estat i; // índex u_char m; // índex de posició de bits int conta; // comptador d'espera

Annexes

188

for (conta=1000; rs_inrcvd()<10 && conta; conta--) /* mentre no es rebi una trama sencera i el comptador no arribi a 0 */ delay(10); // retard temporal de 10 ms if (!conta) return 31; // si el comptador ha arribat a 0 rs_getstr(10,in_lin); // obté la trama (8 by d'info+chksum+EOT) for (i=0, numdiag=ini; numdiag<ini+4; i=i+2, numdiag++) { // pels 4 diagrames if (in_lin[i] || in_lin[i+1]) // si algun estat definit { for(numest=0,m=1;numest<8;numest++,m=m<<1) // pels 8 primers if (in_lin[i] & m) // si el bit corresponent val 1 G.DIAG_EST[numdiag][numest]=1; // activa bit corresponent for(numest=8,m=1;numest<16;numest++,m=m<<1) // per la resta if (in_lin[i+1] & m) // si el bit corresponent val 1 G.DIAG_EST[numdiag][numest]=1; /* s'activa el bit corresponent en memòria */ } } if (!qrecte(in_lin,8)) return 32; // comprova el checksum if (in_lin[9]!=EOT) return 33; // si final de trama correcte return 0; // retorna sense error } /******************************************************************* - Funció que s'encarrega d'obtenir informació del port per tal d'actualitzar la informació que hi ha en memòria i mostrada per pantalla - Retorna l'error comès o 0 si no hi ha error - Paràmetres: tipu: tipus de trama */ char actualitzar_info_serie(int tipu) { u_char nVar, // índex de variables est_a; // estat actiu char in_lin[BUF_SIZ], // buffer per rebre una trama numdiag, // número de diagrama i=0, // índex j=0; // índex per forçats int conta, // comptador d'espera m; // màscara de bit for(conta=1000; rs_inrcvd()<11 && conta; conta--) // espera trama delay(1); if (!conta) return 41; // si s'ha acabat l'espera => error=41 else rs_getstr(11,in_lin); // si la trama està a punt, s’obté switch(tipu) // depenent del tipus de trama.. { case SO: /* cas de trama amb informació de vars. d'entrada, sortida, temporitzadors i forçats (9 by en total)*/ for (nVar=0; i<3; i++) // per als 3 bytes d'entrada for (m=1; m<=128; m=m<<1, nVar++) // per cada var. if (G.VI[nVar][0]!=NULL) // si la var. existeix en mem. if (in_lin[i] & m) /* si el bit corresponent de trama està actiu */ G.VI[nVar][7]=1; // s'activa en memòria

Annexes

189

else // sinó G.VI[nVar][7]=0; // es desactiva en memòria for (nVar=0; i<5; i++) // per als 2 bytes de sortida for (m=1; m<=128; m=m<<1, nVar++) if (G.VO[nVar][0]!=NULL) if (in_lin[i] & m) G.VO[nVar][7]=1; else G.VO[nVar][7]=0; for (nVar=0; i<7; i++) // pels 2 bytes de temporitzadors for (m=1; m<=128; m=m<<1, nVar++) if (G.VT[nVar][0]!=NULL) if (in_lin[i] & m) G.VT[nVar][7]=1; else G.VT[nVar][7]=0; for (nVar=0; i<9; i++) // pels 2 bytes de forçats for (m=1; m<=128; m=m<<1, nVar++) if (G.VF[j][0]!=NULL && G.INFO_DIAG[nVar][1]) /* si cal llegir un nou forçat i el diagrama 'nVar' està definit */ { if (in_lin[i] & m) G.VF[j][7]=1; else G.VF[j][7]=0; j++; } break; case SI: // trama amb info. de variables de marca (8 by) for (nVar=0, i=0; i<8; i++) for (m=1; m<=128; m=m<<1, nVar++) if (G.VM[nVar][0]!=NULL) if (in_lin[i] & m) G.VM[nVar][7]=1; else G.VM[nVar][7]=0; break; case DLE: // trama amb info. d'est. actius (2 est.a. per by) for(numdiag=0,i=0;numdiag<16;numdiag=numdiag+2,i++) { // per cada by est_a=in_lin[i] >> 4; /* s’obté el primer estat actiu dels 4 bits de més pes */ if (est_a>16) return 42; // si valor massa gran=>error=42 G.INFO_DIAG[numdiag][0]=est_a; // carrega est. act. en mem. est_a=in_lin[i] & 0x0F; /* obté 2n est. actiu dels 4 bits de menys pes */ if (est_a>16) return 43; // si valor massa gran=>error=43 G.INFO_DIAG[numdiag+1][0]=est_a; // est. actiu a memòria } break; } if (!qrecte(in_lin,9)) return 44; // comprova el checksum if (in_lin[10]!=EOT) return 45; // si final de trama correcte return 0; // retorna sense error }

Annexes

190

/******************************************************************* - Funció que comprova el checksum d'una trama per determinar-ne si s'ha perdut o modificat informació de forma no desitjada - Paràmetres: i_lin: buffer que conte la trama rebuda */ u_char qrecte (char *i_lin, char pos) { u_char chksum, // valor de checksum rebut del microcontrolador suma=0, // variable on es calcula el nou checksum i; // índex chksum=*(i_lin+pos); // s’obté el checksum rebut del micro for (i=0; i<pos; i++) // per a tots els by de dades de la trama suma=suma+*(i_lin+i); // s'acumula la suma if (suma==chksum) return 1; /* si 'suma' és igual al 'chksum' rebut, la trama és correcte */ else return 0; // sinó, és incorrecte } /******************************************************************* - Funció que s'encarrega de contestar al micro via comunicació sèrie depenent de si ha trobat algun error en les trames rebudes - Paràmetres: error: variable indicadora d'error */ void contesta_error(char error) { if (error) // si alguna trama tenia error.. rs_sndbyt(NAK); // s'envia caràcter d'error ('NAK') else // sinó rs_sndbyt(ACK); // s'envia la confirmació } /******************************************************************* - Funció que envia el caràcter de petició de més trames */ void envia_SYN() { rs_sndbyt(SYN); } /******************************************************************* - Funció que s'encarrega d'enviar una trama per tal d'invertir una variable de la maquina d'estat - Paràmetres: tip: tipus de variable ii: número de variable */ void envia_mod_var(char tip, int ii) { char out_lin[5], // string per enviar una trama numd, // número de diagrama j=0; // comptador if (tip=='F') // si s'ha d'invertir { for (numd=0; numd<16; numd++) // per a tots els diagrames if (G.INFO_DIAG[numd][1]) // si el diagrama està definit {

Annexes

191

}

- Paràmetres:

rs_clrin(); // esborra el buffer d'entrada

if (j==ii) // si coincideix el num. de variable numd=numd+'0'; /* s'hi suma '0', de forma que la condició del 'for' no es complirà */ j++; // s'incrementa el comptador de diags. definits } ii=numd-1; // s'elimina l’últim increment } else ii=ii+'0'; /* per la resta de vars., també s'hi suma el ‘0’, que evita confusions amb els caràcters de control */ out_lin[0]=SOH; out_lin[1]=tip; out_lin[2]=ii; out_lin[3]=EOT; rs_sndstr(4,out_lin);

/******************************************************************* - Funció que inicialitza el port sèrie a utilitzar per la comunicació amb el microcontrolador - Retorna variable amb codi d'error

nby: número de port a utilitzar */ int inicialitza(char port) { int port_ok; rs_close(); // característiques: baudis=9600, no paritat, 8b de dades, 1b d'stop port_ok=rs_initport(port,RS_B9600,RS_NOPAR,RS_DBIT8,RS_SBIT1, BUF_SIZ,in_buf,BUF_SIZ,out_buf); if (port_ok > 0) // si la inicialització no reporta errors { rs_clrout(); // esborra el buffer de sortida

rs_modctrl(RS_WRTMCR,RS_MCRDTR | RS_MCRRTS,RS_LINOFF); // DTR,RTS=off } return(port_ok); } /******************************************************************* - Funció que assegura el tancament del port i de l'entorn gràfic si es pitja 'Ctrl-Break' - Retorna 0 */ int end_it() { rs_close(); // es tanca el port adeu_graf(); // pantalla de sortida del programa closegraph(); // es tanca l'entorn gràfic return 0; } /******************************************************************* - Funció que permet tancar el port des de qualsevol mòdul del projecte */

Annexes

192

void tanca_port() { rs_close(); // es tanca el port }

Codi 7.23. Codi en ‘C’ del fitxer “sericom.c”

7.3.4 Fitxer de Tractament de Dades d’Estructures: “estruk.c” /******************************************************************* -------------------------------------------------------------------- Fitxer on es troben les funcions que manipulen les estructures creades i utilitzades en aquest programa: * estructura d’informació de variables i diagrames - G * estructura de barra - B -------------------------------------------------------------------- *******************************************************************/ #include "capsal.h" /* DECLARACIO DE VARIABLES GLOBALS --------------------------------------------------------------------*/ s_gen G; /* var. de tipus 's_gen', que és l’estructura utilitzada per emmagatzemar en memòria tota la informació referent a les màquines d'estats i a les variables d’aquestes */ s_bar B; /* var. de tipus 's_bar', que és l'estructura utilitzada per emmagatzemar en memòria les coordenades necessàries per dibuixar el cursor que permet desplaçar-se per sobre de les variables */ extern u_char semafor; /* DEFINICIO DE FUNCIONS ------------------------------------------------------------------*/ /******************************************************************* - Funció encarregada de inicialitzar la part corresponent als diagrames d'estat de l'estructura creada per emmagatzemar en memòria la informació d'una maquina d'estats */ void clr_struct_diags(void) { u_char i,j; // índexs G.ndiags=0; for (i=0; i<16; i++) // per als 16 diagrames possibles { G.INFO_DIAG[i][0]=0; // estat actiu = 0 G.INFO_DIAG[i][1]=0; // nombre d'estats = 0 for (j=0; j<16; j++) // per als 16 estats possibles G.DIAG_EST[i][j]=0; // estat no definit } } /******************************************************************* - Funció encarregada de inicialitzar a 0 la part de l'estructura G corresponent a la informació de les variables de les màquines d'estats */ void clr_struct_vars(void)

Annexes

193

{ u_char i; // índex for (i=0; i<128; i++) /* per a totes les variables d'entrada, sortida, marca i temporització possibles */ { G.VI[i][0]=NULL; // se n'esborra el nom G.VO[i][0]=NULL; G.VM[i][0]=NULL; G.VT[i][0]=NULL; } for (i=0; i<16; i++) // per als 16 forçats G.VF[i][0]=NULL; } /******************************************************************* - Funció que inicialitza els paràmetres d'un gràfic en forma de barra solida, utilitzat per esborrar informació per pantalla. S'inicialitza en la posició de la primera variable de tipus entrada */ void ini_s_bar() { B.left=(getmaxx()/2)+4; B.up=40; // se situa en la primera fila B.down=B.up+6; // l'alçada de la barra és de 6 píxels B.right=B.left+50; // l'amplada de la barra és de 50 píxels B.col=1; // es tracta de columna 1 de 4 (entrades) } /******************************************************************* - Funció que inicialitza els paràmetres d'un gràfic en forma de barra solida, utilitzat per esborrar informació per pantalla - Retorna l'error comès (0=no error) */ char ini_vars() { char error, // control d'errors nomfvar[13]; // nom del fitxer de variables clr_struct_vars(); // esborra estruc. d’info. de màq. d’estat error=get_file_vars(nomfvar); // obté el nom del fitxer de vars. if (!error) error=get_nom_vars(nomfvar); // crida a la obtenció de les vars. return (error); } /******************************************************************* - Funció que obté el nom de les variables d'un projecte a traves del seu fitxer de variables - Retorna l'error comès (0=no error) */ char get_file_vars(char *namefvar) { struct ffblk ffblk; // estructura amb informació de fitxer int done; // variable de resposta char *p; // punter auxiliar int x=5, y=5; // coords. d'abscisses i ordenades

Annexes

194

clrscr(); strcpy(namefvar,"*.var"); /* carrega nom per buscar fitxers d’aquesta extensió */ done=findfirst(namefvar,&ffblk,0); // busca primer fitxer if (!done) // si s'ha trobat un primer fitxer { gotoxy(x,y); printf("%s",ffblk.ff_name); // es mostra per pantalla done=findnext(&ffblk); // busca el següent fitxer de vars. for (y=6; !done; y++) { if (y==38) // si s'arriba a la fila 38 { for (y=5; y<38; y++) // dibuixa línia vertical divisòria { gotoxy(39,y); printf("º"); } x=44; // abscissa de la segona columna y=5; } gotoxy(x,y); printf("%s",ffblk.ff_name); // mostra fitxer trobat done=findnext(&ffblk); // busca següent fitxer de vars. } } else return 1; gotoxy(2,39); printf("Write the variables file to open (max=8 chars):"); lc(); namefvar[0]=9; p=cgets(namefvar); // es llegeix el fitxer de variables a obrir while (p[0]!=NULL && !ia_fvar(p)) // si no es troba { p_error(2); p=cgets(namefvar); // es torna a llegir el nom del fitxer } fflush(stdin); if (p[0]==NULL) return 3; // si es pitja 'intro', retorna error=1 else strcpy(namefvar,p); // sinó, copia el nom de fitxer a mem. return 0; // retorna sense errors } /******************************************************************* - Funció que determina si un fitxer de variables existeix - Retorna 1 si es troba, o 0 si no es troba */ char ia_fvar(char *nom) { FILE *fvar; // punter a fitxer de variables char c; // caràcter auxiliar mes_ext(nom,".VAR"); // s'afegeix extensió ".VAR" al fitxer if ((fvar=fopen(nom,"rb"))!=NULL) c=1; // si no s’obra => error else c=0; // si es pot obrir, correcte fclose(fvar); // es tanca el fitxer return (c);

Annexes

195

} /******************************************************************* - Funció que obra el fitxer de variables i n'extreu el nom de les variables deixant-les carregades en memòria - Retorna 1 si hi ha algun error, o 0 si no n'hi ha cap - Paràmetres: nomv: nom del fitxer de variables */ char get_nom_vars(char *nomv) { int c; // caràcter auxiliar per llegir del fitxer u_char i, j, // índexs error=0; // control d'error FILE *fv; // punter a fitxer de variables if ((fv=fopen(nomv,"rb"))!=NULL) { if (getc(fv)!=255) error=5; getc(fv); // llegeix car. i no es guarda pq. no interessa if (getc(fv)!=255) error=5; /* continua amb la lectura de la info. necessària per aquest programa... */ fscanf(fv,"%4x%4x%4x"); c=getc(fv); for (i=0; c==255; i++) { G.VI[i][0]=getc(fv); for (j=0; j<8 && G.VI[i][j]!=NULL; j++) G.VI[i][j+1]=getc(fv); c=getc(fv); } if (c!=254) error=5; getc(fv); if (getc(fv)!=254) error=5; fscanf(fv,"%4x%4x"); c=getc(fv); for (i=0; c==254; i++) { G.VO[i][0]=getc(fv); for (j=0; j<8 && G.VO[i][j]!=NULL; j++) G.VO[i][j+1]=getc(fv); c=getc(fv); } if (c!=253) error=5; getc(fv); c=getc(fv); for (i=0; c==253; i++) { G.VM[i][0]=getc(fv); for (j=0; j<8 && G.VM[i][j]!=NULL; j++) G.VM[i][j+1]=getc(fv); c=getc(fv); } if (c!=252) error=5; getc(fv); c=getc(fv); for (i=0; c==252; i++) {

Annexes

196

getc(fv); c=getc(fv); } if (c!=251) error=5; getc(fv); c=getc(fv); for (i=0; c==251; i++) { G.VT[i][0]=getc(fv); for (j=0; j<8 && G.VT[i][j]!=NULL; j++) G.VT[i][j+1]=getc(fv); c=getc(fv); for (j=0; j<8 && c!=NULL; j++) c=getc(fv); getc(fv); getc(fv); c=getc(fv); } if (c!=250) error=5; c=getc(fv); c=getc(fv); c=getc(fv); if (c!=249) error=5; fclose(fv); // es tanca el fitxer } else error=4; // si no es pot obrir el fitxer, s'activa l'error return (error); } /******************************************************************* - Funció que a partir de la informació obtinguda amb la funció 'obte_4_diags()' completa la informació dels diagrames d'estats. Calcula el nombre d'estats de cada diagrama */ void calcula_info() { u_char sumest, // comptador de nombre d'estats nume, // número d'estat numd; // número de diagrama G.ndiags=0; for (numd=0; numd<16; numd++) // per a tots els diagrames { for(sumest=0,nume=0; nume<16; nume++) // per tots els estats sumest=sumest+G.DIAG_EST[numd][nume]; // se sumen G.INFO_DIAG[numd][1]=sumest; // es guarda la suma en memòria if (sumest) G.ndiags++; } } /******************************************************************* - Funció que a partir de la informació dels diagrames d'estat, inicialitza els forçats */ void obte_forsats() { char i=0, numd; // número de forçat

Annexes

197

for (numd=0; numd<16; numd++) // per a tots els diagrames { if (G.INFO_DIAG[numd][1]) // si el diagrama existeix { sprintf(G.VF[i],"F:D%d",numd); // s'activa el possible forçat i++; } } } /******************************************************************* - Funció que llegeix la tecla que s'ha pitjat, mou el cursor cap al lloc indicat o si es pitja 'ESC', fa que se surti del programa - Retorna 1 si s'ha pitjat 'ESC' i per tant,l'usuari vol sortir */ char manipula_vars() { u_char c; // caràcter de lectura c=getch(); // lectura de tecla pitjada fflush(stdin); // es buida el buffer d'entrada settextjustify(LEFT_TEXT,CENTER_TEXT); // justificació del text switch(c) // depenent de la tecla pitjada { case ESC: return 1; // si s'ha pitjat 'ESC', es retorna 1 case SPC: // si s'ha pitjat la barra espaiadora if (semafor & S_INI) semafor=semafor - S_INI; /* inverteix semàfor indicador d’inicialització realitzada */ else semafor=semafor | S_INI; // pausa o reinicia return 0; case INTRO: modifica_vars(); /* si s'ha pitja 'intro' s’inverteix la variable seleccionada pel cursor */ return 0; case 56: amunt(); // si es pitja la tecla '8', puja el cursor break; case 50: avall(); // tecla '2' => baixa el cursor break; case 52: esquerra(); // tecla '4' => cursor a l'esquerra break; case 54: dreta(); // tecla '6' => cursor a la dreta break; default: return 0; } restaura_var(GRIS); /* es defineix el color gris per la barra cursor que es dibuixarà en la nova posició del cursor */ return 0; // es retorna 0 per continuar mostrant informació } /******************************************************************* - Funció que desplaça la barra cursor una columna a la dreta */ void dreta() { restaura_var(NEGRE); // color negre per eliminar el cursor do { if (B.col==4) // si es tracta de la quarta i ultima columna.. B.col=1; // es passa a la primera columna else // si es tracta d'una altra columna

Annexes

198

B.col++; // s'incrementa el número de columna } while(pos_buida()); /* mentre el cursor se situï en una posició buida, buscarà una altra posició */ B.left=(getmaxx()/2)+4+80*(B.col-1); /* segons la columna, es defineix l'abscissa de l'esquerra */ B.right=B.left+50; // abscissa dreta és 50 píxels a la dreta } /******************************************************************* - Funció que desplaça la barra cursor una columna cap a l'esquerra. És molt semblant a la funció anterior 'dreta()' */ void esquerra() { restaura_var(NEGRE); do { if (B.col==1) B.col=4; else B.col--; // aquí les columnes es mouen cap a l'esquerra } while(pos_buida()); B.left=(getmaxx()/2)+4+80*(B.col-1); B.right=B.left+50; } /******************************************************************* - Funció que determina si en la posició actual del cursor determinada pels camps: 'col' i 'up' de l'estructura 'B' s'hi troba alguna variable. Si no hi ha cap variable en la posició, no té sentit que el cursor se situï a sobre - Retorna 1 si en la posició actual del cursor no hi ha cap variable escrita. Retorna 0 en cas contrari */ char pos_buida() { int i; // número de fila de variables i=(B.up-40)/8; // es calcula el número de la fila switch (B.col) // depenent de la columna actual { case 1: // si es tracta de la primera columna if (G.VI[i][0]==NULL) return(1); /* es mira si està definida la variable d'entrada corresponent */ break; case 2: if (G.VO[i][0]==NULL) return(1); break; case 3: if (G.VM[i][0]==NULL) return(1); break; case 4: if (G.VF[i][0]==NULL) return(1); } return(0); } /******************************************************************* - Funció que desplaça la barra cursor una fila avall */

Annexes

199

void avall() { restaura_var(NEGRE); B.up=B.up+8; // desplaça una fila avall l'ordenada superior if (pos_buida()) B.up=40; /* si correspon a una posició buida, se situa en la primera fila */ B.down=B.up+6; // ordenada inferior està 6 píxels sota de la superior } /******************************************************************* - Funció que desplaça la barra cursor una fila amunt */ void amunt() { restaura_var(NEGRE); B.up=B.up-8; // es desplaça el cursor una fila amunt if (B.up<40) B.up=busca_ultim(); /* si el cursor estava en la primera fila, si situa en la fila de mes a sota */ B.down=B.up+6; } /******************************************************************* - Funció que busca l'ultima variable (o fila) de la columna actual - Retorna el número de pixeu de la ordenada superior */ int busca_ultim() { char i; // índex fila switch (B.col) // depenent de la columna actual { case 1: // es tracta de les variables entrada for (i=0; G.VI[i][0]!=NULL; i++); break; case 2: // es tracta de les variables sortida for (i=0; G.VO[i][0]!=NULL; i++); break; case 3: // es tracta de les variables marca for (i=0; G.VM[i][0]!=NULL; i++); break; case 4: // es tracta de les variables temporitzador for (i=0; G.VF[i][0]!=NULL; i++); } return(40+(i-1)*8); // es calcula i retorna el número de pixeu } /******************************************************************* - Funció que a partir de les coordenades de l'estructura 'B' dibuixa una barra solida del color que indica el paràmetre i rescriu el nom de la variable que pertoca. D'aquesta forma es pot fer moure el cursor (de color gris) - Paràmetres: color: color de la barra solida */ void restaura_var(char color) { char tipu; // tipus de variable (entrada, sortida,...) int i; // número de fila

Annexes

200

setfillstyle(1,color); /* defineix estil per omplir els gràfics de tipus barra: sòlid i de color 'color' */ bar (B.left, B.up, B.right, B.down); /*es dibuixa la barra esborrant així el cursor i la variable que aquest senyalava */ switch (B.col) // depenent de la columna actual { case 1: tipu='I'; break; // es tracta d'una entrada case 2: tipu='O'; break; // es tracta d'una sortida case 3: tipu='M'; break; // es tracta d'una marca case 4: tipu='F'; // es tracta d'un forçat } i=(B.up-40)/8; // es calcula el número de la fila escriu_nom(tipu, i, B.left+4, B.up+4); /* es rescriu el nom de la variable que s'ha esborrat amb la barra */ } void modifica_vars() // es modifica la variable seleccionada { char tipu; // tipus de variable (entrada, sortida,...) int i; // número de fila switch (B.col) // depenent de la columna actual { case 1: tipu='I'; break; // es tracta d'una entrada case 2: tipu='O'; break; // es tracta d'una sortida case 3: tipu='M'; break; // es tracta d'una marca case 4: tipu='F'; // es tracta d'un forçat } i=(B.up-40)/8; // es calcula el número de la fila if (tipu=='I' || tipu=='M' || tipu=='O' || tipu=='F') envia_mod_var(tipu,i); }

Codi 7.24. Codi en ‘C’ del fitxer “estruk.c”

7.3.5 Fitxer de Tractament d’Elements Visuals: “menus2.c” /******************************************************************* -------------------------------------------------------------------- Fitxer on es defineixen les funcions d’interfície amb l'usuari i de l'entorn gràfic -------------------------------------------------------------------- *******************************************************************/ #include "capsal.h" /* DECLARACIO DE VARIABLES GLOBALS EXTERNES ------------------------------------------------------------------*/ extern s_gen G; extern u_char semafor; /* DEFINICIO DE FUNCIONS ------------------------------------------------------------------*/ /******************************************************************* - Funció encarregada d'inicialitzar l'entorn gràfic necessari per aquest programa per tal de mostrar la informació d'un projecte de

Annexes

201

màquines d'estat */ void ini_grafics(void) { int gdriver = DETECT, /* especifica driver de gràfics a utilitzar, s'inicialitza de forma que es detecti automaticam. */ gmode, // especifica el mode inicial de gràfics errorcode; // codi d'error initgraph(&gdriver, &gmode, ""); // inicialització de gràfics errorcode = graphresult(); // llegeix el resultat if (errorcode != grOk) // si hi ha error { gotoxy(2,41); printf("Graphics error: %s. ", grapherrormsg(errorcode)); clr_ln(39); gotoxy(2,39); printf("Press any key to exit..."); lc(); getch(); adeu_no_graf(); exit(1); // acaba amb codi d'error } ini_s_bar(); /* inicialització de l'estructura que conte les coordenades del cursor */ } /******************************************************************* - Funció que mostra la pantalla de presentació del programa de monitorització */ void hola() { textattr(15); // es defineix el tipus de text clrscr(); // esborra pantalla gotoxy(20,19); printf("ÛßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÛ"); gotoxy(20,20); printf("Û STATES DIAGRAMS MONITORIZATION PROGRAM Û"); gotoxy(20,21); printf("ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ"); gotoxy(20,39); printf(" Directed by: Ernest Gil Dolcet"); gotoxy(20,41); printf(" Created by: Enric Dalmau Malet"); gotoxy(20,23); printf(" ...press any key to begin..."); getch(); // espera fins que es pitgi una tecla } /******************************************************************* - Funció que mostra la base gràfica del programa sense la informació del microcontrolador. Inicialitza la pantalla d’informació */ void menu_info() { int midx, // coordenada abscissa del punt mig de la pantalla x, y; // coordenades de píxels: abscisses i ordenades char text[16]={24,',','8',0,25,',','2',0,26,',','6',0,27,',','4',0}; // Fletxes definides amb cars. ASCII: 24=fletxa amunt, 25=avall

Annexes

202

cleardevice(); // esborra la pantalla setcolor(BLANC); // defineix el color blanc per fer els gràfics settextjustify(CENTER_TEXT,CENTER_TEXT); // defineix justificació midx=getmaxx()/2; // es defineix el valor de 'midx' outtextxy(midx, 4,"ÛßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÛ"); outtextxy(midx,12,"Û STATES DIAGRAMS INFORMATION PROGRAM Û"); outtextxy(midx,20,"ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ"); outtextxy(midx*1.125,y=30,"Inputs"); // títols per variables outtextxy(midx*1.375,y,"Outputs"); outtextxy(midx*1.625,y,"Marks"); outtextxy(midx*1.875,y,"Forced"); outtextxy(midx*1.875,y+200,"Temporiz."); line(midx,y=20,midx,getmaxy()); // línies per fer taula de vars. line(midx*1.25,y,midx*1.25,getmaxy()); line(midx*1.5,y,midx*1.5,getmaxy()); line(midx*1.75,y,midx*1.75,getmaxy()); line(midx,36,getmaxx(),36); line(midx*1.75,236,getmaxx(),236); setfillstyle(1,BLAUMARI); /* es defineix l'estil d'omplir elements: sòlid, i blaumarí */ bar(0, getmaxy()-10, getmaxx(), getmaxy()); // barra de menú setfillstyle(1,NEGRE); setcolor(GROC); // color groc per lletres d’accés a les opcions del menú settextjustify(LEFT_TEXT,CENTER_TEXT); // nova justificació outtextxy(x=8, y=getmaxy()-4, text); // dibuixa fletxa amunt i 8 outtextxy(x=x+16+8*6, y, text+4); // fletxa avall i el 2 outtextxy(x=x+16+8*8, y, text+8); // fletxa esquerra i el 4 outtextxy(x=x+16+8*9, y, text+12); // fletxa dreta i el 6 outtextxy(x=x+16+8*8, y, "RETURN"); outtextxy(x=x+16+8*13, y, "SPACE"); outtextxy(x=x+16+8*11, y, "ESC"); setcolor(BLANC); // color blanc per la definició de les opcions outtextxy(x=32, y, ":Up"); outtextxy(x=x+16+8*6, y, ":Down"); outtextxy(x=x+16+8*8, y, ":Right"); outtextxy(x=x+16+8*9, y, ":Left"); outtextxy(x=x+16+8*11, y, ":Change"); outtextxy(x=x+16+8*12, y, ":Pause"); outtextxy(x=x+16+8*9, y, ":Quit"); crea_elipses(); // crea el·lipses per mostrar diags. d'estat } /******************************************************************* - Funció que crea les el·lipses que mostraran la informació dels diags. d'estat, és a dir, els estats que conté cada diagrama, a més de l'estat actiu */ void crea_elipses() { char i, // índex pels diagrames diag[5]="D__:", // plantilla per escriure el num. de diag. nd, // comptador de diagrames definits numd; // nombre de diagrames int centrex, centrey, // coordenades del centre de l'el·lipse xradius, yradius; // radis de l'el·lipse if (G.ndiags%2) numd=G.ndiags+1; /* si es tracta d'un nombre senar

Annexes

203

de diags. 'numd'= nombre de diags.+1 per tal que el tractament sigui igual per parells i senars */ else numd=G.ndiags; xradius=getmaxx() / 8; // radi x 8 vegades inferior al màxim yradius=(getmaxy()-40)/numd; // radi y depèn dels diags. creats settextjustify(CENTER_TEXT,CENTER_TEXT); // justificació centrada for (i=0, nd=0; i<16; i++) // per a tots els diagrames.. { if (G.INFO_DIAG[i][1]!=0) // ..si té algun estat definit.. { if (nd<(numd/2)) // ..i és de la 1ª meitat de diags. { centrex=xradius; // la x del centre es igual al radi x centrey=yradius+29+2*nd*yradius; // calcula y del centre } else // si és de la segona meitat de diags { centrex=xradius*3; // x del centre val 3·radi x centrey=yradius+29+2*(nd-numd/2)*yradius; // calcula y del centre } diag[1]=i/10+'0'; // omple plant. amb num. de diag.(xifra 1) diag[2]=i%10+'0'; // (xifra 2) outtextxy(centrex-16, centrey, diag); // s'escriu ellipse(centrex, centrey, 0, 360, xradius, yradius); /* es dibuixa l'el·lipse que conte la informació del diag. */ mini_elipses(i, centrex, centrey, xradius, yradius); // funció que dibuixa una “miniel·lipse” per cada est. del diag. nd++; // s'incrementa el comptador de diagrames } } } /******************************************************************* - Funció que crea petites el·lipses dins l'el·lipse del diagrama. Cadascuna d'aquestes el·lipses conte un número d'estat definit en el diagrama - Paràmetres: posd: número de diagrama cx: coordenada x del centre del diagrama (o el·lipse gran) cy: coordenada y del centre del diagrama xrad: radi x del l'el·lipse gran yrad: radi y del l'el·lipse gran*/ void mini_elipses(char posd, int cx, int cy, int xrad, int yrad) { char k; // índex de diagrames int xmig, ymig; // coordenades del centre de les miniel·lipses float ang, /* angle de l'arc entre cada estat dins l'el·lipse gran */ angle; // angle del centre de cada estat ang=2*M_PI/G.INFO_DIAG[posd][1]; // definició de l'angle de l'arc for (k=0, angle=M_PI; k<16; k++) // per a tots els estats if (G.DIAG_EST[posd][k]==1) // si l'estat està definit { xmig=cx+floor(cos(angle)*xrad*0.8); // x del centre ymig=cy-floor(sin(angle)*yrad*0.8); // y del centre

Annexes

204

ellipse(xmig, ymig-1, 0, 360, 10, 6); // dibuixa miniel·lipse angle=angle-ang; // decrementa l'angle } } /******************************************************************* - Funció que escriu els números de tots els estats definits de tots els diagrames dins de les "mini" el·lipses creades anteriorment. Al mig de cada diagrama escriu el número de diagrama seguit de l'estat actiu corresponent. Les variables locals definides i l'estructura de la funció són molt semblants a la funció 'crea_elipses()' */ void estats_actius(void) { char i, est[4]="S__", // plantilla per escriure l'estat actiu nd, numd; int centrex, centrey, xradius, yradius; settextjustify(CENTER_TEXT,CENTER_TEXT); // justificació centrada setfillstyle(1,NEGRE); if (G.ndiags%2) numd=G.ndiags+1; else numd=G.ndiags; xradius=getmaxx() / 8; yradius=(getmaxy()-40) / numd; for (i=0, nd=0; i<16; i++) { if (G.INFO_DIAG[i][1]!=0) { if (nd<(numd/2)) { centrex=xradius; centrey=yradius+29+2*nd*yradius; } else { centrex=xradius*3; centrey=yradius+29+2*(nd-numd/2)*yradius; } bar(centrex+4, centrey-5, centrex+34, centrey+5); /* barra solida que esborra l'estat actiu anterior */ est[1]=G.INFO_DIAG[i][0]/10+'0'; // omple plant. d'est. act. est[2]=G.INFO_DIAG[i][0]%10+'0'; // amb el num. corresponent setcolor(VERD); // activa color verd per l'estat actiu outtextxy(centrex+16, centrey, est); // escriu l'estat actiu mostra_estats(i, centrex, centrey, xradius, yradius); nd++; } } } /******************************************************************* - Funció que escriu els números dels estats existents dins les "miniel·lipses”. El tractament és molt semblant al realitzat en la funció 'mini_elipses()'

Annexes

205

- Paràmetres: posd: número de diagrama numds: nombre de diagrames */ void mostra_estats(char posd, int cx, int cy, int xrad, int yrad) { char k, // índex d'estats nume[3]="__"; // plantilla pel número d'estat int xmig, ymig; // coords. del centre de les "miniel·lipses” float ang, // angle de l'arc entre estats, dins l'el·lipse gran angle; // angle del centre de cada estat ang=2*M_PI/G.INFO_DIAG[posd][1]; for (k=0, angle=M_PI; k<16; k++) if (G.DIAG_EST[posd][k]==1) { nume[0]=k/10+'0'; nume[1]=k%10+'0'; /* posa num. d'estat a la plantilla d’estat */ if (G.INFO_DIAG[posd][0]==k) setcolor(VERD); /* si es tracta de l'estat actiu, s'activa el color verd pel text */ else setcolor(VERMELL); // sinó, s'activa el color vermell xmig=cx+floor(cos(angle)*xrad*0.8); // calcula la coord. xmig ymig=cy-floor(sin(angle)*yrad*0.8); // calcula la coord. ymig outtextxy(xmig, ymig, nume); // escriu num. d'estat angle=angle-ang; // es decrementa l'angle } } /******************************************************************* - Funció que mostra la informació referent a les variables. El primer cop que s'executi aquesta funció s'escriuran els noms de les variables per pantalla */ void mostra_vars() { char i, // índex ini; /* var. aux. que indica si és el primer cop que s'executa aquesta funció */ int midx, // valor central de pantalla de les abscisses x, y; // coordenades de pantalla settextjustify(LEFT_TEXT,CENTER_TEXT); setfillstyle(1,NEGRE); ini=!(semafor & S_VPRIM); // primer cop => ini=1; if (ini) restaura_var(GRIS); // si primer cop, dibuixa el cursor midx=getmaxx()/2; for (i=0,y=44; G.VI[i][0]!=NULL; i++,y=y+8) // per totes les entr. { x=midx+8; // coordenada 'x' per escriure info. de la var. if (ini) // si primer cop escriu_nom('I', i, x, y); // escriu el nom u_o_zero(G.VI[i][7], x, y); // escriu valor de la var. (1 o 0) } for (i=0,y=44; G.VO[i][0]!=NULL; i++,y=y+8) // per les sortides { x=midx+88; if (ini) escriu_nom('O', i, x, y); u_o_zero(G.VO[i][7], x, y);

Annexes

206

} for (i=0,y=44; G.VM[i][0]!=NULL; i++,y=y+8) // per les marques { x=midx+168; if (ini) escriu_nom('M', i, x, y); u_o_zero(G.VM[i][7], x, y); } for (i=0,y=44; G.VF[i][0]!=NULL; i++,y=y+8) // pels forçats { x=midx+248; if (ini) escriu_nom('F', i, x, y); u_o_zero(G.VF[i][7], x, y); } for (i=0,y=244; G.VT[i][0]!=NULL; i++,y=y+8) // pels tempors. { x=midx+248; if (ini) escriu_nom('T', i, x, y); u_o_zero(G.VT[i][7], x, y); } semafor=semafor | S_VPRIM; /* s'activa el semàfor que indica que ja s’han mostrat les variables una vegada, almenys */ } /******************************************************************* - Funció que escriu el nom de la variable indicada per pantalla i en la posició adequada - Paràmetres: tipV: tipus de variable ii: índex de variable xx: coordenada x per escriure la variable yy: coordenada y per escriure la variable */ void escriu_nom(char tipV, char ii, int xx, int yy) { setcolor(BLANC); // el nom de la variable s'escriu de color blanc switch (tipV) // depenent del tipus de variable { case 'I': outtextxy(xx, yy, G.VI[ii]); break; // escriu nom d'entrada case 'O': outtextxy(xx, yy, G.VO[ii]); break; case 'M': outtextxy(xx, yy, G.VM[ii]); break; case 'F': outtextxy(xx, yy, G.VF[ii]); break; case 'T': outtextxy(xx, yy, G.VT[ii]); } if (!(semafor & S_VPRIM)) outtextxy(xx+48,yy,": "); /* els punts només s'escriuen el primer cop */ } /******************************************************************* - Funció que escriu el valor de cada variable al costat del nom. Per diferenciar fàcilment les variables actives de les no actives el valor de les primeres s'escriu de color verd i les segones de color vermell. Abans d'escriure cada valor, s'esborra l'anterior amb un quadrat de color negre - Paràmetres: val: valor de la variable xx: coordenada x del nom de la variable yy: coordenada y del nom de la variable */

Annexes

207

void u_o_zero(char val, int xx, int yy) { xx=xx+54; bar(xx+2,yy-4,xx+8,yy+2); if (val) // si la variable està activa { setcolor(VERD); // s'escriu de color verd outtextxy(xx,yy,"1"); } else // si no està activa { setcolor(VERMELL); // s'escriu de color vermell outtextxy(xx+2,yy,"0"); } } /******************************************************************* - Funció que mostra la pantalla de sortida amb format gràfic */ void adeu_graf() { int midx, midy; // valor central de abscisses i ordenades cleardevice(); // es borra la pantalla setcolor(BLANC); // color blanc pels gràfics settextjustify(CENTER_TEXT,CENTER_TEXT); // justificació centrada midx=getmaxx()/2; // valor central de les abscisses midy=getmaxy()/2; // valor central de les ordenades settextstyle(0, HORIZ_DIR, 2); // mida de lletres superior outtextxy(midx, midy, "BYE * 2!!"); // missatge de sortida outtextxy(midx, midy+16,"...press any key to exit..."); getch(); // espera pulsació de tecla } /******************************************************************* - Funció que mostra la pantalla de sortida sense format gràfic */ void adeu_no_graf() { clrscr(); gotoxy(35,20); printf("BYE * 2!!"); gotoxy(25,22); printf("...press any key to exit..."); getch(); textattr(15); clrscr(); } /******************************************************************* - Funció que canvia l'estil de text */ void changetextstyle(int font, int direccio, int charsize) { int ErrorCode; // codi d'error graphresult(); // borra codi d'error settextstyle(font, direccio, charsize); ErrorCode = graphresult(); // comprova resultat if( ErrorCode != grOk ) // si hi ha error

Annexes

208

{ gotoxy(2,41); printf("Graphics error: %s. ", grapherrormsg(ErrorCode)); clr_ln(39); gotoxy(2,39); printf("Press any key to exit..."); lc(); getch(); adeu_graf(); closegraph(); // tanca entorn gràfic exit(1); // surt amb codi d'error } }

Codi 7.25. Codi en ‘C’ del fitxer “menus2.c”

7.3.6 Fitxer de Tractament de Diverses Funcions: “funcion2.c” /******************************************************************* -------------------------------------------------------------------- Fitxer amb funcions diverses -------------------------------------------------------------------- *******************************************************************/ #include "capsal.h" /* DEFINICIO DE FUNCIONS ------------------------------------------------------------------*/ /******************************************************************* - Funció que escriu les línies de comandes per pantalla, ocupant les línies que van de la 38 a la 42 (en total n'hi ha 43): * línia 39: enunciats i missatges de confirmació * línia 40: línia destinada a les comandes teclejades per l'usuari * línia 41: missatges d'error */ void lc() { gotoxy(1,38); printf("ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄ"); printf("ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ"); gotoxy(1,42); printf("ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄ"); printf("ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ"); clr_ln(40); gotoxy(2,40); printf(">> "); } /******************************************************************* - Funció que afegeix a un string una extensió. S'afegeix quan es troba un punt o el caràcter NULL - Paràmetres: nom: nom del fitxer a afegir-li l’extensió ext: extensió a afegir */ void mes_ext(char *nom, char *ext) { u_char i; // índex

Annexes

209

for (i=0; (nom[i]!=NULL) && (nom[i]!='.') && (i<8); i++); // busca '.' o NULL nom=nom+i; // es desplaça el punter strcpy(nom,ext); // s'afegeix l’extensió nom=nom-i; // es torna el punter a l'inici strupr(nom); // es posa tot en majúscules } /******************************************************************* - Funció que esborra una línia de pantalla */ void clr_ln(char nl) { gotoxy(1,nl); printf("%79s"," "); } /******************************************************************* - Funció que mostra un missatge d'error per pantalla. Hi ha 2 tipus de missatge diferents. - Paràmetres: tip: tipus d'error str: string que indica amb que s'ha comès l'error */ void p_error(char tip) { gotoxy(2,41); // es va a la línia de missatges d'error switch (tip) { case 1: // tipus 1: no es troba cap fitxer de variables printf("Error. There isn't any variables file. "); printf("Press any key to exit.. "); break; case 2: // tipus 2: fitxer de variables que no existeix printf("Error. This variables file doesn't exist. "); printf("Press any key to retry.. "); break; case 3: // tipus 3: s'ha pitjat 'intro' printf("Error. No name of variables file writed. "); printf("Press any key to exit.. "); break; case 4: // tipus 4: error obrint el fitxer printf("Error openning the variables file. "); printf("Press any key to exit.. "); break; case 5: // tipus 5: error llegint el fitxer de variables printf("Error reading the variables file. "); printf("Press any key to exit.. "); break; case 6: // tipus 5: error d'inicialització del port printf("Error initializing the port. "); printf("Press any key to exit.. "); break; case 7: // tipus 7: error en l'establiment de comunicacions printf("Error stablishing communications with microcontroller. "); printf("Press any key to exit.. "); }

Annexes

210

lc(); getch(); // s'espera que es pitgi qualsevol tecla clr_ln(41); // s'esborra el missatge d'error lc(); }

Codi 7.26. Codi en ‘C’ del fitxer “funcion2.c”

Annexes

211

7.4 Annex B.2: Llistat dels Fitxers Creats en el Bloc II en Llenguatge Assemblador

7.4.1 Fitxer de Capçalera del Tractament de les Comunicacions: “RS232prj.h” ;########################( include )############################### ;## ## ;## ## ;## RS232prj.h ## ;## ## ;## ## ;################################################################### ;___________________________________________________________________ ;### (RS232prj) #################################################### ;***( iRAM )**************************************** RS232i_Tbuf: .equ 66h ; transmission buffer address (constant) RS232i_Rbuf: .equ 76h ; reception buffer address (constant) RS232i_ctrl: .equ 62h ; control registers (3 bytes) RS232i_sem: .equ 65h ; controla si cal enviar la informació ;***( constants )*********************************** RS232i_Rlen: .equ 0Fh ; longitud del buffer de recepció RS232i_SOH: .equ 01h ; caràcter d'inici de capçalera RS232i_EOT: .equ 04h ; caràcter de final de trama RS232i_ENQ: .equ 05h ; caràcter de petició de comunicació RS232i_ACK: .equ 06h ; caràcter d'acknowledgement RS232i_NAK: .equ 15h ; caràcter de no acknowledgement RS232i_SYN: .equ 16h ; caràcter de sincronització RS232i_SO: .equ 0Eh ; caràcter indicador de vars. d'entrada, sortida i temp RS232i_SI: .equ 0Fh ; caràcter indicador de vars. de marca RS232i_DLE: .equ 10h ; caràcter indicador d'info de SD RS232i_DC1: .equ 11h ; caràcter indicador de 1er grup d'estats actius RS232i_DC2: .equ 12h ; caràcter indicador de 2on grup d'estats actius RS232i_DC3: .equ 13h ; caràcter indicador de 3er grup d'estats actius RS232i_DC4: .equ 14h ; caràcter indicador de 4rt grup d'estats actius .end

Codi 7.27. Codi en assemblador del fitxer “RS232prj.h”

7.4.2 Fitxer de Tractament de Comunicacions per la Monitorització: “RS232prj.asm” ;#######################( include )####################### ;### ### ;### Aplicacio: Tractament RS-232 ### ;### ### ;######################################################### IniRS232: ; inicialització del port sèrie

Annexes

212

push A push PSW mov A,#39 ; 9,6kbit/s (12MHz) call RS232i_open ; inicialitza el port call RS232i_Ren ; enable rec mov RS232i_sem,#00h ; byte semàfor per controlar el número ;de trama a enviar pop PSW pop A ret ;------------------------------------------------------------- RepRS232: ; Tractament a fer al rebre un byte via RS232 push A push B push 00 push 01 push PSW mov R0,#RS232i_Rbuf ; carrega 1ª posició del buffer a R0 cjne @R0,#RS232i_SOH,Rep_act ; si no s'ha rebut SOH, salta mov A,#RS232i_Rbuf-1 ; si 1ª posició del buffer és SOH, es.. ; carrega l'ACC amb una posició menys add A,RS232i_Rcnt ; s'hi afegeix el comptador de bytes rebuts mov R0,A ; es carrega R0 per apuntar l'última pos. del buffer cjne @R0,#RS232i_EOT,Rep_surt ; si no s'ha rebut EOT, surt call Canvia_var ; si es rep EOT, crida el canvi de var. sjmp Rep_surt ; surt Rep_act: call ActuaRS232 ; crida a l'actualització de dades Rep_surt: pop PSW pop 01 pop 00 pop B pop A ret ;------------------------------------------------------------- ActuaRS232: ; Actualització d’informació. S'envia al PC Act_syn: cjne @R0,#RS232i_ENQ,Act_0 ;si no s'ha rebut ENQ, salta mov RS232i_sem,#10h ;s'activa semàfor per començar a rebre sjmp Act_conti ;salta per continuar Act_0: mov A,RS232i_sem ;es copia semàfor a l'ACC jz Act_surt ;si encara cal iniciar, salta al final Act_enq: cjne @R0,#RS232i_SYN,Act_ack ;si no és SYN, salta mov RS232i_sem,#14h ;s'activa semàfor per iniciar cicle sjmp Act_conti ;salta per continuar Act_ack: cjne @R0,#RS232i_ACK,Act_nak ;si no es rep ACK, salta inc RS232i_sem ;s'incrementa el semàfor mov A,RS232i_sem ;es copia el semàfor al ACC cjne A,#17h,Act_conti ;si no s'ha enviat tot, salta dec RS232i_sem ;es decrementa per no fer res més sjmp Act_surt ;surt Act_nak: cjne @R0,#RS232i_NAK,Act_surt ; si no es rep NAK, surt Act_conti: mov A,RS232i_sem ;es copia el semàfor a l'ACC

Annexes

213

Act_DC1: cjne A,#10h,Act_DC2 ;si no s'ha d'enviar trama DC1, ; salta call enviaDC1 ;crida funció que envia trama DC1 Act_DC2: cjne A,#11h,Act_DC3 ;si no s'ha d'enviar trama DC2,salta call enviaDC2 ;crida funció que envia trama DC2 Act_DC3: cjne A,#12h,Act_DC4 ;si no s'ha d'enviar trama DC3, salta call enviaDC3 ;crida funció que envia trama DC3 Act_DC4: cjne A,#13h,Act_SO ;si no s'ha d'enviar trama DC4, salta call enviaDC4 ;crida funció que envia trama DC4 Act_SO: cjne A,#14h,Act_SI ;si no s'ha d'enviar trama SO, salta call env_IOTF ;crida funció que envia trama SO Act_SI: cjne A,#15h,Act_DLE ;si no s'ha d'enviar trama SI, salta call envia_M ;crida funció que envia trama SI Act_DLE: cjne A,#16h,Act_surt ;si no s'ha d'enviar trama DLE, salta call envia_SD ;crida funció que envia trama DLE Act_surt: dec RS232i_Rcnt ;decrementa comptador de recepció ret ;------------------------------------------------------------------- Canvia_var: push DPH push DPL dec R0 ;decrementa el punter al buffer, ja que dec R0 ; apuntava a l'última posició cjne @R0,#'I',Canvia_m ;si no s'ha rebut 'I', salta inc R0 ;si s'ha rebut, es tracta d'una entrada ; i cal posicionar-se a la següent pos. mov A,@R0 ;mou el número de byte a l'ACC subb A,#'0' ;se li resta el valor ASCII de '0' mov B,#8 ;es carrega B amb el valor 8 (=8 bits) div AB ;divideix per obtenir num. de by de la var. ; en l'ACC i el num. de bit en B cjne A,#0,Canv_XI1 ;si no és el primer byte d'entrades, salta mov DPTR,#XIadr0 ;si és el primer, carrega l'adreça externa sjmp Canv_X ;salta per canviar la variable Canv_XI1: .IFDEF XIadr1 ;si està definida l'etiqueta del segon by ; d'entr, s'assembla fins el 2on '.ENDIF' cjne A,#1,Canv_XI2 ;si no es tracta del segon byte, salta mov DPTR,#XIadr1 ;si és el segon, es carrega adreça ext. jmp Canv_X ;salta per canviar la variable Canv_XI2: .IFDEF XIadr2 ;si existeix etiqueta del tercer by, ; s'assembla fins el següent '.ENDIF' cjne A,#2,Canv_surt ;si tampoc és el 3er by, surt mov DPTR,#XIadr2 ;si és al 3er by, carrega l’adr. ext. .ELSE ;si no existeix l’etiqueta ‘XIadr2’ sjmp Canv_surt ;s'introdueix un salt per sortir .ENDIF ;fi de la segona directiva condicional .ELSE ;si no existeix l’etiqueta ‘XIadr1’ sjmp Canv_surt ;s'introdueix un salt per sortir .ENDIF ;fi de la primera directiva condicional Canv_X: movx A,@DPTR ;carrega el by que conté la var. a l'ACC mov R1,A ;es copia a R1 inc B ;s'incrementa B, que farà de comptador setb C ;s'activa el Carry per la instrucció 'rlc' clr A ;s'esborra l'ACC per crear la màscara

Annexes

214

Canv_Xrot: rlc A ;partint del Carry, es mou l'1 cap a l'esquerra djnz B,Canv_Xrot ;decrem. B i si no val 0, torna a rotar mov B,A ;copia la màscara a B anl A,R1 ;es copia a l'ACC el valor de la var. a modificar ; utilitzant la màscara creada jz Canv_Xa1 ;si val 0, salta perquè cal activar-la Canv_Xa0: mov A,B ;sinó, es torna a copiar la màscara a l'ACC cpl A ;inverteix bits, quedant la pos. de la var. a 0 anl A,R1 ;amb màscara invertida, desactiva la var. movx @DPTR,A ;carrega la modificació a la memòria externa sjmp Canv_surt ; surt Canv_Xa1: mov A,B ; si cal activar la var., copia màscara a l'ACC orl A,R1 ; amb la màscara, s'activa la var. movx @DPTR,A ; carrega la modificació a la memòria externa sjmp Canv_surt ; surt Canvia_m: cjne @R0,#'M',Canvia_o ;si no s'ha rebut 'M', salta mov R1,#Madr ;carrega l'adreça interna inicial de sortides sjmp Canv_cont ;salta per modificar la var. Canvia_o: cjne @R0,#'O',Canvia_f ;si no s'ha rebut 'O', salta mov R1,#Oadr ;carrega l'adreça interna inicial de sortides sjmp Canv_cont ;salta per modificar la var. Canvia_f: cjne @R0,#'F',Canv_surt ;si tampoc s'ha rebut 'F', surt mov R1,#Fadr ; carrega l'adreça inicial de forçats Canv_cont: inc R0 ;incrementa el punter al buffer de recepció mov A,@R0 ;copia el número de variable a l'ACC subb A,#'0' ;hi resta el valor ASCII de '0' mov B,#8 ;carrega B amb 8 div AB ;divideix A/B per obtenir by i bit de la var. add A,R1 ;es suma el byte a l'adreça inicial mov R1,A ;es copia el resultat a A inc B ;s'incrementa B, per fer de comptador setb C ;s'activa el Carry per rotar-lo amb l'ACC clr A ;s'esborra l'ACC per rotar-lo amb el Carry Canv_rot: rlc A ;es rota l'ACC amb el Carry djnz B,Canv_rot ;decrementa B, i si no val 0, torna a rotar mov B,A ;es copia la màscara creada a B anl A,@R1 ;amb la màscara s'obté el valor de la var. jz Canv_a1 ;si val 0, salta per activar-la Canv_a0: mov A,B ;sinó, es copia la màscara a l'ACC cpl A ;s'inverteix la màscara anl A,@R1 ;es desactiva el bit corresponent a la var. mov @R1,A ;es modifica la variable en memòria interna sjmp Canv_surt ;surt Canv_a1: mov A,B ;si cal activar la var., copia màscara a l'ACC orl A,@R1 ; s'activa el bit corresponent a la var. mov @R1,A ; es modifica la variable en la memòria interna Canv_surt: mov RS232i_Rcnt,#0 ;finalment, s'esborra comptador de ; by per reutilitzar buffer de recepció pop DPL pop DPH ret ;------------------------------------------------------------------- enviaDC1: ; Envia informació del primer grup de diagrames d'estat

Annexes

215

push A push B push 01 push PSW mov A,#RS232i_DC1 ; carrega el tipus de trama al ACC call IniTrama ; A = paràmetre de la funció 'IniTrama' clr A ; s'esborra l'ACC mov B,A ; i B .IFDEF SD0 ; si està definit el diagrama 0 .IFDEF D00S00T00 ; si està definit l'estat 0 orl A,#01h ; s'activa el bit corresponent .ENDIF .IFDEF D00S01T00 ; es continua de forma idèntica... orl A,#02h .ENDIF .IFDEF D00S02T00 orl A,#04h .ENDIF .IFDEF D00S03T00 orl A,#08h .ENDIF .IFDEF D00S04T00 orl A,#10h .ENDIF .IFDEF D00S05T00 orl A,#20h .ENDIF .IFDEF D00S06T00 orl A,#40h .ENDIF .IFDEF D00S07T00 orl A,#80h .ENDIF .IFDEF D00S08T00 orl B,#01h .ENDIF .IFDEF D00S09T00 orl B,#02h .ENDIF .IFDEF D00S10T00 orl B,#04h .ENDIF .IFDEF D00S11T00 orl B,#08h .ENDIF .IFDEF D00S12T00 orl B,#10h .ENDIF .IFDEF D00S13T00 orl B,#20h .ENDIF .IFDEF D00S14T00 orl B,#40h .ENDIF .IFDEF D00S15T00 orl B,#80h

Annexes

216

.ENDIF .ENDIF call Mou_i_Ini ; carrega l'ACC i B a la trama i s'esborren .IFDEF SD1 .IFDEF D01S00T00 orl A,#01h .ENDIF .IFDEF D01S01T00 orl A,#02h .ENDIF .IFDEF D01S02T00 orl A,#04h .ENDIF .IFDEF D01S03T00 orl A,#08h .ENDIF .IFDEF D01S04T00 orl A,#10h .ENDIF .IFDEF D01S05T00 orl A,#20h .ENDIF .IFDEF D01S06T00 orl A,#40h .ENDIF .IFDEF D01S07T00 orl A,#80h .ENDIF .IFDEF D01S08T00 orl B,#01h .ENDIF .IFDEF D01S09T00 orl B,#02h .ENDIF .IFDEF D01S10T00 orl B,#04h .ENDIF .IFDEF D01S11T00 orl B,#08h .ENDIF .IFDEF D01S12T00 orl B,#10h .ENDIF .IFDEF D01S13T00 orl B,#20h .ENDIF .IFDEF D01S14T00 orl B,#40h .ENDIF .IFDEF D01S15T00 orl B,#80h .ENDIF .ENDIF call Mou_i_Ini .IFDEF SD2 .IFDEF D02S00T00 orl A,#01h

Annexes

217

.ENDIF .IFDEF D02S01T00 orl A,#02h .ENDIF .IFDEF D02S02T00 orl A,#04h .ENDIF .IFDEF D02S03T00 orl A,#08h .ENDIF .IFDEF D02S04T00 orl A,#10h .ENDIF .IFDEF D02S05T00 orl A,#20h .ENDIF .IFDEF D02S06T00 orl A,#40h .ENDIF .IFDEF D02S07T00 orl A,#80h .ENDIF .IFDEF D02S08T00 orl B,#01h .ENDIF .IFDEF D02S09T00 orl B,#02h .ENDIF .IFDEF D02S10T00 orl B,#04h .ENDIF .IFDEF D02S11T00 orl B,#08h .ENDIF .IFDEF D02S12T00 orl B,#10h .ENDIF .IFDEF D02S13T00 orl B,#20h .ENDIF .IFDEF D02S14T00 orl B,#40h .ENDIF .IFDEF D02S15T00 orl B,#80h .ENDIF .ENDIF call Mou_i_Ini .IFDEF SD3 .IFDEF D03S00T00 orl A,#01h .ENDIF .IFDEF D03S01T00 orl A,#02h .ENDIF .IFDEF D03S02T00 orl A,#04h

Annexes

218

.ENDIF .IFDEF D03S03T00 orl A,#08h .ENDIF .IFDEF D03S04T00 orl A,#10h .ENDIF .IFDEF D03S05T00 orl A,#20h .ENDIF .IFDEF D03S06T00 orl A,#40h .ENDIF .IFDEF D03S07T00 orl A,#80h .ENDIF .IFDEF D03S08T00 orl B,#01h .ENDIF .IFDEF D03S09T00 orl B,#02h .ENDIF .IFDEF D03S10T00 orl B,#04h .ENDIF .IFDEF D03S11T00 orl B,#08h .ENDIF .IFDEF D03S12T00 orl B,#10h .ENDIF .IFDEF D03S13T00 orl B,#20h .ENDIF .IFDEF D03S14T00 orl B,#40h .ENDIF .IFDEF D03S15T00 orl B,#80h .ENDIF .ENDIF call Mou_i_Ini call FiTrama12 ; es finalitza la trama i s'envia pop PSW pop 01 pop B pop A ret ;------------------------------------------------------------------- enviaDC2: ; Envia informació del segon grup de diagrames d'estat push A push B push 01

Annexes

219

push PSW mov A,#RS232i_DC2 ; es carrega el tipus de trama call IniTrama ; s'inicialitza la trama clr A ; s'esborra l'ACC mov B,A ; i B .IFDEF SD4 .IFDEF D04S00T00 orl A,#01h .ENDIF .IFDEF D04S01T00 orl A,#02h .ENDIF .IFDEF D04S02T00 orl A,#04h .ENDIF .IFDEF D04S03T00 orl A,#08h .ENDIF .IFDEF D04S04T00 orl A,#10h .ENDIF .IFDEF D04S05T00 orl A,#20h .ENDIF .IFDEF D04S06T00 orl A,#40h .ENDIF .IFDEF D04S07T00 orl A,#80h .ENDIF .IFDEF D04S08T00 orl B,#01h .ENDIF .IFDEF D04S09T00 orl B,#02h .ENDIF .IFDEF D04S10T00 orl B,#04h .ENDIF .IFDEF D04S11T00 orl B,#08h .ENDIF .IFDEF D04S12T00 orl B,#10h .ENDIF .IFDEF D04S13T00 orl B,#20h .ENDIF .IFDEF D04S14T00 orl B,#40h .ENDIF .IFDEF D04S15T00 orl B,#80h .ENDIF .ENDIF call Mou_i_Ini

Annexes

220

.IFDEF D05S01T00

.IFDEF SD5 .IFDEF D05S00T00 orl A,#01h .ENDIF

orl A,#02h .ENDIF .IFDEF D05S02T00 orl A,#04h .ENDIF .IFDEF D05S03T00 orl A,#08h .ENDIF .IFDEF D05S04T00 orl A,#10h .ENDIF .IFDEF D05S05T00 orl A,#20h .ENDIF .IFDEF D05S06T00 orl A,#40h .ENDIF .IFDEF D05S07T00 orl A,#80h .ENDIF .IFDEF D05S08T00 orl B,#01h .ENDIF .IFDEF D05S09T00 orl B,#02h .ENDIF .IFDEF D05S10T00 orl B,#04h .ENDIF .IFDEF D05S11T00 orl B,#08h .ENDIF .IFDEF D05S12T00 orl B,#10h .ENDIF .IFDEF D05S13T00 orl B,#20h .ENDIF .IFDEF D05S14T00 orl B,#40h .ENDIF .IFDEF D05S15T00 orl B,#80h .ENDIF .ENDIF call Mou_i_Ini .IFDEF SD6 .IFDEF D06S00T00 orl A,#01h .ENDIF .IFDEF D06S01T00 orl A,#02h

Annexes

221

.ENDIF .IFDEF D06S02T00 orl A,#04h .ENDIF .IFDEF D06S03T00 orl A,#08h .ENDIF .IFDEF D06S04T00 orl A,#10h .ENDIF .IFDEF D06S05T00 orl A,#20h .ENDIF .IFDEF D06S06T00 orl A,#40h .ENDIF .IFDEF D06S07T00 orl A,#80h .ENDIF .IFDEF D06S08T00 orl B,#01h .ENDIF .IFDEF D06S09T00 orl B,#02h .ENDIF .IFDEF D06S10T00 orl B,#04h .ENDIF .IFDEF D06S11T00 orl B,#08h .ENDIF .IFDEF D06S12T00 orl B,#10h .ENDIF .IFDEF D06S13T00 orl B,#20h .ENDIF .IFDEF D06S14T00 orl B,#40h .ENDIF .IFDEF D06S15T00 orl B,#80h .ENDIF .ENDIF call Mou_i_Ini .IFDEF SD7 .IFDEF D07S00T00 orl A,#01h .ENDIF .IFDEF D07S01T00 orl A,#02h .ENDIF .IFDEF D07S02T00 orl A,#04h .ENDIF .IFDEF D07S03T00 orl A,#08h

Annexes

222

.ENDIF .IFDEF D07S04T00 orl A,#10h .ENDIF .IFDEF D07S05T00 orl A,#20h .ENDIF .IFDEF D07S06T00 orl A,#40h .ENDIF .IFDEF D07S07T00 orl A,#80h .ENDIF .IFDEF D07S08T00 orl B,#01h .ENDIF .IFDEF D07S09T00 orl B,#02h .ENDIF .IFDEF D07S10T00 orl B,#04h .ENDIF .IFDEF D07S11T00 orl B,#08h .ENDIF .IFDEF D07S12T00 orl B,#10h .ENDIF .IFDEF D07S13T00 orl B,#20h .ENDIF .IFDEF D07S14T00 orl B,#40h .ENDIF .IFDEF D07S15T00 orl B,#80h .ENDIF .ENDIF call Mou_i_Ini call FiTrama12 pop psw pop 01 pop B pop A ret ;------------------------------------------------------------------- enviaDC3: ; Envia informació del tercer grup de diagrames d'estat push A push B push 01 push PSW mov A,#RS232i_DC3

Annexes

223

call IniTrama clr A mov B,A .IFDEF SD8 .IFDEF D08S00T00 orl A,#01h .ENDIF .IFDEF D08S01T00 orl A,#02h .ENDIF .IFDEF D08S02T00 orl A,#04h .ENDIF .IFDEF D08S03T00 orl A,#08h .ENDIF .IFDEF D08S04T00 orl A,#10h .ENDIF .IFDEF D08S05T00 orl A,#20h .ENDIF .IFDEF D08S06T00 orl A,#40h .ENDIF .IFDEF D08S07T00 orl A,#80h .ENDIF .IFDEF D08S08T00 orl B,#01h .ENDIF .IFDEF D08S09T00 orl B,#02h .ENDIF .IFDEF D08S10T00 orl B,#04h .ENDIF .IFDEF D08S11T00 orl B,#08h .ENDIF .IFDEF D08S12T00 orl B,#10h .ENDIF .IFDEF D08S13T00 orl B,#20h .ENDIF .IFDEF D08S14T00 orl B,#40h .ENDIF .IFDEF D08S15T00 orl B,#80h .ENDIF .ENDIF call Mou_i_Ini .IFDEF SD9 .IFDEF D09S00T00 orl A,#01h

Annexes

224

.ENDIF .IFDEF D09S01T00 orl A,#02h .ENDIF .IFDEF D09S02T00 orl A,#04h .ENDIF .IFDEF D09S03T00 orl A,#08h .ENDIF .IFDEF D09S04T00 orl A,#10h .ENDIF .IFDEF D09S05T00 orl A,#20h .ENDIF .IFDEF D09S06T00 orl A,#40h .ENDIF .IFDEF D09S07T00 orl A,#80h .ENDIF .IFDEF D09S08T00 orl B,#01h .ENDIF .IFDEF D09S09T00 orl B,#02h .ENDIF .IFDEF D09S10T00 orl B,#04h .ENDIF .IFDEF D09S11T00 orl B,#08h .ENDIF .IFDEF D09S12T00 orl B,#10h .ENDIF .IFDEF D09S13T00 orl B,#20h .ENDIF .IFDEF D09S14T00 orl B,#40h .ENDIF .IFDEF D09S15T00 orl B,#80h .ENDIF .ENDIF call Mou_i_Ini .IFDEF SD10 .IFDEF D10S00T00 orl A,#01h .ENDIF .IFDEF D10S01T00 orl A,#02h .ENDIF .IFDEF D10S02T00 orl A,#04h

Annexes

225

.ENDIF .IFDEF D10S03T00 orl A,#08h .ENDIF .IFDEF D10S04T00 orl A,#10h .ENDIF .IFDEF D10S05T00 orl A,#20h .ENDIF .IFDEF D10S06T00 orl A,#40h .ENDIF .IFDEF D10S07T00 orl A,#80h .ENDIF .IFDEF D10S08T00 orl B,#01h .ENDIF .IFDEF D10S09T00 orl B,#02h .ENDIF .IFDEF D10S10T00 orl B,#04h .ENDIF .IFDEF D10S11T00 orl B,#08h .ENDIF .IFDEF D10S12T00 orl B,#10h .ENDIF .IFDEF D10S13T00 orl B,#20h .ENDIF .IFDEF D10S14T00 orl B,#40h .ENDIF .IFDEF D10S15T00 orl B,#80h .ENDIF .ENDIF call Mou_i_Ini .IFDEF SD11 .IFDEF D11S00T00 orl A,#01h .ENDIF .IFDEF D11S01T00 orl A,#02h .ENDIF .IFDEF D11S02T00 orl A,#04h .ENDIF .IFDEF D11S03T00 orl A,#08h .ENDIF .IFDEF D11S04T00 orl A,#10h

Annexes

226

.ENDIF .IFDEF D11S05T00 orl A,#20h .ENDIF .IFDEF D11S06T00 orl A,#40h .ENDIF .IFDEF D11S07T00 orl A,#80h .ENDIF .IFDEF D11S08T00 orl B,#01h .ENDIF .IFDEF D11S09T00 orl B,#02h .ENDIF .IFDEF D11S10T00 orl B,#04h .ENDIF .IFDEF D11S11T00 orl B,#08h .ENDIF .IFDEF D11S12T00 orl B,#10h .ENDIF .IFDEF D11S13T00 orl B,#20h .ENDIF .IFDEF D11S14T00 orl B,#40h .ENDIF .IFDEF D11S15T00 orl B,#80h .ENDIF .ENDIF call Mou_i_Ini call FiTrama12 pop PSW pop 01 pop B pop A ret ;------------------------------------------------------------------- enviaDC4: ; Envia informació del quart grup de diagrames d'estat push A push B push 01 push PSW mov A,#RS232i_DC4 call IniTrama clr A mov B,A

Annexes

227

.IFDEF SD12 .IFDEF D12S00T00 orl A,#01h .ENDIF .IFDEF D12S01T00 orl A,#02h .ENDIF .IFDEF D12S02T00 orl A,#04h .ENDIF .IFDEF D12S03T00 orl A,#08h .ENDIF .IFDEF D12S04T00 orl A,#10h .ENDIF .IFDEF D12S05T00 orl A,#20h .ENDIF .IFDEF D12S06T00 orl A,#40h .ENDIF .IFDEF D12S07T00 orl A,#80h .ENDIF .IFDEF D12S08T00 orl B,#01h .ENDIF .IFDEF D12S09T00 orl B,#02h .ENDIF .IFDEF D12S10T00 orl B,#04h .ENDIF .IFDEF D12S11T00 orl B,#08h .ENDIF .IFDEF D12S12T00 orl B,#10h .ENDIF .IFDEF D12S13T00 orl B,#20h .ENDIF .IFDEF D12S14T00 orl B,#40h .ENDIF .IFDEF D12S15T00 orl B,#80h .ENDIF .ENDIF call Mou_i_Ini .IFDEF SD13 .IFDEF D13S00T00 orl A,#01h .ENDIF .IFDEF D13S01T00 orl A,#02h

Annexes

228

.ENDIF .IFDEF D13S02T00 orl A,#04h .ENDIF .IFDEF D13S03T00 orl A,#08h .ENDIF .IFDEF D13S04T00 orl A,#10h .ENDIF .IFDEF D13S05T00 orl A,#20h .ENDIF .IFDEF D13S06T00 orl A,#40h .ENDIF .IFDEF D13S07T00 orl A,#80h .ENDIF .IFDEF D13S08T00 orl B,#01h .ENDIF .IFDEF D13S09T00 orl B,#02h .ENDIF .IFDEF D13S10T00 orl B,#04h .ENDIF .IFDEF D13S11T00 orl B,#08h .ENDIF .IFDEF D13S12T00 orl B,#10h .ENDIF .IFDEF D13S13T00 orl B,#20h .ENDIF .IFDEF D13S14T00 orl B,#40h .ENDIF .IFDEF D13S15T00 orl B,#80h .ENDIF .ENDIF call Mou_i_Ini .IFDEF SD14 .IFDEF D14S00T00 orl A,#01h .ENDIF .IFDEF D14S01T00 orl A,#02h .ENDIF .IFDEF D14S02T00 orl A,#04h .ENDIF .IFDEF D14S03T00

Annexes

229

orl A,#08h .ENDIF .IFDEF D14S04T00 orl A,#10h .ENDIF .IFDEF D14S05T00 orl A,#20h .ENDIF .IFDEF D14S06T00 orl A,#40h .ENDIF .IFDEF D14S07T00 orl A,#80h .ENDIF .IFDEF D14S08T00 orl B,#01h .ENDIF .IFDEF D14S09T00 orl B,#02h .ENDIF .IFDEF D14S10T00 orl B,#04h .ENDIF .IFDEF D14S11T00 orl B,#08h .ENDIF .IFDEF D14S12T00 orl B,#10h .ENDIF .IFDEF D14S13T00 orl B,#20h .ENDIF .IFDEF D14S14T00 orl B,#40h .ENDIF .IFDEF D14S15T00 orl B,#80h .ENDIF .ENDIF call Mou_i_Ini .IFDEF SD15 .IFDEF D15S00T00 orl A,#01h .ENDIF .IFDEF D15S01T00 orl A,#02h .ENDIF .IFDEF D15S02T00 orl A,#04h .ENDIF .IFDEF D15S03T00 orl A,#08h .ENDIF .IFDEF D15S04T00 orl A,#10h .ENDIF .IFDEF D15S05T00

Annexes

230

orl A,#20h .ENDIF .IFDEF D15S06T00 orl A,#40h .ENDIF .IFDEF D15S07T00 orl A,#80h .ENDIF .IFDEF D15S08T00 orl B,#01h .ENDIF .IFDEF D15S09T00 orl B,#02h .ENDIF .IFDEF D15S10T00 orl B,#04h .ENDIF .IFDEF D15S11T00 orl B,#08h .ENDIF .IFDEF D15S12T00 orl B,#10h .ENDIF .IFDEF D15S13T00 orl B,#20h .ENDIF .IFDEF D15S14T00 orl B,#40h .ENDIF .IFDEF D15S15T00 orl B,#80h .ENDIF .ENDIF call Mou_i_Ini call FiTrama12 pop PSW pop 01 pop B pop A ret ;------------------------------------------------------------------- envia_SD: ; Envia informació dels estats actius dels 16 diagrames mov A,#RS232i_DLE ; A=tipus de trama call IniTrama ; A = paràmetre de la funció IniTrama mov R0,#Sadr ; adreça inicial d'estats actius mov B,#8 ; inicialitza comptador envia_SD_1: mov A,@R0 ; copia a l’ACC l'estat actiu d'un diagrama inc R0 ; s'incrementa el diagrama swap A ; s'intercanvien nibbles orl A,@R0 ; afegeix l'estat actiu d'un segon diagrama mov @R1,A ; es copia l'ACC a la trama inc R0 ; s'incrementa diagrama

Annexes

231

inc R1 ; s'incrementa posició en la trama djnz B,envia_SD_1 ; si comptador b=0, fi del bucle mov @R1,#0 ; caràcter nul, per omplir la trama (9/9) inc R1 ; incrementa punter a trama call FiTrama13 ; finalitza trama i l'envia ret ;------------------------------------------------------------------- env_IOTF: ; Envia info. d’entrades, sortides ,temporitz. i forçats mov A,#RS232i_SO ; A = tipus de trama call IniTrama ; crida a la inicialització de la trama ; ENTRADES mov R0,#Iadr ; adreça inicial d'entrada mov B,#3 ; s'inicialitza comptador a 3 envia_I: mov A,@R0 ; mou by d'entrades corresponent, a l'ACC mov @R1,A ; es mou a la trama inc R0 ; s'incrementa adreça d'entrades inc R1 ; s'incrementa posició en trama djnz B,envia_I ; bucle de 3 cicles ; SORTIDES mov R0,#Oadr ; adreça de sortides mov B,#2 ; només 2 bytes envia_O: mov A,@R0 ; continua igual que amb entrades mov @R1,A inc R0 inc R1 djnz B,envia_O ; TEMPORITZADORS mov R0,#Tadr ; adreça de temporitzadors mov B,#2 ; igual que amb sortides envia_T: mov A,@R0 mov @R1,A inc R0 inc R1 djnz B,envia_T ; FORÇATS mov R0,#Fadr ; adreça de temporitzadors mov B,#2 ; igual que amb sortides envia_F: mov A,@R0 mov @R1,A inc R0 inc R1 djnz B,envia_F call FiTrama13 ; finalitza trama i l'envia ret ;------------------------------------------------------------------- envia_M: ; Envia via RS232 la informació referent a les marques

Annexes

232

mov A,#RS232i_SI call IniTrama mov R0,#Madr mov B,#8 envia_M_1: mov A,@R0 mov @R1,A inc R0 inc R1 djnz B,envia_M_1 mov @R1,#0 ; caràcter nul, per omplir la trama (9/9) inc R1 call FiTrama13 ; finalitza trama i l'envia ret ;------------------------------------------------------------------- IniTrama: ; Capçalera d'una nova trama mov R1,#RS232i_Tbuf ; 1ª posició del buffer de transmissió mov @R1,#RS232i_SOH ; carrega caràcter d'inici de trama inc R1 ; incrementa punter de trama mov @R1,A ; carrega A, que és el paràmetre que conté ; l’indicador de tipus de trama inc R1 ; incrementa punter de trama ret ;------------------------------------------------------------------- FiTrama12: ; Final d'una trama de 12 bytes call CHKSUM ; retorna el valor de chksum a l'ACC mov @R1,A ; es copia a la trama inc R1 ; s'incrementa el punter de trama mov @R1,#RS232i_EOT ; caràcter de final de trama mov A,#12 ; carrega el paràmetre A, amb el nº. de ; bytes de trama call RS232i_Tsnd ; envia trama de 12 bytes ret ;------------------------------------------------------------------- FiTrama13: ; Final d'una trama de 13 bytes call CHKSUM ; retorna el valor de chksum a l'ACC mov @R1,A ; es copia a la trama inc R1 ; s'incrementa el punter de trama mov @R1,#RS232i_EOT ; es copia caràcter de final de trama mov A,#13 ; carrega A, amb el no. de bytes de trama call RS232i_Tsnd ; envia trama de 13 bytes ret ;------------------------------------------------------------------ CHKSUM: ; Calcula i envia el checksum dels bytes de informació push PSW push 00

Annexes

233

mov A,R1 ; carrega l'ACC amb la posició del chksum mov R0,A ; es copia a R0 clr a ; s'inicialitza el chksum CHKSUM_buc: dec R0 ; es decrementa el número de byte add A,@R0 ; se suma el byte corresponent a l'ACC cjne R0,#RS232i_Tbuf+2,CHKSUM_buc ; si cal sumar més, continua ;bucle pop 00 pop PSW ret ;------------------------------------------------------------------- Mou_i_Ini: ; carrega el buffer de transmissió amb 2 bytes d’informació d'un diagrama ; Paràmetres: A: conté la info dels 8 primers estats d’un diag. B: conté la info dels 8 darrers estats d’un diag. mov @R1,A ; carrega l'ACC a la trama (8 primers estats) inc R1 ; s'incrementa el punter de trama mov @R1,B ; carrega B a la trama (8 darrers estats) inc R1 clr A ; s'esborren A mov B,A ; i B pels següents diagrames ret .end

Codi 7.28. Codi en assemblador del fitxer “RS232prj.asm”

Annexes

234

7.5 Annex C: Software generat

Finalment, només resta comentar que tot el software generat s’ha disposat en un CD, juntament amb aquesta memòria (en format PDF).

El software inclou:

• Fitxer d’execució del compilador: “tot.exe”

• Fitxer d’execució del monitoritzador: “projek.exe”

• Fitxers d’interfície amb el port sèrie en llenguatge ‘C':

o “rs232.h”

o “rs232.c”

• Fitxers en codi assemblador:

o Fitxers d’exemple de màquines d’estats

o Fitxers corresponents al tractament de comunicacions pel sistema de monitorització de les màquines d’estats.

Bibliografia

Bibliografia

[1] Llibre: Bernard Odant, “Microcontroladores 8051 y 8052”, Editorial Paraninfo, 1995.

[2] Llibre: Joe Campbell, “C PROGRAMMER’S GUIDE TO SERIAL COMMUNICATIONS”, SAMS Publishing, 1993

[3] Llibre: Ernest Gil Dolcet, “8051 Arquitectura I Programació”, DEEEA, 1995 [4] Pàgina Web. http://www.semiconductors.philips.com [Informació dels µcontroladors

de la família del 80C51], Abril – 2002.

235