Vous êtes sur la page 1sur 123

I.

CARÁTULA

TESIS DE GRADO

EN INGENIERÍA ELECTRÓNICA

PROYECTO DE AUTOMATIZACIÓN DE UNA


CERVECERÍA ARTESANAL

Autores:

Marti, Matías (Leg. Nº 48093)

Rodríguez, Leandro (Leg. Nº 48401)

Profesores:

Amat, Alfonso Ignacio

Muñoz, Claudio Marcelo

Pingitore, Ricardo Alejandro

2012

1
II. AGRADECIMIENTOS

Agradecemos las colaboraciones de los docentes Daniel Jacoby y Miguel Aguirre, quienes han
aportado valiosa información y apoyo en materia técnica, lo que posibilitó el desarrollo del presente
trabajo.
También expresamos nuestro agradecimiento a nuestros padres, quienes han apoyado nuestros
estudios desde sus inicios. Además, a todos nuestros compañeros, amigos, docentes y personal no
docente que ha convivido con nosotros, dentro del instituto, durante estos cinco años.

2
III. ÍNDICE

I. CARÁTULA 1
II. AGRADECIMIENTOS 2
III. ÍNDICE 3
IV. RESUMEN 6
V. INTRODUCCIÓN 7
1. HISTORIA, ANTECEDENTES 7
2. DEFINICIONES Y GLOSARIO DE TÉRMINOS 7
3. JUSTIFICACIÓN DEL PROYECTO 8
4. OBJETIVOS 8
VII. DEFINICIÓN DEL PRODUCTO 9
1. REQUERIMIENTOS DEL SISTEMA 9
1.1. Requerimientos vs. Especificaciones: Casa de Calidad 10
2. ESPECIFICACIONES 11
2.1. Especificaciones del Hardware 11
2.2. Especificaciones del Software 14
VIII. ANÁLISIS DE FACTIBILIDAD 16
1. FACTIBILIDAD TECNOLÓGICA 16
1.1. Propuesta de Alternativas de Diseño 16
1.2. Elección de una Solución 16
1.3. DFMEA 17
2. FACTIBILIDAD DE TIEMPOS 20
2.1. Planificación (PERT) 20
2.2. Simulación de Montecarlo 22
2.3. Diagrama de Gantt 23
3. FACTIBILIDAD ECONÓMICA 26
4. FACTIBILIDAD LEGAL Y RESPONSABILIDAD CIVIL 30
IX. INGENIERÍA DE DETALLE 31
1. HARDWARE 31
1.1. Diagrama de Bloques 31
1.2. Descripción Detallada de Cada Bloque 31
1.3. Detalles de Selección y Cálculo de los Elementos Circuitales de Cada Bloque 33
1.4. Plan de Pruebas de Cada Módulo 37
2. SOFTWARE 37
2.1. Diagrama de Estados y Flujogramas 38
2.2. Análisis de Complejidad 38

3
2.3. Descripción de Subrutinas 39
2.4. Listados Comentados del Código 42
2.5. Plan de Prueba de Módulos y de Depuración de Soft 68
X. CONTRUCCIÓN DEL PROTOTIPO 69
1. DEFINICIÓN DE LOS MÓDULOS 69
1.1. Gabinete 69
1.2. Placas impresas con sus componentes 69
1.3. Circuito de alimentación 70
1.4. Módulo de censado de temperatura 70
2. DISEÑO DE LOS CIRCUITOS IMPRESOS 70
3. DISEÑO MECÁNICO 73
4. DETALLES DE CONSTRUCCIÓN Y PRECAUCIONES DE MONTAJE 74
XI. VALIDACIÓN DEL PROTOTIPO 76
1. VALIDACIÓN DEL HARD 76
1.1. Plan y protocolos especiales de medición 76
1.2. Medidas 77
1.3. Evaluación 86
1.4. Resultados 87
2. VALIDACIÓN DEL SOFT 87
XII. ESTUDIOS DE CONFIABILIDAD DE HARD Y SOFT 88
1. CONFIABILIDAD DE HARDWARE 88
2. CONFIABILIDAD DE SOFTWARE 89
XIII. CONCLUSIONES 91
1. EXCELENCIAS Y OBJETIVOS ALCANZADOS 91
2. FALLOS Y RECOMENDACIONES PARA FUTUROS DISEÑOS 91
XIV. ANEXOS 92
1. ANÁLISIS COMPLETO DE FIABILIDAD 92
2. LISTADO DE COMPONENTES Y SUS COSTOS 93
2.1. Componentes del equipo: 93
2.2. Componentes de la placa lógica 94
2.3. Componentes de la placa de potencia: 95
2.4. Componentes utilizados para los termómetros: 95
2.5. Accesorios para automatizar la instalación: 96
2.6. Valor de las instalaciones: 96
2.7. Insumos utilizados para la fabricación de cerveza para validar el prototipo: 97
3. SOFTWARE COMPLETO 97
3.1. Archivo main.c 97

4
3.2. Archivo usr_entry.c 98
3.3. Archivo SystemInit.c 99
3.4. Archivo display.c 106
3.5. Archivo Temperatura.c 108
3.6. Archivo botones.c 112
3.7. Archivo Salida.c 112
3.8. Archivo Ejemplo_sistema.c 115
3.9. Archivo JM128_Bootloader.h 115
3.10. Archivo display.h 115
3.11. Archivo Temperatura.h 116
3.12. Archivo maindefs.h 116
3.13. Archivo botones.h 116
3.14. Archivo Salida.h 117
3.15. Archivo Proceso.h 118
4. ESQUEMÁTICOS 121
XV. BIBLIOGRAFÍA 123
1. Hojas de datos 123
2. Información acerca de la elaboración de cerveza 123
3. Libros 123

5
IV. RESUMEN

El presente trabajo describe el diseño, desarrollo y puesta en marcha del prototipo de un


proyecto electrónico. En este caso, se trata de un aparato capaz de controlar bombas, válvulas,
motores, etc. que permitirán automatizar una planta productora de cerveza artesanal, tanto a nivel
casero como para el caso de una PyME. Se trata de buscar una solución a la problemática que
implica el tiempo elevado que el maestro cervecero debe dedicar a la hora de elaborar una tanda (o
batch) de cerveza. El sistema tiene una alta capacidad de adaptación para distintas instalaciones
productivas disponibles, con diferentes capacidades (desde 20 litros hasta varios cientos de litros
por batch).
Se logró la implementación de una planta productora automatizada, a partir de elementos
disponibles, con la que se elaboró una tanda de 50 litros de cerveza. De esta forma, pudo validarse
correctamente el prototipo construido, con resultados muy buenos.

6
V. INTRODUCCIÓN
1. HISTORIA, ANTECEDENTES

La producción de cerveza artesanal, tanto a nivel industrial como hogareño, implica una
participación activa y constante por parte del productor en todo el lapso de producción de un batch (ver
glosario de términos), el cual puede durar desde unas 5 horas, hasta más de 10 horas, dependiendo de la
receta y del estilo elegidos. El maestro cervecero debe realizar mediciones de densidad, tiempos y
temperatura constantemente, de modo de llevar un control de su producción, ya que estos parámetros son
los indicativos del estado del proceso.

2. DEFINICIONES Y GLOSARIO DE TÉRMINOS

 Batch: partida o “tanda” correspondiente a un proceso completo de producción.


 Maceración: parte del proceso de producción de cerveza, que consiste en una infusión de agua
caliente con la malta molida, y tiene por finalidad disolver los azúcares fermentables contenidos
en la malta.
 Malta: se utiliza coloquialmente este término para designar al grano de cebada, que ha recibido un
proceso de malteado. Éste consiste en la germinación parcial del grano, y su posterior secado,
permitiendo que el almidón contenido en la cebada se transforme en distintos tipos de azúcares
fermentables. Existen distintos tipos de maltas, y se clasifican según su color, dado por su nivel
de tostado, que determinará el aspecto cromático del producto final.
 Fermentación: parte del proceso de producción de la cerveza, que consiste en la transformación de
azúcar en alcohol y dióxido de carbono, reacción química que producen las levaduras.
 Lúpulo: término que se refiere a la planta humulus lupulus, de la cual se utiliza su flor hembra
como aditivo en la elaboración de cerveza. Ésta le brinda aroma y amargor a la bebida.
 Cocción/Hervido: proceso de cocción del mosto que sirve para solubilizar ciertos sólidos,
estabilizar el mosto y aumentar la densidad del mismo. Es durante este proceso cuando se
incorporan algunos de los aditivos, entre ellos, lúpulo y clarificante.
 Levadura: es un organismo unicelular, que transforma las moléculas de azúcar en alcohol y dióxido
de carbono, en una reacción exotérmica (libera energía en forma de calor). Es un ingrediente que
le aporta muchas características particulares a la cerveza. Se clasifican en tres grandes grupos:
Ale (fermentación a temperatura alta), Lager (fermentación a temperatura baja) e Híbridas
(típicas de las cervezas de trigo).
 Atenuación: es una característica del tipo de levadura utilizada, y se refiere al porcentaje de azúcar
que una cepa de levadura puede convertir en alcohol. Se distinguen tres niveles de atenuación
(alta, media y baja), que determinarán el cuerpo y la graduación alcohólica del producto final.
 Acción: se definirá una acción como un evento concreto (como encender o apagar una bomba,
válvula, etc.) que comenzará cuando haya finalizado la acción anterior, y terminará cuando se
haya cumplida cierta condición (por ejemplo, cuando se alcance una dada temperatura, o haya
pasado un determinado tiempo).
 Polling: modelo de programación en el que se basa una máquina de estados. El programa verifica
periódicamente se ha ocurrido un evento. En caso afirmativo, actúa en consecuencia. En caso
negativo, continúa verificando la ocurrencia de eventos, en forma circular.

7
3. JUSTIFICACIÓN DEL PROYECTO

Este proyecto busca automatizar el proceso de producción de cerveza artesanal, con el mínimo
costo posible. Con este producto, el maestro cervecero podrá optimizar su tiempo, ya que el sistema,
programado e instalado adecuadamente, realizará la mayoría de las actividades que antes debían
realizarse manualmente. El módulo tendrá un sistema de alarmas que le avisará al productor cuándo debe
prestar atención, tomar una medición de densidad, incorporar aditivos, etc.

4. OBJETIVOS

Diseñar y construir el prototipo de un sistema de automatización de una cervecería artesanal. El


control electrónico sobre el proceso permitirá optimizar el rendimiento de la materia prima utilizada,
mejorar la calidad del producto final, gracias al control sobre temperaturas y tiempos del proceso, y
minimizar el personal necesario para efectuar la producción. Además, se logrará un nivel de producción
homogéneo, reduciendo al mínimo las posibles variaciones entre distintos batchs de una misma receta.

8
VII. DEFINICIÓN DEL PRODUCTO

Con el fin de determinar las especificaciones que tendrá el proyecto, se buscaron cuáles son los
requerimientos que le interesan a un potencial cliente. Para este fin, se realizó un estudio de mercado muy
breve, pero efectivo. Se optó por interrogar a unos pocos distribuidores de productos y equipamientos
para cervecerías artesanales. Este estudio ignora la opinión del cliente final, pero se basa en un punto de
vista muy valioso, ya que los distribuidores consultados son proveedores de nuestros potenciales clientes,
por lo que conocen muy bien sus gustos y preferencias, y también tienen un dominio consistente del
mercado que manejan. Se les envió un mail comentando brevemente la idea del proyecto, y pidiendo
sugerencias, basadas en su experiencia y conocimiento del mercado. La respuesta fue muy positiva, ya
que la mayoría de los distribuidores que respondieron se mostraron interesados en la idea. Las
conclusiones más relevantes que se obtuvieron fueron las siguientes:

 A nivel artesanal, para pequeñas productoras de cerveza artesanal, no existe en el país un producto
similar. (Obviamente, las grandes cervecerías sí están automatizadas, pero no forman parte del
target considerado en este proyecto).
 El requerimiento más importante se encuentra en el precio. El producto más parecido que se puede
conseguir es un controlador que maneja únicamente curvas de maceración programables. Este
atributo sería solamente una parte de nuestro proyecto. En este sentido, se propone como meta, a
nivel económico, igualar el precio de venta de este producto ofreciendo, como valor agregado,
muchas más prestaciones. Este controlador se vende por 520 dólares. Si se logra un costo de
producción que no supere los 300 dólares, se podría vender el producto al mismo precio, con un
margen de ganancia de poco más del 40%.
 Resultaría atractivo incorporar (fue una de las sugerencias más interesantes) un caudalímetro o
algún sensor que sea capaz de medir, directa o indirectamente, los volúmenes de líquidos dentro
de los recipientes. En función de los costos y alternativas, se evaluará esta posibilidad como un
agregado, ya que un sensor de caudal resultaría muy caro, contradiciendo el requerimiento
fundamental de un precio bajo.

Procedemos, entonces, a definir los requerimientos del sistema.

1. REQUERIMIENTOS DEL SISTEMA

 Se deberá implementar una alarma sonora y visual que se active en caso de alguna falla, o lectura
anormal de algún sensor, o cuando se requiera la atención del usuario.

 En todo momento, se deberá poder habilitar el control manual para corregir cualquier desperfecto o
anomalía, en caso de emergencia, por ejemplo, por un corte de luz.

 El sistema deberá poder manejar una cantidad considerable de periféricos (válvulas, bombas,
sensores de temperatura, etc.).

 La interconexión con los periféricos deberá ser sencilla, dando un margen mínimo para errores
humanos de conexión. Los cables deberán tener la menor cantidad de líneas posible, para que los
conectores sean simples.

 El módulo principal tendrá una corriente de salida necesaria para manejar circuitos de relé de
estado sólido (triacs), que a su vez controlarán periféricos que se alimentan de la red eléctrica
(bombas, electroválvulas, etc.).

9
 Los periféricos deben poder ubicarse razonablemente lejos del módulo principal, conectados por
cables sencillos, según las dimensiones de la planta productora, sin que las señales se vean
distorsionadas como para dar lugar a fallas en el control.

 El módulo principal deberá adaptarse para poder controlar varios periféricos al mismo tiempo, en
el caso de que se tenga una cervecería con varios fermentadores, por ejemplo.

 El módulo principal contará con una pequeña pantalla que indique temperaturas censadas, estado
del proceso, alarmas o fallas, etc. Tendrá la cantidad mínima e indispensable de botones. Todas
las configuraciones se harán previamente al proceso.

 El sistema tendrá un programa de producción por defecto, el cual podrá ser modificado mediante
una interfaz simple que permita programar el proceso desde una PC.

 El módulo principal solamente hará los cálculos y manejará las señales de control necesarias,
mientras muestra el estado del proceso en la pantalla LCD.

 El microprocesador requerirá una memoria no volátil para almacenar el programa y sus


parámetros. Necesitará además guardar datos históricos de curvas de temperatura, tiempos, etc.,
por lo que deberá incorporar memoria flash para este fin, o tener la posibilidad de interconexión
con una memoria externa del mismo tipo.

 El gabinete tendrá que afirmarse correctamente a la superficie de apoyo que lo sostenga.

 Todo el sistema electrónico tendrá que consumir la menor cantidad de potencia posible.

 El costo de todo el sistema deberá minimizarse, en la medida de lo posible.

1.1. Requerimientos vs. Especificaciones: Casa de Calidad

Una herramienta fundamental para poder organizar y cumplir los requerimientos del cliente es la
casa de calidad. Esta nos permite saber cómo estamos parados frente a los mismos y como está la
competencia respecto a éstos también. A continuación se desarrolla la misma.

10
Fig.1. Casa de calidad

2. ESPECIFICACIONES

2.1. Especificaciones del Hardware

Del módulo principal:

 Sus dimensiones serán acordes a la necesidad de inclusión de enchufes para controlar los distintos
periféricos y dimensión de las placas, pero deberá ser portable. Por lo tanto, se acotarán sus
dimensiones de la siguiente forma: alto máximo: 10cm +/- 5cm, largo máximo: 40cm +/- 10cm,
profundidad máxima: 30cm +/- 10cm.

11
 Por ser un elemento preparado para permanecer fijo sobre, por ejemplo, un escritorio, no es
necesario que sea extremadamente liviano. Se acotará su peso máximo en 10Kg +/- 5Kg , de
modo que pueda moverse con comodidad.
 Los enchufes de interconexión con los periféricos serán hembras, y se ubicarán de la siguiente
forma: la mitad en la parte posterior y la otra mitad en la parte anterior del módulo. El conector
será una bornera doble por cada salida (vivo y neutro).
 En la parte superior, se ubicará una pequeña pantalla capaz de mostrar caracteres ASCII, indicando
el estado del proceso, temperaturas, etc. La pantalla estará orientada en la parte superior
izquierda del gabinete. Además, sobre el gabinete habrá botones de control, para, por ejemplo,
aceptar alguna orden del sistema. También habrá leds de distintos colores para indicar: equipo
encendido, salidas encendidas, aparición de alarmas, etc.
 La fuente de alimentación será interna, del tipo lineal, para minimizar la complejidad técnica. La
tensión se convertirá a 5V +/- 0,1V de continua, es decir, con un ripple máximo de 100mV, de
modo tal que garantice el correcto funcionamiento del microprocesador, y deberá entregar una
corriente de al menos 300 mA para alimentar al control electrónico, al microprocesador, a los
sensores de temperatura, a la pantalla, led de encendido, etc.
 Habrá una segunda fuente de alimentación de 5V +/- 0,2V, que se encargará de alimentar a los
optoacopladores (optotriacs utilizados para drivear los triacs de potencia) y los leds indicativos
de control de periféricos. El ripple de salida de ésta no es relevante (se acepta hasta 0,2V de
ripple máximo). La corriente de salida deberá ser de al menos 600mA, asumiendo que se active
la totalidad de las salidas al mismo tiempo.
 El sistema contará con, al menos, un enchufe hembra USB, que permita conectar el módulo a una
PC.
 En cuanto a las salidas para conectar periféricos, se colocarán 24 salidas controladas por triacs
(para manejar bombas de agua de 220V, electroválvulas, etc., con la posibilidad de entregar
hasta 2A por salida, es decir, hasta 440W de potencia). Además, habrá 14 salidas (todas
conectadas internamente, con conectores especiales polarizados para facilitar el conexionado)
con protocolo “1-Wire” para conectar los termómetros digitales (por limitaciones del protocolo
elegido, se pueden manipular hasta 255 termómetros simultáneamente, lo cual excede
ampliamente las necesidades mínimas). Esta cantidad de salidas excede el uso normal necesario
en un proceso estándar. No obstante, se elige la mencionada cantidad de salidas para posibles
extensiones futuras. Todas las salidas serán programables, y accesibles al usuario.

En conclusión, a partir de las especificaciones previas, se pueden resumir las características del
equipo en la siguiente lista:

 Dimensiones del equipo: alto: 4,5cm. +/-0,5cm.; largo: 35cm. +/- 0,5cm.; profundidad: 17cm. +/-
0,5cm.

 Fuente: lineal, con transformador de 9VAC de salida, rectificada y filtrada, con capacidad para
entregar 1,5A efectivos. Esto alimentará reguladores de tensión para obtener 5VDC +/-
0,05VDC.

 Interfaz con el usuario: se utilizará un display LCD armado de 16x2 caracteres. Habrá un led de
encendido del equipo (rojo). Habrá 7 botones: 4 para direcciones (arriba, abajo, derecha,
izquierda), 1 de MENU, uno de ENTRAR, y uno para controlar la luz de la pantalla LCD.
Además, habrá 24 borneras numeradas, cada una con su led de encendido, y 14 conectores para
termómetros.

12
Del microprocesador:

 Interfaz con protocolo USB incorporado.


 Memoria flash interna de por lo menos 100 KB.
 Real Time Counter incorporado.
 Deberá tener al menos tres puertos de 8 bits para controlar a los periféricos de potencia (bombas,
válvulas, etc.). Además, se requieren: 11 pines para control LCD (8 de datos y 3 de control), 2
pines para alarma sonora y luz del LCD, 7 pines para entrada de botones, 1 pin para
termómetros, 2 pines de programación inicial, 2 pines para el oscilador, y 1 pin para activar
programación por USB. Esto da un mínimo de 50 pines de I/O. Además, con vistas a mejoras
futuras, se da un margen de 3 entradas extra para aplicaciones futuras (esto evitará futuros
rediseños de la placa en caso de que se quiera mejorar las prestaciones del equipo).
De los sensores de temperatura:

 Deberán tener una precisión de al menos 1ºC.


 Salida digital, para evitar el uso de conversores AD. Por lo tanto, harán la conversión internamente.
 Se utilizarán sensores de silicio (integrados), con salida digital en una sola línea, para minimizar la
cantidad de líneas en los cables de conexión.
 Manejarán un protocolo de comunicación con el microprocesador tipo serial, siendo el micro el
master, y los sensores los esclavos, de forma que se puedan conectar varios sensores a un solo
pin de entrada. Cabe destacar que, por ser la temperatura una magnitud que varía lentamente en
el tiempo (en el orden de los segundos), no resulta crítico el tiempo de conversión o de respuesta
del sensor. Alcanza con que se logre un tiempo de respuesta menor a los 3 segundos.
 Deberán recubrirse, junto con el primer tramo del cable de conexión, de manera tal de lograr
impermeabilidad, para que pueda sumergirse en medios líquidos. La cobertura deberá garantizar
que no ingrese agua a las conexiones con los cables, y deberá presentar la menor resistencia
térmica posible para que la temperatura censada sea coincidente con la temperatura real del
medio líquido.
 Los cables de interconexión tendrán 3 líneas: una de tierra (GND), una de alimentación (VDD), y
una de datos (DATA).
 El rango de temperatura mínimo que deberán manejar se comprende entre 0ºC y 110ºC.
De los cables

 El cable de alimentación del equipo para la red eléctrica será de 3 patas, haciendo una conexión
apropiada a masa de todo el gabinete, como se establece en las normativas vigentes de seguridad
eléctrica.
 Los cables de interconexión con los periféricos serán de un solo recubrimiento, albergando en su
interior la cantidad de líneas de cobre necesarias según la potencia consumida por el periférico.
 Los cables de censado de temperatura tendrán que soportar temperaturas de hasta 100ºC, al igual
que el material utilizado para su cobertura de sellado contra líquidos.
 El cable USB se comprará armado.

13
Otras consideraciones y aclaraciones

 El tipo de bombas y válvulas a utilizar será acorde al nivel productivo de la planta. Su elección y
cálculo queda fuera de los límites de este diseño. El sistema controlará switches de encendido y
apagado (relés de estado sólido, con triacs) de las mismas, únicamente.
 El largo de los cables será variable según la distancia entre el periférico y el módulo principal.
Dicha distancia depende de la disposición de los elementos en la planta. En el prototipo se
utilizará el largo adecuado al caso concreto.
 Se asume que el cliente ya posee una instalación capaz de producir cerveza. Este diseño tiene la
intención de automatizarlo, pero no de diseñar el proceso. Por esta razón, la elección de ollas,
fermentadores, maduradores, quemadores, etc., queda fuera de los límites de este diseño. Para el
prototipo se utilizarán los elementos necesarios para demostrar el funcionamiento del sistema.
 Según el tamaño de los contenedores (ollas, fermentadores, etc.), se podrá colocar más de un
sensor de temperatura por contenedor, para mejorar la precisión de la medición de la temperatura
media, considerando distintos puntos.
 Resultaría deseable poder fijar una cota máxima para el costo total del sistema en US$ 300.

2.2. Especificaciones del Software

 Se escribirá en lenguaje C/C++, para que resulte independiente del microcontrolador a


utilizar.
 Será modular, con el fin de facilitar su seguimiento, debugueo, corrección de errores, y para
garantizar un resultado ordenado.
 Se escribirán todos los drivers que controlarán las señales de control de los periféricos, así
como también el driver de comunicación con el display LCD, y los termómetros de
temperatura con protocolo “one-wire”.
 Todos los drivers serán probados antes de incluirlos en el programa principal, para evitar
errores de bajo nivel.
 El dispositivo LCD seleccionado se controlará con tres líneas de control y ocho líneas de
datos. El protocolo de comunicación de escribirá con los datos técnicos proporcionados en
la hoja de datos del fabricante.
 El protocolo “one-wire” utilizado por los sensores de temperatura seleccionados será escrito
según la información técnica proporcionada por la hoja de datos del fabricante del integrado.
 Los tiempos de escritura en el display no serán un problema para el correcto funcionamiento
del equipo, ya que solamente se escribirán líneas completas en forma ocasional.
 Los tiempos de lectura de los sensores de temperatura podrían dificultar la fluidez del
programa principal. Por este motivo, la lectura de los sensores de temperatura se hará por
pedido explícito del usuario, y midiendo una sola temperatura a la vez. Del mismo modo,
durante el proceso, solamente se leerá la temperatura del sensor que sea pertinente a la etapa
actual del proceso.
 Se definirán una serie de acciones (ver glosario de términos) secuenciales para avanzar en el
desarrollo del proceso de producción. Una acción comenzará cuando se haya cumplido la
condición de finalización de la acción anterior. Las condiciones de finalización pueden estar
dadas por tiempo (en segundos), por temperatura, o por una intervención manual del

14
usuario. Esta condición de secuencialidad resulta más que suficiente para efectuar un
proceso completo de producción, así como también de lavado del equipo, o de fermentación,
permitiendo buenas prestaciones con una dificultad mínima a la hora de diseñar el
programa.
 Las acciones correspondientes al proceso podrán depender de parámetros propios de cada
receta. Así, por ejemplo, una receta tendrá una curva de maceración con 3 mesetas de 30
minutos, y otra receta tendrá una sola meseta a una sola temperatura. Las acciones serán las
mismas, pero cambiarán las condiciones de finalización, valores de temperatura, etc. De este
modo, con un mismo equipo, programado con la misma serie de acciones, se podrán realizar
distintas recetas de cerveza.

15
VIII. ANÁLISIS DE FACTIBILIDAD

1. FACTIBILIDAD TECNOLÓGICA

Se utilizarán componentes estándar, de montaje superficial para el caso del microprocesador, y


algunas resistencias. El prototipo podrá hacerse con componentes discretos con pines comunes. Se
utilizarán triacs (encapsulado TO220), optotriacs (encapsulado DIP6) y borneras para la placa de
potencia.

Para el caso de los sensores de temperatura, se optará por el uso de sensores DS18S20, que tienen
salida digital de una sola línea, y una precisión de 0,5ºC. Las electroválvulas compatibles con este diseño
utilizarán 220V de alimentación. El sistema está pensado para utilizar válvulas económicas del estilo de
un lavarropas. En cuanto a las bombas, serán con motores de inducción monofásicos, de hasta 40W, como
las utilizadas en lavarropas u otros electrodomésticos similares (de todos modos, las salidas serán
diseñadas para soportar cargas de hasta 440W, si la instalación requiriera de bombas u otros motores de
mayor potencia).

