Beruflich Dokumente
Kultur Dokumente
Leopoldo Silva
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.
Botn = False
Driver SRF04
Driver LCD
Desplieg ue en pantalla
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.
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.
El timer cuenta
Rutina de servicio
Se genera trigger
El timer contina su
Rutina de servicio
Se realiza captura 1
El timer contina su
Rutina de servicio
Se realiza captura 2
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.
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:
// 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.
Encendid o Espera 50ms para que se estabilicen los voltajes Cambio a modo de 4 bits
Espera 50us
Espera 50us
Espera 50us
Clear Display
Espera 5ms
Fin inicializacin
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);
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;
/*---------------------------------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
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----------------------------------*/
//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); }
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);
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)); } }
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.