Examen parcial SE-N, octubre 2016 - Academia Cartagena992 = 30k (7) 2 de 17 Examen parcial SE-N,...

17
SISTEMAS ELECTRÓNICOS - N MÁSTER EN INGENIERÍA INDUSTRIAL Examen parcial SE-N, octubre 2016 (Romano Giannetti, José Daniel Muñoz Frías) Nombre: Grupo: Calificación: Examen parcial SE-N, octubre 2016 Curso 2016/2017 1 de 17

Transcript of Examen parcial SE-N, octubre 2016 - Academia Cartagena992 = 30k (7) 2 de 17 Examen parcial SE-N,...

Page 1: Examen parcial SE-N, octubre 2016 - Academia Cartagena992 = 30k (7) 2 de 17 Examen parcial SE-N, octubre 2016 Curso 2016/2017. SISTEMAS ELECTRÓNICOS - N MÁSTER EN INGENIERÍA INDUSTRIAL-+

SISTEMAS ELECTRÓNICOS - NMÁSTER EN INGENIERÍA INDUSTRIAL

Examen parcial SE-N, octubre 2016(Romano Giannetti, José Daniel Muñoz Frías)

Nombre: Grupo:

Calificación:

Examen parcial SE-N, octubre 2016Curso 2016/2017

1 de 17

Page 2: Examen parcial SE-N, octubre 2016 - Academia Cartagena992 = 30k (7) 2 de 17 Examen parcial SE-N, octubre 2016 Curso 2016/2017. SISTEMAS ELECTRÓNICOS - N MÁSTER EN INGENIERÍA INDUSTRIAL-+

SISTEMAS ELECTRÓNICOS - NMÁSTER EN INGENIERÍA INDUSTRIAL

Introducción

L

sensor "P"

sensor "N"

T L0

entrada del líquido

válvula

válvula in

Salida (pérdida)

Figura 1. Estructura del tanque y posición de los sensores.

Tenemos unos sensores resistivos de casi nuevaconcepción (los usamos en el anterior examen) quepermiten medir el nivel de líquido en un tanque (verFig. 1). Estos son sensores resistivos, lineales, basadosen potenciómetros y que miden el nivel de líquidoL (0 ≤ L ≤ 1 m); tienen las siguientes curvas decalibración:

RP (L, T ) = R0(1 + αL+ β∆T ) (1)

RN (L, T ) = R0(1 + α(L0 − L) + β∆T ) (2)

con los parámetros:

R0 = 10 kΩ, α = 1 m−1, β = 2× 10−2 C−1, L0 = 1 m. (3)

Como se puede recordar, el sensor tiene un problema de sensibilidad a la temperatura que puede ser importante;en nuestra aplicación la temperatura nominal es de 25 C y puede variar entre −25 y 75 C. Pero esta vez loacondicionamos para usar la característica a nuestro favor, y tener señales independientes de temperatura ynivel.

Esta vez hemos detectado un problema de pérdidas en el tanque, y hemos añadido un grifo controlado por unaelectroválvula para poder rellenarlo (detalles del control en la parte digital).

Parte analógica (4 puntos)El circuito de acondicionamiento que se decide usar es el de la Fig. 2; la idea es que a la salida v3 tengamosuna tensión que depende solo de L y no de la temperatura, cómo en el problema anterior, y una salida v4 queproporcione una salida dependiente sólo de la temperatura sin ser afectada por el nivel. Las salidas v3 y v4 seconectarán a sendos puertos de entrada analógicos del micro.

a)(1.5 ptos.) Calcular los valores de R1 y R2 de forma que los operacionales oa1 y oa2 no saturen nunca y seobtenga el mayor rango posible en v1 y v2 sin que la salida v3 dependa de la temperatura. Calcule tambiénel valor de R3 y E3 para que la tensión a la salida del sumador (v3) tenga una sensibilidad respecto a L de2 V/m y valga 0 para L = 0 m.

Las salidas v1 y v2 están limitadas en módulos a 3.3 V; claramente visto que la corriente en los sensores esconstante, el caso más crítico va a ser cuando el valor de la resistencias RN y RP sea máxima.

RP (L, T )|max = RP (L, T )|L=1 m,∆T=50 C = 30 kΩ (4)

RN (L, T )|max = RN (L, T )|L=0 m,∆T=50 C = 30 kΩ (5)

Las salidas son

v1 = −3.3RP

R1, v2 = −3.3

RN

R2(6)

entonces para que las salidas no se pasen de los límites de alimentación las resistencias R1 y R2 tendránque ser mayores que 30 kΩ (pueden verse los dos operacionales como amplificadores con inversión con lastensiones de ±3.3 V como entradas; para que no sature la salida la ganancia tiene que ser menor que 1).

Para tener el mayor rango, entonces, elegimos el valor menor posible de R1 y R2; además, para que en elsumador oa3 se elimine el efecto de la temperatura, las dos resistencias tienen que ser iguales:

R1 = R2 = 30 kΩ (7)

2 de 17 Examen parcial SE-N, octubre 2016Curso 2016/2017

Page 3: Examen parcial SE-N, octubre 2016 - Academia Cartagena992 = 30k (7) 2 de 17 Examen parcial SE-N, octubre 2016 Curso 2016/2017. SISTEMAS ELECTRÓNICOS - N MÁSTER EN INGENIERÍA INDUSTRIAL-+

SISTEMAS ELECTRÓNICOS - NMÁSTER EN INGENIERÍA INDUSTRIAL

+

R1

RP(L,T)

+

R2

RN(L,T)

R

R

+

+

R

v4

v1

v2

R=10 kΩ

oa1

oa2

oa3

oa4

v3

R

E3

R

R4

E4

R4

R3+3.3 V

-3.3 V