En suma, todos los componentes del proyecto se consiguen actualmente en el mercado nacional,
por lo que su adquisición es factible. Los periféricos, se recuerda, no se incluyen como parte del proyecto,
aunque también son fácilmente adquiribles, existiendo versiones de bajo costo, lo cual cumple con uno de
los objetivos primordiales del presente diseño.

1.1. Propuesta de Alternativas de Diseño

Como algunos agregados opcionales, se puede mencionar un sistema de enfriamiento con celdas
Peltier, para favorecer y acelerar el proceso de enfriado, y para controlar adecuadamente la temperatura
de fermentación. También resultaría factible diseñar un sistema de agregado automático de lúpulo, a
partir de un contenedor dividido (en al menos 4 compartimientos) con una compuerta independiente para
cada división, que se abra en el momento indicado, independizando así al usuario de maniobras manuales
durante el hervor. Otro agregado interesante sería un sistema de llenado automático, con corte electrónico,
tanto para la cerveza fermentada, como para el adicionado de azúcar (en forma de almíbar, para permitir
gasificación natural en botella).

Como alternativa al diseño de salidas con triacs, se consideró la posibilidad de utilizar relés
(contactores) con bobinas. Esto otorgaría mayor versatilidad al equipo (por ejemplo, para manejar
tensiones distintas a las de la red eléctrica).

1.2. Elección de una Solución

Todas las alternativas de diseño quedarán condicionadas al tiempo y recursos disponibles. El


presupuesto especificado no contempla los agregados opcionales propuestos. El producto mínimo será el
del módulo principal, junto con los periféricos que requiera el prototipo para demostrar el funcionamiento
del sistema en un proceso de fabricación real de cerveza.

En cuanto a la elección concreta de la tecnología de salidas de potencia, se optó por el uso de


triacs, controlados por optotriacs con detector de cruce por cero (de la tensión de línea). La opción de los
relés con bobina se puso en práctica y se realizaron pruebas. El resultado no fue favorable, ya que se

16
percibían reseteos ocasionales del microcontrolador, debido a picos de tensión en la alimentación durante
la conmutación de los relés. Se midió la amplitud de estos picos (que superaban los 10V pico, en la
alimentación de la placa lógica de 5V), y su frecuencia de transitorio (que oscilaba entre los 20MHz y
40MHz). Esta frecuencia puso en evidencia la naturaleza de este ruido de conmutación, de carácter
electromagnético. Además, como el problema se presentaba ocasionalmente, se determinó que su
aparición dependía de la tensión instantánea de la red eléctrica. Así, el pico de ruido aumentaba cuando la
tensión de 220VAC (50Hz) se encontraba cerca de un pico. Por este motivo, se determinó que la solución
sería un rediseño completo de ambas placas, si se seguían utilizando los relés con bobina. En cambio, se
optó por el uso de triacs con detector de cruce por cero, garantizando, de este modo, que la conmutación
se diera con tensión nula (o muy baja), eliminando el problema. Además, se cuenta con la ventaja de que
no aparece el típico ruido de conmutación de los contactos del relé. Este cambio no implica variaciones
considerables en el costo del equipo. En contraparte, se reduce la capacidad de entregar altos valores de
corriente por cada salida.

En cuanto a las fallas que se experimentaron utilizando relés de conmutación por bobina, se
pueden mencionar los siguientes hechos. La falla (evidenciada por un reseteo del microcontrolador) se da
cuando el relé se activa con sus bornes conectados a la línea (220VAC), y una carga (aunque sea mínima)
que haga circular una corriente. Entre las cargas que presentaron inconvenientes, se pueden mencionar:
motores, válvulas, un capacitor de 10nF, un varistor de 400V (incluso la mínima corriente de pérdida de
un varistor generaba reseteos). Cuando el relé no tenía ninguna carga en sus bornes, la conmutación no
traía inconvenientes. Tampoco se generaban reseteos cuando se desonectaba la tensión de línea del relé.
Esto puso en evidencia el carácter electromagnético del problema, descartando la posibilidad de
considerar a la bobina del relé como origen de la falla (la cual se conectó a un diodo de free-wheeling
disponible en el integrado ULN2003 que se utilizaba como driver).

Como recomendaciones para futuros diseños con relés controlados por microcontrolador, se
sugiere tratar de evitar este tipo de circuitos cuando no posean algún detector de cruce por cero de la
tensión o corriente de línea. Es posible que un mejoramiento en el diseño del circuito integrado y una
redistribución inteligente de las pistas pueda reducir el problema. No obstante, por la característica
electromagnética del ruido, resulta muy difícil generar un diseño que carezca de riesgos de fallas
utilizando este método. Algunos microcontroladores (el utilizado en este proyecto incluído) tienen un
circuito que monitorea la tensión de entrada y genera un reset si la misma cae por debajo de cierto valor.
Se probó deshabilitando (mediante la escritura de un registro) este circuito, pero la falla persistió, lo cual
sugiere que el pico de tensión era lo suficientemente importante como para apagar todos los circuitos del
micro. De hecho, se midió la tensión de alimentación (5VDC) durante la conmutación, y se observaron
picos que superaban los 10Vpp (incluyendo picos negativos, es decir, que invertían la polaridad de
alimentación, de hasta -5V), con un transitorio de estabilización que presentaba una frecuencia que
variaba entre 20MHz y 40MHz. Se puede afirmar que, al menos el microprocesador MCF51JM128 no
tolera este nivel de variaciones en su alimentación. También se sugiere, para estos circuitos, incorporar
algún tipo de snubber (por ejemplo, un RC serie en paralelo a la carga) para disminuir la amplitud de este
ruido.

1.3. DFMEA

A continuación, se realiza un estudio de los modos posibles de falla mediante el siguiente D-


FMEA:

17
Ítem Modo de S1 O1 Causas Control de Control de D1 R Acciones
falla prevención detección P recomendadas
N
Módulo No 8 2 Corte de Controlar Led de 1 16 Prever esta
principal enciende luz que siempre encendido situación en
esté todo momento
habilitado el y dejar
control habilitado el
manual del control manual
proceso
No 8 1 Daño de Diseñar para Led de 1 8 Diseñar la
enciende la fuente el peor caso encendido fuente de
de de consumo manera robusta,
alimenta- de corriente y que sea capaz
ción de entregar la
corriente
máxima que
pueda consumir
el sistema
No 6 1 Mala Revisar Vista de 1 6 Revisar las
enciende conexión conexión de caracteres en conexiones
la o la pantalla pantalla internas y
pantalla configura configuraciones
ción
Falla en 6 3 Daño de Controlar el No respuesta 3 54 Realizar
un la ficha correcto de un pruebas de
puerto hembra o funciona- periférico todos los
de salida de miento de puertos una vez
circuitos todos los armada la placa
internos puertos en el
prototipo
Microproce- Señales 8 5 Errores Realizar Mediante 6 24 Debuguear
sador distintas de debugueos mediciones de 0 todos los
a las programa de cada señales módulos, y
progra- ción módulo del generar
madas programa programas de
prueba cuando
hagan falta
Señales 8 1 Errores Revisar el Mediante 6 48 Medir
distintas de ruteo ruteo y las mediciones de continuidad de
a las y soldaduras señales los pines más
progra- soldadura críticos,
madas de la buscando
placa cortocircuitos y
conexiones
Sensores de No hay 6 3 Falla en Conectar Medición de la 5 90 Medir la
temperatura señal del el cable correctament señal de salida funcionalidad
sensor de e las líneas, del sensor de todos los

18
alimenta- y sellar muy sensores antes
ción bien para de utilizarlos
termómetros
sumergibles
Valor 6 2 Desper- Revisar los Medición de 5 60 Realizar un
medido fecto integrados un cambio programa
sin interno antes de muy brusco de optativo de
sentido del utilizarlos temperatura, o inicio que
sensor incoherente controle el
con la estado de los
sensación del termómetros
tacto digitales
Valor 2 3 Calibra- Calibrar Observación 4 24 Calibrar los
medido ción todos los de los valores sensores
con incorrec- sensores medidos previamente a
offset ta su conexión con
el sistema
Periféricos El 7 2 Mal Verificar No respuesta 2 28 Permitir el
(bombas, periféri- funciona- funciona- de un control manual
válvulas etc.) co no miento miento de periférico de cada salida
responde del cada para permitir el
dispositi- dispositivo chequeo de
vo que se conectado al todos los
desea equipo periféricos.
controlar
El 4 1 Falla en Verificar el El dispositivo 3 12 Verificar el
periféri- el estado de no se apaga, y correcto
co no se circuito todos los se enciende funcionamiento
apaga de triacs de solo al de cada salida,
cuando potencia potencia conectar el con carga
corres- de la equipo conectada. No
ponde salida en sobrecargar las
cuestión, salidas
con el exigiendo
triac mayor corriente
siempre que la permitida
cerrado
Cables de No hay 4 4 Rotura de Verificar el Medición de 2 32 Verificar el
interconexión señal una línea estado de los continuidad y estado de todos
del cable cables respuesta de los cables antes
los sistemas de iniciar el
proceso. Habrá
un programa
opcional de
inicio que
verifique
señales

Tabla 1. DFMEA

19
Se observa que las fallas a las que se le deberá prestar más atención son a los errores de
programación, y a la interconexión con los sensores. Para solucionar estos problemas, resultará crucial
realizar pruebas periódicas durante el diseño y el armado del prototipo, midiendo todas las señales
posibles, y debugueando el programa con pruebas y ejemplos simples.

Además, se producen fallas relativamente graves si hay fallas que perturben las mediciones (fallas
de un sensor, o de un puerto de salida). Esto tiene sentido, ya que el funcionamiento de todo el sistema se
basa en mediciones, y en el procesamiento de dichas mediciones para definir tareas de los actuadores.
Entonces, resultará imprescindible testear el correcto funcionamiento de todos los sensores utilizados en
el diseño, así como de todos los puertos de entrada y salida del sistema. Además, se implementará un
sistema de repetición de una misma medición, antes de tomarla como válida.

2. FACTIBILIDAD DE TIEMPOS

2.1. Planificación (PERT)

Para comenzar, debemos definir las tareas asociadas al presente proyecto:

Tareas (tareas precedentes):

1. Realizar estudio de mercado


2. Definición de requerimientos y especificaciones (1)
3. Estudio de factibilidad, modos de falla y casa de calidad (1)
4. Investigación de sensores y actuadores a controlar
5. Definición de interfases y modos de conexión (2,3,4)
6. Elección del microprocesador y armado de placa de desarrollo para realizar pruebas (4)
7. Diseñar e implementar programas de prueba para conectar micro y sensores y actuadores (4,5,6)
8. Diseño de placa final (6)
9. Soldado de placa final (7,8)
10. Pruebas de funcionamiento (9)
11. Diseño y armado de gabinete (8)
12. Pruebas finales (10,11)
13. Prueba en planta del prototipo armado (12)

Como el proyecto presenta la dificultad de incluir tareas nunca antes realizadas, se deberán estimar
los tiempos de cada tarea estadísticamente. A continuación, se determinarán los tiempos esperados,
optimistas y pesimistas para cada una de las tareas mencionadas.

Aclaración: los tiempos se miden en semanas de trabajo.

20
Tarea Precedentes Tiempo Tiempo Tiempo Promedio Desvío
optimista esperado pesimista

1 1 2 3 2 0,33
2 1 1 1 2 1,16 0,16
3 1 1 1 2 1,16 0,16
4 2 3 5 3,16 0,5
5 2,3,4 1 2 5 2,33 0,66
6 4 3 4 7 4,33 0,66
7 4,5,6 8 9 13 10 0,83
8 6 2 3 5 3,16 0,5
9 7,8 1 2 3 2 0,33
10 9 2 4 8 4,33 1
11 8 1 2 4 2,16 0,5
12 10,11 2 3 6 3,33 0,66
13 12 3 4 6 4,16 0,5

Tabla 2. Tareas planificadas con su duración estimada

Nota: el Promedio responde a: Promedio = (Top + 4*Tesp + Tpes)/6

El desvío se calculó mediante: Sigma = (Tpes – Top)/6

Con los datos anteriores, se puede construir un esquema basado en el modelo PERT:

Fig. 2. Esquema de planificación basado en el modelo PERT

21
A partir del mismo, podemos identificar el camino crítico:

Fig. 3. Modelo PERT con camino crítico

El camino crítico está comprendido por las tareas 4,6,7,9,10,12,13. La suma de los tiempos medios
de las actividades críticas da una duración de 215,67 días (casi 31 semanas).

2.2. Simulación de Montecarlo

Fig. 4. Simulación de Montecarlo para planificación propuesta (campana de Gauss)

22
Fig. 5. Simulación de Montecarlo (tiempo en función de la probabilidad)

A partir de la simulación de Montecarlo, para las fechas tempranas, medias y optimistas


consideradas, y asumiendo un nivel de confianza del 90%, se puede afirmar que la duración máxima del
proyecto es de 218 días, es decir, un poco más de 7 meses.

2.3. Diagrama de Gantt

Se toma como fecha de inicio del proyecto el día 1 de abril de 2011. En este sentido, y habiendo
definido las actividades descriptas anteriormente, se realiza la siguiente tabla, donde se muestran las
fechas esperadas de inicio y finalización de cada tarea.

Fig. 6. Lista de tareas y asignaciones previstas

23
A partir de estos datos, se realizó el diagrama de Gantt, que permite estimar la fecha de
finalización del proyecto, respetando los tiempos asignados para cada tarea (diagrama realizado el 15 de
septiembre de 2011).

Fig. 7. Diagrama de Gantt para la planificación prevista

En base a este análisis, resultaba esperable completar el proyecto a fines de octubre de 2011, con lo
cual la totalidad del trabajo hubiese tenido una duración de poco más de 7 meses.

No obstante, la realidad fue muy distinta. Cuando se realizaron las pruebas en planta, con los
actuadores conectados, y las placas dentro del gabinete, surgió un problema grave: el microcontrolador se
reseteaba esporádicamente cuando el sistema cambiaba el estado de una salida. Esto llevó a una
evaluación de la causa del problema, y se resolvió rediseñar la placa de potencia. A partir de este
momento, todo el proyecto se vio seriamente retrasado, ya que tuvieron que redefinirse varias cuestiones
a partir de este inconveniente. Además, comenzó el receso de verano durante el cual no se trabajó. A
continuación, se muestra una lista completa de las actividades que se habían completado, junto con las
que debieron sumarse hasta la fecha de redacción del presente trabajo.

24
Fig. 8. Listado de tareas implementadas realmente

A partir de esta nueva y completa lista de actividades, se realizó un nuevo diagrama de Gantt, que
refleja las duraciones aproximadas reales de las actividades.

25
Fig. 9. Diagrama de Gantt correspondiente a las actividades realizadas realmente

Se observa que el tiempo total del proyecto aumentó considerablemente respecto de lo que se había
planificado. Esto surgió a partir de un imprevisto grave que llevó al rediseño de varias cuestiones.
A modo de autocrítica, se puede afirmar que la actividad 10 (pruebas de funcionamiento) no se
desarrolló de forma correcta, ya que el mencionado error no surgió sino hasta realizar las pruebas en
planta. Además, se subestimó el tiempo que llevaría preparar todo el equipo para probar el prototipo.
Todo esto dio como resultado una duración de casi 16 meses para completar el proyecto que, si se
descuentan los 70 días tomados de receso de verano, se puede afirmar que el tiempo real se duplicó
respecto de lo planificado.

3. FACTIBILIDAD ECONÓMICA

Nota: se considera un tipo de cambio dado por US$ 1= $4,60.

Se comenzará el análisis de factibilidad económica con una breve descripción del mercado de
productores de cerveza artesanal. El mismo incluye tanto a pequeñas cervecerías artesanales, como a
productores independientes, que fabrican para consumo personal. El producto intenta optimizar el proceso
de elaboración de cerveza, ya sea a nivel casero o de cervecerías pequeñas, mediante la automatización
del mismo. En el país no existe un producto similar disponible, lo cual resultará una ventaja a la hora de
capturar el mercado.

El mayor costo del sistema por unidad estará dado por las placas, el gabinete y sus componentes,
junto con el tiempo de diseño. Como se especificó anteriormente, en principio se pretende acotar los
costos a 300 dólares por unidad ($1380). Esto permitiría obtener un precio de venta de poco más de 500
dólares ($2300), compitiendo con el único producto que se ofrece en el mercado: un controlador de
maceración, que controla directamente electroválvulas y puede programar hasta 9 escalones de
temperatura. El presente diseño tendrá más atributos, ya que controlará no solamente la maceración, sino
también el enfriado, hervor, fermentación, etc. El valor agregado se centra en estos atributos extra,
pudiendo así ofrecer un producto mucho más versátil, al mismo precio que la competencia (o algo
parecido a ella).

26
Los costos involucrados en el desarrollo del prototipo de resumen en la siguiente tabla. Se pueden
verificar las tablas completas, con todos los componentes del equipo en el anexo correspondiente.

Componentes Costo ($)

Elementos del hardware (físicos) 415,79

Componentes electrónicos de la placa lógica 111,72

Componentes electrónicos de la placa de potencia 222,83

Termómetros (3 unidades armadas) 86,40

Vainas para termómetros 32,32

Accesorios para prueba del prototipo 852,96

Valor fijo de las instalaciones utilizadas 2010

Insumos para fabricar 50 litros de cerveza (validación) 150

Componentes e insumos para pruebas 500

Tabla 3. Costos del prototipo, ordenados por bloques

Las filas verdes representan el costo de materiales por unidad, es decir, $836,74, que es un número
de suma importancia en el análisis económico del proyecto. El valor fijo de las instalaciones no se tendrá
en cuenta como costo del proyecto, por ser un costo hundido (existe independientemente de la puesta en
marcha del proyecto), dado por la disponibilidad de elementos que poseía uno de los autores. Las filas
amarillas y celeste son los costos que implicaron el montaje de un sistema capaz de validar el prototipo,
que suma un total de $1035,28. Además, se realizó una placa con relés mecánicos que no dio resultado, se
elaboraron unos 20 litros de cerveza negra para verificar el funcionamiento de las instalaciones, y se
realizaron placas de prueba (para el micro, para relés, etc.). Todo esto supone un costo que oscila entre los
$500, y que será considerado como un costo adicional para la validación del prototipo, sumando entonces
unos $1535,28.

Entonces:

 Costo de validación del prototipo: $1535,28

 Costo de materiales por unidad: $836,74

Se considerará un costo inicial dado por los componentes del prototipo, y el tiempo insumido en el
proceso de diseño. Para esto, se consideran 320 horas de trabajo, (160 horas por cada integrante) que
recibe un sueldo de $5000 en 4 semanas, trabajando 8 horas, 5 días a la semana. Esto da lugar a un tiempo
de diseño de 1 mes, si se trabajara en tiempo completo (los tiempos reales expresados en el diagrama de
Gantt no son para trabajo de tiempo completo, ya que el trabajo se realizó en forma cortada, utilizando el
tiempo disponible de cada integrante). Entonces, el costo de mano de obra corresponde a un mes de
trabajo de dos personas, es decir, $10000. Se definió un presupuesto de $837 para construir el prototipo,
unos $1536 para validarlo, lo cual da un costo total de diseño de $12373.

Se había definido el costo máximo de materiales de cada unidad en $837, a lo que debe sumarse la
mano de obra. Para esto, se considera un tiempo de trabajo de 16 horas por cada equipo construido,
probado e instalado. Asumiendo el mismo nivel salarial que el expresado anteriormente, la mano de obra

27
cuesta $31,25 por hora, dando lugar a un costo de $500 por equipo en concepto de mano de obra.
Estableciendo un precio de venta final de $2300 (IVA incluido), se tiene una rentabilidad por unidad e
$963, dada por:

Gbruta  P  C  2300  500  837  963 (1)

Para evaluar la factibilidad económica del producto, se supondrá una venta mensual de 3 unidades,
durante el primer año, aumentando a 4 el segundo año, y 3 el tercero, suponiendo que el producto se irá
consolidando dentro del mercado con el paso del tiempo, y perderá su crecimiento a los dos años porque
el mercado comenzará a saturarse. En este sentido, se define el ciclo de vida de este producto en 3 años a
partir de su lanzamiento (si el producto perdura más, el proyecto tendrá mejores resultados que los
previstos, pero se toma éste como peor caso). Además, estos valores suponen que en el transcurso de unos
siete meses se habrá recuperado la inversión hecha en el diseño. Como se planifica la realización de pocas
placas, las mismas se desarrollarán en baja escala, y en forma manual, al igual que el soldado de los
componentes y puesta a punto.

Habiendo fijado un precio de venta de $2300, y con lo propuesto anteriormente, se obtiene un


costo objetivo de:

Co  $2300  $963  $1337 (2)

El valor actual neto del producto está dado por (se considera una tasa de interés (libre de riesgo) de
10% anual, con los valores expresados en pesos):

n
FC
 E o
VAN i

i1 1ti i (3)

Otro costo a tener en cuenta es el de Ingresos Brutos. Esto corresponde al 3,5% de las ventas
anuales, lo que daría: $2898 el primer año, $3864 el segundo y $2898 el tercero, dando un total de $9660.
Si se consideran las ventas de cada año y se prorratean estos valores a cada equipo, se obtiene una
ganancia neta de $882 en lugar de $963.

Además de ingresos brutos, se calculó la diferencia de IVA que se generó en cada ciclo con los
flujos de caja de cada año obtenidos en las proyecciones de ventas y que debe abonarse al fisco. Esto
quiere decir que en cada flujo de cada año hay un 21% que se debe devolver al estado y que no debe
influir en el análisis del proyecto ya que no es dinero redituable para el empresario. Al resultado de estas
operaciones hay que reducirle un 35% de impuesto a las ganancias. El siguiente cuadro de resultados
muestra lo expresado anteriormente.

Año Ventas Margen bruto antes Ingresos brutos, Utilidad neta


de impuestos e IVA e Imp.
intereses (EBIT) ganancias.
0 0 -12373 -2598 -9775

1 82800 20628 12933 10592

2 110400 27504 17244 14123

3 82800 20628 12933 10592

Tabla 4. Detalle de los flujos de caja

28
Entonces la VAN queda se expresa de la siguiente manera.

10592 14123 10592


VAN  9775     25534
1,11 1,12 1,13 (4)
VAN  $25534

Se observa que el valor actual neto resulta superior a cero, considerando una tasa de interés del
10% (que es mucho más elevada de lo esperable, suponiendo condiciones estables; se tomó este valor
para situarnos en un caso desfavorable).

A continuación se evalúa la tasa interna de retorno:

n
FCi
VAN´ Eo 0
i1 1ti i (5)

El valor (calculado por iteración) para ti es 1,047, es decir, que se obtiene una tasa de interés
equivalente al 104,7% anual.

TIR  104,7% (6)

A continuación se observa el flujo de caja correspondiente a los 3 años proyectados. Se espera una
meseta en el flujo luego del año tres que concluye con una estabilización en el mercado. De esta manera,
en el siguiente gráfico aparecen los flujos finales de caja de cada año.

Flujos de caja
20000

15000

10000

5000

0
0 0,5 1 1,5 2 2,5 3 3,5
-5000

-10000

-15000

Fig. 10. Gráficoque representa los flujos de caja a través de los años

A partir de este análisis, se puede concluir que el producto es económicamente factible.

29
4. FACTIBILIDAD LEGAL Y RESPONSABILIDAD CIVIL

Por ser un sistema eléctrico, el producto necesitará un certificado de seguridad eléctrica, ya que se
alimentará con los 220Vrms de la línea, ya que todos los aparatos eléctricos y electrónicos que funcionen
con más de 24V requieren esta certificación.

En cuanto a la fuente de alimentación, se implementará con circuitos del tipo lineal, con el fin de
simplificar el desarrollo, y abaratar los costos de componentes.

Como este es un producto electrónico, no requiere certificaciones bromatológicas, ya que no habrá


contacto entre el gabinete y el mosto. La única excepción es el sensor de temperatura, que deberá tratarse
de forma tal que pueda sumergirse en el líquido, por lo que tendrá que ser impermeable, y recubierto por
algún material (por ejemplo, acero inoxidable) que sea sanitariamente apto. En este sentido, será
necesario utilizar un material bromatológicamente apto para tener contacto con el mosto. Se insiste, que el
caso del sensor de temperatura sumergido es el único caso que debe contemplarse en este marco. Para el
prototipo, se utilizará un tubo de acero inoxidable, sin costura, con un bulón del mismo material roscado
en uno de sus extremos. La unión se sellará con pasta de teflón, apta desde el punto de vista sanitario. Por
el extremo libre saldrá el cable.

30
IX. INGENIERÍA DE DETALLE

1. HARDWARE

El hardware se dividirá en los siguientes bloques:


 Fuente de alimentación
 Placa de procesamiento
 Placa de salida de potencia
 Interfaz con borneras
 Módulo de censado de temperatura

1.1. Diagrama de Bloques

A continuación, se muestra un esquema general de los distintos bloques del equipo:

Fig. 11. Diagrama en bloques del hardware del equipo

1.2. Descripción Detallada de Cada Bloque

A continuación, se describe la funcionalidad y diseño de cada bloque del hardware:

Fuente de alimentación

La fuente de alimentación será una fuente lineal con una entrada de 220VAC. La misma se llevará
a un valor de 9VAC por medio de un transformador, que trabajará a la frecuencia de línea (50Hz), y
podrá entregar una corriente de hasta 2A. Esta salida será rectificada mediante un puente completo
realizado con diodos del tipo 1N4007. Para filtrar el ripple de línea, se colocará un capacitor de 470uF.
De esto modo, se obtiene una tensión de unos 12 VDC, que alimentará 3 reguladores con salida de 5V de

31
continua, uno utilizado para el bloque de control, y otros dos alimentando cada uno la mitad de los
circuitos de salida de potencia (entrada de led de los optotriacs, y led de encendido de cada salida).

Placa de procesamiento

Incluye al microprocesador, que será un Coldfire V1, de la línea Freescale, con encapsulado tipo
LQFP de montaje superficial. El mismo tiene 64 pines de salida, que pueden multiplexarse para llegar a
trabajar hasta con 51 puertos de I/O. Según los programas de debugueo empleados, se definirán los
puertos de I/O utilizados por el programa para favorecer al máximo el layout de la placa. Los pines de I/O
se utilizarán del siguiente modo:
 24 pines para manejar las salidas de potencia.
 11 pines para controlar el display (8 de datos, y 3 de control).
 7 pines de entrada para los 7 botones del equipo.
 1 pin para controlar la luz del display.
 1 pin para activar un buzzer para una alarma sonora.
 3 pines de entrada auxiliares para actualizaciones futuras.
 1 pin para protocolo “one-wire” que controla los termómetros.
 1 pin para cambiar de modo: bootloader (grabación de firmware) o programa de
