Ejercicios Con MSP430F2013
Ejercicios Con MSP430F2013
Ejercicios Con MSP430F2013
1. Primero nos pedirá que seleccionemos una carpeta en la cual se guardarán todos los
proyectos que realizamos.
4. Ahora dejamos las opciones como se ven en la siguiente figura y seleccionamos next
5. Para esta ventana, dejamos todo como esta y seleccionamos al botón next
6. Seleccionamos el microcontrolador MSP430F2013
Para poder incluir archivos en nuestro proyecto, es muy sencillo, solo tenemos que
seleccionar nuestra carpeta, y presionar el botón secundario del ratón.
Seleccionamos Source file para crear nuestro archivo main.c, cabe mencionar que cuando
queramos incluir archivos de cabecera solo tenemos que seleccionar header file.
A partir de aquí, solo tenemos que empezar a escribir nuestro programa.
Para compilar nuestro proyecto, solo tenemos que seleccionar Project->Build Project
¿Cómo programar el microcontrolador una vez que ya haya terminado mi programa?
Solamente tenemos que presionar el botón que aparece encerrado en el círculo rojo en la figura:
A continuación nos aparece un cambio de opciones en la pantalla, que nos permitirán hacer un
debug en tiempo real, checando valores de variables, memoria, registros y línea del programa.
En la pantalla podemos ver varios iconos que nos demuestran cuales son las herramientas que nos
ofrece este excelente compilador:
Step Into: Una vez que hemos seleccionado Pause, podemos ir recorriendo nuestro programa
línea por línea, entrar a funciones, etc.
Step Into (ensamblador): estos botones sirven para cuando queremos hacer un step para
a un nivel de instrucción en ensamblador.
Step Return: Este comando sirve, para cuando queremos salir de alguna función en la cual
está el compilador corriendo en steps.
Ejercicios con MSP430F2013
#include <msp430f2013.h>
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P1DIR |= 0x01; // Set P1.0 to output direction
for (;;)
{
volatile unsigned int i;
i = 50000; // Delay
do (i--);
while (i != 0);
}
}
Explicación
Aquí podemos ver un sencillo ejemplo, en el cual el objetivo en encender y apagar un led, el
puerto P1.0
El primer registro que vemos es
WDTCTL
Explique la ejecución de esta línea de programación.
_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
PXDIR
Este registro, sirve para determinar si queremos el puerto como entrada o salida:
Con esta orden, lo que hacemos es poner el pin 0 del Puerto 1 como salida, al escribir en el
registro el valor hexadecimal 0x01.
PXOUT1
Este registro sirve para poner el estado lógico en el puerto como salida:
P1OUT ^= 0x01;
_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
EJERCICIO #2 (ENTRADAS DIGITALES)
#include <msp430f2013.h>
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P1DIR |= 0x01; // Set P1.0 to output direction
En la condición:
_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
Con la condición:
if(P1IN==0x10) P1OUT=0x01;
else P1OUT=0x00;
¿Se hace lo mismo que en la anterior condición y por qué?
_______________________________________________________________
_______________________________________________________________
_______________________________________________________________
_______________________________________________________________
#include <msp430f2013.h>
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P1DIR = 0x01; // P1.0 output, else input
P1OUT = 0x10; // P1.4 set, else reset
P1REN |= 0x10; // P1.4 pullup
P1IE |= 0x10; // P1.4 interrupt enabled
P1IES |= 0x10; // P1.4 Hi/lo edge
P1IFG &= ~0x10; // P1.4 IFG cleared
En este ejemplo, utilizamos por primera vez la interrupción para detectar la entrada de
una señal positiva. Para esto utilizamos la directiva:
Cada puerto P1 y P2 tienen interrupciones, configuradas con los registros PxIFG. PxIE, y
PxIES. Todos los pines P1 llaman a un solo vector de interrupción, y todos los pines del
puerto P2 tienen otro vector de interrupción. El registro PxIFG puede ser verificado para
saber el estado de la interrupción.
Arquitectura de pin P1.0
Practicas a realizar para terminar unidad IO
#include <msp430f2013.h>
void delay(void){
volatile unsigned int i;
for(i=0;i<80000;i++);
}
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P1DIR |= 0x0F; // Set P1.0 to P1.3 to output
direction
for (;;)
{
P1OUT = 0x00;
delay();
P1OUT = 0x01;
delay();
P1OUT = 0x02;
delay();
P1OUT = 0x04;
delay();
}
}
Escribe un programa que realice la misma secuencia, con diferentes sentencias:
Realiza un programa que despliegue una secuencia en leds dependiendo del
valor de dos botones:
#include <msp430f2013.h>
void delay(void){
volatile unsigned int i;
for(i=0;i<80000;i++);
}
void secuence(unsigned char value){
if(!value){
P1OUT = 0x00;
delay();
P1OUT = 0x01;
delay();
P1OUT = 0x02;
delay();
P1OUT = 0x04;
delay();
}else{
P1OUT = 0x04;
delay();
P1OUT = 0x02;
delay();
P1OUT = 0x01;
delay();
P1OUT = 0x00;
delay();
}
}
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P1DIR |= 0x0F; // Set P1.0 to P1.3 to output direction
P1REN |= 0x30; // P1.4 P1.5 pullup
P1IE |= 0x30; // P1.4 P1.5 interrupt enabled
P1IES |= 0x30; // P1.4 P1.5 Hi/lo edge
P1IFG &= ~0x30;
flag_secuencia1=0;
flag_secuencia2=0;
for (;;)
{
if(flag_secuencia1){
secuence(0);
flag_secuencia1=0;
if(flag_secuencia2){
secuence(1);
flag_secuencia2=0;
}
}
}
}
Realiza un programa que utilice un display de 7 segmentos e incremente cada
determinado tiempo automáticamente.
Entonces, como ya sabemos los valores que tenemos que imprimir para que se despliegue
el número deseado, pasamos a la programación:
#include <msp430f2013.h>
int valor=0;
void delay(void){
volatile unsigned int i;
for(i=0;i<40000;i++);
}
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P1DIR = 0xFF;
for(;;){
P1OUT=display[valor];
valor++;
if(valor>9)valor=0;
delay();
}
}
Realice un programa que incremente el contador en el display de 7
segmentos cuando no se esté presionando el botón, cuando se mantenga
presionado, se decrementará el contador.
Respuesta:
CAPITULO 2
Como nos explica este articulo, existen tres fuentes de reloj que necesitamos alimentar,
ACLK, MCLK y SMCLK. La primera es para obtener la frecuencia de un cristal de 32.768
KHz, la segunda es la frecuencia que alimentará las ejecuciones de reloj del CPU y por
último, la frecuencia que suministrará de pulsos a los periféricos del microcontrolador
como son ADC, IO, SPI, etc.
El microcontrolador MSP430 está diseñado para aplicaciones de ultrabajo consumo, y se
puede utilizar en diferentes tipos de operación de bajo consumo.
Los registros para configurar el reloj, son:
BCSCTL3
BCSCTL2
IFG1
REGISTER SR
EJERCICIO #2 (VLO)
#include <msp430x20x3.h>
void main(void)
{
volatile unsigned int i; // Volatile to prevent removal
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
BCSCTL3 |= LFXT1S_2; // LFXT1 = VLO
IFG1 &= ~OFIFG; // Clear OSCFault flag
__bis_SR_register(SCG1 + SCG0); // Stop DCO
BCSCTL2 |= SELM_3 + DIVM_3; // MCLK = LFXT1/8
P1DIR = 0xFF; // All P1.x outputs
P1OUT = 0; // All P1.x reset
P2DIR = 0xFF; // All P2.x outputs
P2OUT = 0; // All P2.x reset
for (;;)
{
P1OUT |= 0x01; // P1.0 set
for (i = 10; i > 0; i--); // Delay 1x
P1OUT &= ~0x01; // P1.0 reset
for (i = 1000; i > 0; i--); // Delay 100x
}
}
Para poder configurar el reloj en bajo consumo, en el programa se escriben los siguientes
registros:
BCSCTL3 |= LFXT1S_2; // LFXT1 = VLO
IFG1 &= ~OFIFG; // Clear OSCFault flag
__bis_SR_register(SCG1 + SCG0); // Stop DCO
BCSCTL2 |= SELM_3 + DIVM_3; // MCLK = LFXT1/8
Recordemos que el registro BCSCTL3 sirve para configurar la velocidad de reloj, así que al
poner una operación OR de lo que contiene, más lo que se define como LFXT1S_2,
seleccionamos:
La opción VLO en el microcontrolador MSP430 es el oscilador interno, con una frecuencia
normal de 12KHz, aquí podemos ver algunas de sus especificaciones:
En la siguiente línea, se configura el registro IFG1, lo cual la única tarea que hace, es
limpiar la bandera de la interrupción del oscilador interno.
En la línea:
__bis_SR_register(SCG1 + SCG0);
Configuramos el registro SR para que pongamos a “1” los bits SCG1 y SCG2 para poder
apagar el DCO (digitally controlled oscillator) que permite despertar al microcontrolador
de un estado de “sueño” en tan solo 1us.
Por último se configura el registro BCSCTL2, con valores 3 respectivamente
Es así, como se elige en SELM_3 trabajar con el oscilador interno y con DIVM_3 tenemos
una frecuencia de 12KHz dividida entre 8, que es igual a 1.5KHz de frecuencia de trabajo.
¿En qué modo de operación se encuentra el microcontrolador con los registros SELM_3 y
DIVM_2?
___________________________________________________________________
EJERCICIO #3 (DCO)
#include <msp430f2013.h>
void main(void)
{
WDTCTL = WDTPW +WDTHOLD; // Stop Watchdog Timer
if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
{
while(1); // If calibration constants erased
// do not load, trap CPU!!
}
//1Mhz
BCSCTL1 = CALBC1_1MHZ; // Set range
DCOCTL = CALDCO_1MHZ; // Set DCO step + modulation */
/* //8Mhz
BCSCTL1 = CALBC1_8MHZ; // Set range
DCOCTL = CALDCO_8MHZ; // Set DCO step +
modulation */
/* //12Mhz
BCSCTL1 = CALBC1_12MHZ; // Set range
DCOCTL = CALDCO_12MHZ; // Set DCO step +
modulation*/
/* //16Mhz
BCSCTL1 = CALBC1_16MHZ; // Set range
DCOCTL = CALDCO_16MHZ; // Set DCO step +
modulation*/
while(1)
{
P1OUT |= 0x01; // P1.1 = 1
P1OUT &= ~0x01; // P1.1 = 0
}
}
EJERCICIO #3 (LFxTAL)
#include <msp430x20x3.h>
volatile unsigned int i;
void main(void)
{
WDTCTL = WDT_ADLY_1000; // WDT 1s interval timer
IE1 |= WDTIE; // Enable WDT interrupt
P1DIR = 0xFF; // All P1.x outputs
P1OUT = 0; // All P1.x reset
P2DIR = 0xFF; // All P2.x outputs
P2OUT = 0; // All P2.x reset
// An immedate Osc Fault will occur next
IE1 |= OFIE; // Enable Osc Fault
while(1)
{
P1OUT ^= 0x01; // Toggle P1.0 using exclusive-OR
_BIS_SR(LPM3_bits + GIE); // Enter LPM3 w/interrupt
}
}
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer (void)
{
_BIC_SR_IRQ(LPM3_bits); // Clear LPM3 bits from 0(SR)
}
#pragma vector=NMI_VECTOR
__interrupt void nmi_ (void)
{
do
{
IFG1 &= ~OFIFG; // Clear OSCFault flag
for (i = 0xFFF; i > 0; i--); // Time for flag to set
P1OUT ^= 0x01; // Toggle P1.0 using exclusive-OR
}
while (IFG1 & OFIFG); // OSCFault flag still set?
IE1 |= OFIE; // Enable Osc Fault
}
En este ejercicio podemos notar que por primera vez utilizamos el watchdog, y
habilitamos una interrupción en el registro IE1.
IE1
En la información aparece que debemos de utilizar una forma especial para cargar
información en el registro, mencionan como hacerlo para ensamblador, en c se hace con
una operación OR.
IE1 |= WDTIE;
Esto quiere decir que estamos cargando el registro IE1 con el estado del bit de la
interrupción de watchdog para poder habilitar la interrupción.
En la parte de:
WDTCTL = WDT_ADLY_1000;
_BIS_SR(LPM3_bits + GIE);
Entramos al modo de bajo consumo LPM3, con esta acción, el microcontrolador entrará
en un modo de suspensión y bajo consumo, y solo se despertará cuando suceda alguna
interrupción. Como puede ser la interrupción de cada 1 segundo del watchdog.
En las siguientes sentencias, vemos varias interrupciones, estas se declaran de esta forma:
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer (void)
{
_BIC_SR_IRQ(LPM3_bits); // Clear LPM3 bits from 0(SR)
}
Cada vez que se cumple el segundo, se repite esta función, la cual limpia la bandera del
modo LPM3 y así el CPU vuelva a despertar, lo cual hará que parpadee el led que esté
conectado al pin de salida. Esto lo hacemos con una operación en ensamblador:
_BIC_SR_IRQ(LPM3_bits); // Clear LPM3 bits from 0(SR)
EJERCICIO #4 (OPERACIÓN EN MODO LPM3)
#include <msp430f2013.h>
void main(void)
{
BCSCTL1 |= DIVA_2; // ACLK/4
WDTCTL = WDT_ADLY_1000; // WDT 1s/4 interval timer
IE1 |= WDTIE; // Enable WDT interrupt
P1DIR = 0xFF; // All P1.x outputs
P1OUT = 0; // All P1.x reset
P2DIR = 0xFF; // All P2.x outputs
P2OUT = 0; // All P2.x reset
while(1)
{
int i;
P1OUT |= 0x01; // Set P1.0 LED on
for (i = 5000; i>0; i--); // Delay
P1OUT &= ~0x01; // Reset P1.0 LED off
_BIS_SR(LPM3_bits + GIE); // Enter LPM3
}
}
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer (void)
{
_BIC_SR_IRQ(LPM3_bits); // Clear LPM3 bits from 0(SR)
}
CAPITULO 3
ADC
(SD16)
El periferico SD16 es un convertidor analogico digital de 16 bits. Este modulo de
conversión tipo sigma delta con alta impedancia a la entrada.
Diagrama a bloques del SD16
Ejercicio #1 ADC
#include <msp430f2013.h>
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P1DIR |= 0x01; // Set P1.0 to output direction
SD16CTL = SD16REFON + SD16SSEL_1; // 1.2V ref, SMCLK
SD16INCTL0 = SD16INCH_1; // A1+/-
SD16CCTL0 = SD16UNI + SD16IE; // 256OSR, unipolar, interrupt enable
SD16AE = SD16AE2; // P1.1 A1+, A1- = VSS
SD16CCTL0 |= SD16SC; // Set bit to start conversion
_BIS_SR(LPM0_bits + GIE);
}