0% encontró este documento útil (0 votos)
14 vistas6 páginas

Sed Gitt 2003-09 Panel

Se propone diseñar un sistema electrónico basado en el microcontrolador ATmega2560 para un panel de señalización de tráfico, que incluye una matriz de LEDs y varios sensores para medir velocidad, temperatura y contaminación. El sistema requiere la generación de múltiples señales de salida y la implementación de comunicación serie asíncrona para la actualización de mensajes. Además, se detallan las asignaciones de entradas y salidas, la configuración de interrupciones y la rutina de inicialización en lenguaje C.

Cargado por

pedrolerito
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
14 vistas6 páginas

Sed Gitt 2003-09 Panel

Se propone diseñar un sistema electrónico basado en el microcontrolador ATmega2560 para un panel de señalización de tráfico, que incluye una matriz de LEDs y varios sensores para medir velocidad, temperatura y contaminación. El sistema requiere la generación de múltiples señales de salida y la implementación de comunicación serie asíncrona para la actualización de mensajes. Además, se detallan las asignaciones de entradas y salidas, la configuración de interrupciones y la rutina de inicialización en lenguaje C.

Cargado por

pedrolerito
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

Sistemas Electrónicos Digitales.

5 de Septiembre de 2003

APELLIDOS: NOMBRE:
PROBLEMA

Se desea diseñar un sistema electrónico basado en el microcontrolador ATmega2560


para su uso en un panel de señalización de tráfico. Dicho panel de señalización ha de
cumplir con las siguientes necesidades:

Una matriz de leds con el que se pretende mostrar información (caracteres


alfanuméri-cos). Esta matriz de leds constará de 8 filas y 64 columnas. Con idea
de mejorar la visibilidad no se permite hacer un barrido de las 64 columnas, sino
que se va a dividir la matriz en módulos de 16 columnas para así reducir el barrido:

Es decir, se van a necesitar 36 señales de salida: 8 bits de datos (D0…D7) para


cada uno de los 4 módulos, y 4 señales comunes para todos los decodificadores (para
realizar el barrido).
• 2 señales para señalización de emergencia (intermitentes).
• 2 señales provenientes de 2 bobinas detectoras de vehículos para medir la
velocidad de los vehículos.
• 2 medidas analógicas: temperatura y nivel de contaminación.

Además, dadas las necesidades del programa y del almacenamiento de los datos, se
necesita lo siguiente:

Comunicación serie asíncrona para la actualización de los mensajes escritos en la


matriz de leds y de la señalización de emergencia, y para el envío de los datos
provenientes de las medidas analógicas. Si se recibe el carácter ‘#’, el programa
entiende que se recibirán 64 bytes correspondientes a las 64 columnas de los
paneles. Si se recibe el carácter ‘*’, el programa considera que vendrá un byte (de 0
a 1) que identifica la señalización de emergencia y un segundo byte que indica la
frecuencia (0,1,2,3,4 para indicar las frecuencias: apagado, 0’5hz, 1hz, 5hz y 10hz,
respectivamente.
Se pide:

1. Asignar entradas y salidas. 1 punto.


2. Definir cómo se van generar las 36 señales necesarias para la matriz de
leds. Se necesitará una señal adicional para evitar el efecto sombra: con ésta
señal se deben apagar todos los leds de la matriz. El barrido se realizará de
manera que cada columna esté encendida 1 ms. 1.5 puntos.
3. La señalización de emergencia consiste en 2 señales intermitentes (que
son independientes entre sí) cuya frecuencia puede variar entre 0.5 y 10 Hz.
Indicar como se van a generar dichas señales, indicando a su vez las
configuraciones de los registros internos necesarios. Indicar también los cálculos
necesarios para las frecuencias de 0.5, 1.0, 5.0 y 10 Hz. 1.5 puntos.
4. Dos sensores -de dos espiras- se
utilizan para medir la velocidad de dos
carriles. En la imagen se muestra uno
de los sensores. Cada espira genera un
pulso mientras haya un vehículo encima
de élla. Ambos pulsos entrarán al micro
por un mismo pin.
Se pretende obtener la velocidad
de los vehículos que circulan. Cada
espira tiene un metro de lado y la
distancia entre espiras es de 20m.
Calcular la velocidad de los vehículos
que pasan. Cada vez que pase un
vehículo se enviará por el Puerto
serie la letra ‘V’ seguida de 3
dígitos que indicarán la velocidad
en km/h. La velocidad mínima que
mide este dispositivo es de
20km/h. 2 puntos.

5. Rutina que inicie los registros de los periféricos en lenguaje C:


• El Puerto serie asíncrono UART0 tendrá un formato de trama de 1 bit de comienzo,
8 bits de datos y 1 bit de parada, y una velocidad de 38400 baudios.
• El convertidor analógico digital CAD convierta todas las medidas analógicas
(tempera-tura y nivel de contaminación) de forma continua. 1 punto.

6. Planteamiento global del problema: tareas, interrupciones y variables globales que los
relacionen; así como el contenido de tareas no contempladas en puntos anteriores. 3
puntos.

Nota: Si se van a usar interrupciones, se ruega indicarlo con claridad

SOLUCIÓN: Se van a utilizar interrupciones del Input Capture 4 y 5, y de la uart0.

1) Asignar entradas y salidas