usuario.
Esto nos da un total de 49 pines utilizados como I/O. Además, se tienen:
 2 pines para conectar un oscilador externo
 2 pines de grabación por hardware (protocolo BDM): pin de /RESET y BKDBG.
 2 pines para comunicación USB.
 1 pin de regulación de 3,3V para USB (no utilizado).
 4 pines de referencia para los A/D (VrefL, VrefH, Vssa, Vdda) (no utilizados).
 2 pines de masa (Vss).
 1 pin de alimentación (Vdd).
 1 pin de interrupción externa por hardware (IRQ) (no utilizado).
De este modo se completa el uso de los 64 pines del encapsulado del microcontrolador utilizado.
Solamente quedan sin un uso específico 5 pines (es decir, se aprovecha más del 92%). Las 24 salidas
físicas del microcontrolador, irán directamente a un conector IDC (de 26 vías, 24 de datos, una de
referencia de masa, y otra sin uso), y tendrán una entrada con buffer en la placa de salida, para minimizar
la corriente que debe entregar el microcontrolador.
Sobre esta misma placa se colocará el led de encendido, la placa armada con el display, los 7
botones con sus filtros pasivos, el buzzer, 14 conectores para conectar circuitos de medición de
temperatura digitales, y un conector USB hembra para carga de firmware.

Placa de salida de potencia

Esta placa contiene una bornera para la entrada del transformador (9VAC), con el puente de diodos
y capacitor de filtro correspondiente. También incluye los 3 reguladores mencionados (del tipo 7805, con
encapsulado TO220) para entregar 5VDC regulados y filtrados con capacitores. Se tienen además 4
borneras para alimentar con la tensión de línea (220 VAC) a 4 grupos de 6 salidas de alterna (esto se hace
para permitir alimentación independiente por grupos de 6 salidas, para el caso de que se requiera mucho
consumo; se contempla hasta unos 2,64KW por grupo, es decir, hasta 440W por cada salida, como
máximo).
Por otro lado, se tiene un conector central IDC, de 26 vías, para conectar fácilmente las líneas de
control. Estas líneas entran a 4 integrados de 6 buffers cada uno. A la salida de cada buffer, se conecta el

32
optotriac y el led de encendido de cada salida. A su vez, este optotriac dispara el triac de potencia, que
cerrará el circuito de los 220VAC que pasan por una bornera. Este circuito tiene a su salida un snubber
del tipo RC serie, conectado en paralelo con el triac, para proteger al mismo de posibles picos dados por
cargas inductivas. Esto se repite 24 veces, como se dijo anteriormente, con las salidas numeradas y
agrupadas de a 6.

Módulo de censado de temperatura

Constará del sensor de temperatura (cuya descripción se detalla en el siguiente ítem: 9.1.3), con un
acondicionamiento físico para soportar el ambiente de trabajo. Cada sensor se protegerá con un tubo de
acero inoxidable, con un bulón roscado en un extremo, y sellado con pasta de teflón, que será sumergido
en el líquido cuya temperatura se desea medir. Las conexiones se protegerán con termocontraíble para
evitar cortocircuitos con el tubo de acero. Se utilizarán cables del tipo telefónico, utilizando 3 de sus 4
líneas. Se aprovecha este tipo de cables por tener buena resistencia a la temperatura (se testeó su
comportamiento sometido a 100ºC, con excelentes resultados) y bajo costo. En el otro extremo se soldará
el conector hembra, polarizado, compatible con los utilizados en la placa de control.

1.3. Detalles de Selección y Cálculo de los Elementos Circuitales de Cada Bloque

Argumentos de selección de los distintos elementos del equipo:

Microprocesador:

El ColdFire V1 es un procesador de alta performance, con buena cantidad de


periféricos a disposición del usuario. Tiene conexión USB 2.0 OTG que facilitará ampliamente
el debugueo y cargado de distintos programas de prueba. Pertenece a la marca Freescale, que es
conocida y fue trabajada por los diseñadores del presente trabajo. La interfaz de programación se
da mediante el software CodeWarrior, con el cual los diseñadores también están familiarizados,
y se dispone del mismo por ser software libre. Dentro de la familia de ColdFire V1, se eligió el
encapsulado de montaje superficial de 64 pines (cuyo uso se describe y justifica en la sección
anterior), y la mayor capacidad de memoria disponible (128KB de memoria flash, para uso de
programa), lo que permitirá maximizar las prestaciones, de modo de tener disponible una amplia
variedad de recetas almacenadas en memoria. Además, este microprocesador tiene un muy bajo
costo (US$ 3,73 por unidad a baja escala, directo del fabricante), y ofrece muy buenas
prestaciones, incluyendo la interfaz USB que facilitará ampliamente la grabación de firmware.

Transistor de encendido de led de display (backlight), y activación del buzzer:

Se utilizará un transistor PNP tipo BC547, por ser estándar y versátil, con
buena disponibilidad y bajo costo.

Triacs de potencia:

Se utilizarán triacs del tipo BTA08600, con capacidad de hasta 8A. El mismo
tiene un encapsulado TO220AB. Como la potencia máxima de salida estará dada por la
capacidad de disipación térmica, se establece la corriente máxima de paso por este dispositivo
según los siguientes criterios. Esta limitación de corriente se definió teniendo en cuenta que no
se utilizarán disipadores, ya que éstos ocuparían mucho espacio, y aumentarían mucho el costo
del equipo.

33
Según los datos proporcionados por el fabricante, se tiene:

Rja  60º C / W
Tj(max)  125º C (7)

Utilizando un modelo simplificado, sin disipador, y considerando una temperatura ambiente


típica de 25ºC se tiene:

Tj(max)  Ta  P.Rja  125º C


Tj(max)  Ta 125º C  25º C
P(max)    1,67W
Rja 60º C / W (8)

Utilizando el siguiente gráfico proporcionado por la hoja de datos, se obtiene la corriente


máxima rms admisible:

Fig. 12. Gráfico de potencia disipada en función de la corriente (para triac de potencia)

A partir de este análisis, se determina que la corriente máxima rms admisible es de 2A, lo cual
permite cargas con una potencia de hasta 440W. Esto establece un límite importante para la capacidad de
carga del circuito. No obstante, estos números permiten trabajar, por ejemplo, con bombas que trabajen
con un motor de 0,5HP (unos 373W), que resultan más que suficientes para las aplicaciones previstas
para el equipo.

Display LCD:

Se eligió el modelo de Winstar ELWH1602A-YGH, ya que es el display de 2 líneas x 16


caracteres (que resulta un número apropiado para mostrar mensajes cortos y concisos) más económico del

34
mercado local. Permite iluminarse con un led de backlight, driveado por un transistor, como se explicó
anteriormente.

Conector USB:

Se eligió un conector USB hembra, tipo A, de montaje para placa. Este conector permite
conectar el equipo a una PC para actualizar el firmware. Además, se contempla la posibilidad de
actualizar futuras versiones del programa que puedan leer y escribir un pen drive, que puede conectarse
en este tipo de conectores. Se eligió el protocolo USB por estar soportado por todas las computadoras
modernas, por tener muy buena velocidad, y porque no aumenta considerablemente el costo del equipo.
Todos los microcontroladores modernos soportan esta interfaz.

Sensor de temperatura:

Se escogió el integrado DS18B20, de la firma Dallas Semiconductor. Es un integrado con


encapsulado TO92, con tres pines; dos de alimentación, y uno de datos. Utiliza un protocolo one-wire
para enviar y recibir datos digitales. El mismo circuito realiza la conversión de temperatura, de hasta 12
bits. El protocolo permite conectar hasta 255 integrados al mismo pin (mediante un protocolo de
reconocimiento de código de ROM interna) del microprocesador, por lo que pueden realizarse todas las
mediciones de temperatura y procesarlas utilizando únicamente un pin. Cada integrado tiene un costo
relativamente bajo (unos $24 por unidad), que, sumado al cable, el conector, y termocontraíble, darían un
costo por termómetro de menos de $30 (sin considerar el envainado).

Placa de potencia:

A continuación se detalla el circuito a utilizar para cada salida de potencia:

Fig. 13. Circuito de potencia implementado

Este circuito se repite 24 veces en la placa de potencia. Como se explicó anteriormente, cada buffer
(integrado CD4050, con 6 buffers por integrado), se alimenta con 5VDC suministrados por un regulador
del tipo 7805. El led que muestra el estado de la salida, se eligió de color verde, y tiene una caída de
tensión aproximada de unos 2,4V. En este sentido, para entregarle alrededor de 8mA (con lo que se
obtiene una luminosidad baja, pero visible, con bajo consumo y larga vida útil para el led), se requiere un
valor de resistencia de:

35
V 5V  2,4V
R   325
I 0,008 A (9)

Ubicando el próximo valor comercial de resistencia disponible, se optó por utilizar un valor de
330Ω para R2. Análogamente, y sabiendo que el led del optotriac requiere una corriente de 15mA para
encender el triac, y tiene una caída de tensión típica de 1,3V (valores obtenidos de la hoja de datos),
operando análogamente se obtiene:

V 5V  1,3V
R   246,67
I 0,015 A (10)

En este contexto, se utiliza el valor comercial próximo más bajo, para garantizar la corriente
mínima, es decir, un valor para R1 de 220 Ω. Los valores de R3 y R4 se eligieron siguiendo las
recomendaciones del fabricante, ya que constituyen resistencias de bias que actúan en el circuito interno
del MOC3041. Este optotriac se eligió por ser el integrado de la serie MOC más económico del mercado
(a costa de un mayor consumo en su led de entrada) y tener un circuito de detección de cruce por cero, lo
cual garantizará que el encendido o apagado de un periférico se de con tensión nula (o muy baja), de
modo de no dar lugar a picos elevados de corriente durante el switcheo de los mismos (de hecho, este
problema surgió cuando se realizaron pruebas utilizando relés con bobina, lo cual generaba reseteos
esporádicos del microcontrolador, lo cual no es admisible para el funcionamiento del equipo). Para los
componentes seleccionados para el snubber, se considera lo siguiente: en primer lugar, se toma el caso de
una carga típica, de un motor que consume 1A, y tiene una inductancia de 3mHy. Este es un caso
representativo de motores asincrónicos monofásicos típicos utilizados para bombas centrífugas. En este
caso, se puede calcular la energía almacenada en la bobina del motor según la siguiente fórmula:

1
E  * L * I 2  0,5 * 0,003Hy *12 A2  1, mJ
2 (11)

El capacitor de snubber se diseña con una capacidad de aislamiento que soporte hasta 630V, ya que
un pico de un 50% del valor máximo de tensión (380V) nos da un valor de 570V. Tomando este criterio
como el peor caso (pico de 50% del valor máximo), el valor comercial siguiente resulta el indicado. Con
estas suposiciones, el valor de capacidad capaz de absorber la energía calculada está dado por:

1 2 * E 2 * 0,0015J
E  * C *V 2  C  2   7,56nF
2 V 630 2 (12)

Se toma un valor estándar de 10nF, para otorgar, además, un margen de seguridad. La reactancia
capacitiva, para la frecuencia de línea (50Hz), está dada por:

1 1
Xc    318309,9
2 *  * f * C 2 *  * 50 *1 *108 F (13)

El valor elegido para la resistencia de snubber, prácticamente no modificará el valor de impedancia


de la red RC serie, por tener la reactancia capacitiva un valor muy elevado. Pero sí definirá el tiempo de

36
respuesta ante un pico de corriente. Sabiendo que un ciclo completo dura 20ms (frecuencia de línea de
50Hz), y tomando un margen de tiempo muy cómodo de un tiempo característico que sea unas 500 veces
más rápido que el período de corriente en la bobina, se tiene un tiempo característico de 40us. El tiempo
dado por la red RC, es igual a la inversa del producto de la resistencia y la capacidad, dando un valor de
resistencia de 40Ω. Entonces, se toma como valor elegido el disponible comercialmente más cercano, es
decir, R=39 Ω.

1.4. Plan de Pruebas de Cada Módulo

Previo al armado de cada módulo, se desarrollarán los siguientes pasos de prueba:

 Fuente de alimentación:
Se medirán las tensiones de salidas, cargando a la fuente con una resistencia equivalente
a la carga real, antes de conectarla al equipo.

 Placa de procesamiento:
Se desarrolló una placa de desarrollo con las conexiones básicas necesarias para el
funcionamiento de este microprocesador. Se desarrollarán en mayor profundidad los distintos
drivers y su testeo. En cuanto al hardware, se comprobó el correcto funcionamiento del
microprocesador utilizando esta placa, por lo que se desarrollará el programa final sobre esta
plataforma. El diseño y armado de la placa final respetará los componentes incluidos en esta
placa de desarrollo.

 Placa de salida de potencia:


Se generará una placa multiperforada con el circuito correspondiente a un optotriac con
su triac de potencia. El mismo se probará con distintas cargas, de distintas potencias, para
verificar su correcto funcionamiento, disparándolo con un pin del microprocesador para verificar
que los dos bloques funcionan en simultáneo sin problemas (por ejemplo, sin que ocasionen
reseteos del micro). Una vez verificado el circuito, se diseñará y armará la placa final de
potencia, con las 24 salidas con sus correspondientes borneras.

 Interfaz con borneras auxiliares:


Por ser conectores a tornillo simplemente, no se desarrollarán sistemas de prueba de
conexión para la bornera.

 Módulo de censado de temperatura:


Para el desarrollo del driver del protocolo one-wire, se utilizará el sensor sin protección.
Una vez que se haya verificado el correcto funcionamiento del software de control en distintas
circunstancias (varios integrados conectados simultáneamente, medición simultánea de distintas
temperaturas, etc.), se repetirán las mediciones con la protección del tubo de acero inoxidable.
Se registrarán los datos obtenidos, para tener una noción empírica de los parámetros físicos del
sensor (retardo, diferencias numéricas, etc.), que permitirán optimizar el programa principal (en
cuanto a los sistemas de control digitales).

2. SOFTWARE

El programa consiste en una máquina de estados, donde cada uno corresponde a cada etapa del
proceso de fabricación (Maceración, Cocción, Fermentación, etc.). Dentro de cada una se accionarán los
dispositivos correspondientes y se controlarán las variables específicas de cada proceso.

37
2.1. Diagrama de Estados y Flujogramas

El diagrama siguiente representa la estructura general de la máquina de estados en la cual se


basará la aplicación.

Fig. 14. Estructura general de los estados del proceso de producción previsto

2.2. Análisis de Complejidad

Los algoritmos y cálculos que deberán implementarse no tendrán gran complejidad. La capacidad
de procesamiento del microprocesador elegido supera ampliamente los requerimientos de velocidad que
requerirá el software. El sistema que requiere mayor frecuencia de clock es el protocolo USB, que
requiere un cristal de 12MHz para sincronización. Utilizando entonces un reloj de esta frecuencia, se
permite utilizar el módulo USB, y la capacidad de procesamiento del microcontrolador resulta mayor que
la necesaria para la aplicación concreta, dando lugar a un amplio margen que garantizará un
funcionamiento fluido. Cabe destacar, además, que se utiliza un microcontrolador de buenas prestaciones,
pero de bajo costo, con un valor de US$ 6, si se lo adquiere en bajas cantidades.
En cuanto a la complejidad algorítmica propiamente dicha, se puede afirmar que el tiempo de
procesamiento dentro del programa depende, fundamentalmente, de dos factores; por un lado, los eventos
que pueda producir el usuario cuando oprime un botón, y por el otro, algún evento interno al programa
que genera una serie de acciones correspondientes.
El software funciona en base a un modelo de máquina de estado, en la que se realiza “polling”.
Esto se puede observar en la función principal (main) del programa, que luego de un protocolo de
inicialización ejecuta el siguiente código:

/*Loop infinito, motor de la máquina de estados*/


for(;;)
{
Check_Proceso ();
evento_botones();
}

38
Se puede observar, entonces, que el programa se mantiene infinitamente corroborando si se ha
producido un evento del proceso, o un evento producido mediante un botón oprimido por el usuario.
Como en ambos casos se ejecuta una cantidad fija de instrucciones en el caso de ausencia de
eventos (como sucede en la gran mayoría de los casos), la complejidad algorítmica resulta de orden
unitario (O(1)).
La frecuencia con la que puede interrumpir el proceso es del orden de los segundos, que es
muchísimo tiempo, por lo cual su ni siquiera vale la pena considerarlo. En cuanto al tiempo que puede
transcurrir para que el usuario oprima dos botones, se considera como mínimo unos 100ms. Este es un
tiempo considerable, que podría dar lugar a errores si el programa pasa varias veces por su analizador de
eventos. Por este motivo, se implementó un sistema que verifica que el usuario haya soltado un botón
hasta que se vuelva a actuar frente a un evento.
En conclusión, la complejidad del software resulta varios órdenes de magnitud menor que la
capacidad de procesamiento del microcontrolador, permitiendo garantizar que los tiempos de ejecución de
instrucciones son lo suficientemente pequeños como para asegurar un buen nivel de fluidez en el
programa y su interfaz con el usuario.

2.3. Descripción de Subrutinas

A continuación, se detallan las funciones correspondientes a los distintos drivers, y una breve
descripción de cada una. Las funciones se escribirán en lenguaje C.

Driver del display (Archivo display.h):

#ifndef __DISPLAY_H_
#define __DISPLAY_H_

// Definicion de constantes
#define DELAYCONST 32000
#define DELAYCOM 1000
#define BORRAR_DISPLAY 0x01
//#define RS 0x02
//#define RW 0x10
//#define E 0x20

// Declaracion de funciones
//********************************************************************
*********************
// Funcion : void Delay(int iDelay)
// Descripcion: Realiza un delay a través de un for.
// Para Hacer : Determinar el tiempo aproximado del delay
//********************************************************************
*********************
void Delay(int iDelay);
//********************************************************************
*********************
// Funcion : void InicializarDisplay(void)
// Descripcion: Inicializa el display.
//********************************************************************
*********************
void InicializarDisplay(void);
//********************************************************************
*********************
// Funcion : void EscribeComandoDisplay(unsigned char chComando)
// Descripcion: Escribe un comando en el display.

39
//********************************************************************
*********************
void EscribeComandoDisplay(char chComando);
//********************************************************************
*********************
// Funcion : void EscribeCadenaDisplay(char chLinea,
// char *pszCadena)
// Descripcion: Escribe una cadena, en la linea indicada en el
display.
//********************************************************************
*********************
void EscribeCadenaDisplay(char chLinea, char *pszCadena);
//********************************************************************
*********************
// Funcion : void EscribeDatoDisplay(char chDato)
// Descripcion: Escribe un dato en el display.
//********************************************************************
*********************
void EscribeDatoDisplay(char chDato);
//********************************************************************
*********************
// Funcion : void BuildData (unsigned char ChByte)
// Descripcion: Arma un byte con el comando o dato de salida
//********************************************************************
*********************
void BuildData (char ChByte);

#endif // __DISPLAY_H_

Driver de los sensores de temperatura (Archivo Temperatura.h)

#include "MCF51JM128.h"

//Definición del Hardware


#define ONE_WIRE_PIN PTFD_PTFD3
#define ONE_WIRE_PIN_MODE PTFDD_PTFDD3

#define TEMP_ERR -1

//Prototipos
//********************************************************************
***************
// Funcion : void onewire_reset(void)
// Descripcion: Escribe un comando de reset para todos los
dispositivos conectados al bus
//********************************************************************
***************
void onewire_reset(void);
//********************************************************************
***************
// Funcion : void onewire_write(unsigned char data)
// Descripcion: Escribe un comando de escritura y transmite un byte no
signado al dispositivo activo
//********************************************************************
***************
void onewire_write(unsigned char data);
//********************************************************************
***************
// Funcion : unsigned char onewire_read(void)

40
// Descripcion: lee un byte no signado del dispositivo activo
//********************************************************************
***************
unsigned char onewire_read(void);
//********************************************************************
***************
// Funcion : int ds1820_read(void)
// Descripcion: lee una secuencia completa (7 bytes) del dispositivo
activo
//********************************************************************
***************
int ds1820_read(void);
//********************************************************************
***************
// Funcion : void ds1820_configure(unsigned char TH, unsigned char TL,
unsigned char config)
// Descripcion: Escribe los 3 bytes de configuración al dispositivo
activo
//********************************************************************
***************
void ds1820_configure(unsigned char TH, unsigned char TL, unsigned
char config);
//********************************************************************
***************
// Funcion : void delay_us(int us)
// Descripcion: Retraso de una cantidad fija de microsegundos
//********************************************************************
***************
void delay_us(int us);
//********************************************************************
***************
// Funcion : void delay_ms(int ms)
// Descripcion: Retrasa una cantidad fija de milisegundos
//********************************************************************
***************
void delay_ms(int ms);
//********************************************************************
***************
// Funcion : char recorrer_dato (unsigned char dato, int i)
// Descripcion: Función auxiliar para recorrer los distintos bytes de
un dato completo
//********************************************************************
***************

char recorrer_dato (unsigned char dato, int i);


//Otras definiciones
typedef union {
byte Byte;
struct {
byte DATA0 :1; /* Data
Direction for Port C Bit 0 */
byte DATA1 :1; /* Data
Direction for Port C Bit 1 */
byte DATA2 :1; /* Data
Direction for Port C Bit 2 */
byte DATA3 :1; /* Data
Direction for Port C Bit 3 */
byte DATA4 :1; /* Data
Direction for Port C Bit 4 */
byte DATA5 :1; /* Data
Direction for Port C Bit 5 */

41
byte DATA6 :1; /* Data
Direction for Port C Bit 6 */
byte DATA7 :1; /* Data
Direction for Port C Bit 7 */
} Bits;
} DATA;

//DS18B20 lista de comandos


#define DS1822_CMD_READROM 0x33
#define DS1822_CMD_SKIPROM 0xCC
#define DS1822_CMD_CONVERTTEMP 0x44
#define DS1822_CMD_WRITESCRATCHPAD 0x4E
#define DS1822_CMD_READSCRATCHPAD 0xBE
#define DS1822_CMD_COPYSCRATCHPAD 0x48
#define DS1822_CMD_MATCHROM 0x55

//DS18B20 registros de ROM


#define DS1822_ROM_DEVTYPE 0
#define DS1822_ROM_SERIAL1 1
#define DS1822_ROM_SERIAL2 2
#define DS1822_ROM_SERIAL3 3
#define DS1822_ROM_SERIAL4 4
#define DS1822_ROM_SERIAL5 5
#define DS1822_ROM_SERIAL6 6
#define DS1822_ROM_CRC 7

Estos dos drivers corresponden al conjunto de subrutinas que requieren un desarrollo y debugueo
independientes, probándolos en distintas circunstancias y bajo condiciones diversas, de modo que se
pueda garantizar su correcto funcionamiento y no den lugar a errores de bajo nivel mientras se desarrollan
las capas más superficiales del programa.
Por supuesto, se han desarrollado distintas funciones de servicio y subrutinas, que se adjuntan en
los anexos correspondientes.

2.4. Listados Comentados del Código

A continuación, se mostrará el código correspondiente a los bloques fundamentales del proceso. El


programa completo aparece en los anexos correspondientes.
Archivo main.c

Este archivo alberga la función principal (de inicio para el programa de usuario) que realiza los
protocolos de inicialización, y luego ejecuta un loop infinito para que funcione la máquina de estados.

#include "MCF51JM128.h"
#include "display.h"
#include "Temperatura.h"
#include "botones.h"
#include "Salida.h"
#include "Proceso.h"

//Variables globales
int temp1,temp2,temp3;

//Programa principal
void main(void)

42
{
//Inicializo sistema
system_init();
clear_all_outputs();
InicializarDisplay();

//Inicializo con un botón inerte para generar mensaje de encendido


check_botones (UP);

/*Loop infinito, motor de la máquina de estados*/


for(;;)
{
Check_Proceso ();
evento_botones();
}
}

Archivo botones.c

Este archivo contiene las funciones que verifican eventos de los botones y ejecutan las acciones
correspondientes. Se puede observar la estructura básica del menú del equipo, dado por la secuencia:

1. Iniciar (o Pausar si ya se ha iniciado el proceso)


2. Control Manual
3. Ir a acción
4. Leer temperatura
5. Salir

#include "botones.h"
#include "maindefs.h"
#include "MCF51JM128.h"
#include "display.h"
#include "Salida.h"
#include "Proceso.h"

#define MAX_TEMP 35

//Variables de control
int estado=ENCENDIDO;
int pre_estado=NOTHING;

int released = 1;
int boton_apretado = NOTHING;
int actuator_count = 0;

int boton_flag = 0;
int cont_actuador = 1;
int cont_accion = 0;
int cont_temp=1;
int leyendo_temp = 0;

//Funciones de servicio de flag de impresión


