Tutorial básico MSP430G2553

March 26, 2018 | Author: Ulises Escarcega | Category: Microcontroller, Bit, Computer Hardware, Digital Electronics, Electronics


Comments



Description

Tutorial MSP430 – Prender un Led“Bienvenido a mi casa. Venga libremente, váyase a salvo, y deje algo de la alegría que trae consigo” Dracula, de Bram Stoker Vamos a trabajar con el microcontrolador MSP430F2011, debido a que tiene sólo 14 pines, de los cuales podemos utilizar 10 pines como I/O, 2KB de memoria de programa (Flash Memory) y 12MB de memoria de datos (RAM). Naturalmente si en algún momento nos queda chico este micro migraremos a otro con mayor recursos. En esta direccion de la empresa Texas Instruments se encuentran dos archivos que necesitamos tener a nuestro lado como material de consulta absoluto: 1. Datasheet del MSP430F2011 2. Guia de Usuario de la Familia MSP430X2XX Como podemos ver en la imagen, vamos a realizar un código que active un nivel high en el pin 2 del MSP430F2011. El código que realizará esta tarea se muestra a continuación: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include "io430.h"//libreria del propio IDE //#define LED1 P1OUT_bit.P1OUT_0//definicion del pin LED #define LED1 P1OUT_bit.P0//definicion del pin LED int main( void ) //funcion principal { // Stop watchdog timer to prevent time out reset WDTCTL = WDTPW + WDTHOLD; //CAPD = 0x00;//Habilitamos el output driver de todos los pines del puerto 1. P1SEL = 0x00;//Seteamos la funcion de I/O en todos los pines del puerto 1. P1DIR = 0xFF;//Seteamos todos los pines del puerto 1 como salida. LED1 = 1;//nivel high en el pin LED while(1);//bucle infinito } Como pueden notar se trata de un lenguaje C que respeta el formato del ANSI C, practicamente no hemos tocado aún varios aspectos como el oscilador, modo de arranques, etc. Estos temas los iremos vislumbrando conforme avance el curso. Pero por ahora toca entender que significan estos 3 registros: CAPD, P1SEL, P1DIR, y que significa el label LED1. CAPD, P1SEL, P1DIR se necesitan configurar de la siguiente manera para poder utilizar el pin 2 que corresponde con el P1.0, como output: Observen que para que el pin P1.0 se comporte como un pin de salida (o de entrada) necesita que el bit 0 del registro P1DIR sea cero, debido a que ese registro define el comportamiento de entrada o salida del pin, donde un “1 ” significa “salida” y un “0″ es “entrada” (contrario a como trabajan los PICs por ejemplo). Así mismo el bit 0 de P1SEL tiene que ser cero, pues esto le indica al pin que se comporte como un pin I/O, otro valor configuraría al pin para que trabaje con algun periférico que tiene multiplexado. En otro proyecto usaremos esta configuración. Y el bit 0 del registro CAPD también tiene que ser seteado a cero, para que habilite los buffers de entrada/salida del pin. Este registro tiene mayor relevancia cuando se usa el pin P1.0 en el modo comparador. Después de todo esto ya tenemos el pin P1.0 configurado como salida (en el código lo hemos aplicado a todos los pines del puerto 1), entonces creamos el label LED1 que referencia al bit 0 del registro P1OUT (quien controla los pines de salida del puerto 1). #define LED1 P1OUT_bit.P1OUT_0, donde: P1OUT_bit = registro P1OUT P1OUT_0 = bit 0 del registro P1OUT Finalmente un video para que la visita sea más didáctica: Tutorial MSP430 – Prender y Apagar un Led “Bienvenido a mi casa. Venga libremente, váyase a salvo, y deje algo de la alegría que trae consigo” Dracula, de Bram Stoker En esta nueva entrada vamos a estudiar un programa en el cual haremos prender y apagar (parpadear) un led con un determinado retardo. El programa aparenta ser simple y sencillo, sin embargo la pondremos dificil porque hasta ahora no sabemos a que frecuencia estamos trabajando con el MSP430F2011, es más, ni siquiera sabemos si estamos usando un oscilador externo o interno, no hemos mencionado nada del sistema oscilador del microcontrolador en cuestión. No es cuestión de poner un delay y ver como parpadea, se trata de entender como trabaja todo el sistema, al inicio puede parecer complejo explorar como funciona la oscilacion del MSP430F2011, pero veremos que ordenando la información y con algunos gráficos, todo se vuelve fácil de comprender. El Basic Clock System La frecuencia de oscilación del MSP430F2011 (y de todos los MSP430xxx) depende de lo que se conoce como el Basic Clock System, el cual si miran en el gráfico siguiente, se puede observar que está constituido por 5 elementos globales: 1. Clock Sources 2. Clock Signals 3. Modos de Operacion 4. Registros para configurar Clock Sources y Clock Signals 5. Registros para configurar el Modo de Operacion Parece mucha información, lo és!, pero ya dice el sabio refrán: “divide y vencerás”, por eso anticipo que en esta entrada no exploraremos los puntos 3 y 5, simplemente lo dejaremos con su configuración por defecto que es “Active Mode (AM)”, es decir no tocaremos sus registros de configuración. La aplicación o utilidad de los puntos 3 y 5 se ve reflejado en el tema de ahorro de consumo de energía, las diferentes configuraciones de low power mode permiten tener varios consumos en el orden de micro amperios, según sea la necesidad de la aplicación. Clock Sources y Clock Signals primero debemos configurar los clock sources y después aparecieron los clock signals. el esquema representa los bloques de trabajo del Basic Clock System para el MSP430F2xxx. LFXT1CLK. DCOCLK) se concentran en un punto para . una imagen habla más que 1000 palabras: El gráfico fue extraido del family users guide que les sugerí descargar en el primer post del tutorial. Igual tenemos que hacer nosotros. Además podrán apreciar de izquierda a derecha que los Clock Sources (VLOCLK. Porque? Por el siguiente gráfico. observen además que he colocado unos apuntes de “no está implementado” para que sepan que etapas no están implementadas en el MSP430F2011.“Y Odin creo primero los clock sources y después aparecieron los clock signals“. MCLK. DCOCLK) provienen las señales de oscilación del sistema (ACLK. • VLOCLK: Internal very low power. MCLK. En el caso del MSP430F2011 el LFXT1CLK solo soporta bajas frecuencias en el rango de 10KHz hasta 50KHz. pero podemos cambiar entre una y otra en el tiempo de ejecución del programa del microcontrolador: • LFXT1CLK: Low-frequency/high-frequency oscillator that can be used with low-frequency “watch crystals” or “external clock sources” of 32768 Hz or with standard crystals. LFXT1CLK.06MHz hasta 16MHz. los entendemos como la fuente de oscilación para las señales de reloj (Clock Signals) del sistema. • DCOCLK: “Internal” digitally controlled oscillator (DCO). DCOCLK: “Internal” digitally controlled oscillator (DCO) Este oscilador interno es muy versátil. Es un oscilador interno con un gran rango de configuración de trabajo de hasta 16MHz. SMCLK). Es un oscilador interno de solo 12KHz. El siguiente gráfico lo explicará todo: . Tenemos que seleccionar de que fuente (VLOCLK.dar lugar a los Clock Signals (ACLK. resonators. SMCLK). por ello los demás clock sources no serán analizados por el momento. en distintos niveles o pasos. tiene un gran rango de trabajo que va desde 0. En esta entrada vamos a trabajar con el oscilador interno DCOCLK. Clock Sources Entonces. y tenemos que seleccionar sólo una de ellas. or “external clock sources” in the 400-kHz to 16-MHz range. ya tendrán su respectivo post. utilizado para bajo consumo del sistema. low frequency oscillator with 12kHz typical frequency. Fijense el escalon que tiene por ejemplo RSEL = 0 para cada valor de DCO. del 0 al 15) del grupo de bits RSEL que se encuentran en el registro BCSCTL1. y en el eje vertical los valores (en realidad son 16 valores. a la izquierda en el eje vertical podemos apreciar la frecuencia “aproximada” que conseguimos en alguna de las configuraciones.El gráfico de arriba nos muestra en el eje horizontal los 8 (del 0 al 7) valores para el grupo de bits DCO (son 3 bits) que se encuentran en el registro DCOCTL. . sin embargo no son tema de esta entrada.A esto me refería cuando les decía que tenemos un oscilador muy versátil para trabajar. existen otros valores de frecuencia para el DCO que no están en esta tabla. ahora la pregunta es y cómo saber la frecuencia aproximada que estaremos configurando al utlizalos los bits DOC y RESL? Existen 2 caminos. tendrán su propio post y aplicación didáctica. utilizar los valores por defecto que ofrece el datasheet del MSP430F2011 o averiguar por tu cuenta un valor de frecuencia experimental con que desees trabajar. En la siguiente tabla extraída del datasheet del MSP430F2011 están los valores que debemos cargar alos registros BCSCTL1 (CALBC1_xMHZ) y DCOCTL (CALDCO_xMHZ) para obtener las correspondientes frecuencias: Como mencioné antes. Para este proyecto utilizaremos la configuracion de 1MHz. . the system clock used by the CPU. sourced either from a 32768-Hz watch crystal or the internal LF oscillator. VLOCLK. Para seleccionar el source se utiliza los bits SELS (2 bits) que están en el registro BCSCTL2 y un divisor de frecuencias en los bits del DIVS (2 bits) en el mismo registro. donde cada clock signal tiene su propia configuración y aplicación: • ACLK: Auxiliary clock (ACLK). Por defecto despues de un reset del chip siempre selecciona iniciar con el source DCOCLK. . • MCLK: Main clock (MCLK). the sub-system clock used by the peripheral modules. Puede ser utilizado con los clock source: LFXT1CLK. Puede utilizar todos los source disponibles. Puede utilizar todos los source disponibles. • SMCLK:Sub-Main clock (SMCLK). Por código podemos cambiarlo a otro source si lo requerimos y se realiza esto con los bits SELM (2 bits) que están en el registro BCSCTL2.Clock Signals Son 3 salidas para el source que seleccionemos. El source para esta señal dependera de la configuracion de los bits LFXT1S (2 bits) del registro BCSCTL3 y del bit XTS (1 bit) del registro BCSCTL1. Así mismo tiene un divisor de frecuencias en los bits del DIVM (2 bits) también en el registro BCSCTL2. . // Use 1Mhz cal data for DCO .h" //#define LED1 P1OUT_bit. Programa de aplicacion 1 2 3 4 5 6 7 8 9 10 #include "io430.En este programa utlizaremos el DCO a 1MHz junto con el MCLK con divisor valor 1.h"//libreria del propio IDE #include "intrinsics.P0//definicion del pin LED int main( void ) //funcion principal { // Stop watchdog timer to prevent time out reset WDTCTL = WDTPW + WDTHOLD. así que hay muy poco que manipular. BCSCTL1 = CALBC1_8MHZ.P1OUT_0//definicion del pin LED #define LED1 P1OUT_bit. P1SEL = 0x00. Estos nuevos enlaces estan compilador con la versión del software IAR 5. y deje algo de la alegría que trae consigo” Dracula.//500 milisegundos LED1 = 0.11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 DCOCTL = CALDCO_8MHZ. . de Bram Stoker Vamos a realizar un proyecto en el cual con un boton (normalmente en bajo nivel) iremos desplazando la activación de un led en la salida de un 74xx138 según un contador interno en el MSP430. boxnet.//500 milisegundos } } Video Todos los archivos los pueden encontrar en: 4shared.//Seteamos la funcion de I/O en todos los pines del puerto 1. __delay_cycles(160000). váyase a salvo. P1DIR = 0xFF.// Use 1Mhz cal data for DCO CAPD = 0x00. LED1 = 0.//Habilitamos el output driver de todos los pines del puerto 1. __delay_cycles(160000). Venga libremente.//nivel low en el pin LED while(1)//bucle infinito { LED1 = 1. En este sencillo ejemplo aprenderemos a utilizar los pines del MSP430 como entradas lógicas y también a configurar sus respectivas interrupciones de cambio de estado por flanco de entrada.40 : Tutorial MSP430 – Barra de Leds – Maskable Interrupts for Input Port “Bienvenido a mi casa.//Seteamos todos los pines del puerto 1 como salida. ya que por lo general se lo utiliza la mayor parte del tiempo en modo de bajo consumo (low-power mode) y puede volver al modo activo (AM mode) con una interrupción. • Despertar el CPU del modo Sleep. Esto es muy importante en el MSP430. Esto nos libera de realizar un código con polling (bucle para evaluar constantemente en el orden de microsegundos una entrada lógica). el MSP430 también viene provisto de interrupciones por hardware que permiten realizar diversas aplicaciones según la caraterística de la interrupción que utilizemos. • Tareas de poca frecuencia. Tipos de Interrupciones En el MSP430 tenemos 3 tipos de interrupciones. Podemos usar las interrupciones por ejemplo para los siguientes casos: • Tareas urgentes que deben ser atendidas inmediatamente y con mayor prioridad que el código principal. como el manejo de pulsadores en un humano.Interrupciones en el MSP430 Así como en otros microcontroladores. éstas son: . en la pagina 13.Si revisamos el datasheet del MSP430F2011. está plasmada una tabla con todas las interrupciones que soporta el microcontrolador (en realidad ese datasheet es para las series MSP430F20x3/2/1): . h” que está en los programas que hacemos con el IAR cuando seleccionamos el MSP430F2011. donde dicho orden indica así mismo el rango de prioridad de las interrupciones. separados por tipo y en orden descendente. y buscan lo siguiente: . Y cómo sabemos cuales son las interrupciones que maneja exactamente el MSP430F2011? Pues basta darle un vistazo al archivo “io430x20x1. es decir la interrupcion con prioridad 31 en la posicion de memoria 0xFFFEh correspondiente con el System Reset tiene la prioridad más alta de toda la tabla.Debemos observar en esta tabla que existen 32 posiciones de memoria (0-lowest … 31-highest) o también llamados “vectores” reservados para almacenar la dirección de los ISR correspondientes a la interrupción que los define (también conocidos como los “interrupt handler”). Como pueden apreciar en dicha tabla están plasmados los 3 tipos de interrupciones del MSP430F2011. En esta entrada sólo abarcaremos el estudio de las interrupciones enmascarables (MASKABLE INTERRUPTS) . debemos utilizar la función intrinseca: “__enable_interrupt“. Sino la utlizamos ninguna de las interrupciones enmascarables previamente y correctamente configuradas funcionarán. la cual setea a nivel global la activación de todas las interrupciones enmascarables del MSP430. para eso sirven esos #defines.h”. El formato es el siguiente: . Luego requerimos escribir el “interupt handler” o ISR. existe un formato para escribir el “interrupt handler” o ISR de la interrupción que queremos utilizar. necesitamos saber el nombre del vector de la interrupción que tiene en el microcontrolador que estamos programando (siempre y cuando sea desde el IAR). Para tener la función “__enable_interrupt” disponible necesitamos colocar en la cabecera la inclusión: #include “intrinsics. para los demás tipos prepararemos otras entradas ya que tienen su propio campo de aplicación. Maskable Interrupts for Input Port Las interrupciones enmascarables (MASKABLE INTERRUPTS) tienen la propiedad de activarse individualmente y también como en una capa superior se pueden activar colectivamente. que es el lugar donde haremos el tratamiento de la interrupción. Siempre se pone la linea “__enable_interrupt” al final de la configuración de todas las interrupciones enmascarables. despues de configurar el pin de entrada P2. Esto es. En C para el IAR.Para escribir el “interrupt handler” de la interrupción que queremos gestionar.7 para que genere una interrupcion en cada flanco de subida. por lo tanto el vector name será “PORT2_VECTOR”. <VECTOR_NAME>: aquí escribimos el nombre del vector de la interrupción que deseamos utilizar. __interrupt: es usado para indicar al compilador que haga la llamada convencional que necesita una función de tipo interrupción. <ISR_NAME>: es simplemente el nombre del “interrupt handler”. Interrupcion de Cambio de Estado en el Pin de Entrada P2. Dentro del “interrupt handler” escribimos el código que gestionará las acciones conjunto que realizará la interrupción del hardware especificado.7 Para configurar la interrupcion en el pin P2. En nuestro caso le he puesto de ISR_NAME el literal “InterrupcionPuerto2″.7 necesitamos manipular los siguientes registros: . es decir puede ser cualquier nombre que prefiera el programador. el nombre lo obtenemos del archivo cabecera del micro que usemos.7. Finalmente NUNCA olvidar de borrar el flag de la interrupción invocada. por ejemplo en esta entrada usaremos una interrupción en el pin P2.A continuación explicaremos los campos resaltados: #pragma vector: esta directiva es usada para especificar la dirección del vector de interrupción que se escriba en el campo <VECTOR_NAME>. que permite especificar el flanco de disparo de la interrupción en el pin P2. Luego borramos el flag de interrupcion en el bit 7 del registro P2IFG para evitar sorpresas inesperadas.De la imagen entendemos que debemos configurar el bit 7 del registro P2DIR con valor 0 para indicar “entrada”.7. por ello elegimos la transición de bajada a subida. para especificar si el pin P2.7 tendrá una resistencia de pullup (3. Así mismo hacemos con el bit 7 del registro P2IES. Recordar borrar este flag antes de salir del “interrupt hanlder” o ISR.3V con el pin al aire) o pulldown (0V con el pin al aire) conectada a su entrada. Podemos seleccionar entre una transición de bajada a subida o viceversa. En nuestro caso tenemos una señal normalmente en bajo nivel.7 escribiendo un 1 en el bit 7 del registro P2IE. . Esto por lo general se utiliza con pulsadores normalmente abiertos o cerrados. A continuación habilitamos la interrupción del pin P2. luego el bit 7 del registro P2SEL con valor 0 para indicar funcion de I/O (entrada/salida). También debemos utlizar el bit 7 del registro P2REN. P1DIR_bit.P1DIR_7 = 0.h"//libreria del propio IDE 1 #include "intrinsics. como és el caso del pin P2.P2DIR_7 = 0.” para activar de forma global todas las interrupciones enmascarables previamente configuradas. P1SEL = 0x00. BCSCTL1 = CALBC1_1MHZ.//Habilitamos el output driver de todos los pines del puerto 1.7. P1OUT = 0x00.7 como entradas logicas.// Use 1Mhz cal data for DCO DCOCTL = CALDCO_1MHZ.// Use 1Mhz cal data for DCO CAPD = 0x00.P2SEL_6 = 0.//pin de entrada //Configuramos pin P2. Programa de Aplicación: #include "io430.//input/output function P2DIR_bit.//logic input .//Seteamos la funcion de I/O en todos los pines del puerto 1. int main( void ) //funcion principal { // Stop watchdog timer to prevent time out reset WDTCTL = WDTPW + WDTHOLD.6 y P2.Finalmente agregaremos la linea de comando “__enable_interrupt().P1OUT_3//definicion del pin LED unsigned char aux.P1OUT_1//definicion del pin LED #define OUT_B P1OUT_bit.//logic input P2SEL_bit.P2DIR_6 = 0.P1OUT_2//definicion del pin LED #define OUT_C P1OUT_bit. P2DIR_bit. P1DIR = 0xFF.//Seteamos todos los pines del puerto 1 como salida.h" 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #define OUT_A P1OUT_bit. //habilitamos la interrupcion del pin P2.P2IES_7 P2IE_bit.P2SEL_7 = 0. aux = 7. if((aux OUT_A } if((aux OUT_B } if((aux OUT_C } & 0x01) == 0x01){ = 1. = 0. & 0x04) == 0x04){ = 1.7 = 0.P2IFG_7 = 0. } . OUT_C = 0. if(aux >= 7){ aux = 0. } P2IFG_bit.P2REN_7 P2IES_bit.P2IE_7 = P2IFG_bit. & 0x02) == 0x02){ = 1. while(1)//bucle infinito { } } #pragma vector = PORT2_VECTOR __interrupt void InterrupcionPuerto2(void){ OUT_A = 0.7 = 0.//deshabilitamos la resistencia pullup/pulldown. }else{ aux++. 1.7 activacion de interrupcion interrupción en el pin P2.P2IFG_7 P2.//interrupcion en pulso de subida (low to high).//limpiamos la bandera de interrupcion del pin //Segunda capa de activacion de interrupcion __enable_interrupt().26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 P2SEL_bit.//Borro el flag de interrupcion. OUT_B = 0.//input/output function //Primera capa de //Configuramos la P2REN_bit. En efecto hemos dejado atrás el MSP430F2011 y hemos cambiado al MSP430F2132 debido a su mayor cantidad de memoria y pines. y registros que constituyen el Timer Block del Timer_A que posee el microcontrolador MSP430F2132. configuraciones. .Timer En esta nueva entrada estudiaremos el comportamiento. Está constituido por dos partes principales: Timer Block (gobernado por un solo registro). Timer_A Es en esencia un timer/counter de 16 bits. Verán que no será nada complicado navegar por este nuevo micro. Canales de Captura/Comparación (conformado por varios registros). con registros de control y captura/comparación que en conjunto proporcionan muchas configuraciones que servirán para alcanzar los objetivos de nuestra aplicación. Además implementaremos en el proteus una aplicación para probar todas las configuraciones del Timer Block. por ello en los ejemplos trabajaremos solamente con el Timer0_A3. . Ambos módulos al ser Timer_A funcionan de la misma manera.Debemos mencionar que en los MSP430 pueden haber más de un modulo Timer_A.TA0CCR2).TA1CCR1). por ello para diferenciarlos se suelen enunciar colocando el índice del módulo después de la palabra Timer y al final la cantidad de canales que tiene implementado en dicho micro. Timer1_A2: módulo Timer_A con índice 1 y con 2 canales Capture/Compare (TA1CCR0. Por ejemplo en el MSP430F2132 tenemos dos modulo de Timer_A: Timer0_A3: módulo Timer_A con índice 0 y con 3 canales Capture/Compare (TA0CCR0. migrar los ejemplos al otro timer será cosa de modificar tan sólo el índice en el nombre de los registros.TA0CCR1. El Timer Block no tiene salida directa por algun pin sin embargo genera interrupción con la bandera TAIFG cuando su contador TA0R regresa a cero siempre que se habilite su interrupción con el bit TAIE. Se puede seleccionar la fuente del reloj y un prescaler. Timer Block del Timer0_A3 El Timer Block del Timer0_A3 está gobernado por un registro de control llamado TA0CTL el cual se apoya en un registro timer/counter de 16 bits llamado TA0R cuyo comportamiento se puede configurar. la otra parte principal la dejaremos para la segunda parte del estudio del Timer_A. Así mismo existe un modo de operación donde se genera interrupcion cuando el valor del registro contador TA0R sea igual al valor escrito en el registro TA0CCR0. .Veamos a continuación todos los registros del Timer0_A3 (sombreados en amarillo los registros asociados del Timer Block del Timer0_A3): En esta entrada nos enfocaremos en el estudio del Timer Block del Timer0_A3. /4.0. cuyos valores /1. nos referimos a los bits MC (bits 5-4 del registro TA0CTL) y sus opciones son las siguientes: Stop Mode (0) : se detiene el movimiento del timer TA0R. Finalmente tenemos el bit TACLR (bit 2 del registro TA0CTL) el cual resetea el valor del divisor de reloj (ID bits) y el valor del contador TA0R. Up Mode (1) : el timer TA0R se incrementa hasta alcanzar el valor en el registro TA0CCR0 y luego se reinicia desde cero.1 (TAINCLK) que permite incrementar con flanco de bajada al registro TA0R. Continuous Mode (2) : el timer TA0R se incrementa hasta ser igual a 0xFFFF y luego se reinicia desde cero. . En el MSP430F2132 este registro se llamaTA0R. A continuación nos encontramos con el bloque Input Divider o Divisor de Entrada.Si analizamos el diagrama de bloques del Timer Block empezando por la izquierda. ACLK (1) : señal de reloj previamente configurada del Basic Clock System en el MSP430F2132./2. el cual dividirá la frecuencia que nos proporcione el bloque clock source entre el valor seleccionado. en el MSP430F2132 se ubica en el pin P1. Después nos encontramos con el bloque que configura el comportamiento del registro TA0R. INCLK (3) : señal de reloj proveniente del pin P2. para los demás clock source siempre se incrementará con flanco de subida. SMCLK (2) : señal de reloj previamente configurada del Basic Clock System en el MSP430F2132. tenemos los clock source de donde se selecciona uno mediante los bits TASSEL (bits 9-8 del registro TA0CTL): TACLK (0) : señal de reloj proveniente de un pin externo./8se seleccionan mediante los bits ID (bits 7-6 del registro TA0CTL). Up/Down Mode (3) : el timer TA0R se incrementa hasta alcanzar el valor en el registro TA0CCR0 y luego se decrementa hasta el valor 0×0000. Luego aparece el registro timer de 16 bits llamado TAR. pues en la tabla de vectores de todas las interrupciones enmascarables tiene reservado dos vectores. Interrupcion del Timer Block en el Timer0_A3 Las interrupciones del Timer0_A3 son otro tema. TA0CCR2 CCIFG y TA0CTL TAIFG. el #24 y el #25. TAIFG) del MSP430F2132 las describiremos a continuación. El vector #24 responde a 3 banderas de interrupcion: TA0CCR1 CCIFG.Las señales de interrupción del Timer Block (TAIE. El vector #25 solamente refiere a la bandera TA0CCR0 CCIFG. . . luego de esta lectura el registro se resetea automáticamente. cómo identificamos en el vector #24 a la bandera TAIFG? Sucede que existe un registro llamado TA0IV cuyo valor permite conocer cual de las 3 interrupciones se ha producido. TA0IV significa: Timer0_A3 Interrupt Vector Value. Ahora nos surge una pregunta. debemos de consultar una vez dentro de la ISR al registro TA0IV por su valor para determinar el tipo de interrupción.Para esta primera parte. y tiene la propiedad de que por ejemplo cuando se produce la interrupción del TAIFG (que és cuando existe un desborde del timer TA0R) se carga en dicho registro el valor 0x0A. es decir despues de que el compilador invoque a la función de interrupcion del vector #24 del Timer0_A3. vamos a enfocarnos solamente en el flag TAIFG de la interrupcion Timer0_A3 (vector 24). Continuous Mode: En este modo la interrupcion se produce cuando el valor del registro TA0R se reinicia en cero justo después de que su valor haya sido igual a 0xFFFF (65535 en decimal). .Las interrupciones TAIFG por desborde del registro timer TA0R se configuran con los bits MC (bits 5-4 del registro TA0CTL) y tienen el siguiente comportamiento: Up Mode: En este modo la interrupcion se produce cuando el valor del registro TA0R se reinicia en cero justo después de que su valor haya sido igual al valor del registro TA0CCR0. Finalmente dicha interrupción con flag TAIFG (bit 0 del registro TA0CTL) se activa con el bit TAIE (bit 1 del registro TA0CTL). unsigned char modo1[10] = "UP MODE unsigned char source2[5] = "SMCLK". unsigned char div1[2] = "/2".h" 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 char char char char estadoCLK. unsigned char div0[2] = "/1". Para entender y consolidar el funcionamiento del Timer Block hemos realizado un código donde mediante 3 pulsadores se podrá seleccionar las configuraciones del source clock. estadoDIV. unsigned char linea2[16] = "MODO: ". Programa de Aplicacion: #include "io430.h" 2 #include "bsp\bsp. cambia. unsigned char source1[5] = "ACLK ". del input divider. . unsigned char div2[2] = "/4". unsigned char linea1[16] = "CLK: DIV: ".Up/Down Mode: En este modo la interrupcion se produce cuando el valor del registro TA0R llega a cero justo después de que su valor se haya decrementado desde que el valor de TA0R es igual el valor del registro TA0CCR0. int main( void ) { unsigned char titulo[16] = " microembebidos ".h" 1 #include "intrinsics. ". unsigned char source0[5] = "TACLK". y del mode control.h" 3 #include "lcd2x16\lcd2x16. estadoMODO. unsigned char modo0[10] = "STOP MODE ". switch(estadoCLK){ case 0: LcdStringXY(source0. __enable_interrupt(). break.// Use 1Mhz cal data for DCO DCOCTL = CALDCO_1MHZ. LcdStringXY(linea2.5. estadoDIV = 3. cambia = 1.// Use 1Mhz cal data for DCO ACLKInit(). BotonesInit(). P1DIR_bit.//500mseg LcdStringXY(linea1. LcdStringXY(titulo.5. estadoCLK = 2. TACCR0 = 100.16.1.16.23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 unsigned char modo2[10] = "CONT.MODE ".1). unsigned char div3[2] = "/8". __delay_cycles(500000). cambia = 0. TACLKInit(). case 1: LcdStringXY(source1. unsigned char modo3[10] = "UP/DN MODE".5. case 2: . while(1){ do{ }while(cambia == 0).1. SMCLKInit(). break.1).1).//salida LcdInit().5. BCSCTL1 = CALBC1_1MHZ.16. // Stop watchdog timer to prevent time out reset WDTCTL = WDTPW + WDTHOLD. estadoMODO = 2.1).2).1. unsigned char source3[5] = "INCLK".P1DIR_4 = 1.//activa todas las interrupciones enmascarables. 15. break.6.1). TACTL_bit. } switch(estadoMODO){ case 0: LcdStringXY(modo0. case 3: LcdStringXY(div3.5.2. break. if(aux == 0x0A){ P1OUT_bit.2). case 3: LcdStringXY(source3.70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 LcdStringXY(source2.15.2).6. case 1: LcdStringXY(div1.5.TAIFG = 0.10.10.15. break. case 1: LcdStringXY(modo1.10. break.6. estadoMODO). break. case 2: LcdStringXY(modo2.5.6.P1OUT_4. } switch(estadoDIV){ case 0: LcdStringXY(div0.10. break. case 3: LcdStringXY(modo3.1). } Setup_Timer0_A3(estadoCLK. aux = TAIV. } } #pragma vector = PORT1_VECTOR __interrupt void InterrupcionPuerto1(void) { if(BOTON1_IFG){ .1). } } #pragma vector = TIMER0_A1_VECTOR __interrupt void InterrupcionLowPrioTimer0_A3(void) { unsigned char aux.2).15.1).1). estadoDIV.P1OUT_4 = ~P1OUT_bit.2.5. break. break.2. case 2: LcdStringXY(div2. break.1).2. break.2). } else if(BOTON3_IFG){ estadoMODO++. } cambia = 1. BOTON3_IFG = 0.40 : . BOTON1_IFG = 0. } Video 1_2: Video 2_2: Archivos: Boxnet. } cambia = 1. if(estadoMODO > 3){ estadoMODO = 0.117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 } estadoCLK++. Estos nuevos enlaces estan compilador con la versión del software IAR 5. } else if(BOTON2_IFG){ estadoDIV++. 4Shared. if(estadoCLK > 3){ estadoCLK = 0. BOTON2_IFG = 0. } cambia = 1. if(estadoDIV > 3){ estadoDIV = 0. Lo nuevo son los tres Canales de Captura/Comparación (recordar que en el otro Timer1_A2 sólo tiene dos de estos canales) donde cada canal tiene dos registros propios mediante los cuales podremos configurar y generar la respectiva interrupción para el modo de captura. Para ello hemos realizado dos programas a manera de ejemplos para practicar. de los cuales los que están en amarillo ya han sido estudiados anteriormente. .4Shared esta segunda parte del Timer_A. Veremos lo prácico que resulta utilizar estos registros y sus configuraciones para detectar la duración de un pulso o para decodificar comunicaciones donde el ancho de los pulsos sea importante para obtener los datos. Capture Mode del Timer0_A3 En la primera parte del post del Timer_A. mencionamos los registros que constituyen el Timer0_A3 dentro del MSP430F2132. trataremos con los registros Capture/Compare en su configuracion de Captura (Capture Mode). Tener en cuenta que antes de tener funcionando el Canal 0 del Timer0_A3 en Modo Captura tenemos que configurar siempre su respectivo Timer Block.Observemos que para el Canal 0 existen dos registros. lo mismo para los otros canales. el estudio de los demás canales se deja como tarea al lector. . pues como veremos después. En nuestro proyecto hemos trabajado solamente con el Canal 0. las capturas dependen directamente del valor que tenga el registro TA0R en el preciso momento de la captura. pues verá que son idénticos al Canal 0. todos ellos tienen la misma estructura y función. . Dicha condición se configura en el otro registro del Canal 0 (TA0CCTL0).TA0CCR0 En el Modo Captura este registro almacena el valor del registro TA0R cuando se cumple con la condición de captura de flanco del Timer0_A3. Describiremos a continuación sus campos. Entonces para determinar el ancho del pulso simplemente restamos FB – FS. cuyo resultado estará en función del source clock que tenga configurado el Timer Block del Timer0_A3. (primera captura del flanco de subida en Terminos del TA0CCR0) FB = 1469. 0: Sin captura. TA0CCTL0 El segundo registro del Canal 0 permite configurar el comportamiento del canal.Citamos un ejemplo. Frecuencia TimerBlock = 125KHz (1MHz SMCLK. (segunda captura del flanco de bajada en Terminos del TA0CCR0) Ancho de Pulso en Terminos del TA0CCR0 = FB – FS = 263 Ancho de Pulso en Segundos = 263/(125KHz) =263/125000 seg. digamos que queremos medir el ancho de un pulso (Low-High-Low) entonces en el primer flanco de subida genera interrupcion (después veremos donde está su vector de interrupción y cómo seleccionar el flanco de captura) y leemos el valor del TA0CCR0 (que acaba de capturar el valor del TAoR) para almacenarlo en un registro que llamaremos FS.104 mseg. luego se genera otra interrupcion en el flanco de bajada y guardamos el valor del TA0CCR0 en otro registro FB. CMx (bits 15-14) : Sólo para el Modo Captura. divisor /8) FS = 1206. así como la habilitación de su interrupcion. Permite definir el flanco de captura del Canal 0. = 2. . 1: Captura en flanco de subida. 3: Captura en ambos flancos. 2: Captura en flanco de bajada. Permiten definir la señal de entrada cuyos flancos vamos a capturar.1 (CCI0A) y en P2. 3: VCC. Entrada A para el Canal 0. CCISx (bits 13-12) : Sólo para el Modo Captura. 1: CCI0B.2 (CCI0B): . Pone a nivel bajo la Entrada del Canal 0. Pone a nivel alto la Entrada del Canal 0. Entrada B para el Canal 0. 2: GND. 0: CCI0A. Las entradas CCI0A y CCIoB del MSP430F2132 se ubican en los pines P1. OUTMODx (bits 7-5) : Sólo para el Modo Comparación. Explicaremos estos bits en el tercer post del Timer_A. 1: Modo de Captura. Sirve para sincronizar la captura de la señal con el timer clock. 0: Modo de Comparación. CAP (bit 8) : Bit que permite definir el modo de trabajo de los Canales de Captura/Comparación. . De preferencia siempre habilitarlo.SCS (bit 11) : Sólo para el Modo Captura. SCCI (bit 10) : Bit de sólo lectura que sirve para monitorear el estado actual de la entrada de la señal CCI (señal que proporciona el bloque de los bits CCISx) pero sincronizada. Se debe borrar mediante código.CCIE (bit 4) : Bit para habilitar la interrupcion del Canal de Captura/Comparación. CCI (bit 3) : Bit de sólo lectura que sirve para monitorear el estado actual de la entrada de la señal CCI (señal que proporciona el bloque de los bits CCISx). Explicaremos estos bits en el tercer post del Timer_A. CCIFG (bit 0) : Bandera de la interrupción CCIE del Canal 0. . OUT (bit 2) : Sólo para el Modo Comparación. COV (bit 1) : Sólo para el Modo Captura. Indica de que se ha producido una segunda captura del timer TA0R sin que se halla leído la primera captura almacenada aún en TA0CCR0. Interrupción del Modo Captura del Timer0_A3 La interrupcion del Canal 0 es más simple que la del Timer Block pues tiene su propio vector en la tabla de direcciones. está ubicado en la prioridad 25. . .En el código nos servimos del nombre del vector definido por “TIMER0_A0_VECTOR” para construir la función de gestionará su interrupción de captura. Bueno. ya expuesta la teoría tenemos que echar mano a la práctica. 16. aux = sampleFB .1.1. datos).1).h" "bsp\bsp.P1DIR_4 = 1. Timer0_A3_CaptureInputInit(). ACLKInit(). unsigned char datos[4].//salida LcdInit().2). int main( void ) { unsigned char titulo[16] = " microembebidos ". SMCLKInit(). LcdStringXY(titulo. if(sampleok){ unsigned int aux. char samplestate = 0. while(1){ while((sampleok==0)). // Stop watchdog timer to prevent time out reset WDTCTL = WDTPW + WDTHOLD. } } } #pragma vector = TIMER0_A0_VECTOR .sampleFS. sampleok = 0.// Use 1Mhz cal data for DCO DCOCTL = CALDCO_1MHZ.h" "intrinsics.h" unsigned unsigned unsigned unsigned int sampleFS. ConvertHexToString(aux. Timer0_A3_TimerBlockInit().h" "lcd2x16\lcd2x16. __enable_interrupt(). LcdStringXY(datos. char sampleok = 0.4.Programa de Aplicación En este primer ejemplo tenemos un programa que permite determinar el ancho de un pulso en la entrada CCI0A del Canal 0 del Timer0_A3: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include #include #include #include "io430.// Use 1Mhz cal data for DCO P1DIR_bit. int sampleFB. BCSCTL1 = CALBC1_1MHZ. 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 __interrupt void InterrupcionHighPrioTimer0_A3(void) { if(samplestate == 0){ sampleFS = TACCR0. unsigned int barraFB. unsigned int barraFS.CCIFG = 0. unsigned char sampleok = 0. } #pragma vector = TIMER0_A1_VECTOR __interrupt void InterrupcionLowPrioTimer0_A3(void) { unsigned char aux.h" unsigned char samplestate = 0. } else if(aux == 0x0A){ P1OUT_bit.h" "intrinsics. } } En este segundo ejemplo hemos implementado la lectura de una trama de pulsos que pertenecen a la codificación CODE39 que utlizan las tarjetas de código de barras. samplestate++. samplestate++.CCIFG = 0. } else if(samplestate == 1){ sampleFB = TACCR0. . TACTL_bit.P1OUT_4 = ~P1OUT_bit. } TACCTL0_bit. aux = TAIV. donde el ancho de los pulsos determinan el digito codificado: 1 2 3 4 5 6 7 8 9 10 #include #include #include #include "io430. unsigned char dato.P1OUT_4.h" "lcd2x16\lcd2x16.TAIFG = 0. if(aux == 0x02){ TACCTL1_bit.h" "bsp\bsp. sampleok = 1. // Use 1Mhz cal data for DCO P1DIR_bit. int main( void ) { unsigned char titulo[16] = " microembebidos ". while(1){ while((sampleok==0)).1. Timer0_A3_CaptureInputInit().1). BCSCTL1 = CALBC1_1MHZ. unsigned int lenghtcode39[9].//salida LcdInit(). if(sampleok){ unsigned int aux. } //hallamos el codigo for(digitocode39 = 0. } else { //colocamos un uno . unsigned int peque. peque = lenghtcode39[1]. unsigned int digitocode39.aux = 0. aux < 9. LcdStringXY(titulo. aux++){ if(lenghtcode39[aux] < (peque*2)){ //colocamos un cero digitocode39 = digitocode39 & 0xFE.11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 unsigned int espacioFB. Timer0_A3_TimerBlockInit(). SMCLKInit(). ancho = lenghtcode39[1]. // Stop watchdog timer to prevent time out reset WDTCTL = WDTPW + WDTHOLD. unsigned int espacioFS. unsigned int ancho.P1DIR_4 = 1. ACLKInit(). //determinamos las longitudes if(lenghtcode39[0]>lenghtcode39[1]){ ancho = lenghtcode39[0].16.// Use 1Mhz cal data for DCO DCOCTL = CALDCO_1MHZ. } else { peque = lenghtcode39[0]. __enable_interrupt(). lenghtcode39[0]=barraFB-barraFS. case 2: espacioFS = TACCR0. break. lenghtcode39[2]=barraFB-barraFS. datos). if(digitocode39 == 0x0094){ dato = '*'.58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 digitocode39 = digitocode39 | 0x01. __disable_interrupt(). } else if(digitocode39 == 0x0034){ dato = '0'. lenghtcode39[3]=espacioFS-espacioFB.2). case 5: barraFB = TACCR0.1. espacioFB = barraFB. } LcdStringXY(&dato. } } } #pragma vector = TIMER0_A0_VECTOR __interrupt void InterrupcionHighPrioTimer0_A3(void) { switch(samplestate){ case 0: barraFS = TACCR0. break. break. lenghtcode39[1]=espacioFS-espacioFB. } else if(digitocode39 == 0x0061){ dato = '2'. break. } digitocode39 = digitocode39 << 1. espacioFB = barraFB. } digitocode39 = digitocode39 >> 1. sampleok = 0. } else if(digitocode39 == 0x0121){ dato = '1'. barraFS = espacioFS.1. lenghtcode39[4]=barraFB-barraFS. } else { dato = 'E'. break. . case 4: espacioFS = TACCR0. break. //imprimir el dato //ConvertHexToString(digitocode39. espacioFB = barraFB. case 3: barraFB = TACCR0. case 1: barraFB = TACCR0. barraFS = espacioFS. samplestate++. } } . samplestate++. } else if(aux == 0x0A){ P1OUT_bit. lenghtcode39[7]=espacioFS-espacioFB. break. } else if(samplestate == 1){ barraFB = TACCR0.CCIFG = 0. TACCTL0_bit. lenghtcode39[8]=barraFB-barraFS. espacioFB = barraFB. barraFS = espacioFS. case 8: espacioFS = TACCR0. lenghtcode39[6]=barraFB-barraFS. } if(samplestate == 0){ barraFS = TACCR0.TAIFG = 0. TACTL_bit.P1OUT_4. case 9: barraFB = TACCR0. sampleok = 1.105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 // // // // // // // // } case 6: espacioFS = TACCR0. //espacioFB = barraFB.P1OUT_4 = ~P1OUT_bit. lenghtcode39[5]=espacioFS-espacioFB. case 7: barraFB = TACCR0. break. break.CCIFG = 0. if(aux == 0x02){ TACCTL1_bit. #pragma vector = TIMER0_A1_VECTOR __interrupt void InterrupcionLowPrioTimer0_A3(void) { unsigned char aux. aux = TAIV. break. barraFS = espacioFS. } samplestate++. espacioFB = barraFB. . pero en este laboratorio vamos a centrar en la entrada de propósito general en P1.Interrumpe con ensamblador y C En esta práctica. ejecute el código definido en una rutina de servicio de interrupción. vamos a cubrir dos temas principales: .152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 Videos: Lab 4 .C programación del MSP430 Tutorial y Antecedentes 1 .pero en pocas palabras que son un mecanismo para tomar el control del procesador en función de la petición de hardware. El procesador completa con gracia la instrucción actual y luego los "servicios" de la interrupción.Interrups y rutinas de servicio de interrupción .3 que está unido al pulsador. Hay muchas fuentes de las interrupciones en el MSP430.Las interrupciones en la Asamblea Las interrupciones serán discutidos en la conferencia . finalmente. los niveles estáticos.Una interrupción en P1. las banderas de interrupción debe ser limpiado y. Finalmente. Cada bandera PxIFG se debe restablecer con el software.3 se puede activar mediante el control de varios puertos 1 registros encontrados: P1IE es un registro que permite a las interrupciones para el puerto 1 pins. las alarmas deben estar habilitadas en todo el mundo. Esto asegura que se reconoce cada transición. no causan interrupciones. P1IES es el opositor que determina (si las interrupciones están habilitadas para el pin correspondiente) para que el borde (ascendente o descendente) causa una interrupción. Todos PxIFGx interrumpen banderas solicitar una interrupción cuando su correspondiente bit PXIe y el bit GIE se establecen. la bandera conjunto PxIFGx genera otra interrupción. P1IFG es el registro en el que cada bit PxIFGx es la bandera de interrupción para su correspondiente pin de E / S y se establece cuando el borde de la señal de entrada seleccionada aparece en el pin. . El software también puede configurar cada bandera PxIFG. o si se establece después de la instrucción RETI de una rutina de servicio de interrupción Px se ejecuta. Bit = 0: Sin interrupción está pendiente Bit = 1: Una interrupción está pendiente Sólo las transiciones. proporcionando una manera de generar un programa iniciado interrupción. Si cualquier bandera PxIFGx cuaja durante la rutina de servicio de interrupción Px. Estas tres líneas realizan esta función en este caso. Esto se conoce como "reconocer" la interrupción y evita una solicitud de interrupción siendo administrados más de una vez. P1.Cómo implementar rutinas de servicio de interrupción Para utilizar interrumpe necesita configurar su interrupción específica (puerto 1. P1.3 Interrupción habilitada bis.----------------------------- .b # 008H. y P1IFG. Regreso de ISR . y P1IE.3 Autorizado retina.b # 008H. Usted tendrá que añadir el código del programa específico por encima de la instrucción RETI.3 / borde inferior bic.3 en este caso). . bis.-----------------------------P1_ISR.0 Toggle salida . ------------------------------------------------. . Hi P1. desactive las interrupciones pendientes y habilitar las interrupciones globalmente.-----------------------------. habilitar las interrupciones Añadir este código de ejemplo al final de su programa de la asamblea para incluir una rutina de servicio de interrupción para el puerto 1.b es necesario borrar el indicador de interrupción. IFG P1.----------------------------. ------------------------------------------------. y P1IES. y P1IFG. SR. AÑADIR CÓDIGO AQUÍ PARA SERVICIO DE INTERRUPCIÓN DE RUTINA bic. ------------------------------------------------. Este código hace esto. ------------------------------------------------.3 Autorizado bis.b # 008H.w # GIE. IFG P1.b # 008H. interrupción Vectores . LPM4. El bic. secta "int02. REINICIAR MSP430 Vector . seleccione Proyecto CCS "en el nuevo menú Archivo->. .. reset". fin 2 . . Para crear un proyecto de CCS. REINICIAR corto. P1_ISR corto. secta ". . P1.x Vector . Seleccione un "Proyecto vacío" con el fin de crear un proyecto de C. Usted puede encontrar todo aquí.Introducción a C con el MSP430 TI tiene una amplia documentación sobre el Code Composer Studio.".
Copyright © 2024 DOKUMEN.SITE Inc.