Figura 2. Circuito de acondicionamiento. Los operacionales son iguales y están alimentados entre −3.3 y 3.3V (rail to rail).Las resistencias R valen 10 kΩ.

En la salida v3 las contribuciones de ∆t se anulan:

v3 = −R3

R

(E3 − 3.3

R0

R1︸︷︷︸1/3

(1 + αL) + 3.3R0

R2︸︷︷︸1/3

(1 + αL0 − αL)

)= −R3

R(E3 − 2.2αL+ 1.1αL0) (8)

y los valores para satisfacer cero y sensibilidad serán entonces

R3

R2.2α = 2⇒ R3 =

R

1.1≈ 9.1 kΩ (9)

E3 + 1.1αL0 = 0⇒ E3 ≈ −1.1 V (10)

Apartado a: R1 = R2 = 30 kΩ, R3 ≈ 9.1 kΩ, E3 ≈ −1.1 V.

b)(1.5 ptos.) Calcular R4 y E4 de forma que la salida v4 sea proporcional a la temperatura, con valor 1.65 V

cuando T = 25 C y 2.65 V si T = 75 C (y claramente, ça van san dire, v4 = 0.65 V si T = −25 C).

El operacional oa4 es un diferencial. Por superposición

v4 = −R4

Rv1 +

R4

R+R4

(1 +

R4

R

)v2 +

R

R+R4

(1 +

R4

R

)E4 =

R4

R(v2 − v1) + E4 (11)

v4 =R4

R

(3.3

R0

R2︸︷︷︸1/3

(1 + αL0︸︷︷︸1

−αL+ β∆T ) + 3.3R0

R1︸︷︷︸1/3

(1 +αL+ β∆T )

)+ E4 (12)

Examen parcial SE-N, octubre 2016Curso 2016/2017

3 de 17

Page 4: Examen parcial SE-N, octubre 2016 - Academia Cartagena992 = 30k (7) 2 de 17 Examen parcial SE-N, octubre 2016 Curso 2016/2017. SISTEMAS ELECTRÓNICOS - N MÁSTER EN INGENIERÍA INDUSTRIAL-+

SISTEMAS ELECTRÓNICOS - NMÁSTER EN INGENIERÍA INDUSTRIAL

y finalmente:

v4 =R4

R

(3.3 + 2.2β∆T

)+ E4 (13)

y siendo la sensibilidad necesaria a la salida de 1 V para 50 C, es decir, 0.02 V/C:

R4

R2.2β = 0.02 ⇒ R4 =

R

2.2≈ 4.55 kΩ (14)

1

2.23.3 + E4 = 1.65 V⇒ E4 ≈ 0.15 V (15)

Apartado b: R4 ≈ 4.55 kΩ, E4 ≈ 0.15 V.

c)(1 pto.) Por razones de rango de entrada en modo común, tengo que mantener la alimentación de oa3 y oa4

dual (entre −3.3 y 3.3 V). Esto me pone nervioso porque podría pasar que llegara una tensión demasiadonegativa al micro, que se puede ver dañado por tensiones menores de −0.7 V. Proponer un circuito deprotección para conectar v3 y v4 al micro que sea lo más sencillo posible.

El único problema que podemos tener es con la tensiónnegativa; la tensión positiva será seguramente más pequeñade 3.3 V gracias a las alimentación de los operacionales.Las dos soluciones más sencillas son las de añadir unoperacional alimentado entre 0 y 3.3 V configurado cómo buffer(comprobando que no haya que protegerlo a su vex por lastensiones negativas posibles en entrada) o el sencillo circuito dela derecha.

R

D

vo

vin

Nótese como la resistencia R es fundamental para el correcto funcionamiento del circuito. Si la protecciónno está actuando, no influye; y cuando el diodo sí conduce, limita la corriente que en caso contrario podríaser muy alta y dañar el operacional o el mismo diodo.

Apartado c:

Parte digital (6 puntos)En esta parte se ha de implantar un sistema de control usando el microcontrolador dsPIC33FJ128MC802 paramantener el nivel del depósito aproximadamente constante. Para ello se usará un control todo/nada con histéresis,de forma que cuando el nivel sea igual o inferior a la referencia menos 1 cm se activará la electroválvula y cuandosea superior o igual a la referencia más 1 cm se desactivará dicha electroválvula. La referencia se fijará, medianteun #define para mejorar la legibilidad del código, a 50 cm.

El sistema interactuará con un PC mediante una UART por la que se enviará cada segundo el valor del nivel y dela temperatura. La UART se configurará a 115.200 baudios.

La conexión entre el sistema a controlar y el microcontrolador será la siguiente:

Tensión v3: AN3.

Tensión v4: AN4.

Válvula in: RB15. Un 1 en el pin conecta la válvula y un 0 la desconecta.

Para implantar el sistema puede usar un bucle de scan con interrupciones o el sistema operativo en tiempo realFreeRTOS.

4 de 17 Examen parcial SE-N, octubre 2016Curso 2016/2017

Page 5: Examen parcial SE-N, octubre 2016 - Academia Cartagena992 = 30k (7) 2 de 17 Examen parcial SE-N, octubre 2016 Curso 2016/2017. SISTEMAS ELECTRÓNICOS - N MÁSTER EN INGENIERÍA INDUSTRIAL-+

SISTEMAS ELECTRÓNICOS - NMÁSTER EN INGENIERÍA INDUSTRIAL

El conversor A/D se inicializa mediante la función:

void InicializarADCInt(uint16_t input_pins)

En donde input_pins es un bitmap con los pines que se van a usar como entradas analógicas. Dicha funciónconfigura al conversor A/D para que cada milisegundo convierta automáticamente todos los canales quese le indican mediante la variable input_pins y escriba el valor obtenido mediante DMA1 en la variableglobal static volatile uint16_t dat_adc[].2 Cuando finalice la conversión de todos los canales generará unainterrupción.

