Sie sind auf Seite 1von 17

Seminario de Computadores I: Diseo con Microcontroladores Prof.

Leopoldo Silva

Medidor de Distancia Ultrasnico con Microcontrolador MSP430


Informe Final

Integrantes: Tamara Ramrez Francisco Villa Luis Ehlen Juan Espoz Jaime Daz Josey Avils

Contenido

Resumen Descripcin del sistema Driver SRF-04 Driver LCD Anexo: Cdigo fuente Algunos inconvenientes y soluciones

Resumen
El presente informe describe el trabajo realizado para el desarrollo del proyecto n 1 del Seminario de Computadores I, el cual consisti en el diseo e implementacin de un sistema de medicin de distancia ultrasnico.

Descripcin del Sistema


El sistema desarrollado consiste en un instrumento de medicin de distancia basado en ultrasonido. Para su construccin se utiliz la tarjeta de desarrollo del microcontrolador MSP 430F149, EasyWeb, junto al mdulo de medicin ultrasnico SRF04. El sistema fue concebido para realizar una medicin de distancia cada vez que se presionara uno de los botones disponibles en la tarjeta y luego se desplegara el resultado de la medicin en centmetros. Dadas las caractersticas de funcionamiento del sistema, ste se concibi como un modelo secuencial tal como se describe en la figura 1.

Botn = False

Standby Botn = True Medicin de distancia

Driver SRF04

Driver LCD

Desplieg ue en pantalla

Figura 1. Diagrama de funcionamiento del sistema de medicin.

Para la implementacin del sistema fue necesario desarrollar un driver para el control del LCD y otro para controlar el sensor ultrasnico SRF04, en los cuales radic la complejidad del desarrollo, esto pues el esquema general de funcionamiento es bastante simple. La integracin del sistema se realiz mediante un superloop1, debido a que la caracterstica secuencial del sistema lo haca ms apropiado.

Ver Anexo Cdigo Fuente

Driver SRF-04
Para utilizar el sensor de posicin se tuvo que tener en cuenta las siguientes consideraciones: Para dar aviso al sensor que debe empezar a medir, se debe generar una seal de trigger la cual debe tener un ancho mnimo de 10 [s]. Despus que el trigger es generado, el sensor comienza a medir y emite una seal de vuelta que es proporcional a la distancia medida. El rango de medicin va de 3 [cm] a 3 [m], generando as una seal alta de 5 [V] cuyo ancho est entre los 100 [s] y los 18 [ms]. En caso de no detectar un objeto, el pulso tiene un ancho de 36 [ms] Dado que pueden existir errores en la medicin, se debe adquirir ms de una de ellas, para luego obtener un promedio que finalmente constituye el valor medido y que se despliegue a travs de la pantalla de cristal lquido. Para obtener ms mediciones se debe esperar como mnimo 10 [ms], para generar una nueva seal de trigger e iniciar otra medicin.

Un diagrama de las caractersticas temporales del dispositivo se presenta a continuacin:

Figura 2. Diagrama Temporal de las caractersticas del Sensor de Posicin SRF04.

Funcionamiento general del programa.


La idea principal es la utilizacin de un timer para poder generar la seal de trigger que necesita el sensor y posteriormente medir el ancho de pulso que ste emite.

El siguiente diagrama explica en trminos generales el funcionamiento del driver.

Inicio del oscilador, inicio de puertos, inicio del timer A

El timer cuenta

Se genera interrupcin por

Rutina de servicio
Se genera trigger

El timer contina su

Rutina de servicio

Se genera interrupcin por canto de subida en el pin de recepcin

El timer termina su cuenta

Se realiza captura 1

El timer contina su

Rutina de servicio

Se genera interrupcin por canto de bajada en el pin de recepcin

Se realiza captura 2

Figura 3. Diagrama de flujo del funcionamiento del programa.

El programa comienza con la inicializacin del oscilador interno, en donde se configura el reloj ACLK para que trabaje a una frecuencia de 1 [Mhz], ya que con esta frecuencia se tiene el tiempo necesario para que se generen las seales entre el microcontrolador-sensor y viceversa (ver figura 3), antes de que se genere el overflow del timer.

