Sie sind auf Seite 1von 49

Realizar un proyecto en CODE COMPOSER STUDIO V4

1. Primero nos pedirá que seleccionemos una carpeta en la cual se guardarán todos los
proyectos que realizamos.

2. Ahora pasamos a realizar un nuevo proyecto


3. Escribimos el nombre del proyecto que queramos darle y seleccionamos el botón next

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

7. Y finalmente seleccionamos Finish


Incluyendo archivos .c y .h en CCS

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.

¿Cómo compilar mi proyecto?

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:

Run: Este botón es para arrancar el programa

Pause: para pausar el programa en tiempo real

Terminate: para terminar el debug

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

EJERCICIO #1 (SALIDA DIGITAL)

#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;

P1OUT ^= 0x01; // Toggle P1.0 using exclusive-OR

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.

WDTCTL = WDTPW + WDTHOLD;

_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________

Puertos de entrada y salida digitales

PXDIR
Este registro, sirve para determinar si queremos el puerto como entrada o salida:

P1DIR |= 0x01; // Set P1.0 to output direction

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;

¿Que se realiza con esta orden?

_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________

¿Existe alguna otra forma de realizar la misma orden?

_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
EJERCICIO #2 (ENTRADAS DIGITALES)

#include <msp430f2013.h>

void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P1DIR |= 0x01; // Set P1.0 to output direction

while (1) // Test P1.4


{
if ((0x10 & P1IN)) P1OUT |= 0x01; // if P1.4 set, set P1.0
else P1OUT &= ~0x01; // else reset
}
}

En la condición:

if ((0x10 & P1IN)) P1OUT |= 0x01; // if P1.4 set, set P1.0


else P1OUT &= ~0x01; // else reset
¿Qué se desea hacer?

_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
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é?
_______________________________________________________________
_______________________________________________________________
_______________________________________________________________
_______________________________________________________________

Ejercicio #3 (Interrupciones de entradas)

#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

_BIS_SR(LPM4_bits + GIE); // Enter LPM4 w/interrupt


}

// Port 1 interrupt service routine


#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
P1OUT ^= 0x01; // P1.0 = toggle
P1IFG &= ~0x10; // P1.4 IFG cleared
}

El circuito, es el mismo que se uso en la practica anterior.

En este ejemplo, utilizamos por primera vez la interrupción para detectar la entrada de
una señal positiva. Para esto utilizamos la directiva:

// Port 1 interrupt service routine


#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
P1OUT ^= 0x01; // P1.0 = toggle
P1IFG &= ~0x10; // P1.4 IFG cleared
}

Al declarar #pragma vector= PORT1_VECTOR direccionamos la función _interrupt void


Port_1(void) para que cada vez que detecte un pulso en la entrad 1.4 el led se encienda o
apague según sea el caso. En el registro P1IFG limpiamos la bandera para que se salga de
la interrupción, de lo contrario jamás saldríamos de la función, ocasionando un ciclo
infinito en la función de interrupción.

P1IFG &= ~0x10;

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

Registro de corrimiento para leds

#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>

unsigned char flag_secuencia1, flag_secuencia2;

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;
}

}
}

// Port 1 interrupt service routine


#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
if(!(0x10 & P1IN)){
flag_secuencia1=1;
}
if(!(0x20 & P1IN)){
flag_secuencia2=1;
}

P1IFG &= ~0x30; // P1.4 IFG cleared

}
Realiza un programa que utilice un display de 7 segmentos e incremente cada
determinado tiempo automáticamente.

El display de 7 segmentos se conforma de 7 leds que conforman un número del 1 al 9, se


usan frecuentemente en dispositivos de medición.

La tabla de valores que debemos de tener para desplegar en nuestro puerto 1 es el


siguiente:

Número Codificación Valor Hexadecimal (cátodo Valor Hexadecimal (ánodo


Común) Común)
1 B,C 0x06 0xf9
2 A,B,G,E,D 0x5b 0xa4
3 A,B,G,C,D 0x4f 0xb0
4 F,G,B,C 0x66 0x99
5 A,F,G,C,D 0x6d 0x92
6 A,F,G,E,C,D 0x7d 0x82
7 A,B,C 0x07 0xf8
8 A,B,C,D,E,F,G 0x7f 0x00
9 A,F,G,B,C,D 0x6f 0x90
0 A,B,C,D,E,F 0x3f 0x40

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;

const unsigned char


display[10]={0x40,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};

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

MODOS DE OPERACIÓN Y BAJO CONSUMO


OSCILADOR Y SISTEMA DE RELOJ

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*/

P1DIR |= 0x13; // P1.0,1 and P1.4 outputs


P1SEL |= 0x11; // P1.0,4 ACLK, SMCLK output

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;

Configuramos la interrupción del watchdog cada segundo, recordemos el registro WDTCTL


Con la sentencia

_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

Realizar la lectura del canal A1

#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);
}

#pragma vector = SD16_VECTOR


__interrupt void SD16ISR(void)
{
if (SD16MEM0 < 0x7FFF) // SD16MEM0 > 0.3V?, clears IFG
P1OUT &= ~0x01;
else
P1OUT |= 0x01;
}