La rutina de atención a la interrupción del conversor A/D ha de tener el siguiente prototipo:

void __attribute__ (( interrupt(no_auto_psv) )) _ADC1Interrupt(void)

En dicha rutina tendrá que poner a cero el flag de interrupción (IFS0bits.AD1IF) y disparar las tareas del bucle descan mediante una bandera (o un semáforo si se implanta mediante FreeRTOS). Recuerde que la tarea de controlha de ejecutarse cada milisegundo y la de impresión de medidas cada segundo.

Para implantar el sistema ha de realizar los siguientes apartados.

a)(1,5 ptos) Escriba la rutina de atención a la interrupción.

void __attribute__ (( interrupt ( no_auto_psv ) )) _ADC1Interrupt ( void )

static uint16_t num_ejec = 0;

IFS0bits.AD1IF = 0; // borro el flag

flag_nivel = 1; // y activa el flag para disparar la tarea de control

// El flag de la tarea de impresión se activa sólo cuando se llega a su

// periodo de muestreo , controlado por num_ejec.

num_ejec ++;

if(num_ejec >= T_TAREA_IMPRESION)

num_ejec = 0;

flag_impresion = 1;

b)(1,5 ptos.) Escriba la tarea de control del nivel, denominada TareaNivel, que como se ha dicho antes esdisparada por la rutina de atención a la interrupción del conversor A/D cada milisegundo.

void TareaNivel(void)

uint16_t c_adc; // Copia de la variable compartida con el ADC

float nivel; // Nivel en cm

if (flag_nivel == 1)

flag_nivel = 0;

// Como el dato se escribe por DMA y sólo ocupa un word , no

// hay problemas de incoherencia de datos.

c_adc = dato_adc [0]; // Copia el dato compartido con la interrupción

nivel = c_adc /1023*3.3/ 2*100; //Nivel en cm. 2 voltios son 100 cm.

if(nivel >=( REF_NIVEL + HISTERESIS))

PORTB &= ~(1<< PIN_VALVULA); // Desconecta la válvula

1Direct Memory Access.2En el primer elemento del vector guarda el valor medido en el primer canal (AN3 en este caso) y en el segundo elemento el siguiente

canal.

Examen parcial SE-N, octubre 2016Curso 2016/2017

5 de 17

Page 6: Examen parcial SE-N, octubre 2016 - Academia Cartagena992 = 30k (7) 2 de 17 Examen parcial SE-N, octubre 2016 Curso 2016/2017. SISTEMAS ELECTRÓNICOS - N MÁSTER EN INGENIERÍA INDUSTRIAL-+

SISTEMAS ELECTRÓNICOS - NMÁSTER EN INGENIERÍA INDUSTRIAL

else if (nivel <= (REF_NIVEL - HISTERESIS))

PORTB |= (1<<PIN_VALVULA); // Conecta la válvula

c)(1,5 ptos.) Escriba la tarea que envía por la UART el valor del nivel y la temperatura, la cual ha de llamarseTareaImpresion. Como se ha dicho antes, esta tarea es disparada por la rutina de atención a la interrupcióndel conversor A/D cada segundo.

void TareaImpresion(void)

static char mensaje [40];

uint16_t c_dato_adc [2];

float temperatura , nivel;

if(flag_impresion == 1)

flag_impresion = 0;

// Como el dato se escribe por DMA y sólo ocupa un word , no

// hay problemas de incoherencia de datos.

c_dato_adc [0] = dato_adc [0]; // Copio los valores obtenidos por el ADC

c_dato_adc [1] = dato_adc [1];

// Obtenemos los valores del nivel y temperatura en cm y grados.

// Para el nivel , teniendo en cuenta que 2 V son 100 cm:

nivel = c_dato_adc [0]/1023*3.3 / 2*100;

// Y para la temperatura , teniendo en cuenta que 0,65 V son -25 °C y que

// 2,65 V son 75°C, nuevamente una variación de 2 V son 100, aunque °C en

// este caso.

temperatura = -25 + (c_dato_adc [0]/1023*3.3 - 0.65) /2*100;

sprintf(mensaje , "Nivel = %f cm, Temperatura = %f °C\n",

(double) nivel , (double) temperatura);

putsUART(mensaje);

d)(1,5 ptos.) Escriba el programa principal.

#include <stdio.h>

#include <stdlib.h>

#include <stdint.h>

#include <p33FJ128MC802.h>

#include "DriverPicTrainer/config.h"

#include "DriverPicTrainer/Idle.h"

#include "DriverPicTrainer/uart.h"

#include "DriverPicTrainer/adc.h"

#include "DriverPicTrainer/pwm.h"

#include "DriverPicTrainer/interrupciones.h"

#define REF_NIVEL 50 // Referencia del nivel en cm.

#define HISTERESIS 1 // Histéresis en cm.

#define CANAL_SENSOR_NIVEL 3

#define CANAL_SENSOR_TEMP 4

#define PIN_VALVULA 15

// Periodos de muestreo

6 de 17 Examen parcial SE-N, octubre 2016Curso 2016/2017

Page 7: Examen parcial SE-N, octubre 2016 - Academia Cartagena992 = 30k (7) 2 de 17 Examen parcial SE-N, octubre 2016 Curso 2016/2017. SISTEMAS ELECTRÓNICOS - N MÁSTER EN INGENIERÍA INDUSTRIAL-+

SISTEMAS ELECTRÓNICOS - NMÁSTER EN INGENIERÍA INDUSTRIAL

#define T_TAREA_IMPRESION 1000 // Periodo de la tarea en ms

// Variables compartidas con la interrupción

static uint8_t flag_nivel = 0;