Posteriormente se inicializan y se configuran los pines que sern utilizados para la generacin del trigger y para realizar las capturas, los cuales corresponden al pin P2.0 y el P1.2 respectivamente. Finalmente, el timer A es inicializado para que funcione en modo continuo, con fuente de reloj ACLK. Adems, se configuran las opciones de captura para que se realicen a travs del pin 1.2 y se habilitan las interrupciones La idea del programa, es generar la seal de trigger en la rutina de servicio de la interrupcin por overflow del timer A, el cual ser mantenido por un cierto tiempo (que tiene que ser mayor a 10 [s], de acuerdo a las especificaciones del sensor) y luego esperar que se realicen las capturas, las cuales son hechas en la rutina de servicio por captura del timer A, en donde son guardadas en dos arreglos, uno para las capturas hechas por cantos de subida y otro para las capturas hechas por cantos de bajada. En la captura, lo que se hace es guardar la cuenta que lleva el timer en el momento que se genera la interrupcin, ya sea porque ocurri un canto de subida en la seal entrante o un canto de bajada. Teniendo estos datos almacenados en los arreglos, se puede obtener la duracin del pulso que emiti el sensor y finalmente, convertirlo a distancia, lo que representara la longitud medida. Una medicin es realizada 10 veces, para obtener un promedio de los datos recopilados y con el fin de tener una medicin ms precisa. En la siguiente figura se puede apreciar cmo se generan las seales y los tiempos de cada una. Como se puede apreciar, no hay problemas con los tiempos, ya que debido a la configuracin del timer y a que ACLK es de 1 [Mhz], se tiene el tiempo suficiente para generar la seal de trigger, para que el sensor realice la medicin y se deja tiempo suficiente para el tiempo de resguardo que requiere el sensor, antes que el timer rebalse.

Figura 4. Diagrama temporal de las seales generadas.

En el Anexo se pueden apreciar todas las configuraciones realizadas, junto con las rutinas de servicio para cada interrupcin y el programa principal, en donde se realiza la conversin del tiempo medido del pulso a distancia.

Driver LCD 2
El desarrollo del driver para el LCD comprendi principalmente tres aspectos: Conexiones de Hardware: determina la configuracin de pines y forma de comunicacin con el LCD. Inicializacin del display: secuencia determinada por el fabricante del LCD para su puesta en funcionamiento. Funciones en el cdigo de programa: comandos que permiten mostrar la informacin deseada en el LCD.

Conexiones de Hardware
Para ahorrar pines del microcontrolador la tarjeta EasyWeb emplea slo 4 bits para la transmisin de datos. El LCD utiliza el puerto 2 del microcontrolador para enviar datos y comandos, su configuracin se puede ver en el archivo includes.h donde se encontrar lo siguiente:

#define #define #define #define #define

E_OFF E_ON RS_OFF RS_ON LCD_Data

P2OUT &= ~BIT3 P2OUT |= BIT3

// P2.3 = 0 // P2.3 = 1

P2OUT &= ~BIT2 // P2.2 = 0 P2OUT |= BIT2 // P2.2 = 1 P2OUT //los pines del cero al 7 del puerto2 dedicados al LCD

Las seales RS y E deben ser generadas por el microcontrolador, y deben cumplir las especificaciones de setup y hold. Al estar dedicado slo a escritura (el pin R/W esta conectado a tierra), el driver deber enviar los comandos o datos y esperar que stos se realicen internamente, antes de enviar nuevos comandos o datos. Esto implica conocer la duracin de ejecucin de los comandos y de esta manera aplicar correctamente los delays. Con RS = 0 se envan instrucciones o comandos al display. Con RS =1, se transfieren datos a ser desplegados. En ambos casos, mediante la seal Enable se pasan primero los 4 bits ms significativos y luego la parte menos significativa. La temporizacin se muestra en el diagrama de la figura 5.

El LCD utilizado corresponde al incluido en la tarjeta de desarrollo EasyWeb de Olymex.

Figura 5: Diagrama temporal de las seales del LCD.

Inicializacin del Display.


La inicializacin del display se realiza mediante la funcin Init_Display, la cual se describe mediante el diagrama de flujo de la figura 6. Como se dijo anteriormente, el display se encuentra por defecto en modo de 8 bits, por lo que este debe ser cambiado a 4 bits en la etapa de inicializacin. Se ha demostrado experimentalmente que la instruccin siguiente al cambio de modo debe repetirse 2 veces para que sea realizada.

Encendid o Espera 50ms para que se estabilicen los voltajes Cambio a modo de 4 bits

Espera 50us