Periférico Pin/es E/S Periférico Pin E/S


Panel 0 PORTA S Luz intermit. 1 PF6 S
Panel 1 PORTB S Luz intermit. 2 PF7 S
Panel 2 PORTK S Temperatura PF0 (analóg.) E
Panel 3 PORTL S Contaminación PF1 (analóg.) E
decodificadores PD7:PD4 S UART0 PE0,RX E
Enable decod. PD3 S bobina 1 PL0,ICP4 E
UART0 PE1,TX S bobina 2 PL1,ICP5 E

2) Se va a utilizara una variable global que almacena los datos de las 16


columnas de cada uno de los 4 paneles (64 bytes en total): char
columnas[4][16]. Estos 64 bytes se actualizarán cada vez que llegue una
trama por el Puerto serie que comience por el carácter ‘#’.

La actualización periódica de una salida es fácil realizarla con una tarea si el


periodo es múltiplo del tic del sistema operativo (1ms). En este caso cada
columna estará 1ms encendida. El ojo humano tiene mucha inercia y ve la
columna encendida –todo el tiempo- si se refresca antes de 32ms.

Antes de iluminar una nueva columna, hay que apagar todo para evitar el
efecto sombra (iluminar una columna mientras se acaba de apagar la
anterior).
La tarea que rota las 6 columnas (utilizando las entradas de los
decodificadores) sería la siguiente:

#define enable SBIT(PORTD,3)

static void taskColumnasPaneles(void* pvParameters)


{
uint8_t columSelect=0;
While (1) {
enable=0; // Se apagan todas las columnas
// Se preparan los nuevos datos pero no se pueden ver (todo apagado)
PORTA= columnas[0][columnSelect]; // columnSelect está entre 0 y 15
PORTB= columnas[1][columnSelect]; // columnSelect está entre 0 y 15
PORTK= columnas[2][columnSelect]; // columnSelect está entre 0 y 15
PORTL= columnas[3][columnSelect]; // columnSelect está entre 0 y 15
PORTD= (columSelect << 4); // PD[7:4]= columSelect[3:0]
// Los datos ya están preparados, se hacen visibles para que una columna de
// cada panel esté visible durante un 1ms
enable= 1;
// Incrementa columnSelect. Si desborda el valor de 15, pasa a 0.
columnSelect= (columnSelect+1) & 0b00001111;
vTaskDelay(1);
}
}

3) Habrá una variable global llamada intermitencia[2] que almacena la


frecuencia a la que parpadean las dos señalizaciones.

Cuando una salida se refresca de forma periódica y su periodo es múltiplo


del tic del reloj del sistema operativo (1ms), lo más fácil es utilizar una
tarea que se repita con el periodo correspondiente.

static void taskIntermitencia_0(void* pvParameters)


{
uint8_t tics =100; // Valor inicial
While (1) {
switch (intermitencia[0]) {
case 0: PF6=0; tics = 100; break; // apagado
case 1: PF6=!PF6; tics =1000; break; // parpadeo cada 0,5hz
case 2: PF6=!PF6; tics = 500; break; // parpadeo cada 1hz
case 3: PF6=!PF6; tics = 100; break; // parpadeo cada 5hz
case 4: PF6=!PF6; tics = 50; break; // parpadeo cada 10hz
}
vTaskDelay(tics);
}
}

La segunda señalización tendrá la tarea taskIntermitencia_1 que será


idéntica a la anterior, particularizada para el pin PF7 en lugar del PF6.
También usará la variable intermitencia[1].
4) Cada sensor utilizará la interrupción de un Input Capture para detector dos
flancos de subida consecutivos y obtener la velocidad. Sabemos que v=e/t.
El espacio (e) entre las espiras es de 20m. El tiempo se calculará con dos
interrupciones consecutivas del Input capture (configurado solo para
generar interrupción por flanco de subida). Ese tiempo dependerá del
preescalador. Si al producirse el primer flanco de subida, se pone -en el
caso del IC4- TCNT4=0, entonces el tiempo transcurrido hasta el siguiente
flanco sería:

T(us)= 0.0625us*(ICR4+1)*preescalador (en microsegundos)

La velocidad en km/h, en función del tiempo calculado entre dos flanco, sería:

20 metros 1km 106 us 3600 seg 72*106 km


v * * * 
T ( us ) 1000 metros 1 seg 1 hora T ( us ) h

72*106 km 1152*106 km
v 
0.0625 us *( ICR 4  1) * preescalador h ( ICR 4  1) * preescalador h

Vamos a fijar un preescalador, si la velocidad mínima de un coche es de


20km/h. La velocidad mínima se conseguirá con un valor grande de ICR4
(está en el denominador).
1152*106 km km
v  20  preescalador  878,9
(65535  1)* preescalador h h