static uint8_t flag_impresion = 0;

// Vector en el que el ADC guarda mediante DMA los valores medidos.

static volatile uint16_t dato_adc [2];

void TareaNivel(void);

void TareaImpresion(void);

void InicializarADCInt(uint16_t input_pins);

int main(int argc , char** argv)

InicializarReloj ();

PORTB &= ~(1<< PIN_VALVULA); // Inicialmente dejamos la válvula apagada.

TRISB &= ~(1<< PIN_VALVULA); // Pin de la válvula como salida

inicializarUART (115200);

InicializarADCInt ((1 << CANAL_SENSOR_TEMP)|(1<< CANAL_SENSOR_NIVEL));

while (1)

TareaNivel ();

TareaImpresion ();

// No es necesaria una tarea idle , ya que las tareas se sincronizan con

// la interrupción. Se podría usar si se quisiera en ella poner el

// microcontrolador en bajo consumo. En este caso su periodo tendría

// que ser de 0,5 ms para no estropear la latencia de TareaNivel

Solución con FreeRTOSLa solución si se usa FreeRTOS es similar a la anterior. La principal diferencia es el uso de semáforos en lugar debanderas, lo que mejora la latencia del sistema.

En primer lugar se muestra la rutina de atención a la interrupción:

void __attribute__ (( interrupt ( no_auto_psv ) )) _ADC1Interrupt ( void )

BaseType_t xHigherPriorityTaskWoken = pdFALSE;

IFS0bits.AD1IF = 0; // borro el flag

// Libero el semáforo para que se ejecute la tarea de control de nivel

xSemaphoreGiveFromISR(sem_nivel , &xHigherPriorityTaskWoken);

// El semáforo de la tarea de impresión se activa sólo cuando se llega a su

// periodo de muestreo , controlado por num_ejec.

num_ejec ++;

if(num_ejec >= T_TAREA_IMPRESION)

num_ejec = 0;

xSemaphoreGiveFromISR(sem_impresion , &xHigherPriorityTaskWoken);

Examen parcial SE-N, octubre 2016Curso 2016/2017

7 de 17

Page 8: Examen parcial SE-N, octubre 2016 - Academia Cartagena992 = 30k (7) 2 de 17 Examen parcial SE-N, octubre 2016 Curso 2016/2017. SISTEMAS ELECTRÓNICOS - N MÁSTER EN INGENIERÍA INDUSTRIAL-+

SISTEMAS ELECTRÓNICOS - NMÁSTER EN INGENIERÍA INDUSTRIAL

if(xHigherPriorityTaskWoken == pdTRUE )

taskYIELD (); // Si la liberación del semáforo ha despertado una tarea ,

// se fuerza un cambio de contexto

Lo único destacable es que aunque se llama dos veces a xSemaphoreGiveFromISR, sólo es necesario usar una variablexHigherPriorityTaskWoken que se envía a las dos llamadas. Si alguna de ellas despierta una tarea, se pondrá apdTRUE y al final de la interrupción se llamará al planificador para conmutar las tareas.

La tarea de control de nivel es la siguiente:

void TareaNivel(void *pvParameters)

uint16_t c_adc; // Copia de la variable compartida con el ADC

float nivel; // Nivel en cm

while (1)

if(xSemaphoreTake(sem_nivel , portMAX_DELAY) == pdTRUE)

// Como el dato se escribe por DMA y sólo ocupa un word , no

// hay problemas de incoherencia de datos.

c_adc = dato_adc [0];

nivel = c_adc /1023*3.3/ 2*100; //Nivel en cm. 2 voltios son 100 cm.

if(nivel >=( REF_NIVEL + HISTERESIS))

PORTB &= ~(1<< PIN_VALVULA); // Desconecta la válvula

else if (nivel <= (REF_NIVEL - HISTERESIS))

PORTB |= (1<<PIN_VALVULA); // Conecta la válvula

Dicha tarea se bloquea nada más empezar a la espera de la liberación del semáforo sem_nivel. Cuando esto ocurracalcula el valor del nivel, teniendo en cuenta que tal como está especificado el sistema, cuando V3 sea 2 V elnivel será de 100 cm. Por último ejecuta el control todo o nada con histéresis.

La tarea de impresión es similar a la anterior, solo que ahora en lugar de calcular el control se imprimen el nively la temperatura por la UART:

void TareaImpresion(void)

static char mensaje [40];

uint16_t c_dato_adc [2];

float temperatura , nivel;

while (1)

if(xSemaphoreTake(sem_impresion , portMAX_DELAY) == pdTRUE)

// Como el dato se escribe por DMA y sólo ocupa un word , no

// hay problemas de incoherencia de datos.

c_dato_adc [0] = dato_adc [0]; // Copio los valores obtenidos por el ADC

c_dato_adc [1] = dato_adc [1];

// Obtenemos los valores del nivel y temperatura en cm y grados.

8 de 17 Examen parcial SE-N, octubre 2016Curso 2016/2017

Page 9: Examen parcial SE-N, octubre 2016 - Academia Cartagena992 = 30k (7) 2 de 17 Examen parcial SE-N, octubre 2016 Curso 2016/2017. SISTEMAS ELECTRÓNICOS - N MÁSTER EN INGENIERÍA INDUSTRIAL-+

SISTEMAS ELECTRÓNICOS - NMÁSTER EN INGENIERÍA INDUSTRIAL

// Para el nivel , teniendo en cuenta que 2 V son 100 cm:

nivel = c_dato_adc [0]/1023*3.3 / 2*100;

// Y para la temperatura , teniendo en cuenta que 0,65 V son -25 °C y que

// 2,65 V son 75°C, nuevamente una variación de 2 V son 100, aunque °C en

// este caso.

