HOJA DE EJERCICIOS (curso 2014/15) 1. Realizar un programa en ensamblador para que parpadee el bit P1.0, utilizando un bucle para realizar el retardo.
SOLUCIÓN:
;************************************************************* ; Plantilla que se crea automáticamente ; Conviene especificar el microcontrolador usado, describir ; el programa y si fuera posible las patillas utilizadas ; Microcontrolador: MSP430G2553 ; Descripción: ; MSP430G2553 ; ----------------; /|\| XIN|; | | | ; --|RST XOUT|; | | ; | P1.0|-->LED ; ; Autor: ; Empresa: UA ; Fecha: 07/07/14 ; Herramienta: IAR Embedded Workbench Version: 5.51 ;************************************************************* #include "msp430g2553.h" miSP EQU 0x400 ; define el puntero de la Pila ORG 0FC00h ; inicio del programa en memoria ;----------------------------------------------------------RESET MOV.W #miSP,SP ; Inicializa el SP MOV.W #WDTPW+WDTHOLD,&WDTCTL ; para el watchdog BIS.B
#001h,&P1DIR
; el bit P1.0 como salida
XOR.B MOV.W
#001h,&P1OUT #050000,R15
DEC.W JNZ JMP
R15 L1 INICIO
; ; ; ; ; ;
INICIO
L1
Conmuta el bit P1.0 R15=50000 para realizar un retardo se realiza 50000 veces el bucle L1 Decrementando R15 retardo=(1+2)*50000=150000T vuelve a empezar
;-------------------------------------------; VECTORES ;-------------------------------------------ORG 0FFFEh DW RESET END
1
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 2. Realizar un programa en C para que parpadee el bit P1.0, utilizando un bucle para realizar el retardo.
SOLUCIÓN: //************************************************************* #include <msp430.h> int main(void) { WDTCTL = WDTPW + WDTHOLD; P1DIR |= 0x01;
// Para el watchdog // Configura P1.0 como salida direction
for (;;) { volatile unsigned int i; P1OUT ^= 0x01;
// Conmuta P1.0 usando la XOR
i = 50000; do (i--); while (i != 0); }
// Retardo
}
3. Realizar un programa en C que haga parpadear el bit P1.6, utilizando la función __delay_cicles(nº ciclos)
SOLUCIÓN: /* Enciende el led verde P1.6 Utilizando __delay_cicles() */ #include <msp430.h> #include void main(){ WDTCTL= WDTPW+WDTHOLD;
//inclusiones. //funcion principal //Apagamos el watchdog
P1SEL= 0x00; P1DIR|= BIT6;
//Salida el bit 6 del puerto 1
P1OUT|=BIT6;
//LED parte apagado
while(1){ //Loop infinito P1OUT|=BIT6; //prende el LED __delay_cycles(100000); //espera P1OUT&=~BIT6; //apaga el LED __delay_cycles(100000); //espera } }
2
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 4. Escribe un programa en lenguaje ensamblador en el cual inicialmente el bit P1.6 esté apagado, cuando se pulse el
botón colocado en P1.3 se ponga a uno el bit P1.6 y si se vuelve a pulsar que se apague. Esto se debe realizar de forma indefinida. SOLUCIÓN: ;******************************************************************** #include "msp430g2553.h" ;-----------------------------------------------------ORG 0FC00h ; Definimos la direccion de inicio ;-----------------------------------------------------RESET MOV.W #0400h,SP ; Establecemos el SP MOV.W #WDTPW+WDTHOLD,&WDTCTL ; Detenemos el watchdog timer MOV.B #040h,&P1DIR ; Colocamos P1.6 salida resto entrada MOV.B #00h,&P1OUT BIS.B #BIT3, &P1REN ; Resistencia en la entrda P1.3 BIS.B #BIT3, &P1OUT ; Resistencia de pull-up SIGUE BIT.B #BIT3, &P1IN ; si pulsado 0000 1000 AND XXXX 0XXX JZ ENCIENDE ; si pulsado salta y enciende P1.6 JMP APAGA JMP SIGUE APAGA BIC.B #BIT6,&P1OUT JMP SIGUE ENCIENDE BIS.B #BIT6,&P1OUT JMP SIGUE ;-----------------------------------------------------; Vectores Interrupción ;-----------------------------------------------------ORG 0FFFEh ; Vector RESET MSP 430 DW RESET ; END
3
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 5. Escribe un programa en lenguaje C en el cual inicialmente el bit P1.6 esté apagado, cuando se pulse el botón
colocado en P1.3 se ponga a uno el bit P1.6 y si se vuelve a pulsar que se apague. Esto se debe realizar de forma indefinida. SOLUCIÓN:
#include <msp430g2553.h> int i; void main(void) { WDTCTL = WDTPW + WDTHOLD;
// para el watchdog
P1OUT P1DIR P1DIR P1REN P1OUT
// // // // //
&= ~0x40; |= 0x40; &= ~0x08; |= 0x08; |= 0x08;
P1.6 P1.6 P1.3 P1.3 P1.3
a cero (LED) como salida (push button) como entrada (botón) resistencia habilitada (botón) resistencia pull-up
while (1){ if( BIT3 & ~P1IN ) { P1OUT ^= 0x40; } }
// Si se pulsa botón // led encendidO
}
6. Añade un antirrebotes al ejercicio 3
7. Añade un antirrebotes al ejercicio 4
8. Supongamos que la ejecución normal del programa consiste en el desplazamiento de un bit, empezando en el
P2.0, después se encenderá el P2.0 y el P2.1, después el P2.0, P2.1 y P2.2, así sucesivamente hasta llega al P2.7, que vuelve a empezar. Si en el bit P1.3 hay un flanco de bajada se debe atender la interrupción ejecute el correspondiente servicio (ISR) que deberá sacar por P2 la siguiente secuencia: secu DC8 00000001b,00000010b,00000100b,00001000b
DC8 00010000b,00100000b,01000000b,10000000b
DC8 00000000b,11111111b,00000000b,11111111b
DC8 00000000b,11111111b,00000000b,11111111b
Finsecu DC8 01010101b Cuando se encuentre el valor 01010101b se debe salir de la interrupción y continuar por donde iba. Escribir el programa en ensamblador 4 Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) ;----------------------------------------------------#include "msp430g2553.h" #define miSP 0x400 main ;-------------------------------------------------------------------------------ORG 0xFC00 ;Inicio del programa ;-------------------------------------------------------------------------------RESET MOV.W #miSP,SP ; Inicia SP MOV.W #WDTPW+WDTHOLD,&WDTCTL ; Detiene WD ;----------------------esto es opcional para conseguir la frecuencia-----------MOV.B &CALDCO_1MHZ, &DCOCTL ; calibra la f a 1MHz MOV.B &CALBC1_1MHZ, &BCSCTL1 ; calibra la f a 1MHz ;-------------------------------------------------------------------------------BIC.B #BIT3, &P1DIR ; P1.3 IN #11110111b BIS.B #BIT3, &P1OUT ; P1.3 Resist pullup, resto a cero 00001000b BIS.B #BIT3, &P1REN ; P1.3 Resist pullup habilitada BIS.B #BIT3, &P1IES ; flanco de bajada para P1.3 BIC.B #BIT3, &P1IFG ; borrar flags de interrup para P1.3 BIS.B #BIT3, &P1IE ; interrup locales habilita para P1.3 EINT ; GIE <--1 MOV.B #0xFF,&P2DIR ; P2 como salida 11111111b ;-----------------------------------------------------------------; PROGRAMA PRINCIPAL EN EJECUCIÓN ;-----------------------------------------------------------------MOV.B #00h,&P2SEL ; obligatorio para que P2.6 y P2.7 sean salida sigue MOV.B #00h,&P2OUT ; apagamos los diodos MOV.W #00010h,R14 ; R14 y R15 para pasar parámetros MOV.W #020000,R15 ; R14 y R15 para pasar parámetros CALL #retardo ; que se note que se apagan todos SETC ; C <-- 1 MOV.B #00h, R7 ; R7 <-- 0000 0000 vuelta RLC.B R7 ; rotar R7 a la izda incluido C MOV.B R7,&P2OUT ; P2.0 a P2.7 pone ceros, apaga, MOV.W #0005h,R14 ; R14 y R15 para pasar parámetros MOV.W #025000,R15 ; R14 y R15 para pasar parámetros CALL #retardo MOV.B R7,R8 ; R7 --> R8 para saber si he terminado XOR.B #0FFh,R8 ; averigua si se han apagado P2.0 a P2.7 JZ sigue ; si es así, volvemos a empezar JMP vuelta ; si no, se continua rotando
5
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15)
;--------------------------------------------------------------------P1_3_ISR; Rutina de servicio a la interrupción ;--------------------------------------------------------------------PUSH R7 PUSH R8 PUSH R11 PUSH R12 MOV #secu,R5 ; Asigna a la secu1 el puntero (R5) ETQ1 MOV.B @R5+,&P2OUT MOV.W #7,R14 ; R14 y R15 para pasar parámetros MOV.W #25000,R15 ; a la subrutina retardo CALL #retardo CMP Finsecu,0(R5) JNE ETQ1 BIC.B #BIT3,&P1IFG ; Borra la flag de la interrupción POP R12 POP R11 POP R8 POP R7 RETI ;---------------------------------------------------------------------------retardo ;---------------------------------------------------------------------------MOV R14,R11 ; Valores del retardo b2 MOV R15,R12 ; se pueden ajustar b1 DEC.W R12 ; bucle fino R12 JNZ b1 DEC.W R11 ; bucle grueso JNZ b2 RET ;----------------------------------------------------; Definicion de las secuencias ;----------------------------------------------------secu DC8 00000001b,00000010b,00000100b,00001000b DC8 00010000b,00100000b,01000000b,10000000b DC8 00000000b,11111111b,00000000b,11111111b DC8 00000000b,11111111b,00000000b,11111111b Finsecu DC8 01010101b ;--------------------------------------------------------------------; Vectores de Interrupción y Reset ;--------------------------------------------------------------------ORG 0FFFEh ; Vector para el reset DW RESET ORG 0FFE4h ; Vector para la interrupción del P1 DW P1_3_ISR END main
6
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 9. Supongamos que la ejecución normal del programa consiste en el desplazamiento de un bit, empezando en el
P2.0, después se encenderá el P2.0 y el P2.1, después el P2.0, P2.1 y P2.2, así sucesivamente hasta llega al P2.7, que vuelve a empezar. Si en el bit P1.3 hay un flanco de bajada se debe atender la interrupción ejecute el correspondiente servicio (ISR) que deberá sacar por P2 la siguiente secuencia: secu DC8 00000001b,00000010b,00000100b,00001000b
DC8 00010000b,00100000b,01000000b,10000000b
DC8 01000000b,00100000b,00010000b,00001000b
DC8 00000100b,00000010b,00000001b,00000000b
DC8 11111111b,00000000b, 11111111b,00000000b
Finsecu DC8 01010101b Cuando se encuentre el valor 01010101b se debe salir de la interrupción y continuar por donde iba. Esrcribir el programa en C SOLUCIÓN:
7
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15)
#include <msp430.h> char secu[21] = {0x01,0x02,0x04, 0x08,0x10,0x20,0x40,0x80, 0x40,0x20, 0x10, 0x08,0x04,0x02,0x01}; char secu_interrup[24] = {0x01,0x03,0x07, 0x0F,0x1F,0x3F,0x7F,0xFF, 0x7F,0x3F, 0x1F, 0x0F,0x07,0x03,0x01,0x00,0xFF,0x00, 0xFF,0x00,0xFF,0x00,0xFF,0x00}; int i,r,j; // Rutina de Retardo void RETARDO(void) {r = 20000; do (r--); while (r != 0); } void main(void) { WDTCTL = WDTPW + WDTHOLD; // para el watchdog DCOCTL = CALDCO_1MHZ; //calibra la f a 1MHz BCSCTL1 = CALBC1_1MHZ; // configuración de los puertos P2SEL &= ~0xFF; // P2 como I/O general (GPIO) P2DIR |= 0xFF; // P2 como salida P1DIR &= ~0x08; // P1.3 (push button) como entrada P1REN |= 0x08; // P1.3 (botón) resistencia habilitada P1OUT |= 0x08; // P1.3 (botón) resistencia pull-up // configuración de la interrupción de P1.3 P1IES |= 0x08; // flanco de bajada para P1.3 P1IFG &= ~0x08; // borrar flags de interrup para P1.3 P1IE |= 0x08; // interrup locales habilita para P1.3 _BIS_SR(GIE); // GIE <--1 // __enable_interrupt(); // equivalente a la anterior, se debe cambiar // msp430.h por while(1) for (i = 0; i <15 ; i++) { if( BIT3 & P1IN ){ P2OUT = secu[i]; RETARDO(); }
// Si NO
se pulsa botón
} } //----------------------------------------------------// Rutina de atención de interrupción del puerto P1 //----------------------------------------------------#pragma vector=PORT1_VECTOR __interrupt void P1_Interrupt(void) { for (j = 0; j <24 ; j++) { P2OUT = secu_interrup[j]; RETARDO(); } P1IFG &= ~BIT3; // Reseta IFG para P1.3 }
8
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 10. El circuito de la figura tiene el μC alimentado a 3,3V, y los displays de 7 segmentos son de cátodo común.
Encenderemos los segmentos mediante los bits del P1 y seleccionamos el que debe encenderse mediante el P2(P2.0 y P2.1). Calcula el valor de las resistencias R1 y R2, sabiendo que: ILED=5mA; VLED=1,8V VCEsat=0,2V; β= 200 La corriente proporcionada por cada patilla de un puerto de salida debe estar entre 4 y 5 mA como máximo y la corriente máxima que debe proporcionar un puerto en conjunto no debe exceder de los 25 mA.
Fig.1 circuito SOLUCIÓN: R1=300Ω ≅330Ω ; R2=21600Ω ≅22KΩ 11. Escribir un programa en C para el circuito del problema anterior. Al pulsar el botón se iniciará la cuenta de 0 a 99
con un periodo aproximado de 1s. El pulsador solicita una interrupción en P1.3 por flanco de bajada 9
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) #include <msp430g2553.h> unsigned int r, i, j; char display[10] = {0x77,0x06,0xB3, 0x97,0xC6,0xD5,0xF5,0x07,0xF7,0xC7}; //gfedcba -> p1.7,6,5,4,2,1,0 // Rutina de Retardo void RETARDO(void) {r = 200; do (r--); while (r != 0); } int main(void) { WDTCTL = WDTPW + WDTHOLD; // Paramos el WDT BCSCTL1 = CALBC1_1MHZ; // Y establecemos una frecuencia DCOCTL = CALDCO_1MHZ; // de un 1MHz P1DIR = 0xF7; // P1.3 como entrada, resto como salidas P2DIR = BIT0+BIT1; // P2.0 y P2.1 como salidas P1OUT = BIT3; // resitencia pull-up P1REN = BIT3; // P1.3 con resistencia de pullup P1IE = BIT3; // P1.3 con interrupción habilitada P1IES = BIT3; // y activa por flanco de bajada _BIS_SR(LPM0_bits + GIE); // Habilita interrupciones y deshabilita la CPU y MCLK } #pragma vector=PORT1_VECTOR // Rutina de servicio para la interrupción del P1 __interrupt void Port_1(void) // forma de llamar a la ISR del P1 { i = 0; j = 0; for (j = 0; j < 10; j++) { for (i = 0; i < 10; i++) { int k; for (k=0; k< 100; k++) { P1OUT = display[i]; // Pone el número en P1 P2OUT = 0x01; // Y activa el display de las unidades RETARDO(); P1OUT = display[j]; // Pone el otro número en P1 P2OUT = 0x02; // Y activa el display de las decenas RETARDO(); } } } P2OUT = 0x03; // deja activos los dos displays P1IFG &= ~0x08; // borra el flag de petición de interrupción }
10
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 12. Escribir un programa en ensamblador para el circuito del problema anterior. Al pulsar el botón se iniciará la
cuenta de 0 a 99 con un periodo aproximado de 1s. El pulsador solicita una interrupción en P1.3 por flanco de bajada. SOLUCIÓN: #include <msp430G2553.h> Tmux
DEFINE 300
main
;Esto viene bien por lo del "run tu main", aunque se puede quitar
;------------------------------------------------------------------------------ORG
0F800h
;------------------------------------------------------------------------------RESET ;--------------Configuración -------------------------------------MOV
#0280h,SP
MOV
#WDTPW+WDTHOLD,&WDTCTL
MOV.B &CALBC1_1MHZ,&BCSCTL1
; Funciones de Calibración a 1MHz
MOV.B &CALDCO_1MHZ,&DCOCTL MOV.B
#BIT6+BIT0,&P1DIR
MOV.B
#0x0,&P1OUT
; para que estén apagados
MOV.B #0F7h,&P1DIR
; P1.3 como entrada y el resto como salidas
BIS.B #BIT3,&P1REN
; Resistencia en la entrada P1.3
BIS.B #BIT3,&P1OUT
; Decimos que sea de pull-up
BIS.B #BIT3,&P1IES
; Defino P1.3 como activo por flanco de bajada
BIS.B #BIT3,&P1IE
; Y lo habilito como entrada de interrupción
BIS.B #BIT0+BIT1,P2DIR
; Defino P2.0 y P2.1 como salidas
MOV.B #GIE,SR
; Habilitación global de las interrupciones
;------------------------------------------------------------------------------jmp
$
; Programa principal
;-------------------------------------------------------------------------------
11
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15)
;------------------------------------------------------------------------------; Rutina de tratamiento de la interrupción ;------------------------------------------------------------------------------P1_ISR MOV #TSeg,R4 ; Inicializamos los punteros de Unidades y MOV #TSeg,R5 ; Decenas con la dirección de la tabla de segmentos CLR R6 ; Unidades = 0 CLR R7 ; Decenas = 0 Tiempo MOV.B #100,R10 ETIQ1 MOV.B @R4,&P1OUT ; PUni al Puerto de Salida MOV.B #001h,&P2OUT ; Visualiza dato en posicion de las Unidades CALL #RETARDO ; Tiempo que está encendido el dígito MOV.B @R5,&P1OUT ; PDcn al Puerto de Salida MOV.B #002,&P2OUT ; Visualiza dato en posicion de las decenas CALL #RETARDO ; Tiempo que está encendido el dígito DEC R10 JNZ ETIQ1 INC R6 ; Unidades = Unidades + 1 INC R4 ; Actualiza el puntero de unidades CMP #10,R6 ; ¿Unidades es 9? JNE Tiempo CLR R6 ; Unidades = 0 MOV #TSeg,R4 ; Restaura la dirección de la Tabla de segmentos INC R7 ; Decenas = Decenas + 1 INC R5 ; Actualiza el puntero de decenas CMP #10,R7 ; ¿Decenas es 9? JNE Tiempo CLR R6 ; Unidades = 0 MOV #TSeg,R4 ; Restaura la dirección de la Tabla de segmentos INC R7 ; Decenas = Decenas + 1 INC R5 ; Actualiza el puntero de decenas CMP #10,R7 ; ¿Decenas es 9? JNE Tiempo MOV.B #BIT3,&P1OUT ; Para apagar el display al terminar MOV.B #BIT0+BIT1,&P2OUT BIC.B #BIT3,&P1IFG ; Borra el flag de interrupcion RETI
12
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) ;------------------------------------------------------------------------------;
Subrutina de retardo
;------------------------------------------------------------------------------RETARDO MOV #Tmux,R15 ETIQ2 DEC JNZ
R15 ETIQ2
RET ;------------------------------------------------------------------------------;
Tabla de 7 segmentos
;
Están ordenados g-f-e-d-c-b-a
;------------------------------------------------------------------------------TSeg ; 0, 1 , 2 DC8
, 3 , 4 ,
5 ,
6 ,
7 , 8 , 9
77h,06h,0B3h,97h,0C6h,0D5h,0F5h,07h,0F7h,0C7h
;------------------------------------------------------------------------------;
Vectores de interrupción y reset
;------------------------------------------------------------------------------ORG
0FFFEh
DW
RESET
ORG
0FFE4h
DW
P1_ISR
END
main
; Vector de reset ; Vector de interrupción para P1
13. Escribe un programa en C para que cuando cada vez que se pulse el P1.3, interrupción por flanco de bajada,
cambie la frecuencia de parpadeo de los dos diodos colocados en P1.0 y P1.6 SOLUCIÓN: 13
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15)
#include <msp430.h> #include int j=0; int Tini=30000; void main(){ WDTCTL= WDTPW+WDTHOLD; P1SEL= 0x00; P1DIR|= (BIT0+BIT6); P1DIR&=~BIT3; P1REN|=BIT3;
//resistencia en la entrada habilitada
P1OUT|=BIT3;
// de pull-up
P1IE|=BIT3;
//Habilitamos las interrupciones, //mas información en la userguide.
P1IES|=BIT3; P1IFG&=~BIT3; P1OUT|=BIT0; P1OUT&=~BIT6; _BIS_SR(GIE);
//Habilitamos las interrupciones generales. IMPORTANTE!!
while(1){
//El mismo código anterior
for(j=0;j<Tini;j++); P1OUT^=BIT6; P1OUT^=BIT0; if(Tini<=1500){Tini=30000;} } } Rutina de interrupción. #pragma vector= PORT1_VECTOR __interrupt void Led_ISR (void){ P1IFG&=~BIT3;
//Al
salir de una interrupción
//SIEMPRE es necesario limpiar la bandera. Tini=Tini-5000; }
14
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 14. Escribir un programa en ensamblador para que el bit P1.0 parpadee utilizando la interrupción del Watchdog. El
periodo de parpadeo será aproximadamente 30ms, si la fuente del reloj es por defecto DCO=SMCLK SOLUCIÓN: ;*********************************************************************** #include <msp430.h> ;------------------------------------------------------------------------ORG 0FC00h ; Reset ;------------------------------------------------------------------------RESET mov.w #0400h,SP ; Inicializa stackpointer SetupWDT mov.w #WDT_MDLY_32,&WDTCTL ; WDT~30ms intérvalo del timer bis.b #WDTIE,&IE1 ; habilita interrupción del WD SetupP1 bis.b #001h,&P1DIR ; P1.0 salida ; Mainloop
bis.w Jmp $
#CPUOFF+GIE,SR
; CPU off, habilita Interrup ; se para aquí ; ;----------------------------------------------------------------------WDT_ISR; Cambia P1.0 ;----------------------------------------------------------------------xor.b #001h,&P1OUT ; cambia P1.0 reti ; ; ;----------------------------------------------------------------------; Vectores de Interrupción ;----------------------------------------------------------------------ORG 0FFFEh ; MSP430 RESET Vector DW RESET ; ORG 0FFF4h ; WDT Vector DW WDT_ISR ; END 15
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 15. Escribir un programa en ensamblador para que el bit P1.0 parpadee utilizando la interrupción del Watchdog. El
periodo de parpadeo será exactamente 250ms basado en el cristal de 32KHz colocado en las patillas del microcontrolador . Teniendo en cuenta que la fuente del reloj será ACLK=LFXT1=32768Hz, y MCLK=SMCLK=DCO. Si dividimos los 215 / 213 obtendremos una frecuencia de 4Hz, es decir un T=250ms. SOLUCIÓN: ;********************************************************************* #include <msp430.h> ;-------------------------------------------------------------------ORG 0FC00h ; Reset ;-------------------------------------------------------------------RESET mov.w #0400h,SP ; Inicializa stackpointer Setup mov.w #WDT_ADLY_250,&WDTCTL ; WDT 250ms bis.b #WDTIE,&IE1 ; habiita la INT del WDT SetupP1 bis.b #001h,&P1DIR ; P1.0 salida ; Mainloop bis.w #LPM3+GIE,SR ; Modo LPM3, INT habilitadas Jmp $ ;------------------------------------------------------------------------WDT_ISR; Cambia P1.0 ;------------------------------------------------------------------------xor.b #001h,&P1OUT ; Cambia P1.0 reti ; ; ;------------------------------------------------------------------------; Interrupt Vectors ;------------------------------------------------------------------------ORG 0FFFEh ; MSP430 RESET Vector DW RESET ; ORG 0FFF4h ; WDT Vector DW WDT_ISR ; END 16
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 16. Escribe un programa que utilizando la interrupción software TA_0, cambie el P1.6 cada 50.000 ciclos de SMCLK.
SMCLK proporciona la fuente de reloj para TACLK. Durante la ISR de TA_0, P1.6 se enciende y apaga cada 50.000 ciclos de reloj. La CPU está normalmente apagada y se pone en marcha sólo durante el ISR de TA. SOLUCIÓN: ;************************************************************************* #include <msp430.h> ;------------------------------------------------------------------------ORG 0FC00h ; Reset ;------------------------------------------------------------------------RESET mov.w #0400h,SP ; Inicializa SP StopWDT mov.w #WDTPW+WDTHOLD,&WDTCTL ; Stop WDT SetupP1 bis.b #BIT0,&P1DIR ; P1.0 salida SetupC0 mov.w #CCIE,&CCTL0 ; habilita INT de CCR0 mov.w #50000,&CCR0 ; SetupTA mov.w #TASSEL_2+MC_2,&TACTL ; SMCLK, modo cont ; Mainloop
bis.w #CPUOFF+GIE,SR ; CPU off, INT habilitadas jmp $ ;------------------------------------------------------------------------TA0_ISR; Cambia P1.0 ;------------------------------------------------------------------------xor.b #001h,&P1OUT ; Cambia P1.0 add.w #50000,&CCR0 ; AñAde el Offset a CCR0 reti ; ; ;------------------------------------------------------------------------; Interrupt Vectors ;------------------------------------------------------------------------ORG 0FFFEh ; MSP430 RESET Vector DW RESET ; ORG 0FFF2h ; Timer_A0 Vector DW TA0_ISR ; END
17
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 17. Escribir un programa en ensamblador que visualice ACLK en P1.0 , SMCLK en P1.4 y que en P1.1 se obtenga una
frecuencia de aproximadamente SMCLK/15. SOLUCIÓN: 18. Utilizando consulta (polling), de los bits P1.4 y P1.5. Generar el programa que permita realizar lo siguiente:
a) Cuando P1.4 tengan un flanco de bajada se realizará una salida por el puerto P2 (irán apagándose los leds de mayor a menor peso), con un tiempo de aproximadamente 500ms b) Cuando P1.5 tengan un flanco de bajada se realizará una salida por el puerto P2 (irán apagándose los leds de menor a mayor peso), con un tiempo de aproximadamente 1s SOLUCIÓN
18
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 19. ¿Qué ventaja tiene utilizar _BIS_SR(GIE)frente a __enable_interrupt()para habilitar las interrupciones globales.
SOLUCIÓN: Con _BIS_SR(GIE)se puede, además, modificar el resto de bits del registro SR, por ejemplo establecer el modo de trabajo LPM0, que sería, _BIS_SR(LPM0+GIE)mientras que con __enable_interrupt()solamente podemos habilitar las interrupciones globales.
19
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 20. Escribir un programa que realice lo siguiente. Cuando se pulsa reset se está ejecutando una secuencia que
consiste en desplazar un bit a uno de izquierda a derecha y de derecha a izquierda por los 8 bits del puerto 2. Cuando se pulsa por primera vez el pulsador S2, colocado en P1.3, se para la secuencia y cuando se vuelve a pulsar por segunda vez se continúa por donde iba la secuencia. SOLUCIÓN:
#include <msp430.h> char secuencia[15] =
{0x01,0x02,0x04, 0x08,0x10,0x20,0x40,0x80, 0x40,0x20, 0x10, 0x08,0x04,0x02,0x01};
int i,j; int ii=0;
// variable para saber por donde va las secuencia
int parar=0; void main(void) { WDTCTL = WDTPW + WDTHOLD; DCOCTL = CALDCO_1MHZ;
// para el watchdog //calibra la f a 1MHz
BCSCTL1 = CALBC1_1MHZ; // configuración de los puertos P2SEL &= ~0xFF;
// P2 como I/O general (GPIO)
P2DIR |= 0xFF;
//
P2 como salida
P1DIR &= ~0x08;
//
P1.3 (push button) como entrada
P1REN |=
0x08;
//
P1.3 (botón) resistencia habilitada
P1OUT |=
0x08;
//
P1.3 (botón) resistencia pull-up
// configuración de la interrupción de P1.3 P1IES |= 0x08;
// flanco de bajada para P1.3
P1IFG &= ~0x08;
// borrar flags de interrup
P1IE
|= 0x08;
//_BIS_SR(GIE); __enable_interrupt() ;
20
para P1.3
// interrup locales habilita para P1.3 // GIE <--1 //es equivalente a la anterior
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15)
while(1) { for (i = ii; i <15 ; i++) { P2OUT = secuencia[i]; if (parar==1) break; //P2OUT = secu[i]; __delay_cycles(100000); } ii=i;
//para saber por donde va la secuencia
if (ii==15) ii=0;
// si se ha llegado al final de la secuencia // ponerla a cero
while (parar==1){ P2OUT = secuencia[ii-1];
//se resta para que muestre el adecuado
} } } //----------------------------------------------------// Rutina de atención de interrupción del puerto P1 //----------------------------------------------------#pragma vector=PORT1_VECTOR __interrupt void P1_Interrupt(void) { __delay_cycles(250000);
//antirrebotes software este valor es el más adecuado
parar ^= 1; P1IFG &= ~BIT3;
// Pone a cero IFG para P1.3
}
21
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 21. Utilizar el Timer 1 en modo continuo con el módulo captura/compara 0 para que el led P1.0 parpadee cada
0,1s (utilizar MCLK = 1MHz). SOLUCIÓN: #include <msp430.h> int main(void) { WDTCTL = WDTPW + WDTHOLD; DCOCTL = CALDCO_1MHZ;
// Paramos el WDT //calibra la f a 1MHz
BCSCTL1 = CALBC1_1MHZ; P1DIR |= 0x01; TA1CCTL0 = CCIE;
// P1.0 como salida para el LED // Habilito la interrupciones del // Registro Captura/Compara 0 del Timer A1 TA1CCR0 = 50000; // Y cargo este registro con el número de // ciclos que quiero contar TA1CTL = TASSEL_2 + ID_1 + MC_2; // Seleccionamos SMCLK como fuente de reloj, //la divido por dos y modo continuo // *********************************************************************** // f=1000000; 1000000/2=500000 à T= 2us; cuento 50000 pulsos*2us=0,1ms // *********************************************************************** //En registro de control del timer, para cada uno de los campos está la opción //elegir los bits de forma individual o directamente el modo (aparecen con //subguión) //Como voy a trabajar en modo comparación no hace falta que modifique el bit CAP _BIS_SR(LPM0_bits + GIE);
// habilitamos el modo 0 de bajo //consumo y habilitamos las interrupciones
} // Rutina de servicio de la interrupción del Timer 1 #pragma vector=TIMER1_A0_VECTOR __interrupt void Timer_A0 (void) { P1OUT ^= 0x01; // Hacemos cambiar al LED TA1CCR0 += 50000; // Se recarga el registro con 50000 valor que //debe contar para conseguir 0,1s }
22
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 22. Utilizar el Timer 1 en modo ascendente con el módulo captura/compara 0 para que el led P1.0 parpadee
cada 0,1s (utilizar MCLK = 1MHz) SOLUCIÓN: #include <msp430.h> int main(void) { WDTCTL = WDTPW + WDTHOLD; DCOCTL = CALDCO_1MHZ;
// Paramos el WDT //calibra la f a 1MHz
BCSCTL1 = CALBC1_1MHZ; P1DIR |= 0x01; TA1CCTL0 = CCIE;
// P1.0 como salida para el LED // Habilito la interrupciones del // Registro Captura/Compara 0 del Timer A1 TA1CCR0 = 50000; // Y cargo este registro con el número de // ciclos que quiero contar TA1CTL = TASSEL_2 + ID_1 + MC_1; // Seleccionamos SMCLK como fuente de reloj, //la divido por dos y modo ASCENDENTE // *********************************************************************** // f=1000000; 1000000/2=500000 à T= 2us; cuento 50000 pulsos*2us=0,1ms // *********************************************************************** //En registro de control del timer, para cada uno de los campos está la opción //elegir los bits de forma individual o directamente el modo (aparecen con //subguión) //Como voy a trabajar en modo comparación no hace falta que modifique el bit CAP _BIS_SR(LPM0_bits + GIE);
// habilitamos el modo 0 de bajo //consumo y habilitamos las interrupciones
} // Rutina de servicio de la interrupción del Timer 1 #pragma vector=TIMER1_A0_VECTOR __interrupt void Timer_A0 (void) { P1OUT ^= 0x01; // Hacemos cambiar al LED }
23
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 23. Escribir un programa para que el led P1.0 parpadee unas 8 veces por segundo (suponiendo que MCLK = 1
MHz) por desbordamiento del timer. SOLUCIÓN: Cuando se desborda el timer el flag TAIFG se activa y se produce la llamada a la interrupción. Para saber quien ha producido la llamada a la interrupción bastaría consultar los flags (CCIFG1, CCIFG2, TAIFG), pero habría que hacerlo por encuesta. Para evitarlo, el MSP430 tiene el registro TAIV, que nos ayudará a identificar la fuente de interrupción rápidamente. Este registro contiene un valor que viene determinado por la fuente de interrupción, 0x000A para el overflow del Timer. Este ejemplo es interesante verlo en ensamblador.
#include <msp430.h> int main(void) { WDTCTL = WDTPW + WDTHOLD;
// Paramos el WDT
P1DIR |= 0x01;
// P1.0 como salida para el LED
TA0CTL = TASSEL_2 + MC_2 + ID_1 + TAIE;
// Seleccionamos SMCLK como fuente // de reloj, modo continuo, % por 2 y // habilita interrupciones
_BIS_SR(LPM0_bits + GIE);
// habilitamos el modo 0 de bajo // consumo y habilitamos // las interrupciones globales
} #pragma vector=TIMER0_A1_VECTOR __interrupt void Timer_A0 (void) { /*
switch(TA0IV)
{ case
2: break;
case
4: break;
// Este es el caso de que se haya activado CCIFG1 // Este es el caso de que se haya activado CCIFG2
case 10: P1OUT ^= 0x01; // Y este es el timer overflow break; } */ P1OUT ^= 0x01; }
24
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 24. Repetir el ejercicio anterior, en ensamblador.
SOLUCIÓN:
#include <msp430G2553.h> ;------------------------------------------------------------------------------ORG 0F800h ;------------------------------------------------------------------------------RESET mov.w #0400h,SP ;Incializamos el SP mov.w #WDTPW+WDTHOLD,&WDTCTL ;Paramos el WDT bis.b #001h,&P1DIR SetupTA mov.w #TASSEL_2+ID_1+MC_2+TAIE,&TACTL ;Seleccionamos SMCLK ; ;como fuente de reloj y se % 2 ;modo ascendente Mainloop bis.w #LPM0+GIE,SR ;CPU OFF e interrupciones nop ;------------------------------------------------------------------------------; ISR genérica para CCR1 a 4 y overflow ; TA0IV contiene 2, 4, 6, 8 ó 10 (0A). Lo que se hace es añadir su contenido al ; PC. ; si los ponemos de forma consecutiva, siempre sabremos quién ha producido la ; interrupción y saltar a donde toque. ; Los reti también ocupan 2 bytes, por lo que también es correcto ;En este caso, como en caso de desbordamiento el contenido de TA0IV es 10 (0A) ; y es el último, no hace falta poner salto. ;Eso sí, hay que poner los todos los CCR1 a 4, aunque el nuestro solo tenga 3 ; porque los valores son fijos. ;------------------------------------------------------------------------------TA0_ISR add.w &TA0IV,PC reti ; No hay interrupción pendiente (TA0IV = 0) reti ; CCR1 reti ; CCR2 reti ; CCR3 - Este no existe en nuestro MSP430 reti ; CCR4 - Este no existe en nuestro MSP430 TA_over xor.b #001h,&P1OUT ; Desbordamiento, también JMP tratar_over reti ; ;------------------------------------------------------------------------------; Interrupt Vectors ;------------------------------------------------------------------------------ORG 0FFFEh ; MSP430 RESET Vector DW RESET ; ORG 0FFF0h ; Vector del Timer0_A1 DW TA0_ISR ; END
25
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 25. Escribir un programa para que por la patilla P1.1 se muestre TA.0 (suponiendo que MCLK = 1 MHz) y que la
frecuencia obtenida por P1.1 sea de 1KHz. Utilizando como reloj SMCLK SOLUCIÓN: Se utiliza la patilla P1.1 como salida de TA.0. No hay llamada a interrupciones, se desconecta la CPU y queda simplemente funcionando el Timer con el reloj. El registro TA0CCR0 deberemos cargarlo con un valor que obtenemos de fsal = fSMCLK/TA0CCRO cargamos el registro de comparación con: TA0CCR0 = fSMCLK/ fsal =1000, es decir, como tenemos el tiempo a cero y el tiempo a uno, 1000/2=500, y se empieza la cuenta en 0, TA0CCRO=499
#include <msp430.h> int main(void) { WDTCTL = WDTPW + WDTHOLD;
// Paramos el WDT
BCSCTL1 = CALBC1_1MHZ;
// Ajustamos frecuencia a 1MHz
DCOCTL = CALDCO_1MHZ;
//
P1SEL |= 0x02;
// Configuramos P1.1 como salida del Timer
P1DIR |= 0x07;
// Y la habilitamos como salida
TA0CCTL0 = OUTMOD_4;
// Registro Captura/Compara del Timer A0 pongo // modo Salida Toggle
TA0CCR0 = 499; TA0CTL = TASSEL_2 + MC_1;
// Y en registro del control de timer // seleccionamos SMCLK como fuente de reloj // modo ascendente.
_BIS_SR(LPM0_bits);
// habilitamos el modo 0 de bajo consumo
}
26
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 26. Escribir un programa en ensamblador para que el bit P1.6 se encienda cuando la señal introducida por A1 sea
mayor de 0,5*Vcc, utilizar el convertidor ADC tomando 16 muestras por segundo
;******************************************************************************* #include <msp430.h> ;------------------------------------------------------------------------------ORG 0FC00h ;------------------------------------------------------------------------------#define miSP 0x400 ;------------------------------------------------------------------------------RESET mov.w #miSP,SP ; inicializa stackpointer mov.w #WDTPW+WDTHOLD,&WDTCTL ; Stop WDT mov.w #ADC10SHT_2+ADC10ON+ADC10IE,&ADC10CTL0 ; 16x, enable int. mov.w #INCH_1, &ADC10CTL1 bis.b #0x02,&ADC10AE0 ; P1.1 entrada de ADC10 bis.b #0x040,&P1DIR ; P1.6 salida ; vuelta bis.w #ENC+ADC10SC,&ADC10CTL0 ; empezar muestreo y conversión bis.w #CPUOFF+GIE,SR ; modo LPM0, int global hab bic.b #0x40,&P1OUT ; P1.6 = 0 cmp.w #01FFh,&ADC10MEM ; ADC10MEM = A1 > 0.5*Vcc jlo vuelta ; otra vez bis.b #0x40,&P1OUT ; P1.6 = 1 jmp vuelta ; otra vez ;------------------------------------------------------------------------------ADC10_ISR; Salir de LPM0 y reti ;------------------------------------------------------------------------------bic.w #CPUOFF,0(SP) ; sale de LPM0 y reti reti ; ;------------------------------------------------------------------------------COMMON INTVEC ; Interrupt Vectors ;------------------------------------------------------------------------------ORG ADC10_VECTOR ; ADC10 Vector DW ADC10_ISR ORG RESET_VECTOR ; POR, ext. Reset DW RESET END
27
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 27. Escribir un programa en C para que el bit P1.6 se encienda cuando la señal introducida por A1 sea mayor de
0,5*Vcc, utilizar el convertidor ADC tomando 16 muestras por segundo.
#include <msp430.h> int main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE; // 16x, enable int. ADC10CTL1 = INCH_1; // entrada A1 ADC10AE0 |= 0x02; // PA.1 entrada a convertir P1DIR |= 0x40; // P1.6 salida for (;;) { ADC10CTL0 |= ENC + ADC10SC; __bis_SR_register(CPUOFF + GIE); if (ADC10MEM < 0x1FF) P1OUT &= ~0x40; else P1OUT |= 0x40; }
// inicio de muestro y conversión // modo LPM0 e inter. globales hab. // apagar
P1.6
// encender P1.6
} // ADC10 interrupt service routine #pragma vector=ADC10_VECTOR __interrupt void ADC10_ISR(void) { __bic_SR_register_on_exit(CPUOFF); }
// sacar de LMP0(CPUOFF)
28
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 28. Escribir un programa para que por la patilla P1.1 se muestre TA.0 (suponiendo que MCLK = 1 MHz) y que la
frecuencia obtenida por P1.1 sea de 1KHz. Utilizando como reloj ACLK SOLUCIÓN: El registro TA0CCR0 deberemos cargarlo con un valor que obtenemos de fsal = fACLK/TA0CCRO cargamos el registro de comparación con: TA0CCR0 = fACLK/ fsal =32768/1000=32,7, es decir, como tenemos el tiempo a cero y el tiempo a uno, 32,7/2=16,35 y se empieza la cuenta en 0, TA0CCRO=15 #include <msp430.h> int main(void) { WDTCTL = WDTPW + WDTHOLD;
// Paramos el WDT
P1SEL |= 0x02;
// Configuramos P1.1 como salida del Timer
P1DIR |= 0x07;
// Y la habilitamos como salida
TA0CCTL0 = OUTMOD_4;
// Registro Captura/Compara del Timer A0 pongo // modo Salida Toggle
TA0CCR0 = 15; TA0CTL = TASSEL_1 + MC_1;
// Y en registro del control de timer // seleccionamos ACLK como fuente de reloj // modo ascendente.
_BIS_SR(LPM3_bits);
// habilitamos el modo 3 de bajo consumo
}
29
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 29. Generar una salida PWM en la patilla P1.2 con una frecuencia de 2KHz y un Duty Cycle del 75% y utilizando el
Timer A0 en modo ascendente y salida reset/set, utilizando SMCLK como fuente del reloj SOLUCIÓN: El valor de TA0 define el periodo del PWM y el valor en TACCR1 define el duty cycle que viene dado por TA0CCR1/TA0CCR0. Calculamos el valor de TA0CCR0=500, para obtener un duty cycle del 75% tendremos que poner en TA0CCR1=375, es decir, (500*0.75)=375 fSAL = fSMCLK / TA0CCR0 = 2 KHz à TA0CCR0= fSMCLK/fSAL= 106/2000 = 500 à 499 (0 a 499)à 75% de 500 =375
#include <msp430.h> int main(void) { WDTCTL = WDTPW + WDTHOLD;
// Paramos el WDT
BCSCTL1 = CALBC1_1MHZ;
// f=1Mhz
DCOCTL = CALDCO_1MHZ; P1SEL |= 0x04;
// Configuramos P1.2 como salida del Timer
P1DIR |= 0x04;
// Y la habilitamos como salida
TA0CCTL1 = OUTMOD_7;
// Registro Captura/Compara 1 del Timer A0 // el modo Salida Reset/Set // TA0CCR0 determina el periodo // TA0CCR1 determina el flanco
TA0CCR0 = 499; TA0CCR1 = 375; TA0CTL = TASSEL_2 + MC_1; _BIS_SR(LPM0_bits);
//modo ascendente y SMCLK fuente del reloj // habilitamos el modo 0 de bajo consumo
}
30
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 30. Generar una salida PWM en la patilla P1.2 con una frecuencia de 2KHz y un Duty Cycle del 75% y utilizando el
Timer A0 en modo ascendente y salida reset/set, utilizando ACLK como fuente del reloj SOLUCIÓN: El valor de TA0 define el periodo del PWM y el valor en TACCR1 define el duty cycle, que viene dado por TA0CCR1/TA0CCR0. Calculamos el valor de TA0CCR0=16, para obtener un duty cycle del 75% tendremos que poner en TA0CCR1=375, es decir, (500*0.75)=12
fSAL = fACLK / TA0CCR0 = 2 KHz à TA0CCR0= fACLK/fSAL= 16,3 à15(0 a 15) à 75% de 16 =12
#include <msp430.h> int main(void) { WDTCTL = WDTPW + WDTHOLD;
// Paramos el WDT
BCSCTL1 = CALBC1_1MHZ;
// f=1Mhz
DCOCTL = CALDCO_1MHZ; P1SEL |= 0x04;
// Configuramos P1.2 como salida del Timer
P1DIR |= 0x04;
// Y la habilitamos como salida
TA0CCTL1 = OUTMOD_7;
// Registro Captura/Compara 1 del Timer A0 // el modo Salida Reset/Set // TA0CCR0 determina el periodo // TA0CCR1 determina el flanco
TA0CCR0 = 15; TA0CCR1 = 12; TA0CTL = TASSEL_1 + MC_1; _BIS_SR(LPM0_bits);
//modo ascendente y SMCLK fuente del reloj // habilitamos el modo 0 de bajo consumo
}
31
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 31. Realizar un programa para que la UART transmita el abecedario con la siguiente configuración: 9600, 8bits,
1bit de stop, y sin paridad y que se pueda visualizara través del USB en el hyperteminal. SOLUCIÓN: #include <msp430.h> unsigned int contador = 97; unsigned int i; void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT BCSCTL1 = CALBC1_1MHZ; // frecuencia 1MHz DCOCTL = CALDCO_1MHZ; P1SEL = BIT1 + BIT2 ; // P1.1 = RXD, P1.2=TXD P1SEL2 = BIT1 + BIT2 ; // P1.1 = RXD, P1.2=TXD UCA0CTL1 |= UCSSEL_2; // SMCLK UCA0BR0 = 104; // 1MHz 9600 UCA0BR1 = 0; // 1MHz 9600 UCA0MCTL = UCBRS0; // Modulation UCBRSx = 1 UCA0CTL1 &= ~UCSWRST; // **Inicializa máquina de estado de la USCI IE2 |= UCA0RXIE + UCA0TXIE; // habilita las interru`ciones de RX y TX __bis_SR_register(LPM0_bits + GIE); // Enter LPM0, interrupts enabled } // ISR de TX #pragma vector=USCIAB0TX_VECTOR __interrupt void USCI0TX_ISR(void) { for(i=97; i<123; i++){ while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer preparado? if (contador <123) { UCA0TXBUF = i; // Envío caracter i=97 delay_cycles(1500); //tiempo para transmitir un caracter ~1,5ms } else if (contador==123) { UCA0TXBUF = 0x0D; // Retorno de carro (13 en decimal) IE2 &= ~UCA0TXIE; //deshabilita la transmisión de caracteres } contador=contador+1; } } // ISR de RX #pragma vector=USCIAB0RX_VECTOR __interrupt void USCI0RX_ISR(void) { while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer está preparado? UCA0TXBUF = UCA0RXBUF; // TX -> RXed }
32
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 33. Utilizando la patilla P1.2 como salida TA0.1, generar dos frecuencias con un DC=50% y de 1KHz y 1,25KHz, respectivamente, separadas ente sí por un retardo de 0,5s. De esta manera colocando un Altavoz de 8Ω en dicha patillas obtendremos un sonido semejante a una sirena. El reloj debe ser SMCLK. La sirena no sonará hasta que se solicite la interrupción por flanco de bajada mediante P1.3, en dicho momento la alarma se repetirá 20 veces Mientras se está en reposo la CPU debe estar en modo LPM2. SOLUCIÓN:
33
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) #include <msp430.h> int PVez=0; int main(void) { WDTCTL = WDTPW + WDTHOLD; // Paramos el WDT BCSCTL1 = CALBC1_1MHZ; // f=1Mhz DCOCTL = CALDCO_1MHZ; P1SEL = BIT2; // Configuramos P1.2 como salida del Timer P1DIR = BIT2; // Y la habilitamos como salida // CONFIGURACIÓN DE LA INTERRUPCIÓN P1DIR &=~BIT3; // P1.3 entrada P1REN |=BIT3; // P1.3 resistencia pull-up HABILITADA P1OUT |=BIT3; // P1.3 resistencia pull-up P1IE |=BIT3; //Habilitamos las interrupciones, P1IES |=BIT3; // FLANCO DE BAJADA P1IFG &=~BIT3; // flag a cero no hay INT pendiente // CONFIGURACIÓN DEL TIMER TA0CCTL1 = OUTMOD_7; TA0CTL = TASSEL_2 + MC_1;
// Registro Captura/Compara 1 del Timer A0 // el modo Salida Reset/Set //modo ascendente y SMCLK fuente del reloj
// Programa principal __bis_SR_register(LPM2_bits + GIE); __no_operation();
// Enter LPM2 y habilita INT
} #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { int t; for (t=0;t<20;t++){ //sonará 10s pues cada tono suena 0,5s if (PVez==0){ TA0CCR0 = 999; //f1 = fSMCLK / TA0CCR0 = 10e6/1000=1KHZ TA0CCR1 = 500; // DC=TA0CCR1/TA0CCR0=(500/1000)%=50% PVez++; __delay_cycles(500000); //duración de la frecuencia 1; 0,5s } else { TA0CCR0 = 799; //f2 = fSMCLK / TA0CCR0 = 10e6/800=1,25KHZ TA0CCR1 = 400; // DC=TA0CCR1/TA0CCR0=(400/800)%=50% PVez=0; __delay_cycles(500000); //duración de la frecuencia 2; 0,5s } P1IFG &= ~0x08; // P1.3 IFG BORRADO, permite nueva interrupción } }
34
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15) 34. Este problema reúne los conceptos de emisión-‐recepción serie entre dos microcontroladores
//****************************************************************************** // MSP430G2553 USCI_A0, UART 9600 Full-Duplex, 32kHz ACLK // // Descripción: USCI_A0 se comunica de forma contínua en modo full-duplex // con otro microcontrolador. Está en modo LPM3, con actividad únicamente // cuando se transmiten o se reciben datos. // La ISR de RX transmite un carácter a 9600,8,N,1 en aproximadamente 1ms // La ISR de TX indica a la USCI_A0 que ha recibido un carácter. // ACLK = BRCLK = LFXT1 = 32768Hz, MCLK = SMCLK = DCO ~1MHz // Baud rate 32768Hz XTAL @9600 = 32768Hz/9600 = 3.41 // // MSP430G2xx3 MSP430G2xx3 // --------------------------------// | XIN|/|\| XIN|// | | 32kHz | | | 32kHz // | XOUT|--|RST XOUT|// | | /|\ | | // | RST|--| | // | | | | // | | | | // | UCA0TXD/P1.2|--------->|P1.1 | // | | 9600 | | // | UCA0RXD/P1.1|<---------|P1.2 | // | | | | // | | | | // | GND|----------|GND | // | | | | // | | | | // //****************************************************************************** #include #include "LCD4bits.c" int main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog LCD_INI (Dos_Lineas_5x8, Derecha_NoDesplaza); LCD_Control (CurOFF_BliOFF); LCD_Control (ClearDisplay); __delay_cycles(500000); P1OUT = 0x00; // P1.0/6 setup for LED output P1DIR = BIT0 + BIT6; P1SEL = BIT1 + BIT2 ; // P1.1 = RXD, P1.2=TXD P1SEL2 = BIT1 + BIT2; UCA0CTL1 |= UCSSEL_1; // CLK = ACLK UCA0BR0 = 0x03; // 32kHz/9600 = 3.41 UCA0BR1 = 0x00; UCA0MCTL = UCBRS1 + UCBRS0; // Modulation UCBRSx = 3 UCA0CTL1 &= ~UCSWRST; // **Inicializa USCI máquina estados**
35
Sistemas Electrónicos Digitales
HOJA DE EJERCICIOS (curso 2014/15)
IE2 |= UCA0RXIE + UCA0TXIE;
// habilita interrupción
USCI_A0 TX/RX
LCD_FilaColumna(0,1); LCD_Cadena ("ESPERANDO..."); __delay_cycles(5000000); __bis_SR_register(LPM3_bits + GIE);
// Modo LPM3 e interrupciones globales
} /* En el microcontrolador que sea transmisor hay que descomentar esta rutina USCI A0/B0 Transmisión ISR y comentar la siguiente USCI A0/B0 Recepción ISR */ // USCI A0/B0 Transmisión ISR //#pragma vector=USCIAB0TX_VECTOR //__interrupt void USCI0TX_ISR(void) // //{ // unsigned char TxByteT=0; // TxByteT = 'S'; // LCD_Control (ClearDisplay); // __delay_cycles(1000000); // LCD_FilaColumna(0,1); // LCD_Cadena ("TRANSMIT:"); // LCD_FilaColumna(0,10); // LCD_Caracter(TxByteT); // __delay_cycles(500000); // // UCA0TXBUF = TxByteT; //}
// Lee, y transmite
/* En el receptor cargamos con la rutina USCI A0/B0 Transmisión ISR comentada y la rutina USCI A0/B0 Recepción ISR descomentada */ // USCI A0/B0 Recepción ISR #pragma vector=USCIAB0RX_VECTOR __interrupt void USCI0RX_ISR(void) { unsigned char TxByteR=0; TxByteR=UCA0RXBUF; LCD_Control (ClearDisplay); __delay_cycles(500000); LCD_FilaColumna(1,1); LCD_Cadena ("RECIBIDO:"); LCD_FilaColumna(1,10); __delay_cycles(500000); LCD_Caracter(TxByteR); __delay_cycles(5000000); }
36
Sistemas Electrónicos Digitales