int get_flag (void)
{
return boton_flag;
}
void set_flag (int valor)
{
boton_flag = valor;

43
}
//Función que verifica eventos de botones por polling
//Esta función se llama cuando se oprime un botón, para definir las
acciones a realizar
void check_botones (int boton)
{
//Entradas (Botones)
if(boton==LCD)
{
if (LCD_LIGHT==1)
LCD_LIGHT = 0;
else
LCD_LIGHT = 1;
}
else if(boton==MENU) //Menu
{
EscribeComandoDisplay(BORRAR_DISPLAY);
//EscribeCadenaDisplay(1, nothing);
EscribeCadenaDisplay(1, boton_disp_menu);
//EscribeCadenaDisplay(2, nothing);
estado=MENU;
pre_estado=NOTHING;
leyendo_temp=0;
}
//Estados
if (estado == ENCENDIDO)
{
EscribeCadenaDisplay(1, encendido_1);
EscribeCadenaDisplay(2, encendido_2);
if (boton == ENTER)
{
estado=NOTHING;
//Inicializo el programa principal
Init_System_configuration ();
Init_Proceso();
}
}
else if (estado==MENU)
{
if(boton==RIGHT) //Derecha
{
if (pre_estado==NOTHING)
{
if (Programa_activo()==0)
{
pre_estado=MENU_INICIAR;
EscribeCadenaDisplay(1, menu_iniciar);
}
else
{
pre_estado=MENU_PAUSAR;
EscribeCadenaDisplay(1, menu_pausa);
}
}
else if (pre_estado==MENU_INICIAR)
{
pre_estado=MENU_MANUAL;
EscribeCadenaDisplay(1, menu_control_manual);
}
else if (pre_estado==MENU_PAUSAR)
{

44
pre_estado=MENU_MANUAL;
EscribeCadenaDisplay(1, menu_control_manual);
}
else if (pre_estado==MENU_MANUAL)
{
pre_estado=MENU_IR_A;
EscribeCadenaDisplay(1, menu_ir_a);
}
else if (pre_estado==MENU_IR_A)
{
pre_estado=MENU_LEER_TEMP;
EscribeCadenaDisplay(1, leer_temp);
}
else if (pre_estado==MENU_LEER_TEMP)
{
pre_estado=MENU_SALIR;
EscribeCadenaDisplay(1, menu_salir);
}
else if (pre_estado==MENU_SALIR)
{
if (Programa_activo()==0)
{
pre_estado=MENU_INICIAR;
EscribeCadenaDisplay(1, menu_iniciar);
}
else
{
pre_estado=MENU_PAUSAR;
EscribeCadenaDisplay(1, menu_pausa);
}
}

}
else if(boton==LEFT) //Izquierda
{
if (pre_estado==NOTHING)
{
pre_estado=MENU_SALIR;
EscribeCadenaDisplay(1, menu_salir);
}
else if (pre_estado==MENU_INICIAR)
{
pre_estado=MENU_SALIR;
EscribeCadenaDisplay(1, menu_salir);
}
else if (pre_estado==MENU_SALIR)
{
pre_estado=MENU_LEER_TEMP;
EscribeCadenaDisplay(1, leer_temp);
}
else if (pre_estado==MENU_LEER_TEMP)
{
pre_estado=MENU_IR_A;
EscribeCadenaDisplay(1, menu_ir_a);
}

else if (pre_estado==MENU_IR_A)
{
pre_estado=MENU_MANUAL;
EscribeCadenaDisplay(1, menu_control_manual);
}

45
else if (pre_estado==MENU_MANUAL)
{
if (Programa_activo()==0)
{
pre_estado=MENU_INICIAR;
EscribeCadenaDisplay(1, menu_iniciar);
}
else
{
pre_estado=MENU_PAUSAR;
EscribeCadenaDisplay(1, menu_pausa);
}
}
else if (pre_estado==MENU_PAUSAR)
{
pre_estado=MENU_SALIR;
EscribeCadenaDisplay(1, menu_salir);
}
}
else if(boton==ENTER) //Enter
{
if (pre_estado==MENU_INICIAR)
{
estado=NOTHING;
//Inicializo el programa principal
Init_System_configuration ();
Init_Proceso();
}
else if (pre_estado==MENU_PAUSAR)
{
estado=pre_estado;
EscribeCadenaDisplay(1, pausa_continuar);
//Detengo el programa principal (las salidas no
cambian de estado)
Detener_programa ();
}
else if (pre_estado==MENU_MANUAL)
{
estado=pre_estado;
salida_numero[0]=(char) cont_actuador/10+48;
salida_numero[1]=(char) cont_actuador-
10*(cont_actuador/10)+48;
EscribeCadenaDisplay(1, manual_activar);
EscribeCadenaDisplay(2, salida_numero);
}
else if (pre_estado==MENU_IR_A)
{
estado=pre_estado;
accion_numero[0]=(char) cont_accion/10+48;
accion_numero[1]=(char) cont_accion-
10*(cont_accion/10)+48;
EscribeCadenaDisplay(1, accion_activar);
EscribeCadenaDisplay(2, accion_numero);
}
else if (pre_estado==MENU_LEER_TEMP)
{
estado=pre_estado;
leer_temp_num[13]=(char) cont_temp/10+48;
leer_temp_num[14]=(char) cont_temp-
10*(cont_temp/10)+48;
EscribeCadenaDisplay(1, leer_temp_num);

46
leyendo_temp=1;
}
else if (pre_estado==MENU_SALIR)
{
estado=NOTHING;
EscribeCadenaDisplay(1, nothing);
if (Programa_activo()==0)
{
estado = ENCENDIDO;
check_botones (UP);
}
}
}
}
else if (estado==MENU_PAUSAR)
{
if(boton==RIGHT) //Derecha
{
if (pre_estado==MENU_PAUSAR)
{
pre_estado=PAUSA_DETENER;
EscribeCadenaDisplay(1, pausa_detener);
}
else if (pre_estado==PAUSA_CONTINUAR)
{
pre_estado=PAUSA_DETENER;
EscribeCadenaDisplay(1, pausa_detener);
}
else if (pre_estado==PAUSA_DETENER)
{
pre_estado=PAUSA_RESETEAR;
EscribeCadenaDisplay(1, pausa_resetear);
}
else if (pre_estado==PAUSA_RESETEAR)
{
pre_estado=PAUSA_CONTINUAR;
EscribeCadenaDisplay(1, pausa_continuar);
}
}
else if(boton==LEFT)
{
if (pre_estado==MENU_PAUSAR)
{
pre_estado=PAUSA_RESETEAR;
EscribeCadenaDisplay(1, pausa_resetear);
}
else if (pre_estado==PAUSA_CONTINUAR)
{
pre_estado=PAUSA_RESETEAR;
EscribeCadenaDisplay(1, pausa_resetear);
}
else if (pre_estado==PAUSA_RESETEAR)
{
pre_estado=PAUSA_DETENER;
EscribeCadenaDisplay(1, pausa_detener);
}
else if (pre_estado==PAUSA_DETENER)
{
pre_estado=PAUSA_CONTINUAR;
EscribeCadenaDisplay(1, pausa_continuar);
}

47
}
else if (boton==ENTER)
{
if
((pre_estado==PAUSA_CONTINUAR)||(pre_estado==MENU_PAUSAR))
{
Reanudar_programa();
estado=NOTHING;
}
else if (pre_estado==PAUSA_DETENER)
{
//Seteo con condiciones iniciales las variables
Init_Proceso();
clear_all_outputs();
//Detengo el programa
Detener_programa();
EscribeCadenaDisplay(2, programa_detenido);
estado=PAUSA_DETENIDO;
}
else if (pre_estado==PAUSA_RESETEAR)
{
//Reseteo el programa desde el inicio
Init_Proceso();
estado=NOTHING;
}
}
}
else if (estado==MENU_MANUAL)
{
if (boton==ENTER)
{
if (get_out_state(cont_actuador)==0)
salida_on(cont_actuador);
else if (get_out_state(cont_actuador)==1)
salida_off(cont_actuador);
EscribeCadenaDisplay(1, manual_activar);
EscribeCadenaDisplay(2, salida_numero);
}
else if (boton==UP)
{
cont_actuador++;
if (cont_actuador>24)
cont_actuador=1;
salida_numero[0]=(char) cont_actuador/10+48;
salida_numero[1]=(char) cont_actuador-
10*(cont_actuador/10)+48;
EscribeCadenaDisplay(1, manual_activar);
EscribeCadenaDisplay(2, salida_numero);
}
else if (boton==DOWN)
{
cont_actuador--;
if (cont_actuador<1)
cont_actuador=24;
salida_numero[0]=(char) cont_actuador/10+48;
salida_numero[1]=(char) cont_actuador-
10*(cont_actuador/10)+48;
EscribeCadenaDisplay(1, manual_activar);
EscribeCadenaDisplay(2, salida_numero);
}
else if (boton==RIGHT)

48
{
pre_estado=MENU_IR_A;
estado=MENU;
EscribeCadenaDisplay(1, menu_ir_a);
EscribeCadenaDisplay(2, nothing);
}
else if (boton==LEFT)
{
if (Programa_activo()==0)
{
pre_estado=MENU_INICIAR;
EscribeCadenaDisplay(1, menu_iniciar);
}
else
{
pre_estado=MENU_PAUSAR;
EscribeCadenaDisplay(1, menu_pausa);
}
estado=MENU;
}
}
else if (estado==MENU_IR_A)
{
if (boton==ENTER)
{
Set_contador_de_acciones (cont_accion - 1);
Actualizar_a_proxima_accion ();
estado=NOTHING;
}
else if (boton==UP)
{
cont_accion++;
if (cont_accion>MAX_ACCIONES)
cont_accion=0;
accion_numero[0]=(char) cont_accion/10+48;
accion_numero[1]=(char) cont_accion-
10*(cont_accion/10)+48;
EscribeCadenaDisplay(1, accion_activar);
EscribeCadenaDisplay(2, accion_numero);
}
else if (boton==DOWN)
{
cont_accion--;
if (cont_accion<0)
cont_accion=MAX_ACCIONES-1;
accion_numero[0]=(char) cont_accion/10+48;
accion_numero[1]=(char) cont_accion-
10*(cont_accion/10)+48;
EscribeCadenaDisplay(1, accion_activar);
EscribeCadenaDisplay(2, accion_numero);
}
else if (boton==RIGHT)
{
pre_estado=MENU_LEER_TEMP;
estado=MENU;
EscribeCadenaDisplay(1, leer_temp);
EscribeCadenaDisplay(2, nothing);
}
else if (boton==LEFT)
{
pre_estado=MENU_MANUAL;

49
estado=MENU;
EscribeCadenaDisplay(1, menu_control_manual);
EscribeCadenaDisplay(2, nothing);
}
}
else if (estado==MENU_LEER_TEMP)
{
if (boton==UP)
{
cont_temp++;
if (cont_temp>MAX_TERMOMETROS)
cont_temp=1;
leer_temp_num[13]=(char) cont_temp/10+48;
leer_temp_num[14]=(char) cont_temp-10*(cont_temp/10)+48;
EscribeCadenaDisplay(1, leer_temp_num);
leyendo_temp=1;
}
else if (boton==DOWN)
{
cont_temp--;
if (cont_temp<1)
cont_temp=MAX_TERMOMETROS;
leer_temp_num[13]=(char) cont_temp/10+48;
leer_temp_num[14]=(char) cont_temp-10*(cont_temp/10)+48;
EscribeCadenaDisplay(1, leer_temp_num);
leyendo_temp=1;
}
else if (boton==RIGHT)
{
pre_estado=MENU_SALIR;
estado=MENU;
EscribeCadenaDisplay(1, menu_salir);
EscribeCadenaDisplay(2, nothing);
leyendo_temp=0;
}
else if (boton==LEFT)
{
pre_estado=MENU_IR_A;
estado=MENU;
EscribeCadenaDisplay(1, menu_ir_a);
EscribeCadenaDisplay(2, nothing);
leyendo_temp=0;
}
}
if (estado==NOTHING)
{
//Libero el flag de control
boton_flag=0;
//Borro el display
EscribeCadenaDisplay(1, nothing);
EscribeCadenaDisplay(2, nothing);
}
else
boton_flag = 1;
}
//Esta función se llama periódicamente para verificar si alguien
orpimió algún botón
//Utiliza Polling
void evento_botones (void)
{
int temperatura;

50
//Entradas (Botones)
if ((BOTON_LCD==0)) //LCD
boton_apretado = LCD;
else if((BOTON_MENU==0)) //Menu
boton_apretado = MENU;
else if((BOTON_ENTER==0)) //Enter
boton_apretado = ENTER;
else if((BOTON_ARRIBA==0)) //Arriba
boton_apretado = UP;
else if((BOTON_ABAJO==0)) //Abajo
boton_apretado = DOWN;
else if((BOTON_IZQUIERDA==0)) //Izquierda
boton_apretado = LEFT;
else if((BOTON_DERECHA==0)) //Derecha
boton_apretado = RIGHT;
else
{
boton_apretado = NOTHING;
released = 1;
}
if (leyendo_temp==1)
{
//Leo temperatura
temperatura=Get_Temp(cont_temp);
temp_disp[0]= ((char) (temperatura/100)) + 48;
temp_disp[1]= ((char) ((char) (temperatura -
100*(temperatura/100))/10)) +48;
temp_disp[2]= ((char) (temperatura - 100*(temperatura/100)-
10*(((temperatura - 100*(temperatura/100)))/10))) +48;
//Chequeo de error de temperatura
if ((temp_disp[0]<='9')&&(temp_disp[0]>='0')&&
(temp_disp[1]<='9')&&(temp_disp[1]>='0')&&
(temp_disp[2]<='9')&&(temp_disp[2]>='0'))
EscribeCadenaDisplay(2, temp_disp);
else
EscribeCadenaDisplay(2, temp_err);
}
if ((boton_apretado!=NOTHING) && released)
{
check_botones (boton_apretado);
released = 0;
}
}

Archivo Ejemplo_sistema.c

Este archivo corresponde al programa de ejemplo ejecutado para la validación del prototipo.

#include "Proceso.h"
#include "display.h"
#include "Temperatura.h"
#include "botones.h"

/*Variables de control*/
int proceso_en_marcha = OFF;
int contador_de_acciones;
acc_t accion_actual;
alarm_t alarma_actual;
tiempo_t tiempo_inicio_proceso;
tiempo_t tiempo_actual;
tiempo_t tiempo_inicio_accion;

51
tiempo_t tiempo_fin_accion;
tiempo_t tiempo_fin_proceso;
int temperatura_fin_accion;
int termometro_actual;
char process_disp [16] = "Temperatura: ";
int lcd_flag;
int buzzer_flag;
BOOL Mantener_temperatura;
int Temperatura_a_mantener;
int Aciertos_Temperatura;
int Receta_activa = 1;
int mesetas_temperatura [10];
int contador_temperatura = 0;

/*Acciones por estado*/


acc_t acciones [MAX_ACCIONES];
alarm_t alarmas [MAX_ACCIONES];

/*Este es un ejemplo de aplicación para cargar la


configuración del equipo (conecciones, etc)*/

/* Variables programables para el proceso*/


//Márgenes
int Margen_temperatura_inferior;
int Margen_temperatura_superior;
float Flujo_bomba; //En litros por minuto
float Flujo_libre; //En litros por minuto

/************************/
/* UNIDADES */
/* Temperaturas en ºC */
/* Tiempos en minutos */
/* Volumen en litros */
/************************/

//Defino las variables que almacenarán las recetas


rec_t recetas [N_RECETAS];

/*Variables del proceso*/


int estado_proceso; //MOLIENDA, MACERACION, etc...

//Inicialización de las variables a configurar


//Esta iniialización corresponde al ejemplo utilizado como prueba
void Init_System_configuration (void)
{
//Declaración de variables
int i;
int n_receta;
n_receta = Get_receta_activa();
i=0;
//Definición de variables del sistema
Margen_temperatura_inferior = 2; //ºC
Margen_temperatura_superior = 2; //ºC
Flujo_bomba = 1; //lpm
Flujo_libre = 0.5; //lpm
Aciertos_Temperatura = 0;

//Cargo las variables de la receta


Init_Receta(n_receta);

52
//Aqui inicializo las acciones de este ejemplo
//1-Prendo fuego
acciones[i].proceso = MACERACION;
acciones[i].salida = 17;
acciones[i].on_off = ON;
acciones[i].fin = POR_TEMPERATURA;
acciones[i].valor_fin =
recetas[n_receta].Temperatura_agua_maceracion_inicial;
acciones[i].n_termometro = 1;
acciones[i].alarm = TRUE;
alarmas[i].mensaje = " Inicio ";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Apago fuego
acciones[i].proceso = MACERACION;
acciones[i].salida = 17;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 1;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Prendo bomba 10
acciones[i].proceso = MACERACION;
acciones[i].salida = 10;
acciones[i].on_off = ON;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 15*60; //15 minutos
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Apago bomba 10
acciones[i].proceso = MACERACION;
acciones[i].salida = 10;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 1;
acciones[i].n_termometro = 2;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Inicio de curva de Maceración
//5-Primera meseta
acciones[i].proceso = CURVA_MACERACION;
acciones[i].salida = 1;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = recetas[n_receta].Tiempo_maceracion_1;
//30 minutos
acciones[i].n_termometro = 2;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";

53
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Segunda meseta
acciones[i].proceso = CURVA_MACERACION;
acciones[i].salida = 1;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = recetas[n_receta].Tiempo_maceracion_2;
//30 minutos
acciones[i].n_termometro = 2;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Tercera meseta
acciones[i].proceso = CURVA_MACERACION;
acciones[i].salida = 1;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = recetas[n_receta].Tiempo_maceracion_3;
//15 minutos
acciones[i].n_termometro = 2;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Fin de curva de temperatura
//Preparo agua para lavado
//Abro válvula 16
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 16;
acciones[i].on_off = ON;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 30; //30 segundos
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Prendo fuego
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 17;
acciones[i].on_off = ON;
acciones[i].fin = POR_TEMPERATURA;
acciones[i].valor_fin = recetas[n_receta].Temperatura_agua_lavado;
//80ºC
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//10-Apago fuego
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 17;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;

54
acciones[i].valor_fin = 1;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Apago válvula 16
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 16;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 30; //Espero 30 segundos
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Prendo bomba 11
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 11;
acciones[i].on_off = ON;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 5;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Prendo bomba 12
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 12;
acciones[i].on_off = ON;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 5;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Apago bomba 11
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 11;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 5;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//15-Apago bomba 12
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 12;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 5;

55
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Prendo bomba 11
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 11;
acciones[i].on_off = ON;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 5;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Prendo bomba 12
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 12;
acciones[i].on_off = ON;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 5;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Apago bomba 11
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 11;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 5;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Apago bomba 12
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 12;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 5;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//20-Prendo bomba 11
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 11;
acciones[i].on_off = ON;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 5;
acciones[i].n_termometro = 1;

56
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Prendo bomba 12
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 12;
acciones[i].on_off = ON;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 15*60; //15 minutos
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Apago bomba 11
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 11;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 1;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Apago bomba 12
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 12;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 1;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Prendo bomba 9
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 9;
acciones[i].on_off = ON;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 5;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//25-Apago bomba 9
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 9;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 5;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;

57
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Prendo bomba 9
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 9;
acciones[i].on_off = ON;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 5*60; //5 minutos
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Prendo fuego
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 17;
acciones[i].on_off = ON;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 1;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Abro válvula 18
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 18;
acciones[i].on_off = ON;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 3*60; //3 minutos
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Cierro válvula 18
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 18;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 3*60; //3 minutos
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//30-Abro válvula 18
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 18;
acciones[i].on_off = ON;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 3*60; //3 minutos
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";

58
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Cierro válvula 18
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 18;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 3*60; //3 minutos
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Abro válvula 18
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 18;
acciones[i].on_off = ON;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 3*60;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Cierro válvula 18
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 18;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 3*60; //3 minutos
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Abro válvula 18
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 18;
acciones[i].on_off = ON;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 3*60; //3 minutos
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//35-Cierro válvula 18
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 18;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 3*60; //3 minutos
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;

59
alarmas[i].titilar_lcd = FALSE;
i++;
//Abro válvula 18
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 18;
acciones[i].on_off = ON;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 3*60; //3 minutos
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Cierro válvula 18
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 18;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TEMPERATURA;
acciones[i].valor_fin = 100; //Espero a que
comience a hervir el mosto
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Aviso para inicio de Hervor
acciones[i].proceso = HERVOR;
acciones[i].salida = 1;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = recetas[n_receta].Tiempo_aditivo_1*60;
acciones[i].n_termometro = 1;
acciones[i].alarm = TRUE;
alarmas[i].mensaje = "Inicio Hervor";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Aviso para incorporar Lúpulo Amargor
acciones[i].proceso = HERVOR;
acciones[i].salida = 1;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = recetas[n_receta].Tiempo_aditivo_2*60 -
recetas[n_receta].Tiempo_aditivo_1*60;
acciones[i].n_termometro = 1;
acciones[i].alarm = TRUE;
alarmas[i].mensaje = "Aditivo 1";
alarmas[i].sonido = TRUE;
alarmas[i].titilar_lcd = TRUE;
i++;
//40-Aviso para incorporar Lúpulo Sabor
acciones[i].proceso = HERVOR;
acciones[i].salida = 1;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = recetas[n_receta].Tiempo_aditivo_3*60 -
recetas[n_receta].Tiempo_aditivo_2*60;
acciones[i].n_termometro = 1;
acciones[i].alarm = TRUE;

60
alarmas[i].mensaje = "Aditivo 2";
alarmas[i].sonido = TRUE;
alarmas[i].titilar_lcd = TRUE;
i++;
//Aviso para incorporar Clarificante
acciones[i].proceso = HERVOR;
acciones[i].salida = 1;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = recetas[n_receta].Tiempo_aditivo_4*60 -
recetas[n_receta].Tiempo_aditivo_3*60;
acciones[i].n_termometro = 1;
acciones[i].alarm = TRUE;
alarmas[i].mensaje = "Aditivo 3";
alarmas[i].sonido = TRUE;
alarmas[i].titilar_lcd = TRUE;
i++;
//Aviso para incorporar Lúpulo Aroma
acciones[i].proceso = HERVOR;
acciones[i].salida = 1;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = recetas[n_receta].Tiempo_aditivo_5*60 -
recetas[n_receta].Tiempo_aditivo_4*60;
acciones[i].n_termometro = 1;
acciones[i].alarm = TRUE;
alarmas[i].mensaje = "Aditivo 4";
alarmas[i].sonido = TRUE;
alarmas[i].titilar_lcd = TRUE;
i++;
//Aviso de fin de hervor
acciones[i].proceso = HERVOR;
acciones[i].salida = 1;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 5;
acciones[i].n_termometro = 1;
acciones[i].alarm = TRUE;
alarmas[i].mensaje = "Fin de Hervor";
alarmas[i].sonido = TRUE;
alarmas[i].titilar_lcd = TRUE;
i++;
//Apago fuego
acciones[i].proceso = HERVOR;
acciones[i].salida = 17;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 1;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//45-Aviso para hacer Whirlpool
acciones[i].proceso = HERVOR;
acciones[i].salida = 1;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 1*60; //1 minuto para hacer
whirlpool

61
acciones[i].n_termometro = 1;
acciones[i].alarm = TRUE;
alarmas[i].mensaje = "Whirlpool";
alarmas[i].sonido = TRUE;
alarmas[i].titilar_lcd = TRUE;
i++;
//Prendo bomba 10
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 10;
acciones[i].on_off = ON;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 5;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Apago bomba 10
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 10;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 5;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Prendo bomba 10
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 10;
acciones[i].on_off = ON;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 10;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Apago bomba 10
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 10;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 5;
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//50-Prendo bomba 10
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 10;
acciones[i].on_off = ON;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 20*60; //Enfrío el mosto
circulando por 20 minutos

62
acciones[i].n_termometro = 1;
acciones[i].alarm = FALSE;
alarmas[i].mensaje = "";
alarmas[i].sonido = FALSE;
alarmas[i].titilar_lcd = FALSE;
i++;
//Apago bomba 10
acciones[i].proceso = RECIRCULACION;
acciones[i].salida = 10;
acciones[i].on_off = OFF;
acciones[i].fin = POR_TIEMPO;
acciones[i].valor_fin = 10;
acciones[i].n_termometro = 1;
acciones[i].alarm = TRUE;
alarmas[i].mensaje = "Fin";
alarmas[i].sonido = TRUE;
alarmas[i].titilar_lcd = TRUE;
i++;
}

//Inicio los valores de la receta n