temperatura = -25 + (c_dato_adc [0]/1023*3.3 - 0.65) /2*100;

sprintf(mensaje , "Nivel = %f cm, Temperatura = %f °C\n",

(double) nivel , (double) temperatura);

putsUART(mensaje);

Por último se muestra el programa principal con las inicializaciones y el arranque del planificador:

#include <stdio.h>

#include <stdlib.h>

#include <stdint.h>

#include <p33FJ128MC802.h>

#include "DriverPicTrainer/config.h"

#include "DriverPicTrainer/Idle.h"

#include "DriverPicTrainer/uart.h"

#include "DriverPicTrainer/adc.h"

#include "DriverPicTrainer/pwm.h"

#include "DriverPicTrainer/interrupciones.h"

#include "FreeRTOS.h" // Includes del Kernel

#include "semphr.h"

#include "queue.h"

#include "task.h"

#define TAM_PILA 200

#define PRIO_NIVEL 4

#define PRIO_IMPRESION 3

#define REF_NIVEL 50 // Referencia del nivel en cm.

#define HISTERESIS 1 // Histéresis en cm.

#define CANAL_SENSOR_NIVEL 3

#define CANAL_SENSOR_TEMP 4

#define PIN_VALVULA 15

#define T_TAREA_IMPRESION 1000 // Periodo de la tarea en ms

// Variables compartidas con la interrupción

SemaphoreHandle_t sem_nivel;

SemaphoreHandle_t sem_impresion;

// Vector en el que el ADC guarda mediante DMA los valores medidos.

static volatile uint16_t dato_adc [2];

void TareaNivel(void *pvParameters);

void TareaImpresion(void *pvParameters);

void InicializarADCInt(uint16_t input_pins);

int main(int argc , char** argv)

Examen parcial SE-N, octubre 2016Curso 2016/2017

9 de 17

Page 10: Examen parcial SE-N, octubre 2016 - Academia Cartagena992 = 30k (7) 2 de 17 Examen parcial SE-N, octubre 2016 Curso 2016/2017. SISTEMAS ELECTRÓNICOS - N MÁSTER EN INGENIERÍA INDUSTRIAL-+

SISTEMAS ELECTRÓNICOS - NMÁSTER EN INGENIERÍA INDUSTRIAL

InicializarReloj ();

PORTB &= ~(1<< PIN_VALVULA); // Inicialmente dejamos la válvula apagada.

TRISB &= ~(1<< PIN_VALVULA); // Pin de la válvula como salida

inicializarUART (115200);

InicializarADCInt ((1 << CANAL_SENSOR_TEMP)|(1<< CANAL_SENSOR_NIVEL));

// Creamos los semáforos de sincronización interrupción-tareas

vSemaphoreCreateBinary(sem_nivel);

vSemaphoreCreateBinary(sem_impresion);

// Y los tomamos para evitar una primera ejecución sin datos.

xSemaphoreTake(sem_nivel , (portTickType) 0 );

xSemaphoreTake(sem_impresion , (portTickType) 0 );

// Se crean las tareas

xTaskCreate(TareaNivel , "Niv", TAM_PILA , NULL ,

PRIO_NIVEL , NULL);

xTaskCreate(TareaImpresion , "Imp", TAM_PILA , NULL ,

PRIO_IMPRESION , NULL);

vTaskStartScheduler (); // y por último se arranca el planificador.

return 0; // En teoría no se debe llegar nunca aquí.

10 de 17 Examen parcial SE-N, octubre 2016Curso 2016/2017

Page 11: Examen parcial SE-N, octubre 2016 - Academia Cartagena992 = 30k (7) 2 de 17 Examen parcial SE-N, octubre 2016 Curso 2016/2017. SISTEMAS ELECTRÓNICOS - N MÁSTER EN INGENIERÍA INDUSTRIAL-+

SISTEMAS ELECTRÓNICOS - NMÁSTER EN INGENIERÍA INDUSTRIAL

Documentación del driver de la tarjeta

Driver del módulo ADC

Las funciones siguientes están declaradas en el archivo adc.h

void inicializarADCPolling(unsigned int input_pins); Inicializa el conversor AD para funcionar por polling.Es necesario pasarle a la función un parámetro que indique qué entradas analógicas se van a convertir. Paraello se usa el argumento poniendo a 1 los bits cuyas entradas analógicas queramos usar. Por ejemplo si sevan a usar las entradas AN0 y AN2 el argumento input_pins será igual a 0x05.

Parámetros:

• input_pins: Bitmap con los pines que se van a usar como entradas analógicas.

unsigned int leerADCPolling(unsigned int canal); Lee el canal indicado en el parámetro. Para ello lanzauna conversión y se bloquea a la espera de que finalice dicha conversión.

Parámetros:

• canal: Número del canal que se desea leer.

Valor devuelto:

• Valor leído del ADC.

Driver del módulo PWM

Las funciones siguientes están declaradas en el archivo pwm.h

void inicializarPWM(unsigned int bit_map, unsigned int frecuencia); Inicializa el módulo PWM. La fun-ción configura los pines indicados mediante el parámetro bit_map como salidas del módulo PWM. Dichassalidas se configuran de modo independiente. Además el módulo configura el módulo PWM en el modofree running a la frecuencia indicada mediante el parámetro frecuencia.

Parámetros:

• bit_map: Indica qué pines se conectan a las salidas del módulo PWM (1) o se dejan como E/S digital(0). Por ejemplo si se desea usar el pin RB15 y el RB10 como salidas PWM, bit_map será igual a(1<<15)|(1<<10).

• frecuencia: Frecuencia en Hz de la señal PWM.

void setFrecuencia(unsigned int frecuencia); Define la frecuencia del módulo PWM. Nótese que lafrecuencia es común para las seis salidas del módulo PWM