Los valores que admite el preescalador son 1,8,64,256 y 1024. El valor más
próximo –superior- es 1024. Por tanto, la expresión que se utilizará en
lenguaje C, para optimizar los cálculos, sería:

1152*106 km 1125000 km
v 
( ICR4  1)*1024 h ( ICR4  1) h
Por ejemplo, si el segundo flanco de subida ocurre con ICR4= 15000, la
velocidad del vehículo sería:
1125000 km km
v  75
( ICR 4  1) h h
15000
// Variables globales.
bool icr4_primer_flanco_subida=false, icr5_ primer_flanco_subida=false;

ISR (TIMER4_CAPT_vect) {
int velocidad;

if (icr4_flanco_subida) { // si se detectó el primer flanco de subida de la primera espira


tiempo= uint8_t(round((1125000/(ICR4+1)); // En seg.

velocidad= int(round(1125000/(ICR4+1))); // velocidad es un número entero


[Link](“v0= ”);
[Link](velocidad); // envía un entero por puerto serie
[Link](“km/h\r\n ”);
icr4_flanco_subida=false; // se prepara para el siguiente coche
}
else {
TCNT4= 0; // La cuenta hasta el siguiente flanco comienza desde 0.
icr4_flanco_subida= true; // Primer flanco de subida (primera espira)
}
}

El Segundo sensor utilizará la interrupción del Input Capture 5. Será similar


al anterior pero utilizando la variable icr5_flanco_subida.

5) Rutina de configuración

void setup() {
[Link] (38400, TX_ON+RX_ON); // transmite y recibe utilizando colas

// Configuración del Input Capture del timer 4 para el anemómetro 1


TCCR4A=0b00000000; // modo normal, TCNT4 cuenta continuamente desde 0 hasta 65535
TCCR4B= (1<<ICES4) + (1<<CS42);
TIMSK4= (1<<ICIE4);
TCNT4=0;
// Configuración del Input Capture del timer 5 para el anemómetro 2
TCCR5A=0b00000000; // modo normal, TCNT5 cuenta continuamente desde 0 hasta 65535
TCCR5B= (1<<ICES5) + (1<<CS52);
TIMSK5= (1<<ICIE5);
TCNT5=0;

ADCSRA = (1<<ADEN) // Habilita el convertidor


| (1<<ADSC) // Inicia una conversión
| (0<<ADIE) // No permite interrupción
| (0<<ADATE) // conversión simple (no autodisparo). El reset la pone a 0.
// Esta asignación no es efectiva.
| (1<<ADPS2)
| (1<<ADPS1)
| (1<<ADPS0); // ADC clock: 16MHz/128 = 125KHz

ADCSRB= 0b00000000; // los bits ADTS2:0= 000 -> conversion continua

sei(); // máscara global de interrupciones


}

6) Planteamiento del problema

Variables globales:
- char columnas[4][16];
- uint8_t intermitencia[2];
- bool icr4_primer_flanco_subida, icr5_ primer_flanco_subida;
- uart0_call, semáforo para la interrupción RX

Interrupciones:
- Input Capture 4, para medir velocidad
- Input Capture 5, para medir velocidad
- RX y TX de la uart0. La interrupción TX la gestiona completamente la librería, la interrupción
RX sería la siguiente:

ISR (USART0_RX_vect) {
if (uart0.isr_rx_fifo()) { // recoge el dato recibido y lo mete en la cola
xSemaphoreGive(uart0call); // da aviso al Sistema
}
}

Tareas:
- taskColumnasPaneles (apartado 2)
- taskIntermitencia_0, taskIntermitencia_1 (apartado 3)
- taskSecuencia, procesa los datos que envía la uart0
static void taskSecuencia(void* pvParameters)
{
enum ESTADOS { REPOSO, ESPERA64BYTES,INTERMIT_SENSOR,INTERMIT_DATO};
ESTADOS estado= REPOSO;

char datoRX;

while (1) {

switch (estado) {
case REPOSO:
xSemaphoreTake(uart0_call, portMAX_DELAY);
datoRX= [Link]();

if (datoRX== '#') estado= ESPERA64BYTES;


else if (datoRX== '=') estado= INTERMIT_SENSOR;
break;
case ESPERA64BYTES:
for (int i=0; i<4; i++) {
for ( j=0; j<16; j++) {
xSemaphoreTake(uart0_call, portMAX_DELAY);

columnas[i][j]= [Link]();
}
}
estado= REPOSO;
break;
case INTERMIT_SENSOR:
xSemaphoreTake(uart0_call, portMAX_DELAY);
datoRX= [Link](); // datoRX=0 ó 1 (selecciona la salida)
estado= INTERMIT_DATO;
break;
case INTERMIT_DATO:
xSemaphoreTake(uart0_call, portMAX_DELAY);
intermitencia[datoRX]= [Link](); // datoRX=0,1
estado= REPOSO;
break;
}
vTaskDelay(tics);
}
}

También podría gustarte