Configuracin de lneas y fuente

Espera 50us

Encender Display y cursor

Espera 50us

Clear Display

Espera 5ms

Configuracin de modo de entrada de caracteres al display

Fin inicializacin

Figura 6. Secuencia de Inicializacin del LCD.

Funciones en el cdigo del programa.


Delay: Esta funcin implementa un retardo de 9+a*12 ciclos, donde cada ciclo es de 125ns si se utiliza un reloj de 8Mhz. Delayx100us: Realiza un ciclo for llamando la funcin Delay, de modo de realizar retardos mayores. Send_Char: Con esta funcin se enviarn los caracteres a imprimir en la pantalla del LCD. Como medida de seguridad se espera un tiempo previo para que se terminen de ejecutar funciones anteriores, luego se separa la informacin en paquetes de 4 bits y se envan al LCD con las seales RS y E, respetando los retardos necesarios para que se ejecuten las instrucciones correctamente. Debe notarse que esta funcin solo enva un carcter, por lo tanto se debe utilizar un ciclo for para enviarlos secuencialmente. Send_Cmd: Se implementa esta funcin para ejecutar comandos que ya estn implementados en el controlador interno del LCD, como por ejemplo la funcin Clear Display o Return Home las cuales se definen en el archivo includes.h, la forma de enviar estos comandos al LCD es idntica a la del Send_Char , excepto por la configuracin del registro RS que se deja en OFF para enviar comandos. Adems, hay que destacar que se debe esperar ms para ejecutar los comandos Clear Display y Return Home. Send_Str: Esta funcion se encarga de enviar cadenas de caracteres al LCD. Se le pasa un argumento por referencia, es decir, se le entrega un puntero a la cadena de caracteres que se quiere enviar al LCD, luego en un ciclo for se envian uno a uno los caracteres. Al llegar al caracter 40, se envia el comando de salto de linea.

Anexo: Cdigo Fuente


main.c
#include "includes.h" #include <stdio.h> unsigned char i; char *LCD_Message1 char *LCD_Message2 char *B1_Message = char *B2_Message = char *B3_Message = char *B4_Message = char *B6_Message = = " Medidor de"; = " Distancia "; " La Medicion es : "; " [cm]"; " [Ft] "; " [In] "; "Midiendo";

void Delay (unsigned int a); void Delayx100us(unsigned char b); void SEND_CHAR (unsigned char c); void SEND_CMD (unsigned char e); void SEND_STR (char *Str); void Init_Display(void); void InitOsc(void); void InitPorts(void); float medir(void); int f2ed (int sel, float dato); void main(void) { char mensaje[30]; float distancia; int prueba,prueba2; InitOsc(); InitPorts(); Init_Display(); SEND_STR(LCD_Message1); SEND_CMD(Set_DDRAM_Address+Line2_Offset); SEND_STR(LCD_Message2); SEND_CMD(Return_Home); while (1) { //--------------buttons scan-----------// Inicializacin Oscilador // Inicializacin de puertos // Inicializacin del LCD // Medidor de // Distancia // repeat forever

} }

if ((B2) == 0) //B2 is pressed { STATUS_LED_ON; // switch on status_led SEND_CMD(Clear_Display); // limpia el display SEND_CMD(Return_Home); // cursor en posicin SEND_STR(B1_Message); // La medicin es: distancia = medir(); // llamada a rutina de medicin prueba= f2ed(1,distancia); // retorna parte entera prueba2= f2ed(2,distancia); // retorna parte decimal SEND_CMD(Set_DDRAM_Address+Line2_Offset); // Cursor en 2 lnea sprintf(mensaje," %d.%d ",prueba,prueba2); // medicin string SEND_STR(mensaje); // escribe medicin en display SEND_STR(B2_Message); // unidades [cm] } else { STATUS_LED_OFF; }