Parámetros: frecuencia: Frecuencia en Hz de la señal PWM.

void setDcPWM(unsigned int bit_map, unsigned int dc); Define el factor de servicio de la señal PWM de unao varias salidas, las cuales se definen mediante el parámetro bit_map. Nótese que las salidas RB15–RB14,RB13–RB12 y RB11–RB10 comparten el mismo canal PWM, por lo que su factor de servicio no puede serdistinto.

Parámetros:

• bit_map: Indica qué pines se conectan a las salidas del módulo PWM (1) o se dejan como E/S digital(0). Por ejemplo si se desea usar el pin RB15 y el RB10 como salidas PWM, bit_map será igual a(1<<15)|(1<<10).

• dc: Factor de servicio en tanto por 10000. Por ejemplo si se desea un factor de servicio del 50 %, elparámetro dc ha de valer 5000.

Examen parcial SE-N, octubre 2016Curso 2016/2017

11 de 17

Page 12: Examen parcial SE-N, octubre 2016 - Academia Cartagena992 = 30k (7) 2 de 17 Examen parcial SE-N, octubre 2016 Curso 2016/2017. SISTEMAS ELECTRÓNICOS - N MÁSTER EN INGENIERÍA INDUSTRIAL-+

SISTEMAS ELECTRÓNICOS - NMÁSTER EN INGENIERÍA INDUSTRIAL

void activarPWM(unsigned int bit_map); Activa las salidas PWM indicadas mediante el parámetro bit_map.

Parámetros: bit_map: Indica qué pines se conectan a las salidas del módulo PWM (1) o se dejan como E/Sdigital (0). Por ejemplo si se desea usar el pin RB15 y el RB10 como salidas PWM, bit_map será igual a(1<<15)|(1<<10).

void desactivarPWM(unsigned int bit_map); Desactiva las salidas PWM indicadas mediante el parámetrobit_map. Nótese que la desactivación hace que la salida pase a estar controlada por el módulo de E/S digital,por lo que tomará el valor indicado por el bit correspondiente de PORTB.

Parámetros: bit_map: Indica qué pines se conectan a las salidas del módulo PWM (1) o se dejan como E/Sdigital (0). Por ejemplo si se desea usar el pin RB15 y el RB10 como salidas PWM, bit_map será igual a(1<<15)|(1<<10).

Driver de la UART

Las funciones siguientes están declaradas en el archivo uart.h

void inicializarUART(unsigned long baudrate);

Se inicializa la UART para usar una trama de 8 bits de datos sin paridad y con un bit de stop. El módulousa interrupciones tanto para la recepción como para la transmisión. La comunicación con las rutinas deinterrupción se realiza mediante dos colas.

Parámetros: baudrate: Baudrate de la uart en baudios

void putsUART(char *pcad);

Transmite una cadena de caracteres por la UART.

Parámetros: pcad: cadena de caracteres a transmitir.

Tarea Idle

Las funciones siguientes están declaradas en el archivo idle.h

void InicializarTareaIdle(unsigned int t_s);

En un sistema basado en bucle de scan es necesario usar un timer para que las iteraciones del bucle durensiempre lo mismo. Esta función inicializa el timer 1 con un periodo igual a t_s. Cuando se llame a la funciónTareaIdle, ésta esperará al final de dicho periodo. Ojo, el valor máximo del periodo de muestreo es de423,5 ms; ya que es el máximo valor que puede contar el timer 1 sin rebosar.

Parámetros: t_s: periodo de muestreo en décimas de ms. El valor máximo es de 4235, ya que es el valormáximo que puede contar el timer 1 usando un prescaler de 256 sin rebosar.

void TareaIdle(void);

Esta tarea se queda bloqueada hasta el final del periodo de muestreo, marcado por el final de cuenta deltimer 1. El periodo de muestreo se define con la llamada a InicializarTareaIdle().

Configuración del microcontrolador

La función siguiente está declarada en el archivo config.h

void InicializarReloj(void);

Configura la frecuencia del oscilador FRC (FOSC), cuya frecuencia nominal (Fin) son 7.37 MHz, para queel microprocesador opere a 40 MIPS (en realidad a FCY = 39.61375 MHz)

12 de 17 Examen parcial SE-N, octubre 2016Curso 2016/2017

Page 13: Examen parcial SE-N, octubre 2016 - Academia Cartagena992 = 30k (7) 2 de 17 Examen parcial SE-N, octubre 2016 Curso 2016/2017. SISTEMAS ELECTRÓNICOS - N MÁSTER EN INGENIERÍA INDUSTRIAL-+

SISTEMAS ELECTRÓNICOS - NMÁSTER EN INGENIERÍA INDUSTRIAL

Habilitación de interrupciones

En el archivo interrupciones.h se encuentran las dos macros para habilitar e inhabilitar interrupciones:

Enable(): Habilita las interrupciones (pone IPL a 0).

Disable(): Inhabilita las interrupciones (Pone IPL a 7).

API de FreeRTOSEn las secciones siguientes, para cada función expuesta, se ha escrito antes de su prototipo el archivo cabecera(.h) en el que se declara dicha función.

Inicialización del sistemaCreación de tareas:

#include "task.h"

BaseType_t xTaskCreate( TaskFunction_t pvTaskCode ,

const char * const pcName ,

unsigned short usStackDepth ,

void *pvParameters ,

UBaseType_t uxPriority ,

TaskHandle_t *pvCreatedTask );

La función devuelve pdPASS si se ha creado la tarea o un código de error si no ha sido posible.

Sus argumentos son:

• pvTaskCode es el nombre de la función que implanta la tarea. Recuerde que esta función nunca deberetornar, es decir, ha de consistir en un bucle sin fin.