//Aqui se define la receta utilizada como ejemplo
void Init_Receta (int n_receta)
{
//Agua de maceración
recetas[n_receta].Temperatura_agua_maceracion_inicial = 70;
recetas[n_receta].Volumen_agua_maceracion = 40;
//Curva de maceración
recetas[n_receta].N_mesetas_maceracion = 3;
recetas[n_receta].Temperatura_maceracion_1 = 65;
recetas[n_receta].Tiempo_maceracion_1 = 30*60;
recetas[n_receta].Temperatura_maceracion_2 = 70;
recetas[n_receta].Tiempo_maceracion_2 = 30*60;
recetas[n_receta].Temperatura_maceracion_3 = 75;
recetas[n_receta].Tiempo_maceracion_3 = 10*60;
recetas[n_receta].Temperatura_maceracion_4 = NOT_USED;
recetas[n_receta].Tiempo_maceracion_4 = NOT_USED;
recetas[n_receta].Temperatura_maceracion_5 = NOT_USED;
recetas[n_receta].Tiempo_maceracion_5 = NOT_USED;
recetas[n_receta].Temperatura_maceracion_6 = NOT_USED;
recetas[n_receta].Tiempo_maceracion_6 = NOT_USED;
recetas[n_receta].Temperatura_maceracion_7 = NOT_USED;
recetas[n_receta].Tiempo_maceracion_7 = NOT_USED;
recetas[n_receta].Temperatura_maceracion_8 = NOT_USED;
recetas[n_receta].Tiempo_maceracion_8 = NOT_USED;
recetas[n_receta].Temperatura_maceracion_9 = NOT_USED;
recetas[n_receta].Tiempo_maceracion_9 = NOT_USED;
recetas[n_receta].Temperatura_maceracion_10 = NOT_USED;
recetas[n_receta].Tiempo_maceracion_10 = NOT_USED;
mesetas_temperatura [0] =
recetas[n_receta].Temperatura_maceracion_1;
mesetas_temperatura [1] =
recetas[n_receta].Temperatura_maceracion_2;
mesetas_temperatura [2] =
recetas[n_receta].Temperatura_maceracion_3;
mesetas_temperatura [3] = 0;
mesetas_temperatura [4] = 0;
mesetas_temperatura [5] = 0;
mesetas_temperatura [6] = 0;
mesetas_temperatura [7] = 0;
mesetas_temperatura [8] = 0;

63
mesetas_temperatura [9] = 0;
//Recirculación y lavado
recetas[n_receta].Tiempo_recirculado = 10*60;
recetas[n_receta].Volumen_agua_lavado = 40;
recetas[n_receta].Temperatura_agua_lavado = 80;
//Aditivos durante el hervor
recetas[n_receta].Tiempo_aditivo_1 = 1;
recetas[n_receta].Tiempo_aditivo_2 = 45;
recetas[n_receta].Tiempo_aditivo_3 = 50;
recetas[n_receta].Tiempo_aditivo_4 = 59;
recetas[n_receta].Tiempo_aditivo_5 = 60;
recetas[n_receta].Tiempo_aditivo_6 = NOT_USED;
recetas[n_receta].Tiempo_aditivo_7 = NOT_USED;
recetas[n_receta].Tiempo_aditivo_8 = NOT_USED;
recetas[n_receta].Tiempo_aditivo_9 = NOT_USED;
recetas[n_receta].Tiempo_aditivo_10 = NOT_USED;
recetas[n_receta].Tiempo_de_hervor = 60;
recetas[n_receta].Tiempo_whirlpool = 1;
//Enfriamiento
recetas[n_receta].Tiempo_de_enfriamiento = 20;
}
//Función de inicialización
void Init_Proceso (void)
{
Reset_Timer();
proceso_en_marcha = ON;
contador_de_acciones = -1;
tiempo_inicio_proceso = Get_tiempo_actual();
Actualizar_a_proxima_accion();
set_flag(0);
}
//Función motor de la máquina de estados que avanza en las acciones
void Check_Proceso (void)
{
tiempo_t tiempo_aux;
int temperatura_actual;
int aux_temp;

if (Programa_activo() == ON)
{
//Chequeo condición de fin de acción
if (accion_actual.fin == POR_TIEMPO)
{
//Chequeo tiempo actual vs. tiempo fin
tiempo_aux = Get_tiempo_actual();
//Si se cumplió el tiempo de la acción, paso a la siguiente
if ((tiempo_aux.segundo >= tiempo_fin_accion.segundo)
&& (tiempo_aux.minuto >= tiempo_fin_accion.minuto)
&& (tiempo_aux.hora >= tiempo_fin_accion.hora)
&& (tiempo_aux.dia >= tiempo_fin_accion.dia))
{
Actualizar_a_proxima_accion ();
}
}
else if (accion_actual.fin == POR_TEMPERATURA)
{
aux_temp = Get_Temp(accion_actual.n_termometro);
if (aux_temp != TEMP_ERR)
{
temperatura_actual = aux_temp;
process_disp[13]= ((char) (temperatura_actual/100)) + 48;

64
process_disp[14]= ((char) ((char) (temperatura_actual -
100*(temperatura_actual/100))/10)) +48;
process_disp[15]= ((char) (temperatura_actual -
100*(temperatura_actual/100)-10*(((temperatura_actual -
100*(temperatura_actual/100)))/10))) +48;
}
else
{
temperatura_actual = -1;
process_disp[13]= 'E';
process_disp[14]= 'r';
process_disp[15]= 'r';
}
//Escribo el valor de temperatura, si no hay opciones de menu
if (get_flag()==0)
EscribeCadenaDisplay(1, process_disp);
//Chequeo temperatura actual vs. temp. fin
if (temperatura_actual>=accion_actual.valor_fin)
Aciertos_Temperatura++;
else
Aciertos_Temperatura = 0;
if (Aciertos_Temperatura >= ACIERTOS_TEMP)
{
Actualizar_a_proxima_accion ();
Aciertos_Temperatura = 0;
}
}
else if (accion_actual.fin == POR_BOTON)
{
//Chequeo que se oprima un botón...
if((BOTON_ENTER==0)) //Enter
{
Actualizar_a_proxima_accion ();
}
}
if (Mantener_temperatura == TRUE)
{
//Mido la temperatura
aux_temp = Get_Temp(accion_actual.n_termometro);
if (aux_temp != TEMP_ERR)
temperatura_actual = aux_temp;
//Mantengo la temperatura de maceración dentro del rango
establecido
if (temperatura_actual >= (Temperatura_a_mantener +
Margen_temperatura_superior))
{
//Chequeo que no haya errores de medición, por repetición
del valor
Aciertos_Temperatura++;
if (Aciertos_Temperatura >= ACIERTOS_TEMP)
{
//salida_off (accion_actual.salida);
salida_off(9);
salida_off(17);
salida_off(10);
Aciertos_Temperatura = 0;
}
}
else if (temperatura_actual <= (Temperatura_a_mantener -
Margen_temperatura_inferior))
{

65
//Chequeo que no haya errores de medición, por repetición
del valor
Aciertos_Temperatura++;
if (Aciertos_Temperatura >= ACIERTOS_TEMP)
{
//salida_on (accion_actual.salida);
salida_on(9);
salida_on(17);
salida_on(10);
Aciertos_Temperatura = 0;
}
}
}
}
}
//Funciones de servicio para el control de las acciones
tiempo_t Get_tiempo_actual (void)
{
tiempo_t este_tiempo;
este_tiempo.dia = get_dias();
este_tiempo.hora = get_horas();
este_tiempo.minuto = get_minutos();
este_tiempo.segundo = get_segundos();
return este_tiempo;
}
void Ejecutar_accion (int n_accion)
{
if (acciones[n_accion].on_off == ON)
salida_on (acciones[n_accion].salida);
else
salida_off (acciones[n_accion].salida);
}
void Ejecutar_alarma (int n_accion)
{
if (alarmas[n_accion].sonido == TRUE)
Set_buzzer_flag(TRUE);
//Prender buzzer
if (alarmas[n_accion].titilar_lcd == TRUE)
{
Set_lcd_flag(TRUE);
//Titilar LCD
}
//Actualizo mensaje
EscribeCadenaDisplay(2, alarmas[n_accion].mensaje);
}
void Actualizar_fin_tiempo_accion (int n_accion)
{
tiempo_t fin;
tiempo_t actual;
unsigned int sumar_dias;
unsigned int sumar_horas;
unsigned int sumar_minutos;
unsigned int sumar_segundos;

actual = Get_tiempo_actual();

sumar_dias = acciones[n_accion].valor_fin/(60*60*24);
sumar_horas = acciones[n_accion].valor_fin/(60*60) -
24*sumar_dias;
sumar_minutos = acciones[n_accion].valor_fin/(60) - 24*sumar_dias
- 60*sumar_horas;

66
sumar_segundos = acciones[n_accion].valor_fin - 24*sumar_dias -
60*sumar_horas - 60*sumar_minutos;

fin.dia = actual.dia + sumar_dias;


fin.hora = actual.hora + sumar_horas;
fin.minuto = actual.minuto + sumar_minutos;
fin.segundo = actual.segundo + sumar_segundos;

//Corrección sexagesimal
if (fin.segundo >= 60)
{
fin.minuto++;
fin.segundo -= 60;
}
if (fin.minuto >= 60)
{
fin.hora++;
fin.minuto -= 60;
}
if (fin.hora >= 24)
{
fin.dia++;
fin.hora -= 24;
}
tiempo_fin_accion = fin;
}
void Actualizar_fin_temperatura_accion (int n_accion)
{
temperatura_fin_accion = acciones[n_accion].valor_fin;
termometro_actual = acciones[n_accion].n_termometro;
}
void Actualizar_a_proxima_accion (void)
{
contador_de_acciones++;
accion_actual = acciones[contador_de_acciones];
alarma_actual = alarmas[contador_de_acciones];
Ejecutar_accion (contador_de_acciones);
if (accion_actual.alarm == TRUE)
{
set_flag(ON);
Ejecutar_alarma (contador_de_acciones);
}
else
set_flag(OFF);
if (accion_actual.fin == POR_TIEMPO)
Actualizar_fin_tiempo_accion (contador_de_acciones);
if (accion_actual.proceso == CURVA_MACERACION)
{
Temperatura_a_mantener =
mesetas_temperatura[contador_temperatura++];
Mantener_temperatura = TRUE;
}
else
Mantener_temperatura = FALSE;
}

//Funciones de servicio auxiliares


void Set_lcd_flag (BOOL valor)
{
lcd_flag = valor;
}

67
BOOL Get_lcd_flag (void)
{
return lcd_flag;
}
void Set_buzzer_flag (BOOL valor)
{
buzzer_flag = valor;
}
BOOL Get_buzzer_flag (void)
{
return buzzer_flag;
}
int Programa_activo (void)
{
return proceso_en_marcha;
}
void Reanudar_programa (void)
{
proceso_en_marcha = ON;
}
void Detener_programa (void)
{
proceso_en_marcha = OFF;
}
void Set_contador_de_acciones (int valor)
{
contador_de_acciones = valor;
}
int Get_receta_activa (void)
{
return Receta_activa;
}
void Set_receta_activa (int n_receta)
{
Receta_activa = n_receta;
}

2.5. Plan de Prueba de Módulos y de Depuración de Soft

No se avanzará en el desarrollo del software sin haber completado una etapa previa, la cual incluye
la prueba de los módulos programados. El software se desarrollará en dos etapas:

 Primera etapa: fase del programa de bajo nivel, que incluye el desarrollo y prueba de los distintos
drivers. Las aplicaciones que requieren drivers son: Display LCD, sensores de temperatura,
protocolo para registros de desplazamiento. Cada driver se realizará en forma independiente del
resto, utilizando pines físicos del microprocesador, para que puedan correr simultáneamente.
Una vez que se validen todos los drivers por separado, se procederá a iniciar la segunda etapa de
programación.
 Segunda etapa: fase del programa de mayor nivel, representado por una máquina de estados que
controle el proceso de producción de cerveza. Esta etapa hará uso de los servicios provistos por
los drivers de la primera etapa. Esta etapa actuará directamente sobre el hardware, por lo que se
requerirá tener disponible un prototipo inicial de la placa de potencia, con al menos un circuito
completo para activar una salida. Para depurar la máquina de estados, se utilizará la placa de
salida con sus leds activados directamente desde los buffers, sin alimentar las entradas y alta
tensión (vivo y neutro) lo cual permitirá evaluar el comportamiento del software, son correr
riesgos para la seguridad del programador.

68
X. CONTRUCCIÓN DEL PROTOTIPO

Se construye un prototipo del proyecto, utilizando un gabinete fabricado manualmente, al igual que
las placas impresas. Estos dos elementos serán tercerizados en la etapa de producción. Además, se efectúa
el soldado de componentes, ensamblado del equipo y verificación funcional del sistema, actividades que
sí formarán parte de la producción de cada equipo.

1. DEFINICIÓN DE LOS MÓDULOS

Los módulos que constituyen el equipo se pueden distinguir en los siguientes grupos:

1.1. Gabinete

El gabinete está previsto que se construya en dos partes: una base, y una tapa. Para el caso del
prototipo, por baja disponibilidad de chapa de acero inoxidable, se construyó la tapa dividida en dos
partes. Los planos y el diseño mecánico se detalla en la sección correspondiente (10.3). Se eligió como
material acero inoxidable AISI 304, con un espesor de 0,75mm. Entre las virtudes de este material,
destacamos las siguientes, que llevaron a su selección:

 Por tener una superficie limpia, brillante e inoxidable, no requiere pintura.


 Tiene una buena dureza
 Utilizando un espesor de 0,75mm., se logra un gabinete fácil de plegar (disminuye costos de
fabricación), pero lo suficientemente duro como para incluir agujeros roscados con un macho, de
forma tal de ensamblar sus partes sin necesidad de tuercas.
 Su aspecto y color son compatibles con una instalación productora de cerveza, armonizando con
las ollas, maceradores, fermentadores, etc., para el caso de cervecerías comerciales.

También debe considerarse su desventaja fundamental, que reside en un costo mayor si se lo


compara con un gabinete de acero común. No obstante, esta diferencia se compensa por prescindir de un
tratamiento con pintura, que sería indispensable para el caso de una chapa de acero común.
Dado el diseño previsto (que incluye las borneras en los costados de la placa de potencia), se
descartó la posibilidad de utilizar gabinetes plásticos prefabricados, ya que las medidas deben ser
precisas, y no hay disponible en el mercado un diseño compatible con el presente diseño. Por último, se
descartó la posibilidad de mandar a hacer un gabinete de plástico termoformado a medida, ya que los
costos de la matricería lo hacen inviable, en especial si se prevé trabajar a baja escala.
Cabe destacar que la parte de la base tendrá 6 orificios para atornillar las patas de goma, y otros
dos para amurar el transformador. Además, en su parte posterior tendrá un orificio para el pasa cable y
una caladura para un porta fusibles, y en el lado cercano al transformador, presentará un calado para
permitir una mejor ventilación. Por otra parte, la tapa tendrá 8 orificios (7 botones y el led de encendido),
y una caladura por donde asomará la pantalla del display. Asimismo, presentará una caladura en donde
encastrará la tecla de encendido.

1.2. Placas impresas con sus componentes

El equipo tendrá dos placas impresas, una con los circuitos de la fuente, y salida de potencia, y la
otra con los circuitos lógicos, botones y display. La placa de potencia irá atornillada con 6 tornillos a la
base, mientras que la placa lógica se atornillará con 4 tornillos a la tapa el gabinete. Ambas placas se
comunicarán mediante un cable plano de 26 vías, con conectores IDC. La alimentación de la placa lógica

69
será proporcionada por el circuito de fuente ubicado en la placa de potencia, por lo cual otros dos cables
(positivo y negativo) conectarán estas dos placas.

1.3. Circuito de alimentación

El circuito de alimentación consta de un cable de alimentación armado de 3 patas (como indica la


norma). La línea de tierra se conectará a uno de los tornillos de las patas de goma, de modo que la
totalidad del gabinete quede conectado a tierra. Tanto el vivo como el neutro serán switcheados por la
tecla de encendido, de doble paso, para mayor seguridad del usuario. La línea del vivo tendrá un fusible
conectado en serie antes de ingresar a la tecla de encendido. A las salidas de la tecla, se conectará el
transformador. Para el caso del prototipo implementado, por estar éste desarrollado para una planta de
producción de cerveza de baja potencia, se utilizará la misma alimentación para las salidas de potencia.
Para equipos que requieran mayor consumo, está previsto que se utilicen fuentes de alimentación
independientes, para grupos de 6 salidas, como se explicó anteriormente. La salida del transformador se
conecta al puente de diodos ubicado en la placa de potencia, que alimentará a todo el equipo.

1.4. Módulo de censado de temperatura

Para resolver el censado de temperatura, se optó por un integrado digital, con datos seriales, que
funciona con 3 líneas (Vcc, Gnd y Data). Se utilizará cable del tipo telefónico por disponer de 4 líneas
(una queda sin uso), tener un bajo costo, excelente disponibilidad, y una resistencia térmica suficiente
para la aplicación. En el otro extremo del cable se utiliza un conector polarizado, para evitar errores de
conexión por parte del usuario. Tanto el integrado como el conector irán soldados al cable, y recubiertos
por aislante termocontraíble. Se prevé el uso de vainas de acero inoxidable para sumergir estos
termómetros en el mosto, agua, etc. El usuario podrá disponer de sus propias vainas, que requerirán un
diámetro interno de más de 5,5mm. Para el prototipo se utilizaron varillas cortadas de acero inoxidable
AISI 304, con un roscado en un extremo, en donde se colocó un bulón (también de acero inoxidable). La
unión se selló con pasta de teflón, para garantizar la hermeticidad de la vaina y el correcto
funcionamiento del termómetro.

2. DISEÑO DE LOS CIRCUITOS IMPRESOS

Los circuitos impresos se diseñaron teniendo en cuenta la estructura con la que el equipo fue
ideado. La placa lógica albergaría al microprocesador, junto con los botones, display, y conectores para
los termómetros. Tendría el tamaño justo para que pueda situarse justo por encima de la placa de
potencia, dejando las borneras y los leds indicativos de esta última hacia fuera. La placa lógica va
atornillada a la tapa del gabinete, por lo cual define la posición de todos sus componentes con los que
interactuará el usuario. Por otra parte, la placa de salida tendrá su circuito en la parte central, alrededor del
conector IDC que se ubicará justo por debajo de la placa lógica. Las borneras y leds indicativos deben
quedar fuera del área que cubre la placa lógica.
A continuación, se muestran las figuras correspondientes al diseño de los dos PCBs:

70
Fig. 15. Diseño de PCB de la placa lógica

Fig. 16. Diseño de PCB de la placa de potencia

Las pistas rojas corresponden a la capa superior, mientras que las azules a la inferior, en ambos
casos. Las líneas amarillas corresponden a la forma de los componentes. No se prevé imprimir en las

71
placas finales esta última capa (líneas amarillas) en forma de serigrafía, de modo de minimizar el costo de
impresión de las placas. Por este motivo, la numeración e indicaciones relevantes se realiza utilizando el
mismo cobre de las pistas. Se prevé llevar a cabo el soldado de los componentes teniendo una placa ya
soldada y probada como referencia, de modo tal que el dibujo de los componentes no resulte necesario.
A continuación, se muestran dos imágenes que corresponden a las placas fabricadas manualmente
para el prototipo.

Fig. 17. Prototipo armado de la placa lógica.

Fig. 18. Prototipo armado de la placa de potencia.

72
Consideraciones de ruteo:

Para el caso de la placa de salida de potencia, se procuró conservar una buena distribución de los
componentes, como se dijo antes, de modo de que las borneras y los leds quedaran visibles. Además,
había quedado prefijada la posición del conector IDC a partir del diseño de la placa lógica. En cuanto al
ruteo propiamente dicho, se ubicaron las líneas que conducen corrientes en alta tensión (220VAC) lo más
cerca posible del borde, tratando de que queden lejos de aquellos componentes que requerían la referencia
de tierra lógica (como el caso de los optotriacs). Por este motivo se observa, a grandes rasgos, que los
componentes lógicos (optotriacs y buffers), junto con el circuito de alimentación, se encuentran en la
parte central de la placa; mientras tanto, las borneras de salida, los triacs, y circuitos de snubber se
encuentran en los laterales. Como se mencionó anteriormente, se incorporaron 4 borneras dobles para
recibir la alta tensión, de modo de que cada una de estas borneras esté conectada a 6 triacs, y las salidas se
encuentren independizadas unas de otras, en grupos de a 6. Esto permitirá alimentarlas con distintas
fuentes de 220VAC cuando la potencia requerida sea muy grande. Para mayor información, se disponen
los esquemáticos de los circuitos en los anexos correspondientes.
Para la placa lógica, resultó fundamental la ubicación de algunos componentes, como botones,
display, led de encendido, y conectores para los termómetros, ya que estos saldrían por fuera del gabinete
y determinarían su apariencia. Se optó por ubicar la placa armada del display en el extremo superior
izquierdo de la placa, para evitar tener que realizar un calado interno, lo cual elevaría los costos. Otro
aspecto importante fue el hecho de que el microprocesador, con el encapsulado elegido, requiere de pistas
muy finas, por lo que deberán extremarse los cuidados a la hora de manufacturar esta placa, ya que habrá
muy poco lugar para márgenes de error. Un detalle a destacar es la incorporación de un buffer de entrada
y lugares para 3 pines dobles, que no fueron soldados en el prototipo. Esos componentes están pensados
para eventuales mejoras futuras del equipo, en el cual se incorporen tres entradas lógicas binarias para,
por ejemplo, dar aviso de que un líquido llegó a un nivel dado. Como las dimensiones permitían la
incorporación de estos componentes, y estos no modifican el valor de la placa impresa, se incorporaron
para evitar, en el futuro, tener que rediseñar esta placa.

3. DISEÑO MECÁNICO

El diseño mecánico del equipo está íntimamente relacionado con el diseño de las placas impresas.
El gabinete tiene una base de 17cm. x 35cm. La placa de potencia (17cm. x 20cm.) va atornillada con 6
tornillos (3 por cada lateral) en el la parte derecha del equipo. Esto deja un lugar de 17cm. x 15cm. para
albergar a la tecla de encendido, cable, porta fusible, cables de conexión, y transformador. La otra parte
del gabinete, la tapa, se atornillará a la base con 8 tornillos en la parte superior. A continuación, se
muestran las figuras que corresponden a las formas de la chapa de acero inoxidable. Las medidas de estas
partes corresponden a las especificaciones dimensionales expresadas en la sección correspondiente.

Fig. 19. Dibujos de los planos para recorte de la chapa del gabinete.

73
El resultado del prototipo armado, con sus componentes instalados, se muestra en la siguiente
imagen:

Fig. 20. Prototipo ensamblado

4. DETALLES DE CONSTRUCCIÓN Y PRECAUCIONES DE MONTAJE

El primer paso en el proceso de montaje del equipo consiste en el soldado de todos los
componentes de las dos placas. El gabinete será tercerizado, y se dispondrá del mismo en dos partes, ya
dobladas, con todas las caladuras y agujeros que se muestran en el gráfico del ítem anterior. Los orificios
que serán roscados, tendrán un diámetro de 2,25mm., de modo que se pueda realizar una rosca por medio
de un macho. El resto de los orificios por donde pasarán tornillos serán de 3mm., de modo que tenga una
funcionalidad pasante. Todas las roscas con macho se harán en la parte base del gabinete, para los 8
tornillos de unión entre las partes del gabinete, y para los 6 tornillos de unión entre la base y la placa de
potencia. Una vez realizadas las roscas, se procederá a fijar la placa de potencia, con 6 tornillos con
arandela. En este paso, resulta muy importante fijar dos tiras de goma entre la placa y el gabinete, para
garantizar aislamiento eléctrico. Los tornillos pasarán a través de estas tiras de goma. Seguidamente, se
coloca el cable armado, con un pasa cable por el orificio asignado. Para afirmarlo, se coloca pegamento
de secado rápido entre el cable y el pasa cable, y se lo afirma con un precinto (con su excedente cortado).
Seguidamente se atornilla el porta fusible, con su fusible ya colocado (para el prototipo, se utilizó un
fusible de 10A, aunque su valor podrá variar según la instalación que se desee automatizar, y sus
periféricos). Luego, se procede a atornillar el transformador, con dos tonillos, dos tuercas y cuatro
arandelas. Seguidamente, se colocan las seis patas de goma, con 6 tornillos y sus tuercas
correspondientes. A continuación, se procede al armado de la tapa del gabinete. Para eso se coloca en
posición la placa lógica, y se la afirma a la tapa con 4 tornillos con sus respectivas tuercas. También se
coloca la tecla de encendido, que encastra a presión.

74
Una vez armadas las dos partes, se procede a realizar las conexiones eléctricas. En la línea de tierra
del cable armado, se coloca un terminal circular, que se fijará a la tuerca de la pata de goma más cercana
al cable. La línea de neutro llevará un terminal hembra que irá a la entrada de la tecla de encendido. La
línea del vivo se soldará a un terminal del porta fusible, y se cubrirá la soldadura con termocontraíble. Se
soldará al otro terminal del porta fusible, del mismo modo, una extensión de cable, y se fijará un terminal
hembra en su otro extremo, para conectarlo a la otra entrada de la tecla. En los os bornes de salida de la
tecla, irán conectados los cables del primario del transformador. Además, para este prototipo, se
incorporaron extensiones de cable para alimentar los 4 grupos de 6 salidas de potencia, conectándolos
también a la salida de la tecla de encendido. Todas estas conexiones se realizaron con los terminales
correspondientes, recubiertos adecuadamente con accesorios plásticos. Luego, se atornillan los cables del
secundario del transformador a la entrada de la placa de salida. Se conectan los dos cables de
alimentación de la placa lógica, y finalmente se arma l cable IDC y se conecta en ambas terminales de las
placas. De este modo, todo está listo para terminar de ensamblar el gabinete, uniendo sus dos partes, y
atornillándolos con los 8 tornillos correspondientes.
Aquí se muestra una imagen del prototipo con sus partes, justo antes de unir las partes del gabinete.
Se recuerda que el prototipo tiene leves diferencias estructurales en su gabinete, por la disponibilidad de
chapa, como, por ejemplo, la tapa se encuentra partida en dos.

Fig. 21. Prototipo durante el ensamblado.

75
XI. VALIDACIÓN DEL PROTOTIPO

1. VALIDACIÓN DEL HARD

1.1. Plan y protocolos especiales de medición

Una vez concluidas y validadas las pruebas de cada módulo por separado, se desarrolló un
programa de prueba del prototipo, en el cual se lleva a cabo un proceso completo de producción de
cerveza, desde la molienda del grano, hasta el proceso de enfriado para comenzar la fermentación.
Para esto se armó un sistema basado en los recipientes disponibles en un equipo de cerveza casero. Se
utilizaron 2 barriles plásticos de unos 110 litros de capacidad cada uno, una olla de aluminio con una
capacidad de 98 litros, y dos fermentadores cónicos de 60 litros (de los cuales uno fue utilizado como
macerador, aislándolo térmicamente con lana de vidrio).
Para automatizar esta instalación, se utilizaron 4 bombas plásticas, dos electroválvulas comunes
(utilizadas en los lavarropas), y una electroválvula de mayor calidad para controlar el flujo de gas del
quemador. Todos estos periféricos fueron conectados y controlados desde el prototipo del equipo.
Además, se conectó un motor monofásico de unos 400W de potencia para accionar el molino de
malta, y se controló su encendido desde el equipo, con el fin de demostrar su capacidad de
funcionamiento con altas potencias.

Fig. 22. Instalación utilizada para verificar el funcionamiento del prototipo.

A continuación, se presenta un esquema de la instalación utilizada para la prueba y validación del


prototipo armado. Se generó un programa basado en esta instalación, y se produjo un batch de unos 50
litros de cerveza.
Para mayor información, se detalla el proceso en el próximo ítem (Medidas).

76
Fig. 23. Esquema de la instalación utilizada para la validación del prototipo.

1.2. Medidas

Para medir el desempeño del equipo en un caso real, se preparó la instalación mencionada
previamente. Se procederá a describir brevemente el funcionamiento de la misma, haciendo uso de
esquemas que faciliten su comprensión. Dentro de la siguiente descripción se detalla el proceso de
elaboración de cerveza artesanal. En la sección correspondiente al software se detallan las acciones
programadas para llevar a cabo esta producción de ejemplo.
Ante todo, se deben mencionar los ingredientes que se utilizarán, en este caso, para elaborar unos
50 litros de cerveza rubia del estilo Pilsen Lager, una receta de origen germano.
Para esto se utilizan:

 80 litros de agua
 10 Kg de malta pálida
 400 grs de malta levemente tostada (estilo Caramunich)
 20 grs de lúpulo estilo Cascade
 10 grs de lúpulo estilo Hellertauer
 4 grs de clarificante de hervor (Whirlflock)
 11,5 grs de levadura seca (estilo Saflager-W34/70)

Antes de dar comienzo al proceso automatizado, se preparan los ingredientes. Para ello, se divide
el agua en dos partes (iguales, para esta receta), y se ubican unos 40 litros en un depósito (controlado por
la válvula 16) y los otros 40 litros en la olla.
Por otra parte, debe molerse la malta. El proceso de molienda tiene dos objetivos fundamentales: el
primero, y más importante, es romper el grano para facilitar la disolución de los azúcares fermentables

77
durante la maceración. El segundo, tiene que ver con lograr una textura capaz de actuar como filtro
cuando se asiente, de modo que, al hacer recircular el agua azucarada desde el fondo del macerador hacia
la parte de arriba, el líquido se vaya librando de impurezas para lograr un producto cristalino.
En este caso, la molienda del grano se efectuó utilizando un motor de poco más de 400W de
potencia, y se lo conmutó desde una de las salidas del equipo, para verificar su funcionamiento con cargas
inductivas de una potencia considerable. El resultado fue un éxito, ya que el motor del molino pudo
controlarse sin inconvenientes.
La malta molida, entonces, se coloca en el recipiente macerador, dentro de una bolsa de tela que
ayudará al filtrado, y evitará que se escapen partículas muy grandes que puedan interferir con el
funcionamiento de las bombas. Una vez que la malta está molida en el macerador, y el agua se encuentra
dividida y ubicada en sus recipientes correspondientes, se da lugar al inicio del proceso.
En primer lugar, deben calentarse unos 40 litros de agua, para mezclar con la malta y realizar el
proceso de macerado. Para ello, se abre la válvula de gas (17) y se espera a que la temperatura del agua
alcance unos 70ºC.