int f2ed (int sel, float dato) { int retorno=0; int pentera=0,pdec=0; float decf=0; if (sel == 1) { pentera=dato/1; retorno=pentera; } if (sel == 2) { pentera=dato/1; decf=dato-pentera; decf=decf*1000; pdec=decf/1; retorno=pdec; } return(retorno);

// devuelve parte entera y // decimal de un flotante

medir.c
#include "includes.h" /* --------------------- Driver Sensor SRF04 versin 1.04 con Timer A1 ----------- */ /* ------------------ Inicio y configuracin del Timer A en modo captura --------------- */ void InitTimerA() { WDTCTL = WDTPW + WDTHOLD; TACTL = TASSEL_1 + TACLR + TAIE;

//Stop WDT //TASSEL_1: Selecciona fuente ACLK //TACLR: Limpia el timer A //TAIE: Habilita interrupcin Timer A //CCIE: Habilita int. de captura //CCIS_0: Escoge CCI1A (Pin 1.2 -> DI2) //CAP: habilita modo captura //SCS: Sincrnico //CM_3: Ambos cantos //Modo continuo e INICIO del TA //Habilita interrupciones

TACCTL1 = CCIE+CCIS_0+SCS+CAP+CM_3;

TACTL |= MC_2; _EINT(); _NOP();

/*---------------------------------o----------------------------------*/ int n=0,j=0; int capturaA[10],capturaB[10]; /* Prototipos */ void InitOsc (void); void InitPorts (void); float medir(void) { int a; float Tpromedio=0; float distancia=0; j=0;n=0; //Variables auxiliares //Arreglos donde se guardan las capturas //Inicio del oscilador //Inicio de puetos

for (a=0;a<=10;a++) { capturaA[a]=0; capturaB[a]=0; } InitTimerA(); while(j < 10);

//Inicializacin de arreglos para guardar //datos capturados

if(j == 10) { for(a=1;a<=10;a++) { Tpromedio=(capturaB[a]-capturaA[a])*1/10 + Tpromedio; //Largo promedio en uSeg. } distancia= Tpromedio*0.0166 + 1.3408; //Conversin de uSeg. a distancia en cm. } return(distancia); }

/* ---- Rutina de servico para la interrupcin del timer A ---- */ #pragma_vector=TIMERA1_VECTOR __interrupt void Timer_A (void) { int TAIV2=TAIV; //Se utiliza el registro 1 del timer A

/* ---- CapturaA en canto de subida, capturaB en canto de bajada ---- */ if (TAIV2 == 0x0002) //Comprueba si hay una interrupcin debido //a una captura { n++; if(n == 1) { capturaA[j]=TACCR1; //Captura en canto de subida } if(n == 2) { capturaB[j]=TACCR1; //Captura en canto de bajada j++; n=0; } if(j == 10) { TACTL &= MC_0; //Detencin de Timer A al cabo de 10 //mediciones //Se detiene el timer A, para realizar la //converion a distancia

} } else { /* ---- Rutina Overflow: genera trigger para SRF04 ---- */ if (TAIV2 == 10) //Comprueba si hay una interrupcin debido //a un overflow { Trigger_ON; for(n=0;n<=8;n++); //Delay de 16.8 uSeg. cada 65.5 ms n=0; Trigger_OFF; } } TAIV2=0; } %/*---------------------------------o----------------------------------*/

Los puertos se declaran de la siguiente manera:


void InitPorts(void) { P1SEL |=0x04; P1DIR &=0xFB; P2SEL P2OUT P2DIR P2IE } = 0; = 0; |= 0xFF; &=0x00;

//P1.2 en modo perifrico //P1.2 modo entrada // Mod IO //Slo P2.0 es de salida. //P2.0 y P2.1 sin interrupciones

Finalmente en el inicio del oscilador se configura ACLK a 1 [Mhz] como se muestra en la funcin siguiente:
void InitOsc(void) { WDTCTL = WDTPW | WDTHOLD; BCSCTL1 |= XTS; _BIC_SR(OSCOFF); do 4-12 IFG1 &= ~OFIFG; while (IFG1 & OFIFG); BCSCTL1 |= DIVA_3; IE1 &= ~WDTIE; IFG1 &= ~WDTIFG; IFG1 &= ~OFIFG; BCSCTL2 |= SELM0 | SELM1; //ACLK a 1 [Mhz] // disable WDT int. // clear WDT int. flag // clear osc. fault int. flag // set XT1 as MCLK pg 4-16

// stop watchdog timer // XT1 as high-frequency pg 4-15 // turn on XT1 oscillator // wait in loop until crystal is stable pg

LCD.c
/****************************************************************** ***** lcd.c ***** ***** Funciones para manejar el LCD ***** ******************************************************************/ #include "includes.h" void Delay (unsigned int a) { int k; for (k=0 ; k != a; ++k); }

//9+a*12 ciclos, cada ciclo es de 125ns con un reloj de 8Mhz

void Delayx100us(unsigned char b) { int j; for (j=0; j!=b; ++j) Delay (_100us); } void SEND_CHAR (unsigned char d) { unsigned char temp; //variable temporal para mandar el caracter al lcd Delay(_50us); // retardo de 0.5ms temp = d & 0xf0; // se obtiene la parte ms significativa del caracter de 8 bit LCD_Data &= 0x0f; // se aplica la mascara al puerto LCD_Data |= temp; // se deja el dato en el puerto RS_ON; //se programa el LCD a modo dato para que LCD reciba el caracter E_ON; Delay(_10us); E_OFF; //toggle E para el LCD temp = d & 0x0f; //se obtiene la parte menos significativa del caracter de 8bit temp = temp << 4; //se desplaza el dato temp a la parte ms significativa. LCD_Data &= 0x0f; LCD_Data |= temp; RS_ON; E_ON; Delay(_10us); E_OFF; } void SEND_CMD (unsigned char e) { unsigned char temp; Delay(_50us); temp = e & 0xf0; // se obtiene la parte ms significativa del comando de 8 bit LCD_Data &= 0x0f; // se aplica la mascara al puerto LCD_Data |= temp; // se deja el dato en el puerto RS_OFF; //se programa el LCD a modo comando para que LCD reciba el puntero E_ON; Delay(_10us); E_OFF; //toggle E para LCD temp = e & 0x0f; temp = temp << 4; LCD_Data &= 0x0f; LCD_Data |= temp; RS_OFF; E_ON; Delay(_10us); E_OFF; if((e==Clear_Display) || (e==Return_Home)) Delayx100us(20);

//para estos comandos se debe esperar mas //2ms

void Init_Display(void) { Delayx100us(250); //esperar 50 ms. para estabilizar los voltajes de alimentacion. Queda en modo 8 bits. Delayx100us(250); E_ON; LCD_Data = Set_Function+Data_Length_4+Enable_High;Delay(1); E_OFF;//se configura a modo 4 bits Delay(50); //esperar cambio a modo 4 bits, 39us min. SEND_CMD(Set_Function + Data_Length_4 + Two_Display_Lines + Font_5x7); //configuracion de 2 lineas y tamao de fuente

SEND_CMD(Set_Function + Data_Length_4 + Two_Display_Lines + Font_5x7); //debe repetirse para que sea aceptada SEND_CMD(Set_Display + Display_On + Cursor_On + Blink_Off); //encender el display y el cursor SEND_CMD(Clear_Display);Delayx100us(50); //limpia el display y espera (min 1.53ms) SEND_CMD(Set_Entry_Mode + Increment_Address + Shift_Display_Off); //configura el modo de incremento de la direccion y sin desplazamiento } //Envia un String con salto de linea despues del caracter 40 //El String se recorta a 80 caracteres void SEND_STR(char *Str) { unsigned int l,m; l=strlen(Str); for(m=0 ; (m<l && m<80) ; m++) { if(m==40) SEND_CMD(Set_DDRAM_Address+Line2_Offset); SEND_CHAR(*(Str+m)); } }

Algunos inconvenientes y soluciones


Rutina de Servicio del Timer A.
Dado que el registro TAIV se seteaba cada vez que ocurra una interrupcin por canto, una vez detectado se deba ingresar a una rutina de interrupcin para capturar el valor que el timer tena en ese instante. Para implementar esto se tuvo un problema el cual consista en que el flag TAIV se borraba antes de ingresar en la rutina de captura, impidiendo as almacenar el valor del timer en ese instante. La explicacin de esto est en que el registro TAIV se borra inmediatamente despus de ser ledo una vez. Para solucionar esta situacin se almacen el valor de TAIV en una variable auxiliar TAIV2, en la primera lnea de la rutina de servicio. La cual despus era comparada para poder entrar a la rutina siendo reseteada posteriormente.

Interrupciones
Otro problema que nos mantuvo ocupados bastante tiempo fue cuando se realizaron las primeras pruebas con el Timer, el registro PC (program counter) de la CPU perda su valor de retorno despus de saltar a la rutina de servicio del Timer y, por ende, provocaba un fallo general e IAR se cerraba. El problema estaba en una configuracin del Timer que no respetaba una secuencia de configuracin correcta. La frmula exitosa es como se describe en los cdigos anteriores.

Das könnte Ihnen auch gefallen