• pcName es un nombre descriptivo para la tarea. Sólo es necesario para depuración y su longitud máximaes de 4 caracteres en esta versión de FreeRTOS. Para cambiarlo basta con aumentar este valor en ladefinición de la constante configMAX_TASK_NAME_LEN, que está en el fichero FreeRTOSConfig.h.

• usStackDepth es el tamaño de la pila asociada a la tarea. Esta pila la crea el sistema operativo. Eltamaño se especifica en palabras (2 bytes en esta versión). Un valor razonable es de 150 palabras,aunque si se usan muchas variables locales será necesario aumentarla convenientemente.

• pvParameters es un puntero a los parámetros iniciales. Si la tarea no necesita parámetros se puedeponer a NULL

• uxPriority es la prioridad de la tarea. Recuerde que el valor máximo en esta versión de FreeRTOS esde 5, aunque puede modificarse editando la definición de configMAX_PRIORITIES.

• pvCreatedTask se usa para que la función devuelva un manejador de la tarea creada en caso de quese desee borrarla. Si el sistema es estático, es decir, una vez inicializado no se crean ni se destruyentareas, este argumento se dejará a NULL.

Arrancar el planificador:

#include "task.h"

void vTaskStartScheduler( void );

Esta función arranca el planificador. A partir de este momento el sistema operativo toma el control ydecidirá en cada momento qué tarea se ejecuta en la CPU. Si no hay ninguna tarea lista, ejecutará la tareainactiva, la cual se crea automáticamente en este momento.

Si todo va bien, esta función no retornará nunca, pero si no puede ejecutarse el sistema operativo por faltade RAM, retornará inmediatamente.

Examen parcial SE-N, octubre 2016Curso 2016/2017

13 de 17

Page 14: Examen parcial SE-N, octubre 2016 - Academia Cartagena992 = 30k (7) 2 de 17 Examen parcial SE-N, octubre 2016 Curso 2016/2017. SISTEMAS ELECTRÓNICOS - N MÁSTER EN INGENIERÍA INDUSTRIAL-+

SISTEMAS ELECTRÓNICOS - NMÁSTER EN INGENIERÍA INDUSTRIAL

Gestión de tiempoLas siguientes funciones permiten bloquear una función durante un tiempo o hasta un determinado instante. Enla versión de FreeRTOS para dsPIC33 el tick de reloj por defecto es de 5 ms, aunque puede disminuirse editandola constante configTICK_RATE_HZ si se necesita una temporización más exacta. Para poder especificar tiempos enmilisegundos fácilmente, el periodo del tick de reloj está definido en la constante portTICK_PERIOD_MS.

Bloquea la tarea durante xTicksToDelay ticks. Este tiempo se empieza a contar desde la llamada a la función.

#include "task.h"

void vTaskDelay(const TickType_t xTicksToDelay);

Bloquea la tarea hasta *pxPreviousWakeTime + xTimeIncrement y guarda este valor en la variable *pxPreviousWakeTime.

#include "task.h"

void vTaskDelayUntil(TickType_t *pxPreviousWakeTime ,

const TickType_t xTimeIncrement);

Devuelve el número de ticks transcurridos desde que se arrancó el planificador.

#include "task.h"

volatile TickType_t xTaskGetTickCount(void);

Funciones de manejo de semáforosEn FreeRTOS los semáforos se implantan usando el mecanismo de colas. Es decir, se define una cola de unelemento de tamaño cero, ya que sólo se necesita el mecanismo de sincronización de la cola, pero no sualmacenamiento de datos. Las funciones expuestas a continuación son en realidad macros que son sustituidaspor el preprocesador de C por llamadas a las funciones de manejo de colas. Su definición puede consultarse en elarchivo semphr.h.

La inicialización de un semáforo se realiza con:

#include "semphr.h"

SemaphoreHandle_t xSemaphoreCreateBinary(void);

La función retorna el manejador del semáforo o NULL si el semáforo no ha podido crearse por falta dememoria. Obviamente el manejador retornado por la función ha de ser accesible por todas aquellas tareasque necesiten usar el semáforo.

Para coger un semáforo se usa la macro:

#include "semphr.h"

BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore ,

TickType_t xBlockTime);

Sus argumentos son:

• xSemaphore es el manejador del semáforo que se desea coger.

• xBlockTime el el timeout tras el cual la macro retornará aunque no se haya podido coger el semáforo.

La macro devuelve pdTRUE si se ha obtenido el semáforo o pdFALSE si ha transcurrido el timeout xBlockTimesin obtenerlo.

Para soltar un semáforo se usa:

14 de 17 Examen parcial SE-N, octubre 2016Curso 2016/2017

Page 15: Examen parcial SE-N, octubre 2016 - Academia Cartagena992 = 30k (7) 2 de 17 Examen parcial SE-N, octubre 2016 Curso 2016/2017. SISTEMAS ELECTRÓNICOS - N MÁSTER EN INGENIERÍA INDUSTRIAL-+

SISTEMAS ELECTRÓNICOS - NMÁSTER EN INGENIERÍA INDUSTRIAL

#include "semphr.h"

xSemaphoreGive(SemaphoreHandle_t xSemaphore);

Su argumento indica el semáforo que debe soltarse.

Para soltarlo desde una interrupción:

#include "semphr.h"

xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore ,

signed BaseType_t *pxHigherPriorityTaskWoken);

Sus argumentos son:

• xSemaphore es el manejador del semáforo que se desea soltar.

• pxHigherPriorityTaskWoken es la dirección de una variable en la que esta función devuelve pdTRUE sise ha despertado una tarea de mayor prioridad como consecuencia de la liberación del semáforo.Esto permite realizar un cambio de contexto al terminar la ejecución de la rutina de atención a lainterrupción, tal como se ha mostrado en la sección ??.3