Fig. 24. Estado en el inicio del proceso.

Una vez que se ha alcanzado la temperatura deseada, se bombea el agua (10) hacia el macerador,
para dar inicio a la maceración. El tiempo de bombeo fue estimado midiendo previamente el flujo de la
bomba, y dejando un margen de seguridad importante, ya que a este tipo de bombas no les afecta trabajar
en vacío.

78
Fig. 25. Trasvase del agua hacia el macerador.

Una vez que se completó el trasvase, comienza la etapa de maceración. En esta etapa, de definirá la
calidad de la maceración, que determinará el rendimiento del grano. Una buena maceración debe poder
disolver la mayor cantidad posible de azúcar contenida en el grano, y lograr una especie de jarabe con la
mayor densidad posible. Se puede realizar una maceración pobre, pero utilizando más cantidad de malta
para lograr el mismo resultado, o bien, utilizar la misma cantidad, aunque el resultado tendrá menor
densidad, lo cual determinará un menor cuerpo para el producto final. Entonces, la calidad de la
maceración determinará el rendimiento. Para optimizarlo, es necesario seguir curvas de temperatura y
tiempo, establecidas por el maestro cervecero, que dependerán de las maltas utilizadas, el volumen de
cerveza a producir, el cuerpo que se desea en el producto final, etc. En este ejemplo, se optó por una
maceración de 90 minutos, trabajando 30 minutos a 65ºC, 30 minutos a 70ºC, y 30 minutos a 75ºC.

79
Fig. 26. Equipo durante la maceración.

En la olla se había calentado agua hasta unos 70ºC, pero el proceso de trasvase y el hecho de que la
malta se encuentra fría, reduce la temperatura inicial de maceración unos 60ºC aproximadamente. Cabe
destacar que el macerador fue cubierto con lana de vidrio aluminizada, para preservar mejor la
temperatura interna. En este punto (cuando finaliza el trasvase), el sistema comienza a trabajar para
respetar la curva de maceración especificada en el programa. Para ello, toma un margen de 2ºC
(programable) y el programa comienza un ciclo de calentamiento para elevar la temperatura, o para
cambiar a un nuevo escalón de temperatura. En este caso, esto se realizó bombeando el líquido de
maceración hacia la olla, prendiendo la válvula para que se encienda la llama que caliente el líquido, y
volviéndolo a bombear al macerador, como se muestra a continuación.

80
Fig. 27. Calentamiento del agua de maceración, para elevar su temperatura.

Este ciclo se ideó teniendo en cuenta la disponibilidad de equipamiento. En realidad, se prevé que
un equipo más completo disponga de otro quemador, y la maceración se lleve a cabo en una nueva olla,
de modo que calentar el líquido implica solamente abrir una válvula de gas.
Antes de que finalice la etapa de maceración, y una vez que el líquido alcance una temperatura de
75ºC (último escalón de la curva), se avanza con el siguiente paso (por este motivo, se programa el último
escalón en 15 minutos, teniendo en cuenta el tiempo de estos pasos). Con la olla vacía, se abre la válvula
16 para llenarla con los 40 litros de agua que se habían reservado. A su vez, se abre la válvula de gas (17)
para calentar estos 40 litros. Esta agua se denomina “agua de lavado”, porque será utilizada para lavar el
grano de la maceración.

81
Fig. 28. Recirculación, filtrado con el propio grano. Simultáneamente, se llena la olla.

Cuando el agua alcanza una temperatura de unos 80ºC, se bombea el agua (11) a un reservorio
ubicado encima del macerador. Mientras tanto, el agua de maceración de hace recircular, bombeándola
mediante la bomba 12, como se explicó previamente, para realizar un proceso de filtrado, utilizando el
mismo grano como filtro.

82
Fig. 29. Trasvase del agua de lavado, para desocupar olla.

Cuando la olla se ha vaciado, se comienza a llevar el líquido de maceración (en este punto, la
maceración está completa) hacia la olla, bombeándola con la bomba 9. Cuando se ha vaciado buena parte
del macerador, se comienza el proceso de lavado, dejando caer el agua de lavado (por medio de la válvula
18) sobre el grano depositado en el macerador. Este proceso de realiza en secuencias de 3 minutos (3
minutos encendido y 3 apagado) para que el grano se lave suavemente, sin inundar el macerador.
Mientras tanto, el líquido obtenido se sigue bombeando hacia la olla, y se va calentando, ya que el
siguiente proceso será el hervor, por lo que el almíbar producto de la maceración y lavado debe alcanzar
una temperatura de100ºC.

83
Fig. 30. Vaciado del macerador, y lavado de la malta.

Una vez que se ha alcanzado la temperatura de hervor en la olla, se deja de bombear el líquido de
maceración, ya que para este punto prácticamente se ha vaciado el macerador, aunque la malta absorbe
una cantidad considerable de agua, por lo que siempre goteará un poco. En este punto comienza la
cocción de la cerveza. Durante esta etapa se deben incorporar algunos aditivos, como lúpulo y
clarificante, en distintos momentos. Para esta receta, el tiempo de hervor es de 60 minutos, adicionando
los aditivos de la siguiente forma:

 O minutos (inicio del hervor): 20 grs de lúpulo Cascade (amargor)


 45 minutos: 7 grs de lúpulo Hellertauer (sabor)
 50 minutos: 4 grs de clarificante de hervor (Whirlflock)
 58 minutos: 3 grs de lúpulo Hellertauer (aroma)

Se observa que la adición de lúpulo se realiza en distintos momentos, ya que cada adición tiene una
finalidad específica para aportar amargor, sabor o aroma al producto.
Para este ejemplo, el sistema simplemente ejecuta una alarma sonora en los momentos descriptos,
para que el usuario incorpore manualmente los aditivos. No obstante, cabe destacar que el equipo tiene
libre la mayoría de sus salidas, por lo cual podrían utilizarse 4 de éstas para controlar, por ejemplo,
pequeñas bobinas que, con un dispositivo adecuado, deje caer los aditivos, de modo de independizar al
usuario del proceso.

84
Fig. 31. Etapa de hervor: cocción del mosto.

Cuando finalizan los 60 minutos de cocción, el sistema le avisa al usuario para que realice lo que
en la jerga se denomina “Whirlpool”. Este proceso consiste en revolver el producto de hervor
intensamente de modo de formar una especie de remolino. Este proceso acumula las partículas sólidas (en
especial lúpulo no disuelto) en el fondo de la olla, en el centro, de modo que el producto gane mayor
claridad. Podría prescindirse de este paso (a costa de un producto de fermentación algo más turbio), o
bien podría realizarse mediante una bomba que recircule el líquido. Se recuerda que se han utilizado tan
solo 7 salidas de las 24 disponibles en el equipo.
El último paso del proceso es el enfriado del mosto (cerveza sin fermentar), mediando un enfriador
contracorriente, que consiste de una serpentina de acero inoxidable, cubierta por una manguera que
permite el paso de agua fría en dirección opuesta. De este modo, se enfría el mosto hasta su temperatura
de fermentación (unos 20ºC-25ºC para esta receta). Para este caso, se cambió de lugar una manguera para
que el sistema quede conectado para bombear agua hacia el fermentador. Esto podría remplazarse por una
válvula doble, por ejemplo, o una nueva bomba.

85
Fig. 32. Enfriado del mosto ya hervido, para iniciar fermentación.

Cuando se trasvasa la totalidad del mosto hasta el fermentador, y se alcanza la temperatura


adecuada, se incorpora la levadura (para este caso, se utilizó levadura en polo, que no requiere activación
previa). De este modo, comienza el proceso de fermentación, que durará entre 10 y 20 días, dependiendo
de la temperatura ambiente. Está previsto que el sistema pueda realizar un control de temperatura de
fermentación, el cual requiere una fuente de agua fría con una serpentina para hacerla circular dentro del
fermentador, o algún sistema de enfriamiento. Como no se disponía del equipamiento adecuado para
controlar esta temperatura, se deja actuar a la fermentación a temperatura ambiente, ya que el tipo de
levadura se eligió considerando la época del año (invierno, ya que este tipo de levadura “lager” trabaja
mejor a temperaturas bajas, que oscilan entre los 10ºC y 15ºC, en general). Se insiste en la disponibilidad
de salidas libres, y en que este pretende ser un equipo versátil, adaptable a distintas situaciones de
equipamiento de elaboración cervecera.

1.3. Evaluación

El equipo fue puesto a prueba en un ejemplo concreto utilizando un equipamiento muy elemental.
Esto implicó que el proceso no se haya podido realizar en forma 100% automática, debiendo el usuario
actuar para la incorporación de aditivos de hervor, whirlpool, cambio de una manguera, y apertura de
válvula para circulación de agua fría. No obstante, solamente se utilizaron 7 de las 24 salidas disponibles
en el equipo, y en todos los casos se sugiere una alternativa para automatizar todos los pasos del proceso.
De esta forma, con los recursos económicos que permitan una instalación adecuada de equipamiento, se
puede lograr una automatización completa.

86
1.4. Resultados

Se realizó una prueba exitosa del equipo desarrollado, logrando la automatización de la mayor
parte del proceso cervecero, y logrando una producción de unos 50 litros de cerveza artesanal. El tiempo
de producción resultó similar a otras ocasiones en las que se desarrolló la misma receta, pero de forma
manual. No obstante, las intervenciones del usuario fueron mínimas, dejando lugar para el desarrollo de
otras actividades mientras se produce la cerveza con control electrónico.
Si bien la automatización no fue completa, sí se controló gran parte del proceso de forma
automática, y se dieron alternativas para automatizar la totalidad del proceso, en el caso de que se
disponga de los recursos necesarios.
Otra observación pertinente es que el sistema empleado para controlar la temperatura de
maceración resultó muy lento. El gradiente de temperatura alcanzado generó una curva de maceración
más lineal que escalonada, ya que se tardaba entre 15 y 20 minutos para aumentar los 5ºC de diferencia
entre un escalón u otro. Como se mencionó previamente, la mejora para este inconveniente reside en la
incorporación de una nueva olla con quemador, de modo que la temperatura se controle sencillamente con
una electroválvula de gas, y la capacidad de entregar calor sea mayor. Si bien este problema afecta al
ejemplo realizado, es un problema de instalaciones, y no del equipo en sí. Además, el producto logrado
tuvo una buena densidad final, y aunque la curva no haya sido óptima, se mejoró el rendimiento respecto
de otras producciones manuales, con temperatura constante (o levemente descendente, por imperfecciones
de aislación térmica), ya que se logró una densidad del mosto similar, pero utilizando más agua y
obteniendo alrededor de un 20% más de producto final, con la misma cantidad de malta.

2. VALIDACIÓN DEL SOFT

La validación del software implementado está íntimamente ligada al proceso descripto de


validación de hardware, porque se utilizaron ambos aspectos en conjunto para realizar la prueba de
campo. En este sentido, tanto el desarrollo de la validación, como las medidas, evaluaciones y resultados
se extienden también al software utilizado.
Además, si se observa el código mostrado en la sección correspondiente, se observa que la
descripción del proceso está dado por la inicialización de estructuras del tipo acción (con sus alarmas
correspondientes), y los tiempos y temperaturas se definen en la estructura del tipo receta, de modo que se
puede afirmar que el sistema resulta programable modificando únicamente estos valores, ya que el
programa de prueba hace uso de los mismos, exclusivamente, e independientemente de otras variables.

87
XII. ESTUDIOS DE CONFIABILIDAD DE HARD Y SOFT

1. CONFIABILIDAD DE HARDWARE

Para llevar a cabo un estudio de fiabilidad, se consideraron los componentes electrónicos utilizados
en ambas placas, y se calcularon las tasas de fallas según la norma MIL-HDBK-217F. A continuación, se
muestra una tabla que resume los componentes considerados y la tasa de fallas calculada para cada uno
(en este caso, la tasa mostrada contempla el número de veces que se repite un componente). Las fórmulas
utilizadas son las correspondientes a la norma. Los valores considerados para los factores de cada
componente se detallan en una tabla en el anexo correspondiente.

Placa Parte Valor Encapsulado Cantidad  p(total)


P Lógica Micro (MCF51JM128 ) QFP64 1 1,696
P Lógica Cristal 12 MHz 1 0,1449
P Lógica Resistencia 10M SMD (1206) 1 0,052
P Lógica Resistencia 10K SMD (1206) 9 0,468
P Lógica Resistencia 5K6 SMD (1206) 2 0,104
P Lógica Resistencia 1K SMD (1206) 1 0,052
P Lógica Resistencia 2K2 SMD (1206) 7 0,364
P Lógica Resistencia 330 SMD (1206) 2 0,104
P Lógica Capacitor 10p plate 2 0,009009
P Lógica Capacitor 100n multicapa 11 0,1146717
P Lógica Capacitor 10u (25V) electrolítico 1 0,002964
P Lógica Conector IDC 26 vías macho 1 0,5824
P Lógica Conector USB Tipo A hembra 1 0,66976
P Lógica Bornera doble 1 0,0182
P Lógica Conector polarizado 3 vías macho 14 1,0192
P Lógica Pines comunes rectos pinx1 16 1,1648
P Lógica Pines dobles pinx2 12 0.8736
P Lógica Botón grande para placa pulsador 7 2,24
P Lógica Transistor BC547 2 0,012285702
P Lógica Buzzer armado 5V 1 0,0693
P Lógica Led rojo 3 mm. 1 0,01012
P Lógica Conexiones en PCB 1 0,0392
P Potencia Resistencia 360 metal film 24 0,209894784
P Potencia Resistencia 330 metal film 48 1,04947392
P Potencia Resistencia 220 metal film 24 0,52473696
P Potencia Resistencia 39 metal film 24 1,60507776
P Potencia Capacitor 100n multicapa 7 0,729729
P Potencia Capacitor 10u (25V) electrolítico 3 0,08892

88
P Potencia Capacitor 470u (25V) electrolítico 1 0,122304
P Potencia Capacitor 1n (630V) multicapa 24 2,1683376
P Potencia Conector IDC macho 26 1 0,5824
P Potencia Borneras dobles 30 0,546
P Potencia Zócalo DIP6 24 0,096768
P Potencia Triac BTA08600 TO220AB 24 0,6586272
P Potencia Regulador LM7805 TO220 3 2,3172
P Potencia Hex Buffer CD4050 DIP16 4 0,4472
P Potencia Optotriac MOC041 DIP6 24 4,488
P Potencia Diodo 1N4001 rectificador 4 0,0021384
P Potencia Led verde 3 mm. 24 0,24288
P Potencia Transformador 220-9 18W 0 0
P Potencia Conexiones en PCB 1 0,10374
TOTAL 25,79383803
Tabla 4. Resultados por componente de fiabilidad.

La tabla anterior establece un valor de p del sistema de 25,8 fallas por cada millón de horas de
uso. Entonces, se puede calcular el tiempo medio entre fallas como:

1 1 106 horas
MTBF   .  38770.20hs  4,42años (14)
psist 25,793 fallas

2. CONFIABILIDAD DE SOFTWARE

Para el análisis de confiabilidad de software se utilizó el modelo de Bayesian Fault Rate Estimation
de la norma . Este no se centra en la cantidad de defectos netos sino en el cociente entre defectos y fallas
del sistema, entendiendo por la primera una acción no deseada y por la segunda una falla que hace que el
equipo deje de funcionar.
A continuacón se formulan las hipótesis del modelo:
1. El software es operable. Este ya fue probado y funciona correctamente por lo que no es necesario
desarrollar ninguna predicción sobre el mismo.
2. Los defectos aparecen en un momento indefinido con una tasa (  que tiene una distribución
Gamma con parámetros Xi y Fi+1 (con Xi la media de defectos encontrados por período y Fi+1 el
número de defectos esperados para el próximo período).
3. Los defectos son corregidos entre períodos de prueba y no durante la prueba.
4. El número total de defectos encontrados durante un solo período de prueba con duración t t
responden a una distribución de Poisson con parametro  tt.

Para desarrollar el modelo se deben establecer los valores de los parámetros iniciales, es decir para
el período 0 (incluye todos los intervalos de prueba previos al inicio de la modelización, esto se denomina
experiencia), se habrán contabilizado f0 defectos.

89
Ahora se denomina Ti al tiempo total transcurrido entre todos los intervalos de medición de ese
período y Fi al numero total de defectos encontrados en el período. De esta manera, la confiabilidad queda
expresada por:
R(t) = [Ti-1/(Ti-1 + t)]Fi-1 (15)

Y la tasa de fallas estimada para un tiempo t, está dada por:

(t) = (Fi+1+1)/Ti-1 (16)

Una desventaja con la que cuenta el modelo es que trabaja con valores de períodos de prueba
pasados para la estimación de confiabilidad requiriendo grandes tiempos de recopilación de datos.Como
no se tuvo en cuenta este anñalisis desde el inicio del diseño, se desarrolló la gran mayoria del software
sin tener en cuenta la confiabilidad del mismo. Por este motivo no se realizó un registro de los defectos
ocurridos niel tiempo empleado para su prueba.
Se recomienda para futuros diseños implementar esta ténica desde las distintas fases del proyecto
ya que muchas de ellas pueden subsistir durante su desarrollo.

90
XIII. CONCLUSIONES

1. EXCELENCIAS Y OBJETIVOS ALCANZADOS

Se logró de forma exitosa el diseño y construcción del prototipo de un equipo capaz de automatizar
un proceso de producción de cerveza.
Desde el punto de vista financiero, el costo de materiales utilizado para el diseño estuvo dentro de
los valores previstos. En materia académica, los autores se vieron favorecidos en su formación,
empleando dispositivos que no habían utilizado antes, ganando no solamente experiencia técnica, sino
también práctica en el desarrollo de un producto, completando toda su etapa de diseño.
El proyecto resultó viable desde el punto de vista económico, según el análisis propuesto, que
considera un volumen de venta bajo, es decir, suponiendo bajos ingresos. También se demostró la
viabilidad técnica, ya que se construyó un prototipo y se puso a prueba en una aplicación real. En este
sentido, se puede afirmar que el proyecto está en condiciones de constituir un producto apto para la
comercialización.

2. FALLOS Y RECOMENDACIONES PARA FUTUROS DISEÑOS

El fallo principal de este proyecto fue el retraso en el tiempo que insumió el desarrollo del
proyecto, respecto de la planificación, extendiéndose el plazo a casi el doble de tiempo de lo que se había
previsto. No obstante, no se trabajó durante el verano, con lo cual el retraso real no resultó tan rave,
aunque sí considerable. Este inconveniente surgió por un imprevisto técnico, que llevó al rediseño de toda
la etapa de potencia del equipo. Este error pudo haberse evitado, o al menos disminuido, si se hubiese
profundizado la etapa de pruebas de los distintos módulos. Evidentemente, no se validó el funcionamiento
de los módulos en conjunto de forma adecuada. Se recomienda, para futuros diseños, insistir en la prueba
de los circuitos, en especial cuando se trabaja combinando baja y alta potencia de trabajo.
El inconveniente técnico deja lugar a la duda de cómo debe implementarse un control de relés
mecánicos basados en un microcontrolador. En este sentido, la experiencia ganada durante el presente
trabajo puede afirmar dos cuestiones. En primer lugar, resulta fundamental considerar cuestiones de ruteo
cuando se combinan altas y bajas potencias. En segundo lugar, cuando se switchean altas tensiones, se
generarán necesariamente picos de tensión, con transitorios de alta frecuencia, de carácter
electromagnético en las pistas cercanas. Resulta altamente recomendable, para estos casos, implementar
algún dispositivo que retrase la conmutación hasta que haya un cruce por cero, ya sea de tensión o de
corriente, para minimizar estos picos problemáticos, en especial, cuando el tiempo de conmutación no es
crítico.
Desde el punto de vista de la programación, no se logró implementar una interfaz sencilla y
amigable para programar las secuencias del proceso. Hasta esta etapa del diseño, la programación debe
hacerse en lenguaje C, y actualización del firmware (que se realiza por USB) implica desarmar el
gabinete para cambiar un jumper. Por este motivo, la programación debe realizarse de forma previa a la
instalación del equipo, y adaptarse a cada proceso en particular. No obstante, se prevé realizar una
actualización del firmware de modo que sea capaz de comunicarse con una PC mientras el equipo está en
uso, o bien leer un pen drive que pueda contener archivos de texto con las acciones y recetas grabadas.
Estas actualizaciones son posibles, ya que el microcontrolador tiene la capacidad desde el punto de vista
del hardware (USB OTG), y la memoria flash interna de programa no se ha utilizado en su totalidad.

91
XIV. ANEXOS

1. ANÁLISIS COMPLETO DE FIABILIDAD

A continuación, se detalla una tabla con la totalidad de los componentes considerados en el análisis
de fiabilidad del equipo. Como se estableció anteriormente, las fórmulas empleadas corresponden a las
establecidas por la norma:

Parte Cant. λ b πE πE πQ πR πA πT πS πC C1 C2 πp πv λ p(unit) λ p(total)

MCF51JM128 1 1 2 2 1 1 1 0,6 1 1 0,56 0,68 1 1 1.696 1.696


Cristal 1 0,023 3 3 2,1 1 1 1 1 1 1 1 1 1 0.1449 0.1449
Resistencia 1 0,0013 8 8 5 1 1 1 1 1 1 1 1 1 0.052 0.052
Resistencia 9 0,0013 8 8 5 1 1 1 1 1 1 1 1 1 0.052 0.468
Resistencia 2 0,0013 8 8 5 1 1 1 1 1 1 1 1 1 0.052 0.104
Resistencia 1 0,0013 8 8 5 1 1 1 1 1 1 1 1 1 0.052 0.052
Resistencia 7 0,0013 8 8 5 1 1 1 1 1 1 1 1 1 0.052 0.364
Resistencia 2 0,0013 8 8 5 1 1 1 1 1 1 1 1 1 0.052 0.104
Capacitor 2 0,00099 1 10 10 1 1 1,3 1 0,35 1 1 1 1 0.0045045 0.009009
Capacitor 11 0,00099 1 10 10 1 1 1,3 1 0,81 1 1 1 1 0.0104247 0.1146717
Capacitor 1 0,00012 1 10 10 1 1 1,3 1 1,9 1 1 1 1 0.002964 0.002964
Conector IDC 1 0,04 8 8 2 1 1 0,91 1 1 1 1 1 1 0.5824 0.5824
Conector USB 1 0,046 8 8 2 1 1 0,91 1 1 1 1 1 1 0.66976 0.66976
Bornera 1 0,007 1 1 2 1 1 1,3 1 1 1 1 1 1 0.0182 0.0182
Conector
polarizado 14 0,04 1 8 2 1 1 0,91 1 1 1 1 1 1 0.0728 1.0192
Pines comunes
rectos 16 0,04 1 8 2 1 1 0,91 1 1 1 1 1 1 0.0728 1.1648
Pines dobles 12 0,04 1 8 2 1 1 0,91 1 1 1 1 1 1 0.0728 0.8736
Botón grande
para placa 7 0,04 8 8 1 1 1 1 1 1 1 1 1 1 0.32 2.24
Transistor 2 0,00074 6 6 5,5 0,43 1,5 1 0,39 1 1 1 1 1 0.006142851 0.012285702
Buzzer
armado 1 0,011 3 3 2,1 1 1 1 1 1 1 1 1 1 0.0693 0.0693
Led rojo 1 0,00023 8 8 5,5 1 1 1 1 1 1 1 1 1 0.01012 0.01012
Conexiones en
PCB 1 0,00007 2 2 1 1 1 1 1 1 1 280 1 1 0.0392 0.0392
Resistencia 24 0,0037 4 4 10 1 1 1,1 0,79 1 1 1 0,068 1 0.008745616 0.209894784
Resistencia 48 0,0037 4 4 10 1 1 1,1 0,79 1 1 1 0,17 1 0.02186404 1.04947392
Resistencia 24 0,0037 4 4 10 1 1 1,1 0,79 1 1 1 0,17 1 0.02186404 0.52473696
Resistencia 24 0,0037 4 4 10 1 1 1,3 1,9 1 1 1 0,44 1 0.06687824 1.60507776

92
Capacitor 7 0,00099 10 10 10 1 1 1,3 1 0,81 1 1 1 1 0.104247 0.729729
Capacitor 3 0,00012 10 10 10 1 1 1,3 1 1,9 1 1 1 1 0.02964 0.08892
Capacitor 1 0,00012 10 10 10 1 1 1,3 1 4,9 1 1 1 1,6 0.122304 0.122304
Capacitor 24 0,00099 10 10 10 1 1 1,3 1 0,54 1 1 1 1,3 0.0903474 2.1683376
Conector IDC
macho 1 0,04 8 8 2 1 1 0,91 1 1 1 1 1 1 0.5824 0.5824
Borneras
dobles 30 0,007 1 1 2 1 1 1,3 1 1 1 1 1 1 0.0182 0.546
Zócalo 24 0,00064 3 3 1 1 1 1 1 1 1 1 2,1 1 0.004032 0.096768
Triac 24 0,0022 6 6 5,5 1,4 1 1 0,27 1 1 1 1 1 0.0274428 0.6586272
Regulador 3 0,0025 2 2 1 1 1 0,77 1 1 1 0,0012 1 1 0.7724 2.3172
Hex Buffer 4 0,01 2 2 1 1 1 0,1 1 1 1 0,0059 1 1 0.1118 0.4472
Optotriac 24 0,017 2 2 5,5 1 1 1 1 1 1 1 1 1 0.187 4.488
Diodo 4 0,003 6 6 5,5 1 1 1 0,0054 1 1 1 1 1 0.0005346 0.0021384
Led verde 24 0,00023 8 8 5,5 1 1 1 1 1 1 1 1 1 0.01012 0.24288
Transformador 0 0,14 1 1 3 1 1 1,1 1 1 1 1 1 1 0.462 0
Conexiones en
PCB 1 0,00007 2 2 1 1 1 1 1 1 1 741 1 1 0.10374 0.10374
Total 25.79383803

Tabla 5. Detalle de los valores utilizados en el cálculo de fiabilidad.

2. LISTADO DE COMPONENTES Y SUS COSTOS

2.1. Componentes del equipo:

Componentes Cantidad Costo unitario ($) Costo total ($)


Patas de goma 6 1 6
Tornillos para patas de goma 6 0,45 2,7
Tuercas para patas de goma 6 0,3 1,8
Cable armado 1 12 12
Porta fusible 1 1,5 1,5
Fusible (10A) 1 2 2
Cables para conexiones (en m.) 1 3,5 3,5
Terminal circular 1 0,03 0,03
Terminales hembra 4 0,06 0,24
Cubre terminales hembra 4 0,08 0,32
Tecla de encendido 1 6,6 6,6
Tornillos para ensamblado 18 0,25 4,5

93
Tuercas para ensamblado 4 0,2 0,8
Gabinete (en 2 partes) 1 160 160
Placa impresa lógica 1 65 65
Placa impresa de salida 1 80 80
Tiras de goma (en cm.) 40 0,03 1,2
Bordes de goma (en cm.) 40 0,04 1,6
Termocontraíble (en cm.) 5 0,26 1,3
Alambre de estaño (en cm.) 10 0,01 0,1
Transformador (220V-9V; 2A) 1 60 60
Cable rojo (en cm.) 20 0,03 0,6
Cable negro (en cm.) 20 0,03 0,6
Conectores IDC26 hembra 2 0,9 1,8
Cable plano 26 vías (en cm.) 20 0,08 1,6
SUBTOTAL 415,79
Tabla 6. Costos de los componentes del equipo

2.2. Componentes de la placa lógica

Componentes Cantidad Costo unitario ($) Costo total ($)


Micro (MCF51JM128, QFP64) 1 27,6 27,6
Placa Display LCD (16x2) 1 40 40
Conector IDC macho (placa, 26 vías) 1 0,6 0,6
Cristal 12MHz 1 1,2 1,2
Capacitor 10pF plate 2 0,46 0,92
Resistencia SMD 10M 1 0,2 0,2
Resistencias SMD 10K 9 0,2 1,8
Capacitor multicapa 100nF 11 0,32 3,52
Pines dobles 12 0,027 0,324
Conector USB hembra tipo A 1 4,92 4,92
Capacitor electrolítico 10uF 25V 1 0,09 0,09
Bornera doble 1 1,18 1,18
Transistor BC547 2 0,14 0,28
Buzzer armado 5V con oscilador 1 5 5
Led rojo 3mm. 1 0,15 0,15
Resistencia SMD 330 2 0,2 0,4
Pines comunes rectos 16 0,015 0,24
Resistencia SMD 5K6 2 0,2 0,4
Resistencia SMD 1K 1 0,2 0,2

94
Botón grande para placa (pulsador) 7 1,4 9,8
Resistencia SMD 2K2 7 0,2 1,4
Tornillos para atornillar LCD 3 0,25 0,75
Tuercas para atornillar LCD 3 0,2 0,6
Jumpers 2 0,08 0,16
Conectores polarizados machos (3 vías) 14 0,57 7,98
Alambre de estaño (por m.) 2 1 2
SUBTOTAL 111,714
Tabla 7. Costos de los componentes de la placa lógica.

2.3. Componentes de la placa de potencia:

Componentes Cantidad Costo unitario ($) Costo total ($)


Conector IDC macho (placa, 26 vías) 1 0,6 0,6
Borneras dobles 30 1,18 35,4
Capacitor multicapa 100nF 7 0,32 2,24
Capacitor electrolítico 10uF 25V 3 0,09 0,27
Diodo rectificador 1N4001 4 0,25 1
Capacitor electrolítico 470uF 25V 1 0,22 0,22
Reguladores de Tensión LM7805 (TO220) 3 1,5 4,5
Hex Buffer CD4050 4 1,7 6,8
Resistencia Metal Film 39 (1/8W) 24 0,025 0,6
Capacitor multicapa 10nF 630V 24 0,17 4,08
Triac BTA08-600 (TO220AB) 24 4,16 99,84
Resistencia Metal Film 360 (1/8W) 24 0,025 0,6
Resistencia Metal Film 330 (1/8W) 48 0,025 1,2
Optotriac MOC3041 24 2,4 57,6
Zócalo DIP6 (2x3) 24 0,08 1,92
Resistencia Metal Film 220 (1/8W) 24 0,025 0,6
Led verde 3mm. 24 0,14 3,36
Alambre de estaño (por m.) 2 1 2
SUBTOTAL 222,83
Tabla 8. Costos de los componentes de la placa de potencia.

2.4. Componentes utilizados para los termómetros:

Componentes Cantidad Costo unitario ($) Costo total ($)


Integrado DS18B20 3 24 72
Cable telefónico (en m.) 12 0,57 6,84

95
Conectores polarizados hembra (3 vías) 3 0,42 1,26
Terminales para polarizado 9 0,02 0,18
Termocontraíble (2,4mm) (en cm.) 36 0,17 6,12
SUBTOTAL 86,4
Tubo acero inoxidable AISI 340 (en m.) 2,1 11,73 24,633
Bulones acero inoxidable 3 2,5 7,5
Pasta Teflón (por 1 gr.) 6 0,03 0,18
SUBTOTAL 118,713
Tabla 9. Costos de los elementos utilizados para los termómetros.

2.5. Accesorios para automatizar la instalación:

Componentes Cantidad Costo unitario ($) Costo total ($)


Bomba plástica 4 110 440
Electroválvula común 2 40 80
Electroválvula especial (paso 3mm.) 1 100 100
Cable siliconado (por m.) 40 3,5 140
Terminales hembra 14 0,06 0,84
Cubre terminales hembra 14 0,08 1,12
Alambre de estaño (por m.) 1 1 1
Lana de vidrio aluminizada (por m.^2) 2 10 20
Manguera (por m.) 15 3,5 52,5
Accesorios para mangueras (T, unión, etc.) 5 1 5
Abrazaderas para mangueras 25 0,5 12,5
SUBTOTAL 852,96
Tabla 10. Costos de los accesorios utilizados para automatizar la instalación.

2.6. Valor de las instalaciones:

Componentes Cantidad Costo unitario ($) Costo total ($)


Olla aluminio 98 litros 1 400 400
Barril plástico 110 litros 2 50 100
Fermentador cónico 60 litros 2 300 600
Pie metálico para fermentador 2 100 200
Quemador 1 150 150
Instalación de gas 1 160 160
Enfriador contracorriente 1 180 180
Canillas, válvulas, etc. 1 150 150
Filtro para macerador acero inoxidable 1 20 20

96
Bolsa de maceración de tela 1 25 25
Tapón con Airlock para fermentador 1 25 25
SUBTOTAL 2010
Tabla 11. Valor estimado de las instalaciones utilizadas en la validación dl prototipo.

2.7. Insumos utilizados para la fabricación de cerveza para validar el prototipo:

Componentes Cantidad Costo unitario ($) Costo total ($)


Malta común (por 1 Kg.) 10 5,5 55
Malta especial (Caramunich) (por 200 g.) 2 4 8
Levadura Saflager S34 (por 11,5 g.) 1 38 38
Lúpulo Cascade (por 20 g.) 1 2,8 2,8
Lúpulo Hellertauer (por 10g.) 1 4 4
Clarificante Whirlflock (hervor) (por 2g.) 2 2 4
Azúcar rubia común (por 1 Kg.) 0,4 3 1,2
Tapas corona doradas (por 100 u.) 1,5 10 15
Alcohol etílico (para sanitizar) (por L.) 0,5 5 2,5
Soda Cáustica (por 1 Kg.) 0,25 25 6,25
Agua Corriente (por L.) 500 0,0135 6,75
Electricidad 1 5 5
Gas 1 1,5 1,5
SUBTOTAL 150
Tabla 12. Costos de los insumos utilizados para fabricar 50 litros de cerveza rubia (Pilsen Lager).

3. SOFTWARE COMPLETO

A continuación se presenta la totalidad de los archivos de programa (tanto los de código (.c) como
los headers (.h) correspondientes al software del proyecto. No se transcriben aquellos archivos generados
automáticamente por el entorno de programación (como el header con las definiciones y macros del
procesador utilizado).
Además, cabe destacar la siguiente aclaración. A diferencia de un programa común, este código
comienza por ejecutar la función “void _Entry(void)”, que verifica el estado de un pin. En condiciones
normales, este pin se encuentra en alta impedancia, por lo que el programa salta a la función “main()”, a
partir de la cual se ejecuta el programa de usuario. No obstante, si se conecta este pin a masa mediante un
jumper, el programa entra en lo que se llama “modo Bootloader” que es un programa que, por medio de
una interfaz USB, permite cagar un nuevo programa compilado en el procesador. Esta función
(suministrada por la empresa Freescale, de forma gratuita y con formato “Open Source”, se mantiene en
el proyecto final, ya que permite una actualización sencilla del firmware. Las librerías de esta aplicación
tampoco se transcriben en el presente anexo.

3.1. Archivo main.c

Este archivo ya fue transcripto en el desarrollo del informe.

97
3.2. Archivo usr_entry.c

/*********************************************************************
****
* DISCLAIMER *
* Services performed by FREESCALE in this matter are performed
*
* AS IS and without any warranty. CUSTOMER retains the final decision
*
* relative to the total design and functionality of the end product.
*
* FREESCALE neither guarantees nor will be held liable by CUSTOMER
*
* for the success of this project. FREESCALE disclaims all
warranties, *
* express, implied or statutory including, but not limited to,
*
* implied warranty of merchantability or fitness for a particular
*
* purpose on any hardware, software ore advise supplied to the
project *
* by FREESCALE, and or any product resulting from FREESCALE services.
*
* In no event shall FREESCALE be liable for incidental or
consequential *
* damages arising out of this agreement. CUSTOMER agrees to hold
*
* FREESCALE harmless against any and all claims demands or actions
*
* by anyone on account of any damage, or injury, whether commercial,
*
* contractual, or tortuous, rising directly or indirectly as a result
*
* of the advise or assistance supplied CUSTOMER in connection with
*
* product, services or goods supplied under this Agreement.
*

**********************************************************************
***/

#include "derivative.h"
#include "JM128_Bootloader.h"

extern unsigned long far __SP_AFTER_RESET[];


extern unsigned long far __SP_INIT[];
extern unsigned long far _SP_INIT, _SDA_BASE;
extern unsigned long far _START_BSS, _END_BSS;
extern unsigned long far _START_SBSS, _END_SBSS;
extern unsigned long far __DATA_RAM, __DATA_ROM, __DATA_END;

#define USR_ENTRY_ADDR 0x000011C0

void _Entry(void)
{
byte i;

PTGDD_PTGDD0 = 0; // PTG0 is input


PTGPE_PTGPE0 = 1; // internal pullup for PTG0

// delay some time for oscillator and GPIO stable

98
for(i=0;i<3;i++) {

__RESET_WATCHDOG();
}
if(PTGD_PTGD0)
{
asm (JMP USR_ENTRY_ADDR); // jump to user entry
}
else
{
__asm {

move.w #0x2700,sr
lea __SP_AFTER_RESET,a7;
lea _SP_INIT,a7
movea.l #0,a6
link a6,#0
lea _SDA_BASE,a5
lea _END_BSS, a0
lea _START_BSS, a1
suba.l a1, a0
move.l a0, d0

beq __skip_bss__

lea _START_BSS, a0

__skip_bss__:
}

SOPT1 = 0x00; // disable COP


SOPT2 = 0x00;

MCGC2 = 0x36;
while(!(MCGSC & 0x02)){}; //wait for the OSC stable
MCGC1 = 0x98;
while((MCGSC & 0x1C )!= 0x08){}; // external clock is selected
MCGC3 = 0x48;
while ((MCGSC & 0x48) != 0x48){}; //wait for the PLL is locked
MCGC1 = 0x18;
while((MCGSC & 0x6C) != 0x6C){};

//USBTRC0 = 0x44;
Bootloader_Main();
}
}

3.3. Archivo SystemInit.c

#include <hidef.h> /* for EnableInterrupts macro */


#include "derivative.h" /* include peripheral declarations */
#include "botones.h"
#include "Salida.h"
#include "Proceso.h"

const byte NVPROT_INIT @0x0000040D = 0xFB; // 0x00000000-


0x00000FFF are protected

unsigned int segundos=0;


unsigned int minutos=0;
unsigned int horas=0;

99
unsigned int dias=0;

int second_counter;
int index=1;
int lcd_counter = REPETICIONES;
int buzzer_counter = REPETICIONES;

char line2 [16] = "Tiempo: : : ";

typedef void (* pFun)(void);


extern asm void _startup(void);

void system_init (void);

//Funciones de inicialización de funciones


void RTC_Init (void);
void TMP1_init (void);
void IO_Init (void);

//Funciones de servicio de interrupciones


//Función de interrupción del RTC (contador de tiempo). Interrumpe
cada segundo.
__interrupt void RTC_UpdateTime(void)
{
RTCSC_RTIF = 1; //Borro flag

if (Programa_activo() == ON)
{

second_counter++;
segundos++;
if (segundos > 59)
{
minutos++;
segundos = 0;
}
line2[14]=(char) segundos/10+48;
line2[15]=(char) segundos-10*(segundos/10)+48;
if (minutos > 59)
{
horas++;
minutos = 0;
}
line2[11]=(char) minutos/10+48;
line2[12]=(char) minutos-10*(minutos/10)+48;
if (horas > 23)
{
dias ++;
horas = 0;
}
line2[8]=(char) horas/10+48;
line2[9]=(char) horas-10*(horas/10)+48;

if (get_flag()==0)
EscribeCadenaDisplay(2, line2);

if (Get_lcd_flag() == TRUE)
{
if ((lcd_counter--) >0)
LCD_LIGHT = ~LCD_LIGHT;
else

100
{
lcd_counter = REPETICIONES;
Set_lcd_flag (FALSE);
}

}
if (Get_buzzer_flag() == TRUE)
{
if ((buzzer_counter--) >0)
BUZZER = ~BUZZER;
else
{
buzzer_counter = REPETICIONES;
Set_buzzer_flag (FALSE);
}
}
}

}
//Servicios
unsigned int get_segundos (void)
{
return segundos;
}
unsigned int get_minutos (void)
{
return minutos;
}
unsigned int get_horas (void)
{
return horas;
}
unsigned int get_dias (void)
{
return dias;
}

//Función de interrupción del timer overflow


__interrupt void Timer_Overflow(void)
{
TPM1SC_TOF = 0; // clear flag
}

//Función trivial para completar tabla (Dummy)


__interrupt void dummy_ISR(void)
{
}

/*Tabla de vectores de interrupción*/


void (* const RAM_vector[])()@0x00001000= {
(pFun)&dummy_ISR, // vector_0 INITSP
(pFun)&dummy_ISR, // vector_1 INITPC
(pFun)&dummy_ISR, // vector_2 Vaccerr
(pFun)&dummy_ISR, // vector_3 Vadderr
(pFun)&dummy_ISR, // vector_4 Viinstr
(pFun)&dummy_ISR, // vector_5 VReserved5
(pFun)&dummy_ISR, // vector_6 VReserved6
(pFun)&dummy_ISR, // vector_7 VReserved7
(pFun)&dummy_ISR, // vector_8 Vprviol
(pFun)&dummy_ISR, // vector_9 Vtrace
(pFun)&dummy_ISR, // vector_10 Vunilaop

101
(pFun)&dummy_ISR, // vector_11 Vunilfop
(pFun)&dummy_ISR, // vector_12 Vdbgi
(pFun)&dummy_ISR, // vector_13 VReserved13
(pFun)&dummy_ISR, // vector_14 Vferror
(pFun)&dummy_ISR, // vector_15 VReserved15
(pFun)&dummy_ISR, // vector_16 VReserved16
(pFun)&dummy_ISR, // vector_17 VReserved17
(pFun)&dummy_ISR, // vector_18 VReserved18
(pFun)&dummy_ISR, // vector_19 VReserved19
(pFun)&dummy_ISR, // vector_20 VReserved20
(pFun)&dummy_ISR, // vector_21 VReserved21
(pFun)&dummy_ISR, // vector_22 VReserved22
(pFun)&dummy_ISR, // vector_23 VReserved23
(pFun)&dummy_ISR, // vector_24 Vspuri
(pFun)&dummy_ISR, // vector_25 VReserved25
(pFun)&dummy_ISR, // vector_26 VReserved26
(pFun)&dummy_ISR, // vector_27 VReserved27
(pFun)&dummy_ISR, // vector_28 VReserved28
(pFun)&dummy_ISR, // vector_29 VReserved29
(pFun)&dummy_ISR, // vector_30 VReserved30
(pFun)&dummy_ISR, // vector_31 VReserved31
(pFun)&dummy_ISR, // vector_32 Vtrap0
(pFun)&dummy_ISR, // vector_33 Vtrap1
(pFun)&dummy_ISR, // vector_34 Vtrap2
(pFun)&dummy_ISR, // vector_35 Vtrap3
(pFun)&dummy_ISR, // vector_36 Vtrap4
(pFun)&dummy_ISR, // vector_37 Vtrap5
(pFun)&dummy_ISR, // vector_38 Vtrap6
(pFun)&dummy_ISR, // vector_39 Vtrap7
(pFun)&dummy_ISR, // vector_40 Vtrap8
(pFun)&dummy_ISR, // vector_41 Vtrap9
(pFun)&dummy_ISR, // vector_42 Vtrap10
(pFun)&dummy_ISR, // vector_43 Vtrap11
(pFun)&dummy_ISR, // vector_44 Vtrap12
(pFun)&dummy_ISR, // vector_45 Vtrap13
(pFun)&dummy_ISR, // vector_46 Vtrap14
(pFun)&dummy_ISR, // vector_47 Vtrap15
(pFun)&dummy_ISR, // vector_48 VReserved48
(pFun)&dummy_ISR, // vector_49 VReserved49
(pFun)&dummy_ISR, // vector_50 VReserved50
(pFun)&dummy_ISR, // vector_51 VReserved51
(pFun)&dummy_ISR, // vector_52 VReserved52
(pFun)&dummy_ISR, // vector_53 VReserved53
(pFun)&dummy_ISR, // vector_54 VReserved54
(pFun)&dummy_ISR, // vector_55 VReserved55
(pFun)&dummy_ISR, // vector_56 VReserved56
(pFun)&dummy_ISR, // vector_57 VReserved57
(pFun)&dummy_ISR, // vector_58 VReserved58
(pFun)&dummy_ISR, // vector_59 VReserved59
(pFun)&dummy_ISR, // vector_60 VReserved60
(pFun)&dummy_ISR, // vector_61 Vunsinstr
(pFun)&dummy_ISR, // vector_62 VReserved62
(pFun)&dummy_ISR, // vector_63 VReserved63
(pFun)&dummy_ISR, // vector_64 Virq
(pFun)&dummy_ISR, // vector_65 Vlvd
(pFun)&dummy_ISR, // vector_66 Vlol
(pFun)&dummy_ISR, // vector_67 Vspi1
(pFun)&dummy_ISR, // vector_68 Vspi2
(pFun)&dummy_ISR, // vector_69 Vusb
(pFun)&dummy_ISR, // vector_70 VReserved70
(pFun)&dummy_ISR, // vector_71 Vtpm1ch0

102
(pFun)&dummy_ISR, // vector_72 Vtpm1ch1
(pFun)&dummy_ISR, // vector_73 Vtpm1ch2
(pFun)&dummy_ISR, // vector_74 Vtpm1ch3
(pFun)&dummy_ISR, // vector_75 Vtpm1ch4
(pFun)&dummy_ISR, // vector_76 Vtpm1ch5
(pFun)&dummy_ISR, // vector_77 Vtpm1ovf
(pFun)&dummy_ISR, // vector_78 Vtpm2ch0
(pFun)&dummy_ISR, // vector_79 Vtpm2ch1
(pFun)&dummy_ISR, // vector_80 Vtpm2ovf
(pFun)&dummy_ISR, // vector_81 Vsci1err
(pFun)&dummy_ISR, // vector_82 Vsci1rx
(pFun)&dummy_ISR, // vector_83 Vsci1tx
(pFun)&dummy_ISR, // vector_84 Vsci2err
(pFun)&dummy_ISR, // vector_85 Vsci2rx
(pFun)&dummy_ISR, // vector_86 Vsci2tx
(pFun)&dummy_ISR, // vector_87 Vkeyboard
(pFun)&dummy_ISR, // vector_88 Vadc
(pFun)&dummy_ISR, // vector_89 Vacmpx
(pFun)&dummy_ISR, // vector_90 Viic1x
(pFun)&RTC_UpdateTime, // vector_91 Vrtc
(pFun)&dummy_ISR, // vector_92 Viic2x
(pFun)&dummy_ISR, // vector_93 Vcmt
(pFun)&dummy_ISR, // vector_94 Vcanwu
(pFun)&dummy_ISR, // vector_95 Vcanerr
(pFun)&dummy_ISR, // vector_96 Vcanrx
(pFun)&dummy_ISR, // vector_97 Vcantx
(pFun)&dummy_ISR, // vector_98 Vrnga
(pFun)&dummy_ISR, // vector_99 VReserved99
(pFun)&dummy_ISR, // vector_100 VReserved100
(pFun)&dummy_ISR, // vector_101 VReserved101
(pFun)&dummy_ISR, // vector_102 VReserved102
(pFun)&dummy_ISR, // vector_103 VReserved103
(pFun)&dummy_ISR, // vector_104 VL7swi
(pFun)&dummy_ISR, // vector_105 VL6swi
(pFun)&dummy_ISR, // vector_106 VL5swi
(pFun)&dummy_ISR, // vector_107 VL4swi
(pFun)&dummy_ISR, // vector_108 VL3swi
(pFun)&dummy_ISR, // vector_109 VL2swi
(pFun)&dummy_ISR, // vector_110 VL1swi
};

//Función auxiliar para el Bootloader


void (* const _UserEntry[])()@0x000011C0=
{
0x4E714EF9, //asm NOP(0x4E71), asm JMP(0x4EF9)
_startup,
};

//Función de inicialización del sistema


void system_init (void)
{
//Aqui se copia la tabla de interrupciones a la RAM
dword *pdst,*psrc;
byte i;
asm (move.l #0x00800000,d0);
asm (movec d0,vbr);
pdst=(dword)0x00800000;
psrc=(dword)&RAM_vector;
for (i=0;i<111;i++,pdst++,psrc++)
{
*pdst=*psrc;

103
}

//Selección de clock

SOPT1 = 0x00; // disable COP


SOPT2 = 0x00;

MCGC2 = 0x36;
while(!(MCGSC & 0x02)){}; //wait for the OSC stable
MCGC1 = 0x98;
while((MCGSC & 0x1C )!= 0x08){}; // external clock is selected
MCGC3 = 0x48;
while ((MCGSC & 0x48) != 0x48){}; //wait for the PLL is locked
MCGC1 = 0x18;
while((MCGSC & 0x6C) != 0x6C){};
//Deshabilito detección de baja tensión
SPMSC1_LVDE = 0;

//Habilito interrupciones
EnableInterrupts;

//Inicialización de interrupciones
IO_Init();
RTC_Init();
}

//Definición de funciones de inicialización de interrupciones


void TMP1_init (void)
{
TPM1SC_CLKSx = 0x01; // bus rate clock
TPM1SC_PS = 2; // bus clock (Prescaler=4)
TPM1MOD = 0x3E8; // 1000 (dec)
TPM1SC_TOIE = 1; //Deshabilitado!
}

//Inicialización del RTC


void RTC_Init (void)
{
RTCSC_RTCLKS = 0; //Internal Clock
RTCSC_RTCPS = 0x1; //Prescaler
RTCMOD = 0x7D; //Cuento hasta 125 (1 seg)
RTCSC_RTIE = 1; //Habilito interrupción
}

//Pines usados para el Display y otros periféricos


void IO_Init (void)
{
//Salidas para display
PTCDD_PTCDD6 = 1;
PTFDD_PTFDD7 = 1;
PTFDD_PTFDD5 = 1;

PTFDD_PTFDD6 = 1;
PTEDD_PTEDD0 = 1;
PTEDD_PTEDD1 = 1;
PTEDD_PTEDD2 = 1;
PTEDD_PTEDD3 = 1;
PTEDD_PTEDD4 = 1;
PTEDD_PTEDD5 = 1;
PTEDD_PTEDD6 = 1;

104
//Entradas de botones
PTADD_PTADD4 = 0;
PTADD_PTADD3 = 0;
PTEDD_PTEDD7 = 0;
PTADD_PTADD1 = 0;
PTGDD_PTGDD1 = 0;
PTADD_PTADD2 = 0;
PTADD_PTADD0 = 0;

//Otras salidas
//Buzzer
PTFDD_PTFDD2 = 1;
//LCD Light
PTFDD_PTFDD4 = 1;

//Salidas para Relés


PTCDD_PTCDD5 = 1;
PTCDD_PTCDD3 = 1;
PTADD_PTADD5 = 1;
PTCDD_PTCDD2 = 1;
PTBDD_PTBDD0 = 1;
PTCDD_PTCDD1 = 1;
PTBDD_PTBDD1 = 1;
PTCDD_PTCDD0 = 1;
PTBDD_PTBDD2 = 1;
PTGDD_PTGDD3 = 1;
PTBDD_PTBDD3 = 1;
PTGDD_PTGDD2 = 1;
PTBDD_PTBDD4 = 1;
PTDDD_PTDDD7 = 1;
PTBDD_PTBDD5 = 1;
PTDDD_PTDDD6 = 1;
PTBDD_PTBDD6 = 1;
PTDDD_PTDDD5 = 1;
PTBDD_PTBDD7 = 1;
PTDDD_PTDDD4 = 1;
PTDDD_PTDDD0 = 1;
PTDDD_PTDDD3 = 1;
PTDDD_PTDDD1 = 1;
PTDDD_PTDDD2 = 1;

//Otros servicios
void reset_counter (void)
{
second_counter = 0;
}
int counter_done (int seconds)
{
int ret;

if (second_counter==seconds)
ret=1;
else
ret=0;

return ret;
}
void Reset_Timer (void)
{

105
segundos = 0;
minutos = 0;
horas = 0;
dias = 0;
}

3.4. Archivo display.c

#include "display.h"
#include "MCF51JM128.h"

#define RSP PTCD_PTCD6 //Pin4


#define RWP PTFD_PTFD7 //Pin5
#define ENP PTFD_PTFD5 //Pin6

#define DB0 PTFD_PTFD6 //Pin7


#define DB1 PTED_PTED0 //Pin8
#define DB2 PTED_PTED1 //Pin9
#define DB3 PTED_PTED2 //Pin10
#define DB4 PTED_PTED3 //Pin11
#define DB5 PTED_PTED4 //Pin12
#define DB6 PTED_PTED5 //Pin13
#define DB7 PTED_PTED6 //Pin14

// Funciones generales para el uso del display WH1602C-YGB-STK

// Variables globales
const char gszSecInitDisplay[] = {0x3C, // 8 bits, 2 lines, 5x11 dots.
0x3C, // 8 bits, 2 lines, 5x11 dots.
0x3C, // 8 bits, 2 lines, 5x11 dots.
0x3C, // 8 bits, 2 lines, 5x11 dots.
0x08, // Display off, Cursor off,
Blinkink off.
0x01, // Display clear.
0x06, // Cursor moving direction,
shift off.
0x0C, // Display on, Cursor off,
Blinkink off.
0x00};

//********************************************************************
*********************
// Funcion : void Delay(int iDelay)
// Descripcion: Realiza un delay a traves de un for.
// Delay(DELAYCOM); Esto es aprox. 1ms
//********************************************************************
*********************
void Delay(int iDelay)
{
int iIndex,j;
for(iIndex = 0; iIndex < iDelay; iIndex++)
for (j=0; j<4; j++)
;
return;
}
//********************************************************************
*********************
// Funcion : void InicializarDisplay(void)
// Descripcion: Inicializa el display.
//********************************************************************
*********************

106
void InicializarDisplay(void)
{
char chIndice = 0;
while(gszSecInitDisplay[chIndice])
{
EscribeComandoDisplay(gszSecInitDisplay[chIndice]);
Delay(DELAYCONST);
chIndice++;
}
EscribeComandoDisplay(BORRAR_DISPLAY);
return;
}
//********************************************************************
*********************
// Funcion : void EscribeComandoDisplay(unsigned char chComando)
// Descripcion: Escribe un comando en el display.
//********************************************************************
*********************
void EscribeComandoDisplay(char chComando)
{
RSP = 0;
RWP = 0;
BuildData (chComando);
ENP = 1;
ENP = 0;

Delay(DELAYCOM);
return;
}
//********************************************************************
*********************
// Funcion : void EscribeDatoDisplay(char chDato)
// Descripcion: Escribe un dato en el display.
//********************************************************************
*********************
void EscribeDatoDisplay(char chDato)
{
RSP = 1;
RWP = 0;
BuildData (chDato);
ENP = 1;
ENP = 0;

Delay(DELAYCOM);
return;
}
//********************************************************************
*********************
// Funcion : void EscribeCadenaDisplay(char chLinea,
// char *pszCadena)
// Descripcion: Escribe una cadena, en la linea indicada en el
display.
//********************************************************************
*********************
void EscribeCadenaDisplay(char chLinea,char *pszCadena)
{
char chIndice = 0,
chOffSetPos = 0;
if(chLinea == 2)
chOffSetPos = 0x40;
while(pszCadena[chIndice])

107
{
EscribeComandoDisplay(0x80 | (chIndice + chOffSetPos));
EscribeDatoDisplay(pszCadena[chIndice]);
chIndice++;
}
return;
}
//********************************************************************
*********************
// Funcion : void BuildData (char ChByte)
// Descripcion: Arma un byte con el comando o dato de salida
//********************************************************************
*********************
void BuildData (char chByte)
{
if ((chByte & 1)==0)
DB0=0;
else
DB0=1;

if ((chByte & 2)==0)


DB1=0;
else
DB1=1;

if ((chByte & 4)==0)


DB2=0;
else
DB2=1;

if ((chByte & 8)==0)


DB3=0;
else
DB3=1;

if ((chByte & 16)==0)


DB4=0;
else
DB4=1;

if ((chByte & 32)==0)


DB5=0;
else
DB5=1;

if ((chByte & 64)==0)


DB6=0;
else
DB6=1;

if ((chByte & 128)==0)


DB7=0;
else
DB7=1;
}

3.5. Archivo Temperatura.c

#include "MCF51JM128.h"
#include "Temperatura.h"
#include "display.h"

108
#ifndef ONE_WIRE_C
#define ONE_WIRE_C

//Flags de fin de conversión


int flag_converting=0;

//Definición de los códigos ROM de los termómetros


unsigned char rom_temp[14][8] = {
{40,183,241,187,2,0,0,189},
{40,196,236,187,2,0,0,236},
{40,62,227,187,2,0,0,62},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0}
};
//Funciones de retardo. Los tiempos son aproximados
void delay_us(int us){
int i,j;
for (i=0; i<us; i++){
for (j=0; j<4; j++)
;
}
}
void delay_ms(int ms){
int i;
for (i=0; i<ms; i++)
delay_us(1000);
}
//Función auxiliar para la escritura en protocolo One-Wire
char recorrer_dato (unsigned char dato, int i){
char bit;
bit = dato >> i ;
bit &= 1;
return bit;
}
//Función que genera un pulso de reset en el bus
void onewire_reset() {
ONE_WIRE_PIN_MODE = 1; // como salida
ONE_WIRE_PIN = 0;
delay_us(500);
ONE_WIRE_PIN = 1;
delay_us(500); //Espero que termine la ventana de
inicialización
ONE_WIRE_PIN = 1;
}
//Función que escribe un dato de 8 bits en el bus
void onewire_write(unsigned char data) {
int count;
ONE_WIRE_PIN_MODE = 1; // como salida

for(count = 0; count < 8; ++count) {

109
ONE_WIRE_PIN = 0;
delay_us(2); //pulso bajo para iniciar el time-
slot
ONE_WIRE_PIN = recorrer_dato (data,count);
delay_us(60); //espero que termine el time-slot
ONE_WIRE_PIN = 1; //pulso alto
delay_us(2); //espero al menos 1us
}
}
//Función que lee el bus y devuelve un dato de 8 bits
unsigned char onewire_read (void) {
int count,i;
char data_aux [16];
unsigned char data;
data=0;

for (i=0; i<16; i++)


data_aux [i] = 0;

for(count = 0; count < 8; ++count) {


ONE_WIRE_PIN_MODE = 1; // como salida
ONE_WIRE_PIN = 0;
delay_us(2); //pulso bajo para iniciar el time-
slot
ONE_WIRE_PIN_MODE = 0;
delay_us(10); //espero hasta que se estabilice
el dato
data_aux[7-count] = ONE_WIRE_PIN; //guardo el resultado
delay_us(70); //espero que termine el time-slot
}
//Actualizo variable de retorno
for (i=0; i<8; i++){
data = data<<1;
data += data_aux[i];
}
return data;
}
//Función para leer la ROM de un termómetro (lee de a 1 byte)
void onewire_ds1822_read_rom(unsigned char *data)
{
onewire_write(DS1822_CMD_READROM);
data[DS1822_ROM_DEVTYPE]=onewire_readbyte(); // 0 family code
data[DS1822_ROM_SERIAL1]=onewire_readbyte(); // 1 serial number
LSB
data[DS1822_ROM_SERIAL2]=onewire_readbyte(); // 2 serial number
data[DS1822_ROM_SERIAL3]=onewire_readbyte(); // 3 serial number
data[DS1822_ROM_SERIAL4]=onewire_readbyte(); // 4 serial number
data[DS1822_ROM_SERIAL5]=onewire_readbyte(); // 5 serial number
data[DS1822_ROM_SERIAL6]=onewire_readbyte(); // 6 serial number
MSB
data[DS1822_ROM_CRC]=onewire_readbyte(); // 7 CRC

}
//Función para leer un byte completo de dato
unsigned char onewire_readbyte()
{
//Definición de variables
int count,i;
char data_aux [8];
unsigned char data;
data=0;

110
//Inicializo data_aux[] en cero
for (i=0; i<8; i++)
data_aux [i] = 0;

for(count = 0; count < 8; ++count) {


ONE_WIRE_PIN_MODE = 1; // como salida
ONE_WIRE_PIN = 0;
delay_us(2); //pulso bajo para iniciar el time-
slot

ONE_WIRE_PIN_MODE = 0;
delay_us(10); //espero hasta que se estabilice
el dato
data_aux[7-count] = ONE_WIRE_PIN; //guardo el resultado
delay_us(70); //espero que termine el time-slot
}
//Actualizo variable de retorno
for (i=0; i<8; i++){
data = data<<1;
data += data_aux[i];
}
return data;
}
#endif /*ONE_WIRE_C*/

#ifndef DS1820_C
#define DS1820_C

//Función que lee un dispositivo y devuelve valor de temperatura


int ds1820_read(unsigned char *rom)
{
//Definición de variables
int busy=0;
int i;
int result;
unsigned int temp2,temp1,temp3;
char temp_disp [16];
unsigned char scratchpad [9];

//Inicialización en cero
for (i=0; i<16; i++)
temp_disp [i] = 0;
ds1820_configure(0x00, 0x00, 0x00); //Resolución de 9 bits
onewire_reset();
onewire_write(DS1822_CMD_MATCHROM);
//Inicio conversión de temperatura
for(i=0;i<8;i++)
onewire_write(rom[i]);
onewire_write(DS1822_CMD_CONVERTTEMP);
//Espero que termine el tiempo de conversión
delay_ms(80);
//Selecciono el dispositivo que quiero leer
onewire_reset();
onewire_write(DS1822_CMD_MATCHROM);
//Lectura del scratchpad (memoria interna que almacena valor de
temperatura)
for(i=0;i<8;i++)
onewire_write(rom[i]);
onewire_write(0xBE);
//Leo los dos bytes del scratchpad
for (i=0; i<2; i++)

111
scratchpad[i] = onewire_read();
//Convierto a un solo valor entero
temp1 = scratchpad[0];
temp2 = scratchpad[1];
temp3 = (temp2*256)+temp1;
//result = (int) (temp3 / 2); //Cálculo para resolución de 0.5
ºC
result = (int) temp3 / 16; //Cálculo para resolución de 12
bits
//delay_ms(200);
delay_ms(10);
onewire_reset();
return(result);
}
//Función de escritura de dato de configuración
//Argumentos: alarm trigger high, alarm trigger low, configuration
void ds1820_configure(unsigned char TH, unsigned char TL, unsigned
char config) {
onewire_reset();
onewire_write(0xCC); //Skip ROM
onewire_write(0x4E); //Escribo en el scratchpad
onewire_write(TH);
onewire_write(TL);
onewire_write(config);
}
//Fnción de servicio directo
//Devulve el valor de temperatura medido por el número correspondiete
de termómetro
int Get_Temp (int termometro)
{
int temperatura;
temperatura = ds1820_read (rom_temp[termometro-1]);
if ((temperatura<0)||(temperatura>120))
temperatura = TEMP_ERR;
return temperatura;
}
#endif /*DS1820_C*/

3.6. Archivo botones.c

Este archivo ya fue transcripto en el desarrollo del informe.


3.7. Archivo Salida.c

#include "Salida.h"
#include "Proceso.h"
#include "derivative.h"

void salida_on (int salida)


{
if (salida==1)
SALIDA1=1;
else if (salida==2)
SALIDA2=1;
else if (salida==2)
SALIDA2=1;
else if (salida==3)
SALIDA3=1;
else if (salida==4)
SALIDA4=1;
else if (salida==5)
SALIDA5=1;

112
else if (salida==6)
SALIDA6=1;
else if (salida==7)
SALIDA7=1;
else if (salida==8)
SALIDA8=1;
else if (salida==9)
SALIDA9=1;
else if (salida==10)
SALIDA10=1;
else if (salida==11)
SALIDA11=1;
else if (salida==12)
SALIDA12=1;
else if (salida==13)
SALIDA13=1;
else if (salida==14)
SALIDA14=1;
else if (salida==15)
SALIDA15=1;
else if (salida==16)
SALIDA16=1;
else if (salida==17)
SALIDA17=1;
else if (salida==18)
SALIDA18=1;
else if (salida==19)
SALIDA19=1;
else if (salida==20)
SALIDA20=1;
else if (salida==21)
SALIDA21=1;
else if (salida==22)
SALIDA22=1;
else if (salida==23)
SALIDA23=1;
else if (salida==24)
SALIDA24=1;
}

void salida_off (int salida)


{
if (salida==1)
SALIDA1=0;
else if (salida==2)
SALIDA2=0;
else if (salida==2)
SALIDA2=0;
else if (salida==3)
SALIDA3=0;
else if (salida==4)
SALIDA4=0;
else if (salida==5)
SALIDA5=0;
else if (salida==6)
SALIDA6=0;
else if (salida==7)
SALIDA7=0;
else if (salida==8)
SALIDA8=0;
else if (salida==9)

113
SALIDA9=0;
else if (salida==10)
SALIDA10=0;
else if (salida==11)
SALIDA11=0;
else if (salida==12)
SALIDA12=0;
else if (salida==13)
SALIDA13=0;
else if (salida==14)
SALIDA14=0;
else if (salida==15)
SALIDA15=0;
else if (salida==16)
SALIDA16=0;
else if (salida==17)
SALIDA17=0;
else if (salida==18)
SALIDA18=0;
else if (salida==19)
SALIDA19=0;
else if (salida==20)
SALIDA20=0;
else if (salida==21)
SALIDA21=0;
else if (salida==22)
SALIDA22=0;
else if (salida==23)
SALIDA23=0;
else if (salida==24)
SALIDA24=0;
}

void clear_all_outputs (void)


{
int i;
for (i=1; i<25; i++)
salida_off(i);
}

int get_out_state (int salida)


{
int ret=0;

if (salida==1)
ret=SALIDA1;
else if (salida==2)
ret=SALIDA2;
else if (salida==2)
ret=SALIDA2;
else if (salida==3)
ret=SALIDA3;
else if (salida==4)
ret=SALIDA4;
else if (salida==5)
ret=SALIDA5;
else if (salida==6)
ret=SALIDA6;
else if (salida==7)
ret=SALIDA7;
else if (salida==8)

114
ret=SALIDA8;
else if (salida==9)
ret=SALIDA9;
else if (salida==10)
ret=SALIDA10;
else if (salida==11)
ret=SALIDA11;
else if (salida==12)
ret=SALIDA12;
else if (salida==13)
ret=SALIDA13;
else if (salida==14)
ret=SALIDA14;
else if (salida==15)
ret=SALIDA15;
else if (salida==16)
ret=SALIDA16;
else if (salida==17)
ret=SALIDA17;
else if (salida==18)
ret=SALIDA18;
else if (salida==19)
ret=SALIDA19;
else if (salida==20)
ret=SALIDA20;
else if (salida==21)
ret=SALIDA21;
else if (salida==22)
ret=SALIDA22;
else if (salida==23)
ret=SALIDA23;
else if (salida==24)
ret=SALIDA24;

return ret;
}

void switch_salida (int salida)


{
if (get_out_state (salida) == OFF)
salida_on (salida);
else
salida_off (salida);
}

3.8. Archivo Ejemplo_sistema.c

Este archivo ya fue transcripto en el desarrollo del informe

3.9. Archivo JM128_Bootloader.h

#ifndef _JM128_BOOTLOADER_H_
#define _JM128_BOOTLOADER_H_

#define USB_CONFIG 0x44 //USBTRC0 register

void Bootloader_Main(void);

#endif

3.10. Archivo display.h

115
Este archivo ya fue transcripto en el desarrollo del informe.
3.11. Archivo Temperatura.h

Este archivo ya fue transcripto en el desarrollo del informe.


3.12. Archivo maindefs.h

#ifndef __MAINDEFS_H_
#define __MAINDEFS_H_

//Definiciones de constantes

//Botones
char boton_disp_lcd [16] = "LCD ";
char boton_disp_menu [16] = "Menu ";
char boton_disp_enter [16] = "Enter ";
char boton_disp_up [16] = "Up ";
char boton_disp_down [16] = "Down ";
char boton_disp_left [16] = "Left ";
char boton_disp_right [16] = "Right ";

char nothing [16] = " ";

//Opciones de menu
char menu_iniciar [16] = "Iniciar ";
char menu_pausa [16] = "Pausa ";
char menu_editar_programa [16] = "Editar Programa";
char menu_cargar_programa [16] = "Cargar Programa";
char menu_control_manual [16] = "Control Manual ";
char menu_ir_a [16] = "Ir a accion ";
char menu_salir [16] = "Salir ";
char encendido_1 [16] = "Presione Entrar";
char encendido_2 [16] = " Para Iniciar ";

//Opciones de Pausa
char pausa_continuar [16] = "Continuar ";
char pausa_detener [16] = "Detener ";
char pausa_resetear [16] = "Resetear ";
char programa_detenido [16] = "Prog. Detenido ";

//Opciones de Control Manual


char manual_activar [16] = "Cambiar Salida:";
char salida_numero [16] = " ";

//Opciones de Inicio de una Acción específica


char accion_activar [16] = "Activar Accion:";
char accion_numero [16] = " ";

//Opciones de lectura de temperatura


char leer_temp_num [16] = "Temperatura: ";
char leer_temp [16] = "Ver Temperatura";
char temp_disp [16] = " ";
char temp_err [16] = "Error ";

#endif // __MAINDEFS_H_

3.13. Archivo botones.h

//Definiciones de hardware
#define BOTON_ENTER PTAD_PTAD4

116
#define BOTON_MENU PTAD_PTAD3
#define BOTON_LCD PTED_PTED7
#define BOTON_ARRIBA PTAD_PTAD1
#define BOTON_ABAJO PTGD_PTGD1
#define BOTON_IZQUIERDA PTAD_PTAD2
#define BOTON_DERECHA PTAD_PTAD0

#define BUZZER PTFD_PTFD2


#define LCD_LIGHT PTFD_PTFD4
#define MAX_TERMOMETROS 14

//Constantes de Estados de botones


#define NOTHING 0
#define MENU 10
#define ENTER 20
#define LCD 30
#define UP 40
#define DOWN 50
#define RIGHT 60
#define LEFT 70
#define MENU_INICIAR 11
#define MENU_PAUSAR 12
#define MENU_MANUAL 15
#define MENU_IR_A 16
#define MENU_LEER_TEMP 17
#define MENU_SALIR 18
#define ENCENDIDO 19

#define PAUSA_CONTINUAR 121


#define PAUSA_DETENER 122
#define PAUSA_RESETEAR 123
#define PAUSA_DETENIDO 124
#define MANUAL 150
#define CONFIGURAR 160
#define SALIR 170

//Prototipos
void check_botones (int boton);
void evento_botones (void);
void reset_counter (void);
int counter_done (int seconds);
int get_flag (void);
void set_flag (int valor);

3.14. Archivo Salida.h

#define SALIDA19 PTCD_PTCD5 //21


#define SALIDA20 PTCD_PTCD3 //20
#define SALIDA18 PTAD_PTAD5 //16
#define SALIDA21 PTCD_PTCD2 //19
#define SALIDA17 PTBD_PTBD0 //17
#define SALIDA24 PTCD_PTCD1 //24
#define SALIDA16 PTBD_PTBD1 //18
#define SALIDA23 PTCD_PTCD0 //23
#define SALIDA13 PTBD_PTBD2 //13
#define SALIDA22 PTGD_PTGD3 //22
#define SALIDA14 PTBD_PTBD3 //14
#define SALIDA10 PTGD_PTGD2 //10
#define SALIDA15 PTBD_PTBD4 //15
#define SALIDA11 PTDD_PTDD7 //11
#define SALIDA3 PTBD_PTBD5 //3

117
#define SALIDA12 PTDD_PTDD6 //12
#define SALIDA2 PTBD_PTBD6 //2
#define SALIDA9 PTDD_PTDD5 //7
#define SALIDA1 PTBD_PTBD7 //1
#define SALIDA8 PTDD_PTDD4 //8
#define SALIDA4 PTDD_PTDD0 //6
#define SALIDA7 PTDD_PTDD3 //9
#define SALIDA5 PTDD_PTDD1 //5
#define SALIDA6 PTDD_PTDD2 //4

//Prototipos
void salida_on (int salida);
void salida_off (int salida);
void clear_all_outputs (void);
int get_out_state (int salida);
void switch_salida (int salida);

3.15. Archivo Proceso.h

/*Definición de constantes de proceso*/

#define BOOL char


#define FALSE 0
#define TRUE 1
#define ON 1
#define OFF 0
#define REPETICIONES 6
#define NOT_USED 0

//Procesos posibles
#define UNUSED 0
#define MOLIENDA 1
#define MACERACION 2
#define CURVA_MACERACION 3
#define RECIRCULACION 4
#define LAVADO 5
#define HERVOR 6
#define ENFRIAMIENTO 7
#define FERMENTACION 8
#define FINAL_PROCESO 9
//Condiciones de accion
#define POR_TIEMPO 1
#define POR_TEMPERATURA 2
#define POR_EVENTO 3
#define POR_BOTON 4
#define POR_MANUAL 5
//Activación de alarma
#define ALARMA 25
//Otras definiciones
#define MAX_ACCIONES 100
#define ACIERTOS_TEMP 10
#define N_RECETAS 10

/*Definición de tipo Receta*/


struct receta
{
//Maceración
int Volumen_agua_maceracion;
int Temperatura_agua_maceracion_inicial;
int N_mesetas_maceracion;
//Curva de maceración

118
int Temperatura_maceracion_1;
int Tiempo_maceracion_1;
int Temperatura_maceracion_2;
int Tiempo_maceracion_2;
int Temperatura_maceracion_3;
int Tiempo_maceracion_3;
int Temperatura_maceracion_4;
int Tiempo_maceracion_4;
int Temperatura_maceracion_5;
int Tiempo_maceracion_5;
int Temperatura_maceracion_6;
int Tiempo_maceracion_6;
int Temperatura_maceracion_7;
int Tiempo_maceracion_7;
int Temperatura_maceracion_8;
int Tiempo_maceracion_8;
int Temperatura_maceracion_9;
int Tiempo_maceracion_9;
int Temperatura_maceracion_10;
int Tiempo_maceracion_10;
//Recirculado y lavado
int Tiempo_recirculado;
int Volumen_agua_lavado;
int Temperatura_agua_lavado;
//Adiciones durante el hervor
int Tiempo_aditivo_1;
int Tiempo_aditivo_2;
int Tiempo_aditivo_3;
int Tiempo_aditivo_4;
int Tiempo_aditivo_5;
int Tiempo_aditivo_6;
int Tiempo_aditivo_7;
int Tiempo_aditivo_8;
int Tiempo_aditivo_9;
int Tiempo_aditivo_10;
int Tiempo_de_hervor;
//Enfriado y Fermentación
int Tiempo_whirlpool;
int Temperatura_inicial_fermentacion;
int Tiempo_de_enfriamiento;
};
typedef struct receta rec_t;

//Definición de tipo de accion


struct accion
{
int proceso; //Proceso al que pertenece la acción
int salida; //Salida controlada por la acción
int on_off; //Defino si la accion actúa prendiendo o
apagando una salida
int fin; //Condición de finalización de la acción
(POR_TIEMPO, POR_TEMPERATURA, etc)
int valor_fin; //Valor de condición de finalización (en
segundos, ºC, etc)
int n_termometro; //Selección del termómetro que debe medirse
derante la acción
BOOL alarm; //Activación de un mensaje de alarma al
ejecutarse esta acción
};
typedef struct accion acc_t;
//Definición de tipo alarma

119
struct alarma
{
char* mensaje; //Puntero al mensaje que acompaña la
alarma
BOOL sonido; //Activación de indicación sonora
(Buzzer)
BOOL titilar_lcd; //Activación de parpadeo del LED del LCD
durante la alarma
};
typedef struct alarma alarm_t;
//Definición de tipo tiempo
struct tiempo
{
unsigned int dia;
unsigned int hora;
unsigned int minuto;
unsigned int segundo;
};
typedef struct tiempo tiempo_t;

//Definición de prototipos de funciones


int proceso_maceracion (void);
int proceso_lavado (void);
int proceso_enfriado (void);
int proceso_fermentacion (void);
//Servicios de Timer
unsigned int get_segundos (void);
unsigned int get_minutos (void);
unsigned int get_horas (void);
unsigned int get_dias (void);
//Prototipos de funciones
void Init_System_configuration (void);
void Init_Receta (int n_receta);
void Init_Proceso (void);
void Check_Proceso (void);
tiempo_t Get_tiempo_actual (void);
void Ejecutar_accion (int n_accion);
void Ejecutar_alarma (int n_accion);
void Actualizar_fin_tiempo_accion (int n_accion);
void Actualizar_fin_temperatura_accion (int n_accion);
void Actualizar_a_proxima_accion (void);
//Sevicios de LCD y BUZZER
void Set_lcd_flag (BOOL valor);
BOOL Get_lcd_flag (void);
void Set_buzzer_flag (BOOL valor);
BOOL Get_buzzer_flag (void);
//Servicios de pausa de programa
int Programa_activo (void);
void Reanudar_programa (void);
void Detener_programa (void);
void Set_contador_de_acciones (int valor);
//Servicios del Timer
void Reset_Timer (void);
//Otros
int Get_receta_activa (void);
void Set_receta_activa (int n_receta);

120
4. ESQUEMÁTICOS

A continuación, se adjuntan los esquemáticos de los circuitos de ambas placas. En primer lugar, se
detalla el circuito correspondiente a la placa lógica.

Fig. 33. Esquemático de la placa lógica.

121
En segundo lugar, se detalla el circuito correspondiente a la placa de potencia. Cabe destacar que el
circuito de salida (triac y optotriac) se repite 24 veces. Su entrada se conecta a la salida de los buffers,
denominados “OData1… OData24”.

Fig. 34. Esquemático del circuito de la placa de potencia.

122
XV. BIBLIOGRAFÍA

1. Hojas de datos

 http://www.freescale.com/files/32bit/doc/data_sheet/MCF51JM128.pdf
 http://www.freescale.com/files/32bit/doc/ref_manual/MCF51JM128RM.pdf
 http://cache.freescale.com/files/microcontrollers/doc/app_note/AN3748.pdf
 http://pdf1.alldatasheet.com/datasheet-pdf/view/58557/DALLAS/DS18B20.html
 http://www.datasheetcatalog.org/datasheets/150/363781_DS.pdf
 http://pdf1.alldatasheet.com/datasheet-pdf/view/5039/MOTOROLA/MOC3041.html
 http://www.dfrobot.com/image/data/FIT0127/datasheet.pdf
 http://es.scribd.com/doc/18946526/Datasheet-Lcd-16x2
 http://pdf1.alldatasheet.com/datasheet-pdf/view/50859/FAIRCHILD/CD4050.html

2. Información acerca de la elaboración de cerveza

 http://www.minicerveceria.com/back_office/system/file/curso_abc.pdf
 http://www.minicerveceria.com/back_office/system/articulo/verArticulo.php?idArticulo=38
 http://www.minicerveceria.com/back_office/system/articulo/verArticulo.php?idArticulo=50
 http://www.minicerveceria.com/back_office/system/articulo/verArticulo.php?idArticulo=49

3. Libros

 Mohan, U. et al, Power Electronics: Converters, Applications, and Design, Tercera Edición,
Editorial Wiley, 2003

123

Vous aimerez peut-être aussi