Академический Документы
Профессиональный Документы
Культура Документы
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
INICIO
XOR.B #001h,&P1OUT ; Conmuta el bit P1.0
MOV.W #050000,R15 ; R15=50000 para realizar un retardo
L1 ; se realiza 50000 veces el bucle L1
DEC.W R15 ; Decrementando R15
JNZ L1 ; retardo=(1+2)*50000=150000T
JMP INICIO ; 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; // Para el watchdog
P1DIR |= 0x01; // Configura P1.0 como salida direction
for (;;)
{
volatile unsigned int i;
P1OUT ^= 0x01; // Conmuta P1.0 usando la XOR
i = 50000; // Retardo
do (i--);
while (i != 0);
}
}
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()
*/
P1SEL= 0x00;
P1DIR|= BIT6; //Salida el bit 6 del puerto 1
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
SOLUCIÓN:
#include <msp430g2553.h>
int i;
void main(void) {
while (1){
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:
DC8 00010000b,00100000b,01000000b,10000000b
DC8 00000000b,11111111b,00000000b,11111111b
DC8 00000000b,11111111b,00000000b,11111111b
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
;---------------------------------------------------------------------
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
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:
DC8 00010000b,00100000b,01000000b,10000000b
DC8 01000000b,00100000b,00010000b,00001000b
DC8 00000100b,00000010b,00000001b,00000000b
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:
#include <msp430.h>
char secu[21] = {0x01,0x02,0x04, 0x08,0x10,0x20,0x40,0x80,
0x40,0x20, 0x10, 0x08,0x04,0x02,0x01};
// 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 <io430.h>
while(1)
for (i = 0; i <15 ; i++)
{
//-----------------------------------------------------
// 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
}
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
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:
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
#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
}
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
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
; 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
;-------------------------------------------------------------------------------
; Subrutina de retardo
;-------------------------------------------------------------------------------
RETARDO MOV #Tmux,R15
ETIQ2 DEC R15
JNZ ETIQ2
RET
;-------------------------------------------------------------------------------
; Tabla de 7 segmentos
; Están ordenados g-f-e-d-c-b-a
;-------------------------------------------------------------------------------
TSeg
; 0, 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9
DC8 77h,06h,0B3h,97h,0C6h,0D5h,0F5h,07h,0F7h,0C7h
;-------------------------------------------------------------------------------
; Vectores de interrupción y reset
;-------------------------------------------------------------------------------
ORG 0FFFEh ; Vector de reset
DW RESET
ORG 0FFE4h ; Vector de interrupción para P1
DW P1_ISR
END main
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:
#include <msp430.h>
#include <inttypes.h>
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
P1OUT|=BIT0;
P1OUT&=~BIT6;
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.
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
;
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. 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
;
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
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.
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>
void main(void) {
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
}
SOLUCIÓN:
#include <msp430.h>
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Paramos el WDT
DCOCTL = CALDCO_1MHZ; //calibra la f a 1MHz
BCSCTL1 = CALBC1_1MHZ;
P1DIR |= 0x01; // P1.0 como salida para el LED
TA1CCTL0 = CCIE; // 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
SOLUCIÓN:
#include <msp430.h>
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Paramos el WDT
DCOCTL = CALDCO_1MHZ; //calibra la f a 1MHz
BCSCTL1 = CALBC1_1MHZ;
P1DIR |= 0x01; // P1.0 como salida para el LED
TA1CCTL0 = CCIE; // 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
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
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. 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.
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
#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; // inicio de muestro y conversión
__bis_SR_register(CPUOFF + GIE); // modo LPM0 e inter. globales hab.
if (ADC10MEM < 0x1FF)
P1OUT &= ~0x40; // apagar P1.6
else
P1OUT |= 0x40; // encender P1.6
}
}
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.
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
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
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
}
SOLUCIÓN:
#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
// Programa principal
__bis_SR_register(LPM2_bits + GIE); // Enter LPM2 y habilita INT
__no_operation();
}
#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
}
}
//******************************************************************************
// 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 <io430.h>
#include "LCD4bits.c"
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog
LCD_FilaColumna(0,1);
LCD_Cadena ("ESPERANDO...");
__delay_cycles(5000000);
//#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
//}
36
Sistemas
Electrónicos
Digitales