La macro devuelve pdTRUE si se ha podido soltar el semáforo. En caso contrario devuelve errQUEUE_FULL.

Funciones de manejo de colasCreación de la cola:

#include "queue.h"

QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength ,

UBaseType_t uxItemSize);

Esta función crea una cola de longitud uxQueueLength. Cada elemento tendrá el tamaño uxItemSize. Lafunción devuelve una estructura para manejar la cola o 0 si no puede crearla. Dicha estructura ha de sercreada previamente y ha de ser accesible para todas las tareas que necesiten usar la cola.

Para enviar datos a la cola:

#include "queue.h"

BaseType_t xQueueSend(QueueHandle_t xQueue ,

const void *pvItemToQueue ,

TickType_t xTicksToWait);

Esta función envía el dato al que apunta pvItemToQueue a la cola xQueue. Si la cola está llena la tarea sebloquea. Si después de pasar xTicksToWait ticks sigue sin haber sitio en la cola, la función retornará.

La función devuelve pdTRUE si el dato se ha enviado o errQUEUE_FULL si transcurrido el timeout la cola siguellena.

Para recibir datos de la cola:

#include "queue.h"

Base_Type_t xQueueReceive(QueueHandle_t xQueue ,

void *pvBuffer ,

TickType_t xTicksToWait);

3En esta sección se ha mostrado esta funcionalidad para el manejo de colas, pero en el caso de los semáforos se realiza de la mismamanera.

Examen parcial SE-N, octubre 2016Curso 2016/2017

15 de 17

Page 16: Examen parcial SE-N, octubre 2016 - Academia Cartagena992 = 30k (7) 2 de 17 Examen parcial SE-N, octubre 2016 Curso 2016/2017. SISTEMAS ELECTRÓNICOS - N MÁSTER EN INGENIERÍA INDUSTRIAL-+

SISTEMAS ELECTRÓNICOS - NMÁSTER EN INGENIERÍA INDUSTRIAL

Esta función recibe un dato de la cola xQueue. El dato se almacena en la dirección pvBuffer, por lo que dichopuntero ha de apuntar a una variable del mismo tipo que las albergadas en la cola. Si la cola está vacía, lafunción se bloquea hasta que llegue un dato a la cola o hasta que transcurran xTicksToWait ticks de reloj.

La función devuelve pdTRUE si el dato se ha recibido o pdFALSE en caso contrario.

Para enviar datos a la cola desde una interrupción:

#include "queue.h"

BaseType_T xQueueSendFromISR(QueueHandle_T pxQueue ,

const void *pvItemToQueue ,

BaseType_t *pxHigherPriorityTaskWoken);

Esta función es igual a xQueueSend salvo que no se bloquea cuando la cola está llena y por tanto, como supropio nombre indica, puede usarse desde una rutina de interrupción.

El argumento pxHigherPriorityTaskWoken es la dirección de una variable en la que esta función devuelvepdTRUE si se ha despertado una tarea de mayor prioridad como consecuencia del envío de un dato a lacola. Esto permite realizar un cambio de contexto al terminar la ejecución de la rutina de atención a lainterrupción.

Para recibir datos de la cola en una interrupción:

#include "queue.h"

BaseType_T xQueueReceiveFromISR(QueueHandle_t pxQueue ,

void *pvBuffer ,

BaseType_t *pxHigherPriorityTaskWoken);

Esta función es igual a xQueueReceive salvo que no se bloquea cuando la cola está vacía y por tanto, comosu propio nombre indica, puede usarse dentro de una rutina de interrupción.

El argumento pxHigherPriorityTaskWoken es la dirección de una variable en la que esta función devuelvepdTRUE si se ha despertado una tarea de mayor prioridad como consecuencia de la recepción de un dato dela cola. Esto permite realizar un cambio de contexto al terminar la ejecución de la rutina de atención a lainterrupción.

La función devuelve pdTRUE si se ha recibido un dato o pdFALSE en caso contrario.

A continuación se muestra un ejemplo de uso de esta función. En el ejemplo se ha supuesto que existeuna cola para enviar caracteres al puerto serie y una rutina de atención a la interrupción del puerto serieque extrae un dato de la cola y lo envía por la UART. El ejemplo está basado en el microcontroladordsPIC33FJ128MC802.

#include <p33FJ128MC802.h>

#include "FreeRTOS.h"

#include "queue.h"

QueueHandle_t xcola_env;

// La cola xcola_env se inicializará en el arranque del

// sistema. Desde alguna tarea se enviarán datos a esta

// cola.

// Rutina de atención a la interrupción de recepción

// del puerto serie

void __attribute__ ((interrupt ,no_auto_psv))

_U1TXInterrupt(void)

16 de 17 Examen parcial SE-N, octubre 2016Curso 2016/2017

Page 17: Examen parcial SE-N, octubre 2016 - Academia Cartagena992 = 30k (7) 2 de 17 Examen parcial SE-N, octubre 2016 Curso 2016/2017. SISTEMAS ELECTRÓNICOS - N MÁSTER EN INGENIERÍA INDUSTRIAL-+

SISTEMAS ELECTRÓNICOS - NMÁSTER EN INGENIERÍA INDUSTRIAL

char car_env;

BaseType_t xHigherPriorityTaskWoken;

if(xQueueReceiveFromISR(cola_rec , &car_rec ,

&xHigherPriorityTaskWoken) == pdTRUE)

U1TXREG = car_rec;

IFS0bits.U1TXIF = 0; // Borra la bandera de interrupción

if(xHigherPriorityTaskWoken == pdTRUE )

taskYIELD (); // Si el envío a la cola ha despertado

// una tarea, se fuerza un cambio de

// contexto

Examen parcial SE-N, octubre 2016Curso 2016/2017

17 de 17