Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Rubio
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit, vestibulum ut, placerat ac,
adipiscing vitae, felis. Curabitur dictum gravida mauris. Nam arcu libero, nonummy eget, consectetuer
id, vulputate a, magna. Donec vehicula augue eu neque. Pellentesque habitant morbi tristique senectus
et netus et malesuada fames ac turpis egestas. Mauris ut leo. Cras viverra metus rhoncus sem. Nulla et
lectus vestibulum urna fringilla ultrices. Phasellus eu tellus sit amet tortor gravida placerat. Integer
sapien est, iaculis in, pretium quis, viverra ac, nunc. Praesent eget sem vel leo ultrices bibendum.
Aenean faucibus. Morbi dolor nulla, malesuada eu, pulvinar at, mollis ac, nulla. Curabitur auctor semper
nulla. Donec varius orci eget risus. Duis nibh mi, congue eu, accumsan eleifend, sagittis quis, diam. Duis
eget orci sit amet orci dignissim rutrum.
Nam dui ligula, fringilla a, euismod sodales, sollicitudin vel, wisi. Morbi auctor lorem non justo. Nam
lacus libero, pretium at, lobortis vitae, ultricies et, tellus. Donec aliquet, tortor sed accumsan bibendum,
erat ligula aliquet magna, vitae ornare odio metus a mi. Morbi ac orci et nisl hendrerit mollis.
Suspendisse ut massa. Cras nec ante. Pellentesque a nulla. Cum sociis natoque penatibus et magnis dis
parturient montes, nascetur ridiculus mus. Aliquam tincidunt urna. Nulla ullamcorper vestibulum
turpis. Pellentesque cursus luctus mauris.
Nam dui ligula, fringilla a, euismod sodales, sollicitudin vel, wisi. Morbi auctor lorem non justo. Nam
lacus libero, pretium at, lobortis vitae, ultricies et, tellus. Donec aliquet, tortor sed accumsan bibendum,
erat ligula aliquet magna, vitae ornare odio metus a mi. Morbi ac orci et nisl hendrerit mollis.
Suspendisse ut massa. Cras nec ante. Pellentesque a nulla. Donec aliquet, tortor sed accumsan
bibendum, erat ligula aliquet magna, vitae ornare odio metus a mi. Morbi ac orci et nisl hendrerit
Pellentesque cursus luctus mauris.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit, vestibulum ut, placerat ac,
adipiscing vitae, felis. Curabitur dictum gravida mauris. Nam arcu libero, nonummy eget, consectetuer
id, vulputate a, magna. Donec vehicula augue eu neque. Pellentesque habitant morbi tristique senectus
et netus et malesuada fames ac turpis egestas. Mauris ut leo. Cras viverra metus rhoncus sem. Nulla et
lectus vestibulum urna fringilla ultrices. Phasellus eu tellus sit amet tortor gravida placerat. Integer
sapien est, iaculis in, pretium quis, viverra ac, nunc. Praesent eget sem vel leo ultrices bibendum.
Aenean faucibus. Morbi dolor nulla, malesuada eu, pulvinar at, mollis ac, nulla. Curabitur auctor semper
nulla. Donec varius orci eget risus. Duis nibh mi, congue eu, accumsan eleifend, sagittis quis, diam. Duis
eget orci sit amet orci dignissim rutrum.
Nam dui ligula, fringilla a, euismod sodales, sollicitudin vel, wisi. Morbi auctor lorem non justo. Nam
lacus libero, pretium at, lobortis vitae, ultricies et, tellus. Donec aliquet, tortor sed accumsan bibendum,
erat ligula aliquet magna, vitae ornare odio metus a mi. Morbi ac orci et nisl hendrerit mollis.
Suspendisse ut massa. Cras nec ante. Pellentesque a nulla. Cum sociis natoque penatibus et magnis dis
parturient montes, nascetur ridiculus mus. Aliquam tincidunt urna. Nulla ullamcorper vestibulum
turpis. Pellentesque cursus luctus mauris.
Nam dui ligula, fringilla a, euismod sodales, sollicitudin vel, wisi. Morbi auctor lorem non justo. Nam
lacus libero, pretium at, lobortis vitae, ultricies et, tellus. Donec aliquet, tortor sed accumsan bibendum,
erat ligula aliquet magna, vitae ornare odio metus a mi. Morbi ac orci et nisl hendrerit mollis.
Suspendisse ut massa. Cras nec ante. Pellentesque a nulla. Cum sociis natoque penatibus et magnis dis
parturient montes, nascetur ridiculus mus. Aliquam tincidunt urna. Cum sociis natoque urna. Is
parturient montes, nascetur ridiculus mus. Aliquam tincidunt urna. Nulla ullamcorper vestibulum
turpis. Pellentesque cursus luctus mauris.
2 Solución ................................................................................................................................................... 4
Bibliografía .............................................................................................................................................. 14
Debido a que este informe se realiza durante la primera asignatura de la carrera, que tiene un carácter
introductorio al mundo de la ingeniería, es que no se profundiza en los distintos aspectos más técnicos
del informe. El objetivo es una introducción a lo que es la programación con código, no se espera
obtener un amplio dominio del lenguaje de programación, ya que eso está muy por sobre el alcance de
este proyecto.
El presente informe trata acerca del uso del microcontrolador conocido como ARDUINO y de la
implementación de un código que permita representar imágenes y figuras fácilmente reconocibles en
una matriz LED de 8x8 luces.
Objetivos generales
Obtener una primera aproximación a lo que son los lenguajes de programación.
Desarrollar e implementar un código en el entorno de programación ARDUINO.
Redactar en conformidad un informe que ocupe la plantilla de informes EIE.
1
1 Antecedentes Generales y Propuesta
El MAX7219 es ideal para controlar fácilmente una gran cantidad de diodos LED o dígitos de 7
segmentos. También podemos controlar una matriz de LED de 8x8 con un sólo chip.
1.3 Pong
El juego Pong es un juego de deportes en dos dimensiones que simula una mesa. El jugador controla
una paleta moviéndola verticalmente y puede competir tanto contra la maquina u otro jugador humano.
Los jugadores usan las paletas para pegarle a una pelota de un lado hacia el otro. El juego consiste en
que el jugador con más puntos consigue llevarse la victoria. Estos puntos se consiguen cuando el
jugador adversario falla intentando devolver la pelota.
2
Error! Use the Home tab to apply Título 1 to the text that you want to appear here. Error! Use the
Home tab to apply Título 1 to the text that you want to appear here.
Arduino Uno:
Arduino Uno es una placa electrónica basada en el microcontrolador ATmega328. Cuenta con 14
entradas/salidas digitales, de las cuales 6 se pueden utilizar como salidas PWM (Modulación por ancho
de pulsos) y otras 6 son entradas analógicas. Además, incluye un resonador cerámico de 16 MHz, un
conector USB, un conector de alimentación, una cabecera ICSP y un botón de reseteado. La placa incluye
todo lo necesario para que el microcontrolador haga su trabajo, basta conectarla a un ordenador con
un cable USB o a la corriente eléctrica a través de un transformador.
Potenciometro:
3
2 Solución
En el presente segmento se procederá a explicar el código utilizado en el proyecto para la
implementación del conocido juego Pong. No sea realiza una explicación exhaustiva de cada línea de
código ni de cada comando utilizado, ya que eso estaría por sobre el alcance del presente proyecto, pero
sí se realiza una explicación del algoritmo de trabajo y de las distintas variables utilizadas.
Las primeras líneas de código hasta la línea 71 se utilizan principalmente para definir diferentes
parámetros y variables globales utilizados en el proyecto, los cuales se detallan a continuación
4
Error! Use the Home tab to apply Título 1 to the text that you want to appear here.
byte direction: número de 8 bits que representa la dirección que puede tomar la pelota. Puede
tomar cualquier valor entre 0 y 7. El 0 corresponde al norte y el resto de los valores toman la
dirección que corresponde según el sentido horario.
Int xball: posición actual de la pelota en el eje x.
Int yball: posición actual de la pelota en el eje y.
Int yball_prev: posición de la pelota en el eje y durante el estado anterior.
Byte xpad: número de 8 bits que se ocupa para definir la posición en el eje x de la “paleta” en
el juego. Corresponde a la totalidad de la paleta.
ball_timer: variable utilizada para asignar el delay al comenzar una nueva partida.
En funciones posteriores se definen otras variables de tipo local que no es necesario definirlas de
manera global.
Los comandos debug y serial.print no son necesarios para el algoritmo de trabajo, pero son necesarios
para verificar el buen funcionamiento del código. [2]
Las líneas 79 a 94 que se muestran a continuación definen la función newGame que fija el protocolo
que se sigue cada vez que el programa llama a esta función. Lo que hace es primero definir la posición
inicial de la pelota junto con su dirección, que puede tomar en este caso valores 3, 4 o 5, que
corresponden a las direcciones sureste, sur y suroeste, respectivamente. Luego prende sucesivamente
todas las luces de la matriz, presenta la figura de byte smile por 1,5 segundos y finalmente apaga todas
las luces.
79 void newGame() {
80 lc.clearDisplay(0);
81 // posición inicial
82 xball = random(1, 7);
83 yball = 1;
84 direction = random(3, 6); // Movimiento al sur
85 for(int r = 0; r < 8; r++){
86 for(int c = 0; c < 8; c++){
87 lc.setLed(0, r, c, HIGH);
88 delay(NEW_GAME_ANIMATION_SPEED);
89 }
90 }
91 setSprite(smile);
92 delay(1500);
93 lc.clearDisplay(0);
94 }
La función “setPad” le asigna un valor a la variable xpad de acuerdo a la posición del potenciómetro.
Gracias a la línea de código 97 es que el programa sabe en qué posición colocar la paleta.
96 void setPad() {
97 xpad = map(analogRead(POTPIN), 0, 1020, 8 - PADSIZE, 0);
98 }
5
Error! Use the Home tab to apply Título 1 to the text that you want to appear here.
Entre las líneas 114 y 137 se definen tres nuevas variables que se ocupan para analizar el estado actual
de la pelota para saber cómo responder. La variable checkBounce se ocupa para ver cuándo la pelota
llega a los bordes del display. Mientras la pelota no llegue a los bordes, la variable tendrá valor 0, pero
si la pelota llega a algún borde la variable tomará el mismo valor que la variable auxiliar bounce. La
variable getHit se ocupa para ver si la pelota toca a la paleta al llegar a la parte inferior del display y
toma diferentes valores dependiendo de en qué sección la pelota toca a la paleta o si no la toca. La
variable checkLoose toma el valor 1 cuando la pelota llega a la parte inferior del display y la variable
getHit tiene el valor de HIT_NONE.
Las líneas de código entre la 139 y la 241 definen el movimiento de la pelota mientras está en juego a
través de la función moveBall. Cuando la pelota choca con algún borde o con la paleta cambia su
dirección dependiendo de la dirección desde la que golpea y el lugar en el que golpea. Si todo funciona
bien y la partida no ha terminado, los valores de posición de la pelota en el eje x y en el eje y aumentan
o disminuyen en 1 durante cada iteración del programa.
6
Error! Use the Home tab to apply Título 1 to the text that you want to appear here.
152 break;
153 case 6:
154 direction = 2;
155 break;
156 case 7:
157 direction = (bounce == BOUNCE_VERTICAL) ? 1 : 5;
158 break;
159 case 5:
160 direction = (bounce == BOUNCE_VERTICAL) ? 3 : 7;
161 break;
162 case 3:
163 direction = (bounce == BOUNCE_VERTICAL) ? 5 : 1;
164 break;
165 case 4:
166 direction = 0;
167 break;
168 }
169 debug("->");
170 }
171
172 // Verificar golpe: direccion modificada es izquierda o derecha
173 switch(getHit()){
174 case HIT_LEFT:
175 if(direction == 0){
176 direction = 7;
177 } else if (direction == 1){
178 direction = 0;
179 }
180 break;
181 case HIT_RIGHT:
182 if(direction == 0){
183 direction = 1;
184 } else if(direction == 7){
185 direction = 0;
186 }
187 break;
188 }
189
190 // Verificar direcciones ortogonales y bordes
191 if((direction == 0 && xball == 0) || (direction == 4 && xball == 7)){
192 direction++;
193 }
194 if(direction == 0 && xball == 7){
195 direction = 7;
196 }
197 if(direction == 4 && xball == 0){
198 direction = 3;
199 }
200 if(direction == 2 && yball == 0){
201 direction = 3;
202 }
203 if(direction == 2 && yball == 6){
204 direction = 1;
205 }
206 if(direction == 6 && yball == 0){
207 direction = 5;
208 }
209 if(direction == 6 && yball == 6){
210 direction = 7;
211 }
212
213 // Caso de las esquinas
214 if(xball == 0 && yball == 0){
215 direction = 3;
216 }
7
Error! Use the Home tab to apply Título 1 to the text that you want to appear here.
La función gameOver cuando es llamada produce la imagen del byte sad en el display por 1,5 segundos
y luego apaga todas las luces. La función gameDraw traspasa la información de posición de la pelota al
display. Cada vez que la pelota cambia de posición prende la luz que corresponde a la nueva posición y
borra (apaga) la última posición que tomó la pelota.
La función setup debe realizarse cada vez que se prenda el dispositivo, ya que el modo normal del
MAX7219 cada vez que se prende es el de ahorro de energía. Esta función activa al MAX7219, define la
intensidad de brillo del display y llama a la función newGame para comenzar una partida.
8
Error! Use the Home tab to apply Título 1 to the text that you want to appear here.
9
3 Desarrollo
En la presente sección se procederá a indicar los distintos elementos físicos utilizados y a explicar el
esquema de conexión, como para que puedan fácilmente reproducirse los resultados del proyecto.
Los primeros pasos a seguir son conseguir los elementos necesarios y realizar el esquema de conexión
para la implementación del proyecto, como se muestra en la Figura 1. [3]
10
Error! Use the Home tab to apply Título 1 to the text that you want to appear here.
ARDUINO UNO.
Matriz LED 8x8.
C.I. MAX7219.
Potenciómetro de 10 [kΩ].
Piezo Buzzer.
Protoboard.
Cambles de conexión.
El C.I. se utiliza principalmente porque el ARDUINO no tiene suficientes salidas como para activar
individualmente cada LED de la matriz. El MAX7219 permite usar solo una salida del ARDUINO para
enviar las señal de encendido y apagado a toda la matriz LED.
Para esta aplicación se puede eliminar el Piezo Buzzer, puesto que no hace nada, pero puede ocuparse
para añadir algunos sonidos que inmerjan al jugador
Los terminales del potenciómetro se conectan a la salida de 5 [V] del ARDUINO, al terminal de GROUND
y a la entrada A5
11
4 Resultados
12
Discusión y conclusiones
Las conclusiones finales del trabajo no se consideran como capítulos del texto, sin embargo ellas son
obligatorias para la estructura general del informe de proyecto e independientes de aquellas que
puedan existir en cada capítulo.
En ella, se deben indicar las conclusiones finales obtenidas, su proyección futura, usos, modificaciones,
limitaciones, etc. No debe incluir datos nuevos. Recuerde que las explicaciones de cada tema las dio a
conocer en cada uno de los capítulos anteriormente descritos.
Para el trabajo de un año (Proyecto I y II para ingenieros, seminario y proyecto para civiles), se espera
que su discusión y conclusiones tenga más o menos la misma extensión que la introducción, es decir
entre tres y cinco páginas.
13
Bibliografía
[1] E. d. I. Eléctrica, «Perfil de Egreso Carrera Ingeniería Civil Eléctrica,» Valparaíso, 2013.
[4] A. Passoti, «Arduino Pong with 8x8 LED matrix and MAX7219,» itOPEN, 09 Marzo 2012. [En línea].
Available: https://www.itopen.it/.
14
A Código de Juego Pong en ARDUINO [4]
Listado A-1 Código Completo Juego Pong en ARDUINO
1 /**
2 * Jugar pong en una matriz 8x8
3 *
4 * 0 1 2 3 4 5 6 7
5 * 0
6 * 1
7 * 2 7 0 1
8 * 3 6 X 2 (direcciones)
9 * 4 5 4 3
10 * 5
11 * 6
12 * 7 [pad]
13 *
14 *
15 *
16 *
17 */
18
19
20 #include "LedControl.h"
21 #include "Timer.h"
22
23
24 #define POTPIN A5 // Potenciometro
25 #define PADSIZE 3
26 #define BALL_DELAY 200
27 #define GAME_DELAY 10
28 #define BOUNCE_VERTICAL 1
29 #define BOUNCE_HORIZONTAL -1
30 #define NEW_GAME_ANIMATION_SPEED 50
31 #define HIT_NONE 0
32 #define HIT_CENTER 1
33 #define HIT_LEFT 2
34 #define HIT_RIGHT 3
35
36
37 //#define DEBUG 1
38
39 byte sad[] = {
40 B00000000,
41 B01000100,
42 B00010000,
43 B00010000,
44 B00000000,
45 B00111000,
46 B01000100,
15
Error! Use the Home tab to apply Título 6 to the text that you want to appear here. Error! Use the
Home tab to apply Título 6 to the text that you
want to appear here.
47 B00000000
48 };
49
50 byte smile[] = {
51 B00000000,
52 B01000100,
53 B00010000,
54 B00010000,
55 B00010000,
56 B01000100,
57 B00111000,
58 B00000000
59 };
60
61
62 Timer timer;
63
64 LedControl lc = LedControl(4,3,2,1);
65
66 byte direction; // Rosa de los vientos, 0 es el norte
67 int xball;
68 int yball;
69 int yball_prev;
70 byte xpad;
71 int ball_timer;
72
73 void setSprite(byte *sprite){
74 for(int r = 0; r < 8; r++){
75 lc.setRow(0, r, sprite[r]);
76 }
77 }
78
79 void newGame() {
80 lc.clearDisplay(0);
81 // posición inicial
82 xball = random(1, 7);
83 yball = 1;
84 direction = random(3, 6); // Movimiento al sur
85 for(int r = 0; r < 8; r++){
86 for(int c = 0; c < 8; c++){
87 lc.setLed(0, r, c, HIGH);
88 delay(NEW_GAME_ANIMATION_SPEED);
89 }
90 }
91 setSprite(smile);
92 delay(1500);
93 lc.clearDisplay(0);
94 }
95
96 void setPad() {
97 xpad = map(analogRead(POTPIN), 0, 1020, 8 - PADSIZE, 0);
98 }
99
100 void debug(const char* desc){
101 #ifdef DEBUG
102 Serial.print(desc);
103 Serial.print(" XY: ");
104 Serial.print(xball);
105 Serial.print(", ");
106 Serial.print(yball);
107 Serial.print(" XPAD: ");
108 Serial.print(xpad);
109 Serial.print(" DIR: ");
110 Serial.println(direction);
16
Error! Use the Home tab to apply Título 6 to the text that you want to appear here. Error! Use the
Home tab to apply Título 6 to the text that you
want to appear here.
111 #endif
112 }
113
114 int checkBounce() {
115 if(!xball || !yball || xball == 7 || yball == 6){
116 int bounce = (yball == 0 || yball == 6) ? BOUNCE_HORIZONTAL : BOUNCE_VERTICAL;
117 #ifdef DEBUG
118 debug(bounce == BOUNCE_HORIZONTAL ? "HORIZONTAL" : "VERTICAL");
119 #endif
120 return bounce;
121 }
122 return 0;
123 }
124
125 int getHit() {
126 if(yball != 6 || xball < xpad || xball > xpad + PADSIZE){
127 return HIT_NONE;
128 }
129 if(xball == xpad + PADSIZE / 2){
130 return HIT_CENTER;
131 }
132 return xball < xpad + PADSIZE / 2 ? HIT_LEFT : HIT_RIGHT;
133 }
134
135 bool checkLoose() {
136 return yball == 6 && getHit() == HIT_NONE;
137 }
138
139 void moveBall() {
140 debug("MOVE");
141 int bounce = checkBounce();
142 if(bounce) {
143 switch(direction){
144 case 0:
145 direction = 4;
146 break;
147 case 1:
148 direction = (bounce == BOUNCE_VERTICAL) ? 7 : 3;
149 break;
150 case 2:
151 direction = 6;
152 break;
153 case 6:
154 direction = 2;
155 break;
156 case 7:
157 direction = (bounce == BOUNCE_VERTICAL) ? 1 : 5;
158 break;
159 case 5:
160 direction = (bounce == BOUNCE_VERTICAL) ? 3 : 7;
161 break;
162 case 3:
163 direction = (bounce == BOUNCE_VERTICAL) ? 5 : 1;
164 break;
165 case 4:
166 direction = 0;
167 break;
168 }
169 debug("->");
170 }
171
172 // Verificar golpe: direccion modificada es izquierda o derecha
173 switch(getHit()){
174 case HIT_LEFT:
17
Error! Use the Home tab to apply Título 6 to the text that you want to appear here. Error! Use the
Home tab to apply Título 6 to the text that you
want to appear here.
175 if(direction == 0){
176 direction = 7;
177 } else if (direction == 1){
178 direction = 0;
179 }
180 break;
181 case HIT_RIGHT:
182 if(direction == 0){
183 direction = 1;
184 } else if(direction == 7){
185 direction = 0;
186 }
187 break;
188 }
189
190 // Verificar direcciones ortogonales y bordes
191 if((direction == 0 && xball == 0) || (direction == 4 && xball == 7)){
192 direction++;
193 }
194 if(direction == 0 && xball == 7){
195 direction = 7;
196 }
197 if(direction == 4 && xball == 0){
198 direction = 3;
199 }
200 if(direction == 2 && yball == 0){
201 direction = 3;
202 }
203 if(direction == 2 && yball == 6){
204 direction = 1;
205 }
206 if(direction == 6 && yball == 0){
207 direction = 5;
208 }
209 if(direction == 6 && yball == 6){
210 direction = 7;
211 }
212
213 // Caso de las esquinas
214 if(xball == 0 && yball == 0){
215 direction = 3;
216 }
217 if(xball == 0 && yball == 6){
218 direction = 1;
219 }
220 if(xball == 7 && yball == 6){
221 direction = 7;
222 }
223 if(xball == 7 && yball == 0){
224 direction = 5;
225 }
226
227 yball_prev = yball;
228 if(2 < direction && direction < 6) {
229 yball++;
230 } else if(direction != 6 && direction != 2) {
231 yball--;
232 }
233 if(0 < direction && direction < 4) {
234 xball++;
235 } else if(direction != 0 && direction != 4) {
236 xball--;
237 }
238 xball = max(0, min(7, xball));
18
Error! Use the Home tab to apply Título 6 to the text that you want to appear here. Error! Use the
Home tab to apply Título 6 to the text that you
want to appear here.
239 yball = max(0, min(6, yball));
240 debug("AFTER MOVE");
241 }
242
243 void gameOver() {
244 setSprite(sad);
245 delay(1500);
246 lc.clearDisplay(0);
247 }
248
249 void drawGame() {
250 if(yball_prev != yball){
251 lc.setRow(0, yball_prev, 0);
252 }
253 lc.setRow(0, yball, byte(1 << (xball)));
254 byte padmap = byte(0xFF >> (8 - PADSIZE) << xpad) ;
255 #ifdef DEBUG
256 //Serial.println(padmap, BIN);
257 #endif
258 lc.setRow(0, 7, padmap);
259 }
260
261 void setup() {
262 // El MAX72XX está en modo de ahorro de energia cuando se prende,
263 // se necesita realizar un llamado de activación
264 pinMode(POTPIN, INPUT);
265
266 lc.shutdown(0,false);
267 // Fijar el brillo a un valor medio
268 lc.setIntensity(0, 8);
269 // y limpiar el display
270 lc.clearDisplay(0);
271 randomSeed(analogRead(0));
272 #ifdef DEBUG
273 Serial.begin(9600);
274 Serial.println("Pong");
275 #endif
276 newGame();
277 ball_timer = timer.every(BALL_DELAY, moveBall);
278 }
279
280
281 void loop() {
282 timer.update();
283 // Panel de movimiento
284 setPad();
285 #ifdef DEBUG
286 Serial.println(xpad);
287 #endif
288 // Actualizar pantalla
289 drawGame();
290 if(checkLoose()) {
291 debug("LOOSE");
292 gameOver();
293 newGame();
294 }
295 delay(GAME_DELAY);
296 }
19