cursomsp430 assembly&c

201
CURSO MSP430 – Ensamblador y C http://todomcu.scienceontheweb.net/index.html http://todomcu.scienceontheweb.net/msp430/ejemplos-asm/asm.html Contenido ¿QUE ESPERAR DE ESTA PAGINA?. ............................9 ADEMAS DEL CURSO. ........................................9 RETORALIMENTACION. ......................................10 EL CURSO DE MSP430. .....................................10 CARACTERISTICAS DE LOS MSP430™. .........................10 ACERCA DE LOS PERIFERICOS. ..............................11 DESARROLLO DE APLICACIONES. .............................11 LAUNCHPAD ...............................................12 eZ430 ™ .................................................15 IAR .....................................................17 LA ARQUILECTURA .........................................18 CARACTERISTICAS PRINCIPALES EN LA CPU ...................18 LOS REGISTROS DE LA CPU. ................................21 R2 y R3.-Generador de constantes (Constant Generator). ...23 R4-R15.-Registros de propósito general (General Prupose). 23 MODOS DE DIRECCIONAMIENTO. ..............................23 Modo registro. ..........................................24 Modo Indexado. ..........................................25 Modo simbólico. .........................................26 Modo Absoluto. ..........................................27 Modo Indirecto. .........................................28 Modo indirecto con autoincremento. ......................29

Upload: lizeth-catherine-hernandez-roncancio

Post on 25-Oct-2015

504 views

Category:

Documents


2 download

TRANSCRIPT

CURSO MSP430 – Ensamblador y C

http://todomcu.scienceontheweb.net/index.html

http://todomcu.scienceontheweb.net/msp430/ejemplos-asm/asm.html

Contenido

¿QUE ESPERAR DE ESTA PAGINA?. ..................................................................................9

ADEMAS DEL CURSO. .......................................................................................................9

RETORALIMENTACION. ..................................................................................................10

EL CURSO DE MSP430. ...................................................................................................10

CARACTERISTICAS DE LOS MSP430™. ............................................................................10

ACERCA DE LOS PERIFERICOS. .......................................................................................11

DESARROLLO DE APLICACIONES. ...................................................................................11

LAUNCHPAD ..................................................................................................................12

eZ430 ™ .........................................................................................................................15

IAR .................................................................................................................................17

LA ARQUILECTURA .........................................................................................................18

CARACTERISTICAS PRINCIPALES EN LA CPU ...................................................................18

LOS REGISTROS DE LA CPU. ...........................................................................................21

R2 y R3.-Generador de constantes (Constant Generator). .............................................23

R4-R15.-Registros de propósito general (General Prupose). ..........................................23

MODOS DE DIRECCIONAMIENTO. .................................................................................23

Modo registro. ...............................................................................................................24

Modo Indexado. ............................................................................................................25

Modo simbólico. ............................................................................................................26

Modo Absoluto. .............................................................................................................27

Modo Indirecto. .............................................................................................................28

Modo indirecto con autoincremento. ...........................................................................29

Modo Inmediato. ...........................................................................................................30

Instrucciones Aritmeticas ..............................................................................................31

Suma Destino y C.- ADC .................................................................................................31

Añadir.- ADD [0101] .......................................................................................................31

Añadir con acarreo.- ADDC [0110] .................................................................................32

Suma decimal con C.- DADC ..........................................................................................32

Suma en BCD.- DADD [1010] .........................................................................................32

Decremento.- DEC .........................................................................................................32

Doble Decremento.- DECD ............................................................................................32

Incremento.- INC ...........................................................................................................33

Doble Incremento.-INCD ...............................................................................................33

Sustraer.- SUB [1000] ....................................................................................................33

Sustrae con acarreo.- SUBC [0111] ................................................................................33

Instrucciones Logicas. ....................................................................................................33

Y lógica.-AND [1111] ......................................................................................................34

Borra bits seleccionados en destino.- BIC [1100] ...........................................................34

Coloca bits seleccionados en destino.- BIS [1101] .........................................................34

Comprobar bits en destino.- BIT [1011] .........................................................................34

Negación.- INV ...............................................................................................................35

Corrimiento a la izquierda.- RLA ....................................................................................35

Corrimiento a la izquierda con C.- RLC ...........................................................................35

Corrimiento aritmético a la derecha.- RRA [000100010] ...............................................35

Corrimiento a la derecha con acarreo.- RRC [000100000] .............................................35

Intercambia Bytes.- SWPB [000100001] ........................................................................36

Extiende el signo.- SXT [000100001] ..............................................................................36

O exclusiva lógica.- XOR [1110] .....................................................................................36

Instrucciones De Datos. .................................................................................................36

Borrar.- CLR ...................................................................................................................37

Borra Acarreo.- CLRC .....................................................................................................37

Borra Negativo.- CLRN ...................................................................................................37

Borra Cero CLRZ .............................................................................................................37

Comparar.- CMP [1001] .................................................................................................37

Mover.- MOV [1000] .....................................................................................................37

Sacar elemento de la pila.- POP .....................................................................................38

Almacena en la pila.- PUSH [000100100] ......................................................................38

Colocar C.- SETC .............................................................................................................38

Colocar N.- SETN ............................................................................................................38

Coloca Z.- SETZ ...............................................................................................................38

Prueba.- TST ..................................................................................................................39

.......................................................................................................................................39

Incremento.- INC ...........................................................................................................39

Decremento.- DEC .........................................................................................................39

Doble Incremento.-INCD ...............................................................................................39

Doble Decremento.- DECD ............................................................................................39

Corrimiento a la izquierda.- RLA ....................................................................................39

Corrimiento a la izquierda con C.- RLC ...........................................................................40

Suma Destino y C.- ADC .................................................................................................40

Suma decimal con C.- DADC ..........................................................................................40

Negación.- INV ...............................................................................................................40

Instrucciones De Control. ..............................................................................................40

Brinco.- BR .....................................................................................................................41

Llamar subrutina.- CALL [000100101] ............................................................................41

Inhabilita las interrupciones.- DINT ...............................................................................41

Habilita las interrupciones.- EINT ..................................................................................41

Salta si C.- JC [001011] ...................................................................................................41

Salta si mayor o igual.- JGE [001101] .............................................................................42

Salta si menor.- JL [001110] ...........................................................................................42

Salta.- JMP [001000] ......................................................................................................42

Salta si N.- JN [001100] ..................................................................................................42

Salta si C no es cero.- JNC [001010] ...............................................................................42

Salta si Z no es cero JNE/JNZ [001000] ..........................................................................42

Salta si Z.- JEQ/JZ [001001] ............................................................................................42

Sin operación.- NOP .......................................................................................................42

Regreso de Subrutina.- RET ...........................................................................................43

Regreso de la interrupción.- RETI [0001001100000000 completo] ...............................43

ORGANIZACIÓN DE LA MEMORIA ..................................................................................43

REGISTROS DE FUNCION ESPECIFICA .............................................................................43

REGISTROS DE LOS PERIFERICOS ...................................................................................44

RAM ...............................................................................................................................45

MEMORIA DE ARRANQUE .............................................................................................45

MEMORIA DE INFORMACIÓN ........................................................................................45

MEMORIA DE CODIGO ...................................................................................................45

VECTORES DE INTERRUPCION .......................................................................................46

TIPOS DE MEMORIA ......................................................................................................46

ESTRUCTURA DE UN PROGRAMA ..................................................................................47

LAS SUBRUTINAS ...........................................................................................................49

SUBRUTINAS DE RETARDO ............................................................................................51

INTERRUPCIONES ..........................................................................................................53

BANDERAS DE INTERRUPCION .......................................................................................55

VECTOR DE INTERUPCIONES ..........................................................................................55

TABLAS Y APUNTADORES ..............................................................................................57

CORRIMIENTOS A LA IZQUIERDA ...................................................................................60

CORRIMIENTOS A LA DERECHA .....................................................................................62

SUMA Y RESTA A 32 BITS ...............................................................................................63

SUMA Y RESTA A 64 BITS ...............................................................................................64

PROGRAMA DE APLICACIÓN ..........................................................................................64

Obtener codigo fuente ..................................................................................................67

MULTIPLICACION DE 16X16 BITS ...................................................................................67

DESARROLLO DE LA SUBRUTINA ....................................................................................71

EL PROGRAMA DE APLICACIÓN .....................................................................................73

Obtener codigo fuente ..................................................................................................77

PUERTOS DIGITALES DE ENTRADA Y SALIDA ..................................................................77

FUNCIONAMIENTO Y NOTACION ...................................................................................78

SELECCIÓN DE FUNCION ................................................................................................79

LOS REGISTROS I/O ........................................................................................................81

CONFIGURAR COMO SALIDA .........................................................................................85

INTERRUPCION EN LOS PUERTOS ..................................................................................86

CONFIGURAR LAS INTERRUPCIONES. ............................................................................86

BANDERA DE INTERRUPCION PARA LOS PUERTOS. .......................................................88

HABILITAR LA INTERRUPCION. .......................................................................................88

DECLARANDO EL VECTOR PARA LOS PUERTOS ..............................................................89

APLICACIÓN DE EJEMPLO ..............................................................................................91

EL SISTEMA BASICO DE RELOJ ........................................................................................94

LAS FUENTES DE RELOJ ..................................................................................................94

LAS SEÑALES DE RELOJ ..................................................................................................95

EL TIMER A .....................................................................................................................96

TIMER_A COMO TEMPORIZADOR .................................................................................97

MODOS DE CUENTA ......................................................................................................98

TIMER EN CAPTURA .....................................................................................................100

TIMER EN COMPARACION ...........................................................................................102

EL PERRO GUARDIÁN ...................................................................................................106

MODO GUARDIÁN .......................................................................................................107

MODO INTERVALOS .....................................................................................................108

OPERACIÓN SEGURA ...................................................................................................109

ACERCA DE IAR EMBEDDED WORKBENCH ® ................................................................109

DESCARGA E INSTALACION DE IAR. .............................................................................110

Descarga e instalacion IAR - VIDEO..........................................................................................110

CREAR PROYECTO EN ENSAMBLADOR. ........................................................................111

Configuras IAR en Ensamblador - VIDEO..................................................................................111

CREAR PROYECTO EN C++. ...........................................................................................111

Configurar IAR en C++ - VIDEO.................................................................................................112

CONFIGURACION DEBUG/RELEASE. ............................................................................112

Debug Release con IAR - VIDEO................................................................................................112

¿PARA QUE CONFIGURAR DEBUG Y RELEASE?. ...........................................................113

EJEMPLOS EN ENSAMBLADOR DE MSP430™ ...............................................................113

Arquitectura: ...............................................................................................................114

Puertos: .......................................................................................................................114

Timer_A: ......................................................................................................................114

Perro Guardian ............................................................................................................114

EJEMPLO 1: TABLAS Y APUNTADORES.....................................................................................114

EJEMPLO 2: CORRIMIENTOS A LA IZQUIERDA..........................................................................117

CORRIMIENTOS A LA DERECHA ...................................................................................119

EJEMPLO 3: SUMA Y RESTA A 32 BITS......................................................................................120

SUMA Y RESTA A 64 BITS .............................................................................................121

PROGRAMA DE APLICACIÓN ........................................................................................122

Obtener codigo fuente - suma-resta.s43..................................................................................125

EJEMPLO 4: MULTIPLICACION DE 16X16 BITS..........................................................................125

DESARROLLO DE LA SUBRUTINA ..................................................................................128

EL PROGRAMA DE APLICACIÓN ...................................................................................130

Obtener codigo fuente - multiplicacion.s43.............................................................................134

PRACTICAS MANEJO DE PUERTOS............................................................................................135

PRACTICA 1 - Encender un led al pulsar .......................................................................135

CODIGO FUENTE ..........................................................................................................135

Practica 1.flv - VIDEO http://www.youtube.com/watch?v=rRrhoKI3HbE&feature=player_embedded...........................................................................136

PRACTICA 2 - Encender un led, apagar otro al pulsar ..................................................136

CODIGO FUENTE ..........................................................................................................136

Practica 2.flv - VIDEO................................................................................................................137

PRACTICA 3 - Encender un led por 10 segundos ..........................................................137

CODIGO FUENTE ..........................................................................................................137

Practica 3.flv - VIDEO ...................................................................................................139

PRACTICA 4 - Secuencia de 8 leds ................................................................................139

CODIGO FUENTE ..........................................................................................................139

PRACTICA 5 - PWM de 10% en 10% .............................................................................141

CODIGO FUENTE ..........................................................................................................141

Practica 5.flv - VIDEO ...................................................................................................143

PRACTICA 6 - Cuenta de display de 0 a 99 ...................................................................143

CODIGO FUENTE ..........................................................................................................143

Practica 6.flv - VIDEO ...................................................................................................145

Timer_A....................................................................................................................................145

PRACTICA 1 - Encender un led por 10 segundos ...........................................................145

CODIGO FUENTE ..........................................................................................................146

Timer_A Practica 1.flv - VIDEO .....................................................................................147

PRACTICA 2 - Secuencia con corrimientos ....................................................................147

CODIGO FUENTE ..........................................................................................................147

Timer_A Practica 2.flv - VIDEO .....................................................................................149

PRACTICA 3 - Secuencia cualquiera con tablas ............................................................149

CODIGO FUENTE ..........................................................................................................149

Timer_A Practica 3.flv - VIDEO .....................................................................................151

PRACTICA 4- PWM automatico con Time_A y WDT .....................................................151

CODIGO FUENTE ..........................................................................................................152

Timer_A Practica 4.flv - VIDEO .....................................................................................153

PERRO GUARDIAN....................................................................................................................153

PRACTICA 1 - Conmutar un led cada 5s .......................................................................153

CODIGO FUENTE ..........................................................................................................153

Perro guardián practica1.flv - VIDEO ...........................................................................154

PRACTICA 2 - La entrada digital numero 11.............................................................................154

CODIGO FUENTE ..........................................................................................................155

Perro guardian practica 2 version 1.flv - VIDEO........................................................................156

Perro guardian practica 2 versión 2.flv - VIDEO........................................................................157

¿QUE ESPERAR DE ESTA PAGINA?.

En esta página encontraras un curso completo y gratuito en español del desarrollo con los microcontroladores MSP430™ de Texas Instruments ™ tanto en lenguaje C/C++ como e ensamblador, este abarcara desde la arquitectura básica, set de instrucciones, los modos de direccionamiento hasta el uso de los periféricos como los puertos de entrada y salida, el Timer_A, el Perro guardián, el sistema básico de reloj que son los que actualmente están disponibles pero pronto añadiremos mas descripciones del uso y configuración de otros periféricos.

Además como el nombre de la dirección URL lo indica (todomcu) en este sitio pretendemos con posterioridad incluir el uso y configuración de otros microcontroladores por el importante papel que desempeñan en las áreas de diseño a pequeña y gran escala, además de que contribuyen a la formación integral de un profesionista o aficionado, ya que saber utilizar solo una arquitectura de microcontroladores es reducir mucho las consideraciones de diseño.

Cabe aclarar que por el momento nos centraremos en el completar los contenidos de los MSP430™ para poder así continuar con otro tipo de microcontroladores, los próximos serán de ATMEL y posteriormente de Freescale.

ADEMAS DEL CURSO.

Como complemento a todo curso descrito en esta página tendremos a disposición de ustedes ejemplos 100% funcionales los cuales en el caso de poseer el hardware necesario los puedes probar sin falla alguna. También estará disponible el diagrama de flujo de dichos ejemplos, todo esto en C/C++ y en ASM.

Los proyectos también son de vital importancia ya que aquí es donde en verdad se pone a prueba el potencial de cada arquitectura en cuanto a desempeño y facilidad de programación, esta es ciertamente una sección en desarrollo ya que aun estamos preparando los proyectos que serán incluidos en esta sección entre los cuales esta un robot de sumo, un control de nivel de agua a través del efecto capacitivo y con posterioridad desarrollaremos un sistema operativo funcional para esta arquitectura. Todos estos proyectos serán completamente documentados, además de que su código fuente estará completamente disponible para visualización o descarga.

También disponemos de video tutoriales los cuales te enseñaran de manera muy adecuada como es que se realizan algunas configuraciones en el software de desarrollo que utilizaremos.

RETORALIMENTACION.

Ya que esta pagina surge como un servicio para los estudiantes y personas interesadas en el tema, es de vital importancia su ayuda, comentarios y criticas las cuales nos ayuden a proporcionar un servicio mas adecuado para los requerimientos personales de los visitantes, para ello ponemos a tu disposición una forma de contacto por medio de internet y otra a través de correo electrónico.

Así que esperamos tu colaboración para que nos envíes programas o proyectos los cuales hayas desarrollado y desees difundir, así como ejemplos o cualquier tipo de información que tu consideres útil para los demás. También podrás solicitar nuevos temas o arquitecturas a estudiar y publicar, así como ejemplos que desees que desarrollemos. Recuerda que tu colaboración y opinión es muy importante.

EL CURSO DE MSP430.

En esta sección tratamos de explicarte de una manera clara y entendible como es que se usan estos microcontroladores a través del uso de ejemplos los cuales están disponibles en la sección de Ejemplos en ASM o Ejemplos en C/C++.

Al concluir el curso serás capaz de crear programas en 2 lenguajes distintos (ensamblador y C/C++), sabrás como configurar la mayoría de periféricos, además de que sabrás ejecutar programas paso a paso y detectar problemas de lógica con las herramientas de Debug y Release.

CARACTERISTICAS DE LOS MSP430™.

Los microcontroladores MSP430™ tiene varias características que los hacen muy competentes a la hora de realizar aplicaciones. Hablaremos un poco de esas características a manera de introducción en esta pequeña sección.

Para empezar MSP quiere decir Mixed Signal Processor lo cual significa procesadores de señal mixta, esto nos habla micho de sus funciones, al ser una familia de microcontroladores están preparados nativamente para el uso y generación de señales de forma digital, pero también cuentan con periféricos que hacen que estos puedan trabajar con señales analógicas, esto los hace útiles para aplicaciones de control, medición y electrónica de consumo.

Estos microcontroladores son los que menos energía consumen incluso por debajo de los PIC´s esto se logra combinado de marera correcta las varias fuentes de interrupción, los periféricos independientes a la CPU y la selección correcta de las fuentes de reloj para la CPU y los periféricos.

Cuentan con una CPU RISC de 16 bits y una arquitectura Von Neuman además como ya se menciono tiene un sistema de reloj muy flexible. Esta familia esta formada por 5

generaciones las cuales en total suman mas de 200 dispositivos, cada generación ofrece diferentes niveles de integración analógica, periféricos digitales y protocolos de comunicación lo cual ayuda a los desarrolladores a solventar de la manera mas apropiada sus necesidades.

Por último la característica mas destacable es que sus herramientas son muy fáciles de usar y de bajo costo así como sus dispositivos, un ejemplo de ello es que cuentan con la plataforma de desarrollo mas barata en el mercado, estamos hablando del LaunchPad, la cual nos será de mucha utilidad a la hora de hacer nuestros desarrollos en formato DIL (Dual In Line) en una Protoboard sin necesidad de realizar circuitos impresos para su prueba de funcionalidad.

Una característica que hay que resaltar es que la mayoría de sus dispositivos son de montaje superficial lo cual nos permitirá hacer desarrollos poderosos, de menor tamaño y con un mejor atractivo visual.

A lo largo de esta web aprenderás a utilizar los periféricos mas básicos de estos microcontroladores como los puertos de entrada y salida, temporizadores, sistemas de reloj hasta los mas avanzados como los diversos tipos de convertidores, comunicaciones seriales, controlador de la FLASH, controlador de acceso directo a memoria etc.

ACERCA DE LOS PERIFERICOS.

Muy importante mencionar que la configuración y uso de los periféricos del microcontrolador se realiza a través de registros (de 8 y 16 bits) con este propósito, lo que debes de saber es la manera de configurar estos registros para obtener una función específica del periférico a configurar, para ello te daremos a conocer los registros que son involucrados en el uso y configuración de los periféricos, te mostraremos también de manera dinámica como usar estos registros para funciones especificas.

En cada capítulo buscaremos crear una aplicación útil en el mismo momento que te expliquemos el código ya que esta manera nos ha parecido la mas didáctica debido a que el momento en que aprendes aplicas el conocimiento adquirido, esto es mucho mejor que presentarte solo contenido que no tiene una aplicación práctica inmediata.

Al final de cada sección encontraras links a ejemplos que siguen esta misma dinámica, además encontraras su diagrama de flujo, la explicación de su funcionamiento, algún video o foto y el código completo listo para ser descargado o visualizado.

DESARROLLO DE APLICACIONES.

Cuando estamos dispuestos a desarrollar aplicaciones para los microcontroladores MSP430™ tendremos que hacer uso de distintas herramientas tanto de software como de hardware, en esta sección te presentaremos estas herramientas a manera introductoria para posteriormente a lo largo de los contenidos de esta página las conozcas más a fondo.

Conforme obtengamos mas herramientas de hardware y comencemos a experimentar con software nuevo (tanto propio como suministrado por Texas Instruments ™) esta sección irá creciendo. Por lo pronto comenzaremos por el Launchpad.

El objetivo de esta sección es mostrar las herramientas de desarrollo con las cuales disponemos para poder enseñarte el uso de la mayor cantidad de periféricos, así como también mostrarte las ventajas y desventajas de estas herramientas que para nosotros son importantes y pueden ayudarte a ti a tomar una buena decisión.

LAUNCHPAD

Esta es la herramienta que mas usaremos debido a su bajo costo la cual en México puede obtenerse desde los $100 a $150 aproximadamente, lo cual es mucho menos que otros programadores que proporcionan otros fabricantes.

En el caso de los PIC pueden ser programados con muy pocos componentes como en el caso de NOPP pero con este hardware "hecho en casa" solo podemos programar algunos PIC, pero no estará ni cerca de lo que el LAUNCHPAD ofrece. Ya que no es solo un programador, sino una herramienta de desarrollo muy completa.

Además de poder programar todos los dispositivos de la línea de evaluación MSP430G2xx (alrededor de 40 dispositivos) podemos correr paso a paso nuestro programa en tiempo real desde nuestra PC, consultar todos los registros e incluso modificarlos, a esto se le conoce como depurar. En forma adicional se puede establecer comunicación serial entre el dispositivo y la computadora vía USB, esto a través de un puerto COM emulado.

Con estas prestaciones podremos crear aplicaciones como esta:

http://www.youtube.com/watch?v=U0mGoRtYbyg&feature=player_embedded#!

El kit de desarrollo LAUNCHPAD contiene dos microcontroladores de la línea de evaluación, un cable USB, conectores, un oscilador de 32KHz, una guía de inicio rápido, la tarjeta de desarrollo y dos lindas etiquetas.

El microcontrolador que viene insertado en la tarjeta de desarrollo tiene un programa cargado desde fabrica, el cual es el que vimos en el video, básicamente lo que hace este programa es utilizar el sensor de temperatura que tiene integrado para generar una señal de PWM proporcional a la temperatura de su superficie y además enviar las lecturas de temperatura a la PC vía USB. Texas Instruments ™ provee también una GUI (Graphical User Interface) escrita en java para hacer lo que en el video, es decir mostrar la medición de temperatura en la PC.

En lo próximo crearemos un tutorial en el cual te mostraremos el procedimiento para probar esta aplicación. Con este programa de demostración podemos ver el potencial de este kit que a pesar de su bajo costo tiene características superiores a la de muchos disponibles en el mercado al doble de su precio.

Esta herramienta es la que mas recomendamos para comenzar a desarrollar aplicaciones con los MSP430™ ya que el microcontrolador está en formato DIP lo cual permite su fácil inserción en Protoboard, cabe aclarar que la mayoría de dispositivos MSP430™ son de montaje superficial (SMD) lo cual dificulta su desarrollo para proyectos a pequeña escala, ya hallaremos una forma de utilizar los miembros más poderosos de esta familia que se encuentran en este tipo de encapsulados.

Es precisamente esta su característica más sobresaliente (además de su precio), el formato DIP ya que hay herramientas de desarrollo con mejores prestaciones pero en formato SMD lo cual dificulta su flexibilidad a la hora de modificar el hardware disponible, con este formato DIP lo único que requerimos es sacar nuestro microcontrolador ya programado para situarlo en una Protoboard y hacer las conexiones necesarias para comenzar con nuestros proyectos.

ACERCA DEL MSP430G2231

-Cuenta con 10 entradas y salidas digitales (11 utilizando la interrupción no enmascarable)

-Puede trabajar hasta 1MHz -Convertidor Analógico-Digital de 10 bits -USI con SPI e I2C -Emulación vía Spy Bi-Wire -Timer_A con 2 módulos de captura y comparación -2Kb de memoria Flash y 128b de RAM

ACERCA DEL MSP430G2211

-Cuenta con 10 entradas y salidas digitales (11 utilizando la interrupción no enmascarable)

-Puede trabajar hasta 1MHz -Comparador analógico -Emulación vía Spy Bi-Wire -Timer_A con 2 módulos de captura y comparación -2Kb de memoria Flash y 128b de RAM

eZ430 ™

Esta es al igual que el LAUNCHPAD una herramienta de desarrollo muy completa, su costo no es tan reducido ya que ronde entre los $500 en México, lo mejor de esta herramienta de desarrollo es su atractivo visual ya que además de tener un reducido tamaño parece una memoria flash USB.

Esta herramienta consta de dos partes, una de ellas es el emulador USB y la otra de ellas es el microcontrolador a programar que en este caso es el MSP430F2013 el cual puede ser desprendido del emulador USB, podemos adaptar esta tarjeta para proporcionar una conexión fácil con una Protoboard.

Con esta herramienta de desarrollo podemos programar todos los miembros de la familia MSP430F2xx con 48 dispositivos aproximadamente vía Spy Bi-Wire. El kit que se puede obtener directamente de Texas Instruments ™ contiene una herramienta de desarrollo, una guía de inicio rápido y un CD con el software de desarrollo y la documentación necesaria para comenzar a crear aplicaciones.

La desventaja de esta herramienta es que no habilita la comunicación serial entre el microcontrolador y la PC pero fuera de esto ofrece casi las mismas prestaciones que el LaunchPad a diferencia de que los dispositivos que puede programar cuentan con mayos memoria y frecuencia de trabajo.

ACERCA DEL MSP430F2013

Este microcontrolador ofrece las mismas características de bajo consumo de los MSP430™, no es un dispositivo tan poderoso ni extenso como otros de la familia MSP430F2xx pero posee características que lo hacen muy útil.

-Cuenta con 10 entradas y salidas digitales (11 utilizando la interrupción no enmascarable)

-Puede trabajar hasta 16MHz -Convertidor Analógico-Digital de 16 bits -USI con SPI e I2C -Emulación vía Spy Bi-Wire -Timer_A con 2 módulos de captura y comparación -2Kb de memoria Flash y 128b de RAM

IAR

Esta es una herramienta de desarrollo muy importante ya que con esta escribiremos, simularemos, emularemos y depuraremos nuestros programas ya que la gran flexibilidad de este software lo permite, la versión completa de este software tiene un costo el cual desconozco pero Texas Instruments ™ en conjunto con la compañía que desarrolla este software ofrecen una versión gratuita con la cual podremos crear aplicaciones las cuales tienen un limite en el tamaño pero es suficiente para utilizar en nuestras herramientas de desarrollo que actualmente contamos como el LaunchPad y el eZ430 ™.

Con este software de desarrollo podremos editar programas tanto en C/C++ como en ensamblador y además de ello podremos mezclar ambos lenguajes para sacarle provecho a las características mas resaltables de ambos. Esto nos proporciona una mayor flexibilidad de diseño al tomar el poder de C/C++ y la eficiencia de ensamblador.

LA ARQUILECTURA

Antes de comenzar a crear aplicaciones para los MSP430™ debemos de conocer la arquitectura de su CPU para lograr un manejo mas dinámico a la hora de programar, hacer más eficientes nuestros programas y conocer nuestros límites en cuanto al hardware a utilizar. En adelante explicaremos algunas de las características con las que cuentan los MSP430™.

CARACTERISTICAS PRINCIPALES EN LA CPU

ALU de 16 bits que efectúa operaciones lógicas (AND, OR, XOR), substracciones, adiciones y comparaciones.

RISC(Reduced Instruction Set Computing) con 27 instrucciones y 7 modos de direccionamiento.

Arquitectura Ortogonal, además cualquier instrucción se puede usar con cualquier modo de direccionamiento.

Todos los registros en la CPU son completamente accesibles. Las operaciones entre registros se llevan a cabo en un ciclo. Los registros de 16 bits reducen la cantidad de veces que se accede a la memoria al

ejecutar una instrucción. El bus de direcciones de 16 bits permite el acceso y los brincos a lo largo de todo el

mapa de memoria. El generador de constantes proporciona las 6 constantes mas usadas para reducir el

tamaño del código y facilitar la programación a través de instrucciones emuladas. Transferencias de memoria a memoria sin necesidad de registros intermedios. Instrucciones y modos de direccionamiento para 8 y 16 bits (Byte y Word). 12 registros de propósito general que pueden almacenar tanto datos como

direcciones. Construida utilizando lógica estática con la cual no hay un mínimo de frecuencia de

operación, lo cual permita que la CPU pueda ser detenida.

Estas características son logradas al tomar las mejores características de la arquitectura RISC y mejorarlas. Por ejemplo los PIC´s contienen un solo registro de trabajo (W) donde se almacena un operando, el otro operando es tomado de otro registro, después se ejecuta la instrucción y el resultado se almacenado ya sea en el registro de trabajo o en el otro registro que fue usado como segundo operando, además el direccionamiento indirecto solo esta disponible para un único registro.

En el caso de los HCS12 de Freescale cuentan con un registro acumulador para almacenar datos y dos registros índices para almacenar direcciones.

Al comparar la CPU de los MSP430™ con otras CPU que pertenecen a microcontroladores podemos notar que la arquitectura de los MSP430™ nos permite una programación mas eficiente, reduce el tamaño de código que una aplicación pueda requerir, permite también realizar una función específica con menos instrucciones que en otro tipo de microcontroladores y brinda al desarrollador una flexibilidad y portabilidad que en verdad se agradece, por supuesto todo esto reduce el costo de los productos finales.

También nos hace pensar si en realidad estos microcontroladores en verdad son RISC ya que no cumplen unas cuantas características de esta filosofía ya que la longitud de las instrucciones cambia, y no todas las instrucciones se ejecutan en un ciclo de reloj ya que pueden tardar de 1 a 5 ciclos de reloj, esto hace que estos microcontroladores sean una mezcla entre las principales arquitecturas (CISC y RISC).

En este diagrama a bloques de la CPU MSP430 proporcionado por Texas Instruments ™ podemos observar los 16 registros que la conforman, así como la ALU de 16 bits la cual puede recibir sus operandos de cualquiera de los 16 registros los cuales a su vez a través del bus de direcciones y datos pueden acceder a cualquier parte de la memoria.

También podemos ver las banderas del Registro de Estado que son afectadas cuando se ejecuta una instrucción, las demás banderas en el registro de estado solo son afectadas para entrar a un modo de ahorro de energía o permitir las interrupciones enmascarables. Otro punto interesante en esta diagrama a bloques es que la ALU toma su señal de reloj desde MCLK (Ver sección SISTEMA DE RELOJ) y solamente esta.

LOS REGISTROS DE LA CPU.

La CPU cuenta en total con 16 registros, los primeros 4 cumplen con funciones especificas y sus valores tienen repercusiones inmediatas en el dispositivo, mas adelante veremos porque. Los otros 12 son como ya lo mencionamos de propósito general y pueden ser usados para contener datos y direcciones lo cual permite usarlos como variables o apuntadores ya que todos son de 16 bits. A continuación describimos cada uno de ellos:

Se encarga de apuntar a la siguiente instrucción a ejecutar. Como cada instrucción emplea un numero par de bytes (2, 4 o 6) el PC se incrementa de acuerdo a esa cantidad de bytes correspondiente. Ya que el PC solo contiene números pares el bit menos significativo de este registro siempre será cero.

Generalmente se trata de evitar la manipulación de este registro, salvo que se desee implementar un switch-case estilo C/C++ o un manipulador de interrupciones.

Como su nombre lo dice es un registro apuntador lo que quiere decir que contiene una dirección. ¿Dirección de qué? , pues la dirección de la Pila la cual es de tipo FILO (First In Last Out es decir primero en entrar último en salir) y se sitúa en la posición de la RAM que asignemos a este registro. Nos es útil para que las subrutinas e interrupciones se lleven a cabo de manera correcta, se recomienda que sea lo primero que se inicialice y que después de eso se evite su uso ya que puede provocar que el programa se descontrole. Si es completamente necesario el uso de la pila se recomienda usar una instrucción POP por cada instrucción PUSH (ver el set de instrucciones).

Todo esto quedara claro más adelante cuando comencemos con los primeros programas.

Cabe mencionar que por ejemplo en los PIC´s la pila tiene un numero de niveles fijo, en algunos casos es de 8 o mas, esto limita nuestros programas ya que no puede haber mas de cierto numero de subrutinas o interrupciones.

En este registro se hallan diversas banderas que nos informaran como su nombre lo dice del estado del microcontrolador, a pesar de que el registro es de 16 bits, solo están implementados 9 por lo que los otros 7 serán usados por el generador de constantes. En este registro se almacenan 4 banderas las cuales reflejan el estado de la ALU después de que una instrucción es ejecutada, estos son: C( Acarreo), Z(Cero), N(Negativo), V(Sobre flujo).

También contiene 4 bits más que definen el modo de operación en el que se encuentra el microcontrolador, los cuales se explican en la sección de Modos De Ahorro De Energía, por lo pronto enunciamos la función de cada uno de estos 4 bits. SCG1(Sistema generador de reloj 1), SCG0(Sistema generador de reloj 0), OSCOFF, CPUOFF.

El ultimo bit por mencionar es el de GIE (General Interrupt Eneable o Habilitar Interrupciones Globales) el cual al estar en 1 permite las interrupciones de manera global.

Muchos bits aquí mencionados se explicaran en su momento, por ahora es suficiente con entender por ejemplo los bits que por lo regular vienen en otro tipo de

microcontroladores (C, Z, N y V) los demás son solo implementados en los MSP430 y por lo tanto describiremos su uso en los periféricos a los cuales de alguna manera pertenecen.

R2 y R3.-Generador de constantes (Constant Generator).

Estos registros contienen las 6 constantes más usadas las cuales sirven para emular instrucciones, esto con el objetivo de hacer más ágil y fácil la programación, por ejemplo para incrementar se usa 1 y 2, para borrar un registro se usa 0 etc. A través de el generador de constantes se pueden obtener 24 instrucciones emuladas.

R4-R15.-Registros de propósito general (General Prupose).

Como ya se ha mencionado, estos registros pueden guardar tanto datos como direcciones ya que todos son de 16 bits. Es bueno mencionar que las operaciones entre registros son mucho más rápidas que las que tienen que acceder a la memoria (ver modos de direccionamiento). Se recomienda usar estos registros lo más posible.

En el momento de la programación se hara referencia de estos registros mediante las notaciones aquí expuestas, es decir PC,SP,SR,R4-R15.

MODOS DE DIRECCIONAMIENTO.

Los modos de direccionamiento al igual que el set de instrucciones serán empleados solo por el lenguaje ensamblador o cuando se mescle este lenguaje con C/C++, así que si solo deseas programar los MSP430™ usando C/C++ no es necesario que leas esta sección ni la de set de instrucciones.

Los modos de direccionamiento son usados para que la CPU conozca la manera en que le serán accedidos los operandos de la instrucción a ejecutar. Las instrucciones se dividen en dos grandes grupos:

Operando Simple del tipo: [instrucción] destino Doble Operando del tipo: [instrucción] fuente, destino

Los MSP430™ soportan 7 modos de direccionamiento, de los cuales solo 4 de ellos son implementados físicamente en la CPU (Registro, Indexado, Indirecto e Indirecto con autoincremento) es decir grabados en cilicio, 2 de ellos resultan de usar el PC como un registro (Simbólico e Inmediato) y el ultimo se obtiene indexando un registro cuyo valor es cero (Absoluto), es decir SR cuando se usa como Generador De Constantes.

Las instrucciones de Operando Simple pueden ser usadas con los 7 modos de direccionamiento, en el caso de las instrucciones de Doble Operando, para el caso de su operando fuente se pueden usar los 7 modos de direccionamiento, pero para el caso de el operando destino solo se pueden usar 4.

A continuación se describen los 7 modos de direccionamiento con ejemplos, una breve descripción, ya que no es el objetivo aburrir con teoría complicada acerca de los modos de direccionamiento y por ultimo una tabla con la cantidad de ciclos de reloj que se tarda en ejecutar alguna instrucción dependiendo sus modos de direccionamiento.

Modo registro. Ejemplo de Operando simple:

Registro Antes. R8=0000hInstrucción INC R8Registro Después. R8=0001h

Descripción: Dado que utilizamos la instrucción INC, lo que hace este ejemplo es incrementar en 1 el valor del registro 8 (R8).

Ejemplo de Operando doble:

Registros Antes. R4=0010h, R5=07F0hInstrucción MOV R4,R5Registro Después. R4=0010h, R5=0010h

Descripción: Ya que se usa la instrucción MOV lo que hace el ejemplo es que mueve el contenido de R4 a R5.Como podemos ver independientemente de la instrucción a usar se nota que solo se usaron registros de la CPU, de hecho este modo de direccionamiento solo se puede usar con los 16 registros de la CPU lo cual hace que este modo sea de los mas veloces y que menos espacio ocupa. Para mas instrucciones ve al set de instrucciones.

Ciclos requeridos:

Operandos Modo en el destino Instrucción Ciclos Longitud

2 Por registro Cualquiera 1 1

2 Indexado, Simbolico o Absoluto Cualquiera 4 2

1 ---------- RRA, RRC, SWPB o SXT 1 1

1 ---------- CALL o PUSH 5 1

Usos: Cuando utilizamos o accedemos un valor mas de 4 o 5 veces se recomienda cargarlo en un registro de la CPU y trabajar con este modo de direccionamiento para así reducir los tiempos de ejecución.

Modo Indexado. Sintaxis:

[instrucción] n(destino)[instrucción] n(fuente), *otro modo

Donde: [instrucción] es cualquiera en el set de instrucciones, fuente y destino son cualquier registro de la CPU, n es un numero cualquiera y *otro modo significa cualquier otro modo de direccionamiento disponible para el destino incluyendo indexado.

Ejemplo de Operando simple:

Registro Antes. R8=0300hLocación de memoria antes. 0303h=FF0Eh

Instruccion DEC 3(R8)

Registro Después. R8=0300hLocación de memoria despues. 0303h=FF0Dh

Descripción: La instrucción no altera a R8 si no que altera a la locación de memoria R8 + 3, es decir 300+3=303 que es donde se realiza el decremento ya que se utilizo la instrucción DEC.

Ejemplo de Operando doble:Registro Antes. R4=0240h, R5=A0F1hLocación de memoria antes 0245h=FFFFh y A0F7=O777h

Instrucción MOV 5(R4), 6(R5)

Registro Después. R4=0240h, R5=A0F1hLocación de memoria despues 0245h=FFFFh y A0F7=FFFFh

Descripción: Como en el caso anterior no se modifican los registros R4 ni R5 si no que se modifica el contenido de la dirección R4 +5 y R5+6 es decir (240h+5h=245h) y (A0F1h+6h=A0F7h). Así como con el modo registro, los operandos solo pueden ser registros de la CPU. Para mas instrucciones ve al set de instrucciones.

Ciclos requeridos:

Operandos Modo en el destino Instrucción Ciclos Longitud

2 Por registro Cualquiera 3 2

2 Indexado, Simbolico o Absoluto Cualquiera 6 3

1 ---------- RRA, RRC, SWPB o SXT 4 2

Operandos Modo en el destino Instrucción Ciclos Longitud

1 ---------- CALL o PUSH 5 2

Usos: Se suele usar para la búsqueda en tablas, así como para medir la distancia entre localidades de memoria, también para crear listas, apuntadores, matrices etc.

Modo simbólico. Sintaxis:

[instrucción] etiqueta1 [instrucción] etiqueta1, *otro modo

Donde: [instrucción] es cualquiera en el set de instrucciones, etiqueta1 es como su nombre lo dice una etiquete la cual contiene una dirección y *otro modo significa cualquier otro modo de direccionamiento disponible para el destino incluyendo el simbólico.

Ejemplo de Operando simple:

Locación de memoria antes ETQ1=FF0EhInstrucción CLR ETQ1Locación de memoria después ETQ1=0000h

Descripción: ETQ1 es una etiqueta que hace referencia a una localidad de memoria, en este caso borra la localidad de memoria ya que eso hace CLR.

Ejemplo de Operando doble:

Locación de memoria antes ETQ1=FEAFh y ETQ2=7421hInstrucción MOV ETQ1, ETQ2Locación de memoria después ETQ1=FEAFh y EQT2=FEAFh

Descripción: Como podemos ver el contenido de ETQ1 se mueve a ETQ2. Para mas instrucciones ve al set de instrucciones.

Ciclos requeridos:

Operandos Modo en el destino Instrucción Ciclos Longitud

2 Por registro Cualquiera 3 2

2 Indexado, Simbolico o Absoluto Cualquiera 6 3

1 ---------- RRA, RRC, SWPB o SXT 4 2

Operandos Modo en el destino Instrucción Ciclos Longitud

1 ---------- CALL o PUSH 5 2

Usos: Para acceder a cualquier locación de memoria incluida la RAM.

Modo Absoluto. Sintaxis:

[instrucción] &etiqueta1 [instrucción] &etiqueta1, *otro modo

Donde: [instrucción] es cualquiera en el set de instrucciones, etiqueta1 es una etiqueta la cual contiene una dirección , *otro modo significa cualquier otro modo de direccionamiento disponible para el destino incluido Absoluto y "&" es el que caracteriza a este modo.

Ejemplo de Operando simple:

Locación de memoria antes ETQ1=FF0EhInstrucción CLR &ETQ1Locación de memoria después ETQ1=0000h

Descripción: Como podemos ver ocurre exactamente lo mismo que con el modo simbólico esto porque la función que cumplen es la misma, lo único que cambia es como la hacen, aunque como usuarios nunca nos enteramos de la diferencia.

Ejemplo de Operando doble:

Locación de memoria antes ETQ1=FEAFh y ETQ2=7421hInstrucción MOV &ETQ1, &ETQ2Locación de memoria después ETQ1=FEAFh y EQT2=FEAFh

Descripción: Ocurre lo mismo que en el modo anterior, edemas de que estos modos cumplen la misma función además generan la misma cantidad de código.

Ciclos requeridos:

Operandos Modo en el destino Instrucción Ciclos Longitud

2 Por registro Cualquiera 3 2

2 Indexado, Simbolico o Absoluto Cualquiera 6 3

1 ---------- RRA, RRC, SWPB o SXT 4 2

Operandos Modo en el destino Instrucción Ciclos Longitud

1 ---------- CALL o PUSH 5 2

Usos: Específicamente este modo de direccionamiento lo usaremos para referirnos a los registros de función especial (SFR) y para los registros de los periféricos por ejemplo P1IN, TAR, WDTCTL, etc. para conservar la portabilidad entre dispositivos.

Modo Indirecto. Sintaxis:

[instrucción] @fuente [instrucción] @fuente, *otro modo

Donde: [instrucción] es cualquiera en el set de instrucciones, fuente es cualquier registro de la CPU, *otro modo significa cualquier otro modo de direccionamiento disponible para el destino y "@" caracteriza a este modo.

Ejemplo de Operando simple:

Registro Antes. R5=0240hLocación de memoria antes 0240h=0021h

Instrucción CLR @R8

Registro Después. R5=0240hLocación de memoriaantes 0240h=0000h

Descripción: Podemos notar que R5 no se ve afectado si no el contenido de R5

Ejemplo de Operando doble:

Registro Antes. R4=0060h, R9=1000hLocación de memoria antes 0060h=AAA0

Instrucción MOV @R4, R9

Registro Después. R4=0060h, R9=AAA0hLocación de memoria despues 0060h=AAA0

Descripción: R4 esta actuando como apuntador, lo que hace la instrucción es mover el contenido de la dirección apuntada por R4 al registro 9 (R9) esto se hace sin alterar R4. Hay que mencionar que este modo de direccionamiento es exclusivo de la fuente.

Ciclos requeridos:

Operandos Modo en el destino Instrucción Ciclos Longitud

2 Por registro Cualquiera 2 1

2 Indexado, Simbolico o Absoluto Cualquiera 5 2

1 ---------- RRA, RRC, SWPB o SXT 3 1

1 ---------- CALL o PUSH 4 1

Usos: El que realmente saca provecho de esta instruccion es el compilador de C/C++ ya que com el se pueden hacer apuntadores y arreglos, aunque nosotros lo usaremos de manera mas especifica en tablas o arreglos pero implementados en lenguaje ensamblador.

Modo indirecto con autoincremento. Sintaxis:

[instrucción] @fuente+ [instrucción] @fuente+, *otro modo

Donde: [instrucción] es cualquiera en el set de instrucciones, fuente es cualquier registro de la CPU, *otro modo significa cualquier otro modo de direccionamiento disponible para el destino y "@" junto con "+" caracterizan a este modo.

Ejemplo de Operando simple:

Registro Antes. R7=0F28hLocación de memoriaantes 0F28h=0062h

Instrucción DINC @R7+

Registro Después. R7=0F29hLocación de memoria despues 0F28h=0064h

Descripción: En este caso se usa la instrucción de doble incremento, lo cual se hace sobre el contenido de la dirección a la que apunta R7, pero aquí si se modifica el registro que usamos como apuntador, es decir R7=R7+1.

Ejemplo de Operando doble:

Registro Antes. R5=FF00h R9=00A0hLocación de memoria antes FF00h=0034h

Instrucción MOV @R5+, R9

Registro Después. R5=FF01h R9=0034h

Locación de memoria despues FF00h=0034h

Descripción: Dado que R5 actua como apuntador, lo que se modifica es R9 ya que se copia el valor apuntado por R5 a R9 y también R5 ya que se incrementa en 1. También hay que mencionar que este modo solo es para la fuente al igual que el anterior.

Ciclos requeridos:

Operandos Modo en el destino Instrucción Ciclos Longitud

2 Por registro Cualquiera 2 1

2 Indexado, Simbolico o Absoluto Cualquiera 5 2

1 ---------- RRA, RRC, SWPB o SXT 3 1

1 ---------- CALL o PUSH 4 1

Usos: Este modo es útil para recorrer tablas, para copiar o leer secciones enteras de memoria etc.

Modo Inmediato. Sintaxis:

[instrucción] #cte, *otro modo

Donde:: es cualquiera en el set de instrucciones, cte es un valor numérico constante, *otro modo significa cualquier otro modo de direccionamiento disponible para el destino y "#" caracteriza a este modo.

Ejemplo de Operando doble:

Registro Antes. R15=0FF0hInstrucción MOV #000F, R15Registro Después. R15=00Fh

Descripción: Mueve la constante 000Fh al registro 15 (R15), este modo es solo para el operando fuente.

Ciclos requeridos:

Operandos Modo en el destino Instrucción Ciclos Longitud

2 Por registro Cualquiera 2 2

2 Indexado, Simbolico o Absoluto Cualquiera 5 3

1 ---------- RRA, RRC, SWPB o SXT - -

1 ---------- CALL o PUSH 5 2

Usos: Se emplea para asignar valores constantes a registros o localidades de memoria, si esas constantes son valores especificos como 0000h,0001h,0002h,0004h,0008h, y FFFFh pueden ser generados por los registros R2 y R3 y en ese caso el modo de direccionamiento se convierte en el modo por registros.

Instrucciones Aritmeticas

Con estas instrucciones las utilizaremos para realizar operaciones tanto de forma binaria como decimal, además realizar multiplicaciones esto es útil de muchas formas, solo pretendemos darte un panorama general para que puedas llevar a cabo tus ideas de forma mas sencilla.

Suma Destino y C.- ADC Sintaxis: ADC (.B o .W) destino

Descripción: Suma el destino con la bandera de acarreo

Emulada por: ADDC (.B o .W) #0 , destino

Añadir.- ADD [0101] Sintaxis: ADD (.W o .B) fuente, destino

Descripción: El operando fuente es sumado al operando destino, el resultado es almacenado en destino.

Operación realizada: destino = destino + fuente

Banderas afectadas: Todas las banderas son afectadas normalmente.

Añadir con acarreo.- ADDC [0110] Sintaxis: ADDC (.B o .W) fuente, destino

Descripción: Se realiza la suma entre la fuente, el destino y la bandera de acarreo, el resultado se almacena en destino. Instrucción útil para realizar sumas de cifras mayores a 16 bits.

Operación realizada: destino = destino + fuente + C

Banderas afectadas: Todas las banderas son afectadas normalmente.

Suma decimal con C.- DADC Sintaxis: DADC (.B o .W) destino

Descripción: La bandera de acarreo es sumada al destino de forma decimal, es decir 9+1=10 (en hexadecimal 9+1=A como normalmente se hace)

Emulada por: DADD (.B o .W) #0 , destino

Suma en BCD.- DADD [1010] Sintaxis: DADD (.B o .W) fuente, destino

Descripción: La fuente y el acarreo son sumados en formato decimal con el destino almacenando el resultado en destino. Útil para operaciones decimales como BCD lo permite.

Operación realizada: destino = destino + fuente + C (Todo en BCD)

Banderas afectadas: Z si el resultado es 0, C si el resultado es mayor a 9999(si se usa .W) o si el resultado es mayor a 99 (si se usa .B), N toma el valor del bit mas significativo (MSB), V resulta indefinido.

Decremento.- DEC Sintaxis: DEC (.B o .W) destino

Descripción: El destino es decrementado por 1

Emulada por: SUB (.B o .W) #1 , destino

Doble Decremento.- DECD Sintaxis: DECD (.B o .W) destino

Descripción: Decrementa por dos el destino

Emulada por: SUB (.B o .W) #2 , destino

Incremento.- INC Sintaxis: INC (.B o .W) destino

Descripción: Incrementa en 1 el destino.

Emulada por: ADD (.B o .W) #1 , destino

Doble Incremento.-INCD Sintaxis: INCD (.B o .W) destino

Descripción: Incrementa por dos el destino

Emulada por: ADD (.B o .W) #2 , destino

Sustraer.- SUB [1000] Sintaxis: SUB (.B o .W) fuente, destino

Descripción: Sustrae o resta la fuente del destino, el resultado es almacenado en destino. Instrucción parecida a CMP solo que aquí los registros si son modificados.

Operación realizada: destino = destino - fuente

Banderas afectadas: Z si el resultado es cero, C si se produce un acarreo al sumar destino y el complemento a dos de la fuente, N si fuente>=destino , V si ocurre un sobre flujo aritmético.

Sustrae con acarreo.- SUBC [0111] Sintaxis: SUBC (.B o .W) fuente, destino

Descripción: Resta la fuente y el acarreo del destino, el resultado se almacena en destino. Instrucción útil para realizar restas con valores que ocupen mas de 16 bits.

Operación realizada: destino = destino - fuente -1 + C

Banderas afectadas: Z si el resultado es cero, C si se produce un acarreo al sumar destino y el complemento a dos de la fuente, N si fuente>=destino , V si ocurre un sobre flujo aritmético.

Instrucciones Logicas.

Estas instrucciones nos serán de utilidad para configurar de manera especifica ciertos módulos de algún periférico, además de ello nos serán útiles para implementar lógica binaria con cualquier dato en el sistema, bien nos podrían ser útiles para filtrados digitales, para codificación y decodificación.

Y lógica.-AND [1111] Sintaxis: AND (.W o .B) fuente destino

Descripción: Realiza la operación lógica "y" entre el operando fuente y el operando destino, esto lo usamos mara poner ciertos bits del destino a 0, bits que son seleccionados por la fuente.

Operación realizada: destino = destino & fuente

Banderas afectadas: Z si el resultado es cero, C es contraria a Z, N toma el valor del MSB (bit mas significativo) y V se pone a 0.

Borra bits seleccionados en destino.- BIC [1100] Sintaxis: BIC (.B o .W) fuente, destino

Descripción: Los bits especificados en la fuente serán borrados en el destino, esto nos es útil para modificar los SFR (Registros de Función especifica) y además los registros de los periféricos.

Operación realizada: destino= destino & (-fuente)

Banderas afectadas: Ninguna bandera afectada.

Coloca bits seleccionados en destino.- BIS [1101] Sintaxis: BIS (.B o .W) fuente, destino

Descripción: Pone a 1 los bits del destino en las posiciones que indiquen los bits de la fuente, esta instrucción la usamos para poner a 1 bits específicos en un registro cualquiera aunque la usaremos mas con los registros de los periféricos.

Operación realizada: destino=destino | fuente.

Banderas afectadas: Ninguna bandera afectada.

Comprobar bits en destino.- BIT [1011] Sintaxis: BIT (.B o .W) fuente, destino

Descripción: Sirve para saber si el o los bits especificados en fuente son 1 o 0 en destino, esta instrucción de utiliza en conjunto con los saltos condicionales para obtener sentencias de control de flujo. Cabe mencionar que la instrucción no afecta a los operandos, solo afecta a las banderas.

Operación realizada: destino & fuente

Banderas afectadas: Z si el resultado es cero, C es contraria a Z, N toma el valor del MSB (bit mas significativo) y V se pone a 0.

Negación.- INV Sintaxis: INV (.B o .W) destino

Descripción: Los bits en el destino son invertidos, es decir el destino es negado

Emulada por: XOR #0FFFFh , destino (Con .W) XOR #0FFh , destino (Con .B)

Corrimiento a la izquierda.- RLA Sintaxis: RLA (.B o .W) destino

Descripción: Realiza un corrimiento aritmético de bits a la izquierda

Emulada por: ADD (.B o .W) destino , destino

Corrimiento a la izquierda con C.- RLC Sintaxis: RLC (.B o .W) destino

Descripción: Realiza el corrimiento de bits a la izquierda a través de la bandera de acarreo

Emulada por: ADDC (.B o .W) destino , destino

Corrimiento aritmético a la derecha.- RRA [000100010] Sintaxis: RRA (.B o .W) DESTINO

Descripción: Realiza un corrimiento de bits aritmético, el MSB es conservado y el LSB es desplazado a la bandera de acarreo.

Operación realizada:

Banderas afectadas: Z si el resultado es cero, C toma el valor del LSB, N si el resultado es mayor a cero, V =0.

Corrimiento a la derecha con acarreo.- RRC [000100000] Sintaxis: RRC (.B o .W) destino

Descripción: Todos los bits en el destino son rotados hacia la derecha por una posición, el acarreo es recorrido a el MSB y el LSB es recorrido a la bandera de acarreo.

Operación realizada:

Banderas afectadas: Z si el resultado es cero, C toma el valor del LSB, N si el resultado es mayor a cero, V si destino es mayor a cero y C=1.

Intercambia Bytes.- SWPB [000100001] Sintaxis: SWPB destino

Descripción: El byte alto y el byte bajo de destino son intercambiados, el resultado es almacenado en el destino.

Operación realizada: Intercambia Bytes.

Banderas afectadas: Las banderas no son afectadas.

Extiende el signo.- SXT [000100001] Sintaxis: SXT destino

Descripción: El signo del byte bajo (bit7) es copiado en todo el byte alto (bits 8-15).

Operación realizada: bits 8-15 de destino= bit7 de destino

Banderas afectadas: Z si el resultado es 0, C es contrario a Z, N si el resultado es mayor a cero, V=0.

O exclusiva lógica.- XOR [1110] Sintaxis: XOR (.B o .W) fuente, destino

Descripción: Esta instrucción realiza la operación lógica o exclusiva (XOR) entre la fuente y el destino, esto sirve para cambiar de estado los bits en destino seleccionados por la fuente es decir si un bit es 0 lo cambiamos a 1 sin afectar el resto.

Operación realizada: destino = destino XOR fuente

Banderas afectadas: Z si el resultado es cero, C es contraria a Z, N toma el valor del MSB (bit mas significativo) y V se pone a 1 si ambos operandos son negativos (MSB=1).

Instrucciones De Datos.

Estas instrucciones nos serán útiles para la manipulación de datos en registros o bien en localidades de memoria, así como manipular de manera fácil e intuitiva las banderas del registro de estado. La manipulación de datos es de suma importancia ya que con ayuda de estas instrucciones y otras mas podremos configurar nuestros periféricos de manera deseada.

Además de ello también tendremos acceso a la pila la cual utilizaremos para resguardar la información en los registros durante una interrupción o bien para guardar copias de seguridad de datos o direcciones.

Borrar.- CLR Sintaxis: CLR (.B o .W) destino

Descripción: Borra el destino.

Emulada por: MOV (.B o .W) #0 , destino

Borra Acarreo.- CLRC Sintaxis: CLRC

Descripción: Borra la bandera de acarreo en el registro de estado (Status)

Emulada por: BIC #1 , SR

Borra Negativo.- CLRN Sintaxis: CLRN

Descripción: Borra la bandera de negativo en el registro de estado (Status)

Emulada por: BIC #4 , SR

Borra Cero CLRZ Sintaxis: CLRZ

Descripción: Borra la bandera de cero en el registro de estado (Status)

Emulada por: BIC #2 , SR

Comparar.- CMP [1001] Sintaxis: CMP (.B o .W) fuente, destino

Descripción: La fuente es restada del destino pero no altera a ninguno de los operandos, esto con el objetivo de solo modificar las banderas. Esta instrucción es usada junto con los saltos condicionales.

Operación realizada: destino - fuente

Banderas afectadas: Z si el resultado es cero, C si se produce un acarreo al sumar destino y el complemento a dos de la fuente, N si fuente>=destino , V si ocurre un sobre flujo aritmético.

Mover.- MOV [1000] Sintaxis: MOV (.B o .W) fuente, destino

Descripción: esta instrucción hace que la fuente sea copiada en el destino. Es una de las instrucciones mas útiles ya que la usaremos para asignar valores a cualquiera de los registros, conforme avancemos con los ejemplos veras lo útil que es.

Operación realizada: destino = fuente

Banderas afectadas: Ninguna bandera afectada.

Sacar elemento de la pila.- POP Sintaxis: POP (.B o .W) destino

Descripción: El valor en la cima de la pila es movido a el destino

Emulada por: MOV (.B o .W) @SP+ , destino

Almacena en la pila.- PUSH [000100100] Sintaxis: PUSH (.B o .W) fuente

Descripción: Almacena la fuente en la pila

Operación realizada: SP=SP-2 y @SP=fuente

Banderas afectadas: Las banderas no son afectadas.

Colocar C.- SETC Sintaxis: SETC

Descripción: Coloca la bandera de acarreo del registro de estado (Status) en 1

Emulada por: BIS #1 , SR

Colocar N.- SETN Sintaxis: SETN

Descripción: Coloca la bandera de negativo del registro de estado (Status) en 1

Emulada por: BIS #1 , SR

Coloca Z.- SETZ Sintaxis: SETZ

Descripción: Coloca la bandera de cero del registro de estado (Status) en 1

Emulada por: BIS #2 , SR

Prueba.- TST Sintaxis: TST (.B o .W) destino

Descripción: Comprueba el estado de el destino con respecto a cero

Emulada por: CMP (.B o .W) #0 , destino

Incremento.- INC Sintaxis: INC (.B o .W) destino

Descripción: Incrementa en 1 el destino.

Emulada por: ADD (.B o .W) #1 , destino

Decremento.- DEC Sintaxis: DEC (.B o .W) destino

Descripción: El destino es decrementado por 1

Emulada por: SUB (.B o .W) #1 , destino

Doble Incremento.-INCD Sintaxis: INCD (.B o .W) destino

Descripción: Incrementa por dos el destino

Emulada por: ADD (.B o .W) #2 , destino

Doble Decremento.- DECD Sintaxis: DECD (.B o .W) destino

Descripción: Decrementa por dos el destino

Emulada por: SUB (.B o .W) #2 , destino

Corrimiento a la izquierda.- RLA Sintaxis: RLA (.B o .W) destino

Descripción: Realiza un corrimiento aritmético de bits a la izquierda

Emulada por: ADD (.B o .W) destino , destino

Corrimiento a la izquierda con C.- RLC Sintaxis: RLC (.B o .W) destino

Descripción: Realiza el corrimiento de bits a la izquierda a través de la bandera de acarreo

Emulada por: ADDC (.B o .W) destino , destino

Suma Destino y C.- ADC Sintaxis: ADC (.B o .W) destino

Descripción: Suma el destino con la bandera de acarreo

Emulada por: ADDC (.B o .W) #0 , destino

Suma decimal con C.- DADC Sintaxis: DADC (.B o .W) destino

Descripción: La bandera de acarreo es sumada al destino de forma decimal, es decir 9+1=10 (en hexadecimal 9+1=A como normalmente se hace)

Emulada por: DADD (.B o .W) #0 , destino

Negación.- INV Sintaxis: INV (.B o .W) destino

Descripción: Los bits en el destino son invertidos, es decir el destino es negado

Emulada por: XOR #0FFFFh , destino (Con .W) XOR #0FFh , destino (Con .B)

Instrucciones De Control.

Recordando la sintaxis de varios lenguajes de programación de alto nivel utilizan cierto conjunto de instrucciones denominadas de Control de Flujo (if, else, while, do-while, shitch, foreach, etc) ya que estas logran que el programa tenga ramificaciones las cuales suceden dependiendo de ciertas condiciones.

Las instrucciones de Control de Flujo de los lenguajes son traducidas a instrucciones en lenguaje ensamblador como las que mostraremos aquí.

Estas instrucciones de Control de Flujo han demostrado ser capaces de resolver los problemas que se enfrentan a la hora de programar de una manera eficiente y sencilla. Además de esto los problemas que suelen suscitarse al implementar estas instrucciones de control son solo de lógica del programa los cuales son fáciles de resolver con tan solo cambiar las condiciones de salto, sin embargo al utilizar saltos (JMP) y brincos (BR) de manera no controlada podemos llegar a un momento en la ejecución del programa en el que este se descontrole.

Para lograr programas robustos, fáciles de mantener y extender es muy recomendable utilizar saltos condicionales los cuales solo se sucintan si cierta condición se cumple.

Brinco.- BR Sintaxis: BR destino

Descripción: Realiza un brinco incondicional a cualquier locación en la memoria

Emulada por: MOV destino , PC

Llamar subrutina.- CALL [000100101] Sintaxis: CALL destino

Descripción: Se realiza la llamada de una subrutina indicada por destino, esto alterara el flujo del programa, se recomienda el uso de subrutinas cuando una porción de código se tenga que repetir muchas veces.

Operación realizada: PUSH PC (Almacena el PC en la pila) y PC= destino (se carga el PC con la dirección de la subrutina)

Banderas afectadas: Ninguna, las banderas no son afectadas.

Inhabilita las interrupciones.- DINT Sintaxis: DINT

Descripción: No permite que las interrupciones sean generadas de manera glogal

Emulada por: BIC #8 , SR

Habilita las interrupciones.- EINT Sintaxis: EINT

Descripción: Las interrupciones serán permitidas de manera global

Emulada por: BIS #8 , SR

Salta si C.- JC [001011]

Descripción: Ocurre un salto a el destino si la bandera de acarreo es 1, de lo contrario realiza un NOP

Salta si mayor o igual.- JGE [001101]

Descripción: Ocurre un salto a destino si la bandera de sobre flujo y la de negativo tienen el mismo valor, de lo contrario realiza un NOP.

Salta si menor.- JL [001110]

Descripción: Ocurre un salto a destino si la bandera de sobre flujo y la de negativo tienen valores opuestos, de lo contrario ocurre un NOP

Salta.- JMP [001000]

Descripción: Ocurre un salto incondicional a destino

Salta si N.- JN [001100]

Descripción: Ocurre un salto a destino cuando si la bandera de negativo es 1, de lo contrario ocurre un NOP

Salta si C no es cero.- JNC [001010]

Descripción: Ocurre un salto a destino si la bandera de acarreo es cero, de lo contrario realiza un NOP

Salta si Z no es cero JNE/JNZ [001000]

Descripción: Ocurre un salto a destino si la bandera de cero es cero, de lo contrario realiza un NOP

Salta si Z.- JEQ/JZ [001001]

Descripción: Ocurre un salto a destino si la bandera de cero es 1, de lo contrario realiza un NOP

Sin operación.- NOP Sintaxis: NOP

Descripción: Consume un ciclo de reloj sin hacer nada, esta instrucción tampoco contiene fuente o destino

Emulada por: MOV #0 , R3

Regreso de Subrutina.- RET Sintaxis: RET

Descripción: Es el complemento a toda instrucción CALL, sirve para regresar de una subrutina. Como podemos notar este no tiene ningún argumento.

Emulada por: MOV @SP+ , PC

Regreso de la interrupción.- RETI [0001001100000000 completo]

Sintaxis: RETI

Descripción: Regresa el flujo del programa desde una interrupción al punto donde se genero. Para mas información consulte la sección de Interrupciones y Sub rutinas.

Operación realizada: POP SR (Saca SR de la Pila) y POP PC (Saca el PC de la pila)

Banderas afectadas: Todas, ya que son restauradas las banderas tal y como estaban antes de que sucediera la interrupción.

ORGANIZACIÓN DE LA MEMORIA

La ventaja mas critica de la estructura de la memoria es que los registros de los periféricos, así como los de las interrupciones, los de función especifica están rodos mapeados dentro de las direcciones 0x0000 hasta la 0xFFFF, esto nos da una eficiencia alta, ya que todos los registros pueden ser accesados con cualquier instrucción y modo de direccionamiento.

En el caso de los PIC´s que cuentan con dos bancos de memoria es un tanto ineficiente tener que perder un ciclo de reloj para cambiar la selección entre banco y banco, esto no ocurre con esta arquitectura.

A continuación veremos la forma en la que se organiza la memoria en estos microcontroladores, así como la función que cumple cada segmento.

REGISTROS DE FUNCION ESPECIFICA

Estos se encuentran en las primeras localidades de memoria, desde la 0x0000 a la 0x000F (16 registros), por lo regular solo los primeros 6 se usan, el primero se encarga de habilitar interrupciones, las localidades 0x002 y 0x0003 contienen banderas de interrupción, y en las ultimas dos (0x0004 y 0x0005) contienen bits que son utilizados por la USART (Universal Synchronous Asynchronous Receiver Transmitter).

Esto es claro de manera general, pero para el caso del MSP430G2231 o el MSP430F2013 solo se usan los 4 primeros registros de 8 bits, es decir el de habilitación

de interrupciones y las banderas de interrupción. A continuación se muestran esos dos registros.

Solo son presentados a manera de ejemplo ya que posteriormente utilizaremos algunos bits de estos registros para algunos periféricos. En el datasheet especifico de cada dispositivo podremos ver la configuración de estos 16 registros y la función que cumplen si es que están implementados

REGISTROS DE LOS PERIFERICOS

Todos los registros de los periféricos están mapeados en la memoria justo después de los registros de función especial, esto para facilitar el acceso a ellos. Existen dos tipos de registros de periféricos:

Los que pueden accederse con instrucciones de byte (.B) que se encuentran en 0x010 a 0x0FF.

Los que pueden accederse con instrucciones de word (.W) y se encuentran desde 0x100 a 0x1FF.

Estos se utilizan para la configuración de los periféricos como puertos de entrada y salida digital, convertidor, temporizadores, módulos de reloj básico, etc. El uso y repercusión de los valores que pueden contener estos registros se detallaran en la sección dedicada a cada periférico.

RAM

La memoria RAM comienza en la dirección 0x200 en todos los dispositivos y dependiendo de la cantidad de cantidad que tenga cada dispositivo, dependerá el lugar donde termine ya que hay modelos con 128, 256, 512, 1024, y 2048 bytes de RAM, esta nos será útil en tiempo de ejecución de los programas cargados en la memoria de programa.

La RAM se usa para guardar variables que serán utilizadas muchas veces dentro del programa, para almacenar variables globales y lo mas importante: la pila.

Hay que ser muy consientes de localizar a la pila dentro de la RAM, ya que de no ser situada en un lugar optimo, puede ocurrir que el programa se descontrole por completo, así se recomienda situar la pila después de la mitad de la RAM.

MEMORIA DE ARRANQUE

La memoria de arranque solo esta disponible en los dispositivos FLASH en las localidades que van de 0x0C00 a 0xFFF, esta sección de la memoria es la única que no se puede modificar, ya que cuenta con un cargador de arranque el cual es utilizado para programar los bloques de la memoria FLASH.

MEMORIA DE INFORMACIÓN

Al igual que el segmento anterior solo se aplica en los dispositivos con memoria flash ya que esta información es la encargada de llevar a cabo la grabación de la memoria FLASH. También contiene las constantes de calibración para el DCO (Ver sección de SISTEMA DE RELOJ)

MEMORIA DE CODIGO

La dirección de inicio de este segmento es variable ya que depende de la cantidad de memoria disponible para este objetivo. Hay dispositivos con 2,4,8,12,16,24,32,48,60 kilobytes de memoria de programa.

En este lugar se almacenara lo correspondiente a instrucciones, tablas, las constantes mas usadas, etc. El final de este segmento es constante para todos los dispositivos y termina en la dirección 0xFFDF.

VECTORES DE INTERRUPCION

Los vectores de interrupción están localizados al final de la memoria desde la localidad 0xFFE0 a 0xFFFF, estos son de vital importancia para sacar el mayor provecho a esta familia de microcontroladores, ya que como su nombre lo dice nos ayudaran con el uso de las interrupciones (Ver sección de Interrupciones).

El contenido del vector depende de los periféricos implementados en cada dispositivo, pueden ser consultados en el datasheet del dispositivo en cuestión a continuación se muestra un ejemplo del vector de interrupciones del MSP430G2231.

TIPOS DE MEMORIA

Los MSP430™ están disponibles con diferentes tipos de memoria obviamente para distintas aplicaciones comerciales, la forma de identificar que memoria posee cada dispositivo es a través de su matricula ya que la letra después de MSP430™ representa el tipo de memoria que ese dispositivo posee.

ROM

Los dispositivos de este tipo se entregan ya programados por el distribuidor, el costo de estos dispositivos es muy bajo, pero solo en grandes cantidades de producción además de que deben ser programados con código que haya comprobado su estabilidad, de lo contrario para corregir errores no detectados se debe de repetir cierta parte del diseño inicial. En la matricula se identifica con la letra "C".

OTP

Es la solución ideal a diseños en los que aun de duda de su estabilidad, además de ser muy adecuado para producciones medianas ya que aunque son un poco mas caros que los dispositivos ROM estos se pueden programar en el momento que sea necesario. En la matricula se identifica con la letra "P".

EPROM

Dispositivos que no han sido pensados para producciones a gran escala ya que su costo es en realidad muy elevado en comparación con dispositivos con otro tipo de memoria, han sido creados para etapas de diseño, para emular el funcionamiento de dispositivos ROM, estos cuentan con ventanas por las cuales el programa puede ser borrado vía luz UV. En la matricula se identifica con la letra "E".

FLASH

Este tipo de memoria puede ser borrada y reprogramada miles de veces si es necesario con lo cual se puede poner a disposición del usuario final actualizaciones de software y a pesar de que es mas cara este tipo de memorias, es mucho mas flexible En la matricula se identifica con la letra "F".

ESTRUCTURA DE UN PROGRAMA

En esta sección te mostramos la estructura de un programa escrito en lenguaje ensamblador ya que todos los programas siguen esta misma estructura. También te describiremos parte por parte los elementos que conforman a esta plantilla.

Comenzaremos por la sección de librerías y definición, en esta sección antes que nada nos servirá para incluir la librería correspondiente al dispositivo con el cual trabajaremos la cual contiene las direcciones de los Registros de Función Especifica, los Registros para la configuración de los puertos, la notación para los registros de la CPU.

Lo que sigue son las definiciones que haremos, la mas importante es la de inicioSP, además de ello se recomienda poner en este lugar otras constantes numéricas ya que desde esta parte las podemos identificar y modificar de manera muy sencilla y hacerle cambios de ultimo momento a nuestros programas con el mínimo esfuerzo.

#include "msp430g2231.h"#define inicioSP 0x240….mas definiciones útiles

Después de esta parte sigue la palabra main requerida por el IDE para un correcto funcionamiento.

A continuación están la dirección de inicio de la memoria de programa la cual inicia para nuestro caso en la dirección 0xF800, la palabra ORG la utilizamos para indicarle al compilador a partir de que dirección puede comenzar a grabar el código que hay a continuación.

ORG 0xF800 ;Inicio del programa

Después viene la declaración de la etiqueta RESET correspondiente al vector que se definirá al final del programa para la condición de RESET, después de eso se inicia la pila a la mitad de la RAM, si deseamos la podemos cambiar de posición, con solo modificar el valor de la definición de inicioSP.

RESET MOV.W #inicioSP,SP

Después de esto de apagara el perro guardián para evitar un reinicio del sistema por que se agoto la cuenta del Perro Guardián (Ver sección Perro Guardian).

MOV.W #WDTPW+WDTHOLD,&WDTCTL

A continuación podemos escribir nuestro código, se recomienda que se hagan las inicializaciones de los puertos en esta zona.

Después de el programa se sitúa la definición de las sub-rutinas y rutinas de servicio a la interrupción, continuando por la definición de las tablas y por último de los vectores de interrupción. Al final de todo esto se coloca la palabra END la cual al igual que main es necesaria para un funcionamiento optimo de IAR.

;-------------------------------------------------------------------------------; Zona de librerias y definicion de constantes;-------------------------------------------------------------------------------#include "msp430g2231.h"#define inicioSP 0x240

main ; Necesario para el buen funcionamiento de IAR

;-------------------------------------------------------------------------------

ORG 0xF800 ; Direccion de inicio del programa;-------------------------------------------------------------------------------RESET MOV.W #inicioSP,SP ; Inicialización del stackpointer

MOV.W #WDTPW+WDTHOLD,&WDTCTL ; Detener el Perro Guardian

;-------------------------------------------------------------------------------; Zona del programa principal; Añadir aqui las instrucciones que tu programa requiera

;-------------------------------------------------------------------------------;-------------------------------------------------------------------------------; Zona de declaracion de sub-rutinas y ; rutinas de servicio a la interrupcion en ese orden;-------------------------------------------------------------------------------;-------------------------------------------------------------------------------; Definicion de las tablas;-------------------------------------------------------------------------------;-------------------------------------------------------------------------------; Vectores de Interrupción y Reset;------------------------------------------------------------------------------- ORG 0xFFFE ;Vector de RESET del MSP430 DW RESET .

. . ; mas vectores para las interrupciones . . .

END

LAS SUBRUTINAS

Las subrutinas son una de las herramientas mas útiles de el lenguaje ensamblador ya que nos permiten reducir el código de un programa ya que estas las utilizaremos cuando una pequeña sección de código se tenga que repetir muchas veces, ya que en lugar de escribir toda esa sección de código en el programa principal cada vez que se use, solo la escribimos una vez y después de eso solo la mandamos a llamar con la instrucción CALL.

Una analogía con el lenguaje de alto nivel C/C++ serian las funciones, ya que estas se llaman solo cuando se necesitan y además solo se escriben una sola vez. Las funciones además alteran el flujo normal del programa principal de igual manera lo hacen las subrutinas.

El proceso que se lleva acabo cuando la CPU se encuentra con una subrutina es el siguiente:

Almacena el registro Contador de Programa (PC) en la pila. Carga en el registro Contador de Programa la dirección en donde inicia la subrutina. El código de la subrutina se ejecuta. Se saca el valor del Contador de Programa (PC) de la pila y se restablece.

Ahora veremos como es que se implementan utilizando las instrucciones correspondientes en lenguaje ensamblador, además también te haremos algunas recomendaciones para que no cometas los errores mas comunes.

La declaración de una subrutina se puede hacer en cualquier parte del programa pero te recomendamos ampliamente que la hagas justo antes de las rutinas de servicio a la interrupción, a continuación declararemos una subrutina que enciende y apaga un led 100 veces, esta subrutina tendrá en nombre de "SUB1" y el led esta ubicado en P1.0.

;-------------------------------------------------------------------------------SUB1; Prende y apaga un led en P1.0;-------------------------------------------------------------------------------

MOV #100,R15 ; Guarda en R15 el numero 100ETQ1 BIS.B #BIT0,P1OUT ; Enciende el led en P1.0

BIC.B #BIT0,P1OUT ; Apaga el led en P1.0DEC R15 ; Decrementa R15JNZ ETQ1 ; Cuando R15 sea cero continua, de lo

contrario; salta a ETQ1

RET ; Termina la subrutina y se regresa el programa a donde

; fue llamada

SUB1 es una etiqueta necesaria para llamar e identificar a la subrutina, las demás instrucciones las puedes ver en la sección de arquitectura, aunque en el código anterior se da una pequeña explicación de su funcionamiento especifico para este ejemplo.

Para llamar a esta subrutina lo único que tenemos que hacer es lo siguiente:

CALL #SUB1

Así en cualquier parte del programa podremos llamar a esta subrutina con la instrucción anterior sin necesidad de escribir de nuevo todo el código de la subrutina.

Otro punto interesante por mencionar es que una subrutina comienza con una etiqueta (en este caso SUB1) y termina con RET, si no lo hacemos así obtendremos errores o bien nuestro programa se comportara de manera impredecible y por tanto incorrecta.

ETIQUETA

CODIGO DE LA SUBRUTINA...............

RET

SUBRUTINAS DE RETARDO

Las subrutinas de retardo son una herramienta útil para diferentes aplicaciones de tiempo donde no se requiera de gran precisión como encender un led durante cierto tiempo, generar secuencias de luces, rechazo de rebotes generados pos los pulsadores.

Incluimos esta explicación en la sección de puertos digitales ya que para leer botones desde los puertos es necesario aplicar una subrutina de tiempo para evitar que el microcontrolador reaccione a los rebotes generados por la imperfección física de los pulsadores.

Como veremos en algunas aplicaciones en las que se use solo los puertos de entrada y salida es necesario el uso de subrutinas para diversos fines, en la sección de ejemplos en ASM podremos ver como es que una subrutina se implementa para diversos fines.

El principio básico de una subrutina de retardo es mantener ocupada a la CPU y que consuma tiempo ocioso de acuerdo a nuestra necesidad, claro que esto estará en una subrutina. A continuación te mostramos una forma de realizar esto en ensamblador.

;-------------------------------------------------------------------------------RETARDO; Surrituna de retardo;-------------------------------------------------------------------------------

MOV #700,R14 ; Guarda en R14 el numero 700ETIQ3 DEC R14 ; Decrementa R14

JNZ ETIQ3 ; Cuando R14 sea cero continua, de lo contrario

; salta a ETQ1RET ; Termina la subrutina y se regresa el

programa a donde ; fue llamada

Aquí como podemos ver declaramos una subrutina llamada RETARDO, lo primero que hace es cargar en el registro R15 el numero 700, después decrementa este registro hasta que sea cero y después regresa.

Para calcular el tiempo total de la subrutina recurriremos al numero de ciclos que se tarda cada una en ejecutarse.

MOV #700,R14 ; 2 ciclos en ejecutarseDEC R14 ; 2 ciclos en ejecutarseJNZ ETIQ3 ; 2 ciclos en ejecutarseRET ; 2 ciclos en ejecutarse

Crearemos una ecuación para modelar el comportamiento del tiempo de la subrutina y averiguar cuanto tiempo se tarda en ejecutar.

Tiempo = [ 2 + 100 * ( 2+2 ) + 2 ] * periodoTiempo = [ 4 + 100 * 4 ] * periodo

Donde periodo es el periodo de la frecuencia principal, como siempre trabajaremos a 1MHz entonces este siempre será de 1ms (microsegundo). Así el tiempo en ejecutarse es:

Tiempo = 404 * 1x10e-6=404us

Si queremos por ejemplo una subrutina de 1ms utilizaremos la formula siguiente:

Tiempo = [ 4 + constante * 4 ] * periodoTiempo = [ 4 + constante * 4 ] * periodoConstante = [ (tiempo/4*periodo) - 1 ]

Sustituyendo:

Constante = [ (1ms/4*1us) - 1 ] = 249

Así para lograr una subrutina que sea capaz de durar 1ms se utiliza el siguiente código:

;-------------------------------------------------------------------------------RETARDO; Surrituna de retardo;-------------------------------------------------------------------------------

MOV #249,R14 ; Guarda en R14 el numero 700ETIQ3 DEC R14 ; Decrementa R14

JNZ ETIQ3 ; Cuando R14 sea cero continua, de lo contrario

; salta a ETQ1RET ; Termina la subrutina y se regresa el

programa a donde ; fue llamada

Notemos que esta sección de programa es diferente al anterior solo por la instrucción MOV ya que en lugar de poner 100 ponemos 249.

El limite de esta subrutina es de 262.144ms ya que el valor mas grande que podemos almacenar en un registro es 65,535 y utilizando una de las formulas anteriores obtenemos este valor, para obtener valores mas grandes de tiempo utilizaremos la instrucción NOP la cual no realiza ninguna operación mas que gastar dos ciclos de reloj. A continuación mostraremos un programa para extender el tiempo que puede durar la subrutina.

;-------------------------------------------------------------------------------RETARDO; Surrituna de retardo;-------------------------------------------------------------------------------

MOV #cte,R14 ; 2 ciclos en ejecutarseETIQ3 NOP ; 2 ciclos en ejecutarse; ….. mas NOP si son necesarios

DEC R14 ; 2 ciclos en ejecutarseJNZ ETIQ3 ; 2 ciclos en ejecutarseRET ; 2 ciclos en ejecutarse

Así la formula con la cual obtendremos el tiempo máximo así como un tiempo especifico es la siguiente:

Tiempo = [ 4 + ( 4+2*n ) * constante ] * periodoDonde:Tiempo= el tiempo que durara la subrutina.Periodo= periodo del reloj principal, para nuestro caso siempre será 1us.Cte= valor a poner al inicio de la subrutina esta entre 0 y 65,535.N= numero de NOP en la subrutina.

INTERRUPCIONES

Las interrupciones son el elemento de hardware mas importante para las aplicaciones de bajo consumo de energía ya que mediante ellas es posible activar a la CPU cuando sea necesario. Es cierto que no por usarlas ya tendremos una aplicación de ultra bajo consumo ya que esto implica la combinación de diversos aspectos que esta arquitectura permite, pero nos serán de muchísima utilidad para hacer el manejo de programas mas sencillo.

El concepto de interrupción viene precisamente de la acción que realiza ya que interrumpe a la CPU en el momento que sea para realizar una subrutina. Esta es principalmente la diferencia entre una interrupción y una subrutina, la subrutina es llamada en un momento especifico que el programador define, en cambio una interrupción puede ocurrir en cualquier momento.

Hay que aclarar que las interrupciones deben de ser generadas por algún periférico ya que si estas no ocurren, la "subrutina" dedicada a la interrupción nunca se ejecutara, todos los periféricos de los MSP430™ pueden generar interrupciones hacia la CPU lo cual es una tremenda ventaja para las aplicaciones de bajo consumo.

Es en cierta manera correcto llamar subrutina a la porción de código que se ejecuta cuando es generada una interrupción pero para explicaciones posteriores serán llamadas rutinas de servicio a la interrupción (ISR por sus siglas en ingles). Existen dos tipos de interrupciones las cuales pueden ocurrir en cualquier tipo de microcontrolador y estas son las enmascarables y las no enmascarables.

INTERRUPCIONES NO ENMASCARABLES

Las interrupciones no enmascarables son generadas por periféricos de gran importancia como el controlador de la memoria FLASH, el Perro Guardián, el Sistema de Reloj, el Supervisor de Alimentación ya que este tipo de interrupción se generara sin importar el estado del bit GIE en el Registro de Estado, estas suelen tener las prioridades más altas porque se generan en las ocasiones en las cuales el sistema puede dejar de funcionar si no se hace algo al respecto, o bien el sistema dejara de funcionar después de ejecutar la ISR.

Son muy pocas las fuentes de este tipo de interrupciones pero de gran importancia ya que su debida configuración da robustez y confiabilidad al sistema desarrollado.

INTERRUPCIONES ENMASCARABLES

Las interrupciones enmascarables son las que pueden ser ignoradas si el bit llamado GIE en el Registro de Estado es cero, además cada periférico tiene la posibilidad de permitir o no las interrupciones que pudiese generar. Así para que una interrupción no enmascarable sea atendida deben de cumplirse tres condiciones:

Que la interrupción sea generada poniendo a 1 su respectiva bandera de interrupción Que la interrupción sea habilitada de manera local (Esto depende de cada periférico) Que la interrupción sea habilitada de manera global, es decir que GIE en el Registro de

Estado sea 1 lo cual se logra con la siguiente instrucción:

MOV #GIE,SR

O bien:

EINT

También hay que aclarar que las interrupciones NO SE GENERAN CON NIVELES ESTÁTICOS si en el cambio de niveles, es decir cuando se producen flancos ascendentes o descendentes. A continuación una imagen la cual muestra gráficamente estas dos condiciones y el momento en el que la interrupción es generada.

El proceso que se lleva acabo cuando la CPU es interrumpida por cualquier periférico es el siguiente:

Se termina cualquier instrucción que se este ejecutando. Contador de Programa (PC) es colocado en la pila. Se carga el contenido del Registro de Estado (SR) en la pila. Si ocurrieron múltiples interrupciones se selecciona la de mayor prioridad. La bandera de interrupción es borrada automáticamente si solo hay una bandera de

interrupción, de lo contrario debe ser borrada por software. Se borra el Registro de Estado (SR) con lo cual se termina con cualquier modo de

ahorro de energía presente. El contenido del vector de interrupciones es cargado en el Contador de Programa, así

la CPU ejecuta la rutina de servicio a la interrupción.

El proceso que ocurre al terminar la rutina de servicio a la interrupción es el siguiente:

El Registro de Estado es restablecido en su lugar surtiendo efecto en ese mismo instante.

El Contador de Programa es sacado de la pila y restablecido regresando al mismo punto donde estaba antes de la interrupción.

BANDERAS DE INTERRUPCION

Una bandera es un bit el cual indica que algo ha ocurrido o no, como las banderas del registro de estado, una de ellas es la bandera de Cero la cual es igual a 1 si el bit mas significativo de un registro (ya sea 8 o 16 bits) es 1 después de una instrucción.

Las banderas de interrupción son bits los cuales indican si se produjo o no una interrupción, estas banderas pueden estar situadas en registros de control de periféricos o bien pueden estar en registros los cuales contienen otras banderas de interrupción.

Además de indicar si existe una interrupción pendiente son útiles para saber de donde proviene la interrupción en el caso de que varias banderas estén situadas en un solo registro, también para crear una lista de espera que ejecute las de mayor prioridad en caso de que muchas interrupciones sucedan a la vez.

Otro punto importante acerca de las banderas de interrupción es que ocurre con ellas al terminar la ISR y esto depende de si son las únicas que puede generar un periférico o no.

Si un periférico puede generar solo una interrupción entonces la bandera se borrara automáticamente al terminar la ISR. Si un periférico puede generar múltiples interrupciones entonces la bandera de interrupción deberá ser borrada por software. La importancia de mencionar esto radica en que si la bandera o banderas de interrupción no son borradas entonces la CPU jamás podrá salir de la ISR.

Esto de no borrar por software las banderas de interrupción antes de salir de una ISR es un problema muy común el cual solo puede ser solucionado revisando la sintaxis del programa o bien depurando el programa a través de una simulación o emulación paso a paso cosa que te explicamos en la sección de tutoriales.

VECTOR DE INTERUPCIONES

Un vector de interrupciones es una tabla la cual se localiza al final de la memoria de programa, la cual cumple un objetivo en especifico el cual es almacenar direcciones de inicio de las rutinas de servicio a la interrupción.

Cuando sucede una interrupción como ya vimos antes la CPU recurre a este vector para saber donde se hallan las instrucciones que ejecutara como respuesta a que la interrupción fue generada. Cada periférico tiene su propio lugar en el vector de interrupciones, esto para evitar confusión de rutinas de servicio a la interrupción.

El vector mas importante es el de RESET ya que sin este el programa no funcionara, ya que la CPU no sabe que hacer en caso de RESET (Cuando se enciende por primera vez

el microcontrolador se genera una interrupción de RESET), es decir no sabe donde se haya la primera instrucción del programa principal.

Para definir un vector de interrupciones no es necesario que inicialicemos vectores de periféricos que no vamos a utilizar, si no solo definiremos los vectores correspondientes a cada periférico que utilizaremos con interrupciones.

Los vectores comienzan en la dirección 0xFFE0 de la memoria, y en todo datasheet de cada dispositivo de esta familia podemos hallar los vectores de interrupción y su correspondiente posición en la tabla, he notado que están estandarizados, es decir que son los mismos en todo dispositivo los MSP430™.

A continuación tenemos una tabla con los vectores con los que cuenta nuestro MSP430G2231 con su respectiva dirección, prioridad y periférico al que pertenece.

Para saber como utilizar los vectores utilizaremos como ejemplo el vector del primer programa para entender la definición del vector mas importante, el de RESET y conociendo esto podremos definir cualquier otro vector.

;-------------------------------------------------------------------------------; Vectores de interrupcion y reset;-------------------------------------------------------------------------------

ORG 0FFFEh ; Vector de resetDW RESETEND main

A continuación veremos como es que se define el vector RESET con ayuda de la tabla que se encuentra en el datasheet y conociendo el uso de las interrupciones en los puertos podremos configurar el vector del puerto 1 y 2.

ORG 0FFFEh ; Vector de reset

Esta instrucción define donde se comenzara a grabar en la memoria, la dirección que tiene en seguida como podemos ver en la tabla se encuentra con la prioridad mas alta y corresponde al RESET y es generada al encender el sistema, a un reset externo mediante un pulsador por ejemplo, al perro guardián, a la violación del acceso en la flash o a que el Contador de Programa salga de rango.

DW RESET

Esta instrucción significa definir palabra, y lo que hace es escribir en la memoria un numero de 16 bits, en este caso es una etiqueta llamada RESET, pero hay que recordar que las etiquetas contienen direcciones, en este casi de 16 bits y solo son usadas para hacer mas fácil la programación.

Por tanto la etiqueta RESET debe de estar junto a la primera instrucción del programa que siempre será:

MOV #midram,SP

En conjunto las dos instrucciones escriben en la dirección especificada por ORG la dirección contenida por la etiqueta después de DW.

Lo importante en saber cómo es que trabajan las interrupciones radica principalmente en que una interrupción anula cualquier modo de ahorro de energía haciendo que se ejecute la ISR con la CPU a la máxima frecuencia, al terminar la ISR se restaura el modo de ahorro de energía anterior o incluso uno diferente, esto nos ayuda a ahorrar energía ya que podemos hacer uso de la CPU cuando sea necesario. Así podremos sacarle mayor provecho a cada periférico que pueda trabajar mediante interrupciones para hacer así amigables con el medio ambiente. JA!!

TABLAS Y APUNTADORES

Otro recurso de software muy importante es el de los apuntadores ya que a través de ellos podemos acceder a gran cantidad de información a partir de solo una dirección, haciendo la analogía con C/C++ podemos implementar arreglos de información.

Las tablas nos permiten almacenar información en la FLASH junto con el programa principal en el momento de la grabación, esta información puede ser útil o no dependiendo la manera en que la implementemos, pueden ser algoritmos, secuencias para motores paso a paso, valores de una función continua, valores de una función discreta, aproximaciones para el cálculo de funciones matemáticas, posiciones de objetos etc. Todo depende de nuestro hardware conectado y además de nuestro programa.

En esta sección te enseñaremos como declarar un apuntador y asociarlo a una tabla ya que a menudo utilizaremos estos conceptos en programas de ejemplo. Además de que será de gran ayuda conocer estas herramientas.

DEFINIENDO UNA TABLA

Para esto tenemos dos opciones, una de ellas es guardar datos de 8 bits o bien de 16 bits, tu decidirás cual es la que se ajusta más a tus opciones. Para ello seguiremos la siguiente sintaxis primero para 8 bits:

ETIQ DC8 00000001b,00000010b,00000100b,00001000bFINT DC8 0

ETIQ es el nombre de la tabla y para cada tabla este debe de ser diferente, el segundo renglón llamado FINT indica que la tabla ha acabado, esto hace fácil el proceso de añadir más elementos a la tabla además de que es útil al momento de programar para detectar el fin de la tabla.

La palabra clave DC8 es la que se encarga de indicarle al compilador que los datos que están a continuación deberán guardarse en la FLASH tal como están. También podemos ver que cada elemento de la tabla es separado por una coma.

En este ejemplo los datos se ingresan de manera binaria, pero también se pueden hacer de forma hexadecimal (valor máximo 0xFF), decimal (valor máximo 255) e incluso con caracteres los cuales serán codificados en la FLASH en código ASCII. Así se pueden definir tablas de la siguiente manera:

ETIQ DC8 10,20,30,40,50,60,70,80,90,100FINT DC8 0ETIQ1 DC8 0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0x100FINT1 DC8 0ETIQ2 DC8 'HOLA MUNDO CRUEL!!'FINT2 DC8 0

La palabra reservada DC8 solo aplica a un renglón, si se nos acaba el espacio disponible en el editor de IAR entonces debemos de poner otro DC8 y continuar con la definición de la tabla. Así si queremos agregar mas elementos a la tabla llamada ETIQ haremos lo siguiente:

ETQT DC8 00000001b,00000010b,00000100b,00001000bDC8 00010000b,00100000b,01000000b,10000000b

FINT DC8 0

Para definir tablas con datos de 16 bits lo único que debemos hacer es cambiar DC8 por DC16 y entonces comenzar a definir los datos de forma binaria(no muy recomendada por la longitud de los datos al momento de la edición), decimal (valor máximo 65,535), hexadecimal (valor máximo 0xFFFF) o con caracteres de la misma forma que lo hicimos con la tabla con datos de 8 bits.

DECLARANDO UN APUNTADOR

Para crear un apuntador primero requerimos una dirección a la cual apuntara, esa dirección puede ser la de la tabla llamada Sec0 declarada a continuación:

Sec0 DC8 'Copiando letra por letra a la RAM'DC8 'Copia finalizada!!'

FIN0 DC8 0

Así para asignar un apuntador a esa tabla (arreglo de datos haciendo una analogía con C/C++) haremos la siguiente instrucción:

MOV #Sec0,R4

Recordemos que los registros de la CPU pueden ser utilizados para guardar tanto datos como direcciones, en el caso de guardar direcciones entonces serian considerados como apuntadores. Lo que estamos haciendo con esta instrucción es convertir a R4 en un registro apuntador ya que estamos copiando la dirección de la tabla llamada Sec0 en su interior.

Ahora lo que haremos es mover el contenido de la tabla a la RAM solo como ejemplo. La RAM para el MSP430G2231 inicia en la posición 0x200 así que comencemos definiendo la constante inicioRAM con un valor de 0x200 así:

#define inicioRAM 0x200

Ya que tenemos el registro el cual apunta a nuestra tabla necesitamos uno que nos indique a partir de que dirección iniciara la copia, este será R5 el cual hay que inicializar.

CLR R5

Utilizaremos la siguiente instrucción para mover el contenido de la dirección apuntada (el primer elemento de la tabla) a la primera posición de la RAM

MOV.B @R4+,inicioRAM(R5)

El apuntador R4 tiene la dirección del siguiente elemento de la tabla pero R5 tiene la misma dirección, por lo cual para hacer que apunte a la próxima posición en la RAM debemos incrementar a R5 con la siguiente instrucción:

INC R5

Si esto lo combinamos con un ciclo el cual pare hasta que se llegue al fin de la tabla entonces tendremos lo que hemos estado buscando, donde R4 apunta al dato de la tabla y R5 apunta a la dirección donde será copiado el dato. Este ciclo quedaría definido así:

ETQ0 MOV.B @R4+,inicioRAM(R5)INC R5CMP #FIN0,R4JNE ETQ0

Podemos notar que después del incremento comparamos la dirección de fin de la tabla con la dirección que contiene R4, si no son iguales significa que aun no se ha finalizado la copia de la tabla, cuando la dirección del fin de la tabla sea igual a la dirección contenida por R4 significara que se ha concluido la transferencia.

Veras que esto de los apuntadores y las tablas nos será de gran utilidad, además con este programa podemos copiar cualquier posición de la memoria a la RAM lo cual será útil cuando escribamos en la FLASH o bien para implementar un administrador de memoria en un sistema operativo o para que tu apliques tus propias variaciones para tus aplicaciones.

CORRIMIENTOS A LA IZQUIERDA

Los corrimientos son importantes para crear algoritmos útiles, entre sus aplicaciones mas destacadas están las de multiplicación, división, registros de corrimiento para comunicaciones seriales, secuencias de multiplexaje y otras más que puedes descubrir a medida que desarrollas aplicaciones.

En esta sección haremos introducción a el concepto de los corrimientos, así como también te enseñaremos la flexibilidad de esta arquitectura para extender el tamaño de sus operandos. Esta arquitectura tiene 4 tipos de corrimientos en sus set de instrucciones, ya sean emuladas o no, de estas cuatro dos son para realizar corrimientos a la izquierda y dos mas para realizar corrimientos a la derecha.

Comenzaremos con los corrimientos a la izquierda, el set de instrucciones de los MSP430™ cuenta como acabamos de mencionar con dos instrucciones con las cuales se pueden realizar corrimientos hacia la izquierda, estas son las siguientes:

RLA(.B) dstRLC(.B) dst

La primera es el corrimiento aritmético el cual coloca un cero en la posición cero del registro de destino, después el bit que antes estaba en la posición 0 pasa a la posición 1, el bit que estaba en la posición 1 pasa a la posición 2 y así hasta que el bit en la posición numero 15 pasa a la bandera de acarreo. La imagen siguiente ejemplifica el proceso de manera grafica.

Esto si se realiza la instrucción con 16 bits, es decir sin el modificador .B si elegimos realizar esta instrucción con solo 8 bits entonces ignoraremos los 8 bits mas altos así:

Se le conoce como corrimiento aritmético debido a que esta instrucción realiza una multiplicación aritmética dst x 2. Para demostrar esto un ejemplo.

Suponiendo que en el registro R15 de la CPU tenemos el siguiente valor binario: 0011011100101101, el cual tiene el valor decimal de 14125, al realizar la siguiente instrucción:

RLA R15

El valor en R15 es 0110111001011010 el cual tiene un valor binario de 28250 el cual como podemos notar es el numero contenido en R15 de manera inicial multiplicado por dos. Ademas de esto si realizamos esta instrucción ya sea 16 (sin el modificador .B) u 8 veces(con el modificador .B) entonces nuestro registro se encontrara vacio.

La otra instrucción de corrimiento a la izquierda es RLC la diferencia principal entre esta instrucción y la vista anteriormente es que en lugar de añadir un cero en el bit 0 se añade el contenido del acarreo. A continuación mostramos el proceso para ambas versiones de esta instrucción.

Para 8 bits.

Esta instrucción sirve como complemento a la primera ya que en la primera el máximo de bits con los cuales se puede realizar un corrimiento es 16, pero utilizando dos registros podemos hacer un corrimiento con un numero de 32 bits con solo combinar estas dos instrucciones de la siguiente manera:

RLA R14RLC R15

Con lo que gráficamente obtendríamos lo siguiente:

Como podemos ver el acarreo que genera el bit 15 es rescatado por la segunda instrucción la cual en lugar de introducir un cero, introduce el valor del acarreo. De esta manera podemos incrementar la longitud del corrimiento hasta el valor que deseemos o que requiramos, por ultimo veremos que para un corrimiento de 64 bits lo único que debemos hacer es añadir dos instrucciones RLC mas.

RLA R12RLC R13RLC R14RLC R15

El resultado estará contenido entonces por 4 registros de 16 bits los cuales para este caso han sido R12,R13,R14 Y R15 como veremos en secciones posteriores esto puede ser útil para realizar operaciones con más de 16 bits e incluso para operaciones con números menores a 16 bits.

CORRIMIENTOS A LA DERECHA

En principio este tipo de corrimientos son muy parecidos a los mostrados anteriormente, es decir en lugar de desplazar los bits a la izquierda los desplazan a la derecha.

Las dos instrucciones correspondientes para realizar este tipo de corrimientos son RRA y RRC, la sintaxis es la misma que para los corrimientos hacia la izquierda, en realizad tienen funciones simétricas a excepción de RRA la cual actúa de la siguiente manera:

Como podemos ver el bit 15 permanece sin cambio, pero en la posición 14 se copia el valor del bit 15, esto para conservar el signo, así en lugar de realizar una multiplicación por 2 binaria realiza la división entre 2.

Esto no es en realidad cierto si el bit mas significativo es 1, ya que este bit representa el signo de un numero por ejemplo en el caso de 1000100101101001 puede ser interpretado como 35177 en decimal o bien como -33129 por lo cual si aplicamos un corrimiento de este tipo obtendremos el siguiente numero: 1100010010110100 el cual puede ser interpretado como 50356 en decimal o bien como -17588 el cual es el primer numero dividido entre -2, para realizar una división entre 2 con 16 bits recomendamos la otra instrucción de corrimiento la cual presentaremos a continuación o bien después de ejecutar esta instrucción verificar si la bandera N fue colocada, si este es el caso aplicaremos la siguiente instrucción:

BIC #80h,dst

Donde dst es el registro o localidad de memoria donde fue ejecutada la instrucción RRA previamente, esta instrucción borra el bit mas significativo del registro o localidad de memoria de 16 bits. Esto también puede ser interpretado como quita el signo.

Para la versión a 8 bits de la instrucción a través del modificador (.B) obtenemos el mismo resultado.

El set de instrucciones incluye de igual manera una instrucción de corrimiento a la derecha con acarreo, esta nos es útil para realizar divisiones entre dos sin necesidad de verificar si el resultado es positivo o negativo. A continuación una imagen.

Para 8 bits.

Como podemos ver esta instrucción es igual a RLC solo que los bits cambian de posición en sentido contrario, es decir hacia le derecha en lugar de a la izquierda, también se pueden combinar las dos instrucciones para poder realizar corrimientos a la derecha de 16, 36, 64 bits y hasta mas, dependiendo de nuestras necesidades.

SUMA Y RESTA A 32 BITS

En esta sección solo te demostramos como realizar sumas y restas con operandos de mas de 16 bits de longitud si es que algún día lo requieres, además es útil para demostrar la flexibilidad que nos brinda el set de instrucciones. Utilizaremos 6 identificadores para esta sección los cuales al final asignaremos a registros de la CPU mediante las directivas define.

Dos identificadores serán para almacenar el primer operando de 32 bits, estos son OP1L y OP2H. Otros dos serán para almacenar el segundo operando de 32 bits y estos son OP2L y OP2H, además de almacenar el segundo operando estos identificadores almacenaran el resultado una ves que se ejecute la suma.

Comenzaremos entonces por realizar sumas de 32 bits con el uso de solo dos instrucciones:

ADD OP1L,OP2LADDC OP1H,OP2H

La primera instrucción suma la parte baja de ambos operandos y guarda el resultado en OP2L, si se genera un acarreo en esta suma entonces a través de la siguiente instrucción consideraremos este acarreo para obtener un resultado correcto ya que ADDC suma los

dos operandos junto con el acarreo y el resultado es almacenado en OP2H, así el resultado de la suma se encontrara en OP2L y OP2H.

Para realizar una resta de 32 bits utilizaremos los mismos identificadores de manera que las instrucciones que realizan una resta de 32 bits son las siguientes:

SUB OP1L,OP2LSUBC OP1H,OP2H

Como podemos notar solo sustituimos la instrucción ADD por SUB y la instrucción ADDC por SUBC, el resultado es almacenado en OP2L y OP2H.

SUMA Y RESTA A 64 BITS

Para guardar un números de 64 bits requerimos 4 registros de 16 bits por lo que para realizar tanto sumas como restas con números de 64 bits requerimos 8 registros en total.

Para ello utilizaremos identificadores como en la sección anterior, para almacenar el operando 1 utilizaremos OP1_0, OP1_1, OP1_2 y OP1_3, para el operando 2 y resultado utilizaremos los siguientes OP2_0, OP2_1, OP2_2 u OP2_3.

Ya definidos los identificadores veremos que realizar una suma o resta de 64 bits es mas sencillo de lo que parece. A continuación el código necesario para ejecutar la suma:

ADD OP1_0,OP2_0ADDC OP1_1,OP2_1ADDC OP1_2,OP2_2ADDC OP1_3,OP2_3

Así si entre cada 16 bits se genera un acarreo este será considerado por la instrucción ADDC ya que esta suma ambos operandos junto con el acarreo para depositar el resultado en el Segundo operando.

La resta como en el caso de 32 bits se hace solo sustituyendo instrucciones ADD por SUB e instrucciones ADDC por SUBC para obtener lo siguiente:

SUB OP1_0,OP2_0SUBC OP1_1,OP2_1SUBC OP1_2,OP2_2SUBC OP1_3,OP2_3

Como podemos ver es fácil implementar sumas, restas y corrimientos con valores mayores a los 16 bits esto gracias al set de instrucciones que proporciona soluciones fáciles a problemas fáciles.

PROGRAMA DE APLICACIÓN

Realizaremos un programa el cual realice sumas y restas tanto con 32 como 64 bits para demostrar el uso de estas subrutinas, además como extra de la sección mostraremos un

video donde te enseñamos a verificar tus algoritmos mediante el uso de IAR Embedded Workbench® a través de la herramienta de simulación que este IDE contiene.

A continuación te mostramos el código que hemos desarrollado para esta sección.

01|#include "msp430f2013.h"02|03|#define inicioSP 027Fh // Locacion en la RAM para la pila04|// Operando 1:05|// |Parte3||Parte2||Parte1||Parte0|06|#define OP1_0 R8 // Operando 1 parte 007|#define OP1_1 R9 // Operando 1 parte 108|#define OP1_2 R10 // Operando 1 parte 209|#define OP1_3 R11 // Operando 1 parte 310|// Operando 2:11|// |Parte3||Parte2||Parte1||Parte0|12|#define OP2_0 R12 // Operando 2 parte 013|#define OP2_1 R13 // Operando 2 parte 114|#define OP2_2 R14 // Operando 2 parte 215|#define OP2_3 R15 // Operando 2 parte 316|17|main18|19|;-------------------------------------------------------------------------------20| ORG 0xF800 ; Direccion de inicio del programa21|;-------------------------------------------------------------------------------22|RESET MOV #inicioSP,SP ; Inicio de la pila23| MOV #WDTPW+WDTHOLD,WDTCTL ; Apaga el perro guardian24|25|;**************************** Operaciones con 32 bits***************************26|27| MOV #0xAF70,OP1_0 ; El numero 0x11FAAF70 (301641584 decimal)28| MOV #0x11FA,OP1_1 ; es colocado en OP1_0 y OP1_129| MOV #0x00FA,OP2_0 ; El numero 0x1A0F00FA (437190906 decimal)30| MOV #0x1A0F,OP2_1 ; es colocado en OP2_0 y OP2_131| CALL #SUMA32 ; Se realiza la suma de estos dos numeros, el32| ; resultado 0x2C09B06A (738832490) se almacena33| ; en OP2_0 y OP2_134|35| MOV #0xAF70,OP1_0 ; Se carga en OP1_0 y OP1_1 el mismo valor para36| MOV #0x11FA,OP1_1 ; obtener los valores iniciales37| CALL #RESTA32 ; Se realiza la resta como resultado obtenemos38| ; 0x1A0F00FA (437190906 decimal)39|40|;**************************** Operaciones con 64 bits***************************41|42| MOV #0xAF70,OP1_0 ; Cargamos en el operando 1 0x4000B00111FAAF70

43| MOV #0x11FA,OP1_1 ; (4611879537070485360 en decimal) en los cuatro44| MOV #0xB001,OP1_2 ; registros correspondientes45| MOV #0x4000,OP1_346|47| MOV #0x00FA,OP2_0 ; Cargamos en el operando 2 0x500O21321A0F00FA48| MOV #0x1A0F,OP2_1 ; (360324469258911994 en decimal) en los cuatro49| MOV #0x2132,OP2_2 ; registros correspondiente50| MOV #0x5000,OP2_351| CALL #SUMA64 ; Al sumar obtenemos 0x4500D1332C09B06A52| ; (4972204006329397354 en decimal)53|54| MOV #0x00FA,OP2_0 ; Cargamos el operando 1 con los valores que55| MOV #0x1A0F,OP2_1 ; tenia desde el principio para que al realizar56| MOV #0x2132,OP2_2 ; la suma obtengamos en el operando 2 lo que57| MOV #0x500,OP2_3 ; teniamos antes de realizar la suma 58| CALL #RESTA64 ; es decir: 0x500O21321A0F00FA59| ; (4611879537070485360 en decimal)60|61|62| BIS #CPUOFF,SR63| NOP64|;-------------------------------------------------------------------------------65|; Suma Con Operandos De 32 bits66|;-------------------------------------------------------------------------------67|SUMA32 ADD OP1_0,OP2_068| ADDC OP1_1,OP2_169| RET70|71|;-------------------------------------------------------------------------------72|; Resta Con Operandos De 32 bits73|;-------------------------------------------------------------------------------74|RESTA32 SUB OP1_0,OP2_075| SUBC OP1_1,OP2_176| RET77|78|;-------------------------------------------------------------------------------79|; Suma Con Operandos De 64 bits80|;-------------------------------------------------------------------------------81|SUMA64 ADD OP1_0,OP2_082| ADDC OP1_1,OP2_183| ADDC OP1_2,OP2_284| ADDC OP1_3,OP2_385| RET86|87|;-------------------------------------------------------------------------------88|; Resta Con Operandos De 64 bits89|;-------------------------------------------------------------------------------

90|RESTA64 SUB OP1_0,OP2_091| SUBC OP1_1,OP2_192| SUBC OP1_2,OP2_293| SUBC OP1_3,OP2_394| RET95|96|;-------------------------------------------------------------------------------97|; Vectores de Interrupción y Reset98|;-------------------------------------------------------------------------------99| ORG 0xFFFE ; Vector para el RESET100| DW RESET ; Etiqueta correspondiente101|102| END

Primero debemos acordar algunas definiciones para hacer mas clara la programación y la legibilidad, es decir definir que registros de la CPU formaran parte del operando 1 y que registros forman parte del operando 2 para operaciones a 32 y 64 bits.

Para ello en las líneas 6-9 vemos que asignamos de la siguiente manera los registros que forman parte del operando 1, OP1_0 a R8, OP1_1 a R9, OP1_2 a R10 y OP1_3 a R11 de igual forma para el operando 2 definimos OP2_0 a R12, OP2_1 a R13, OP2_2 a R14 y por ultimo OP2_3 aR15.

Podemos ver también que las instrucciones vistas en secciones anteriores fueron convertidas en subrutinas con nombres muy representativos. En las líneas 67-69 se encuentra la subrutina que realiza una suma a 32 bits, en las líneas 74-76 se encuentra la resta a 32 bits, en las líneas 81-85 esta la suma a 64 bits y por ultimo en las líneas 90-94 se encuentra la resta a 64 bits.

El programa principal el cual utilizara estas subrutinas está definido desde la línea 22 hasta la 63, antes de mandar a llamar a cada subrutina cargamos valores tanto en el operando 1 como en el operando 2 a través de instrucciones MOV.

A continuación te mostramos un video en el cual realizamos la simulación mediante IAR para verificar que realmente el programa hace lo que debe. Como estas subrutinas son elementos puramente de software no podemos armar un circuito y comprobar que todo va bien, si no que debemos de simular a la CPU.

Obtener codigo fuente

MULTIPLICACION DE 16X16 BITS

Las practicas de la sección de arquitectura te introduciremos al uso de algunos algoritmos útiles para la realización de otras aplicaciones o programas más complejos, te presentamos los algoritmos a manera de apoyo para que refuerces tus conocimientos, así como para que puedas adaptarlos a tus aplicaciones si así lo ameritan.

En esta página en especifico realizaremos la multiplicación de dos números de 16 bits sin signo, esto a manera introductoria para los demás algoritmos de multiplicación que continúan.

Antes de comenzar con el desarrollo de este programa hay que mencionar que una multiplicación binaria se realiza de igual forma que una multiplicación decimal. Para entender mejor el algoritmo realizaremos un ejemplo en el cual multiplicaremos de forma binaria los números 1011010111010011 y 1101100.

Primero hay que ordenar de cierta manera a los dos operandos, nosotros los hemos ordenado de esta manera ya que así el algoritmo es más corto pero recordemos que en la multiplicaciones el orden de los factores no altera el producto. Después de eso lo que haremos es recorrer el operando 1 que se encuentra en la parte inferior bit a bit.

Comenzando por el bit menos significativo del operando 1 remarcado en azul multiplicaremos este bit por el operando 2 y lo pondremos como resultado.

Ahora haremos lo mismo con el segundo bit, el cual para este caso es cero por lo cual obtendremos lo siguiente:

El procedimiento continua así hasta terminar con el bit mas significativo del operando 1

Ya que hayamos terminado de recorrer todos los bits del operando 1 entonces estaremos listos para realizar la suma que nos llevara a obtener el resultado correcto.

De esta manera es como se realiza la multiplicación binaria, al analizar el algoritmo descrito podemos notar algunos aspectos los cuales nos serán útiles al momento de realizar el algoritmos correspondiente. Esos aspectos se mencionan a continuación.

1.-En cada iteración se realiza un corrimiento a la izquierda. 2.-El bit del operando 1 que ya fue utilizado jamás en el proceso vuelve a ser utilizado.

Tomando esto en cuenta podemos realizar el algoritmo de la siguiente manera:

El primer bit es cero por lo cual haremos un corrimiento a la izquierda en el operando 2 y un corrimiento a la derecha en el operando 1

Como podemos notar en verde añadimos un cero como resultado del corrimiento a la izquierda en el operando 2, pero en el operando 1 eliminamos el cero que comprobamos, como ese bit era cero el resultado permanece en ceros. Ahora como el siguiente bit a comprobar también es cero haremos lo mismo, es decir un corrimiento a la izquierda al operando 2 y un corrimiento a la derecha en el operando 1.

Como podemos ver el resultado continua en ceros, esto debido a que los bits que hasta ahora hemos comprobado han sido cero, pero ahora vemos que es lo que ocurre cuando el bit a comprobar es un 1.

Primero sumamos el operando 2 a resultado.

Después hacemos lo mismo que cuando encontramos un cero, es decir realizar un corrimiento a la izquierda en operando 2 y uno a la derecha en operando 1. Esta es una forma distinta de ver el proceso de la multiplicación la cual nos será más útil.

DESARROLLO DE LA SUBRUTINA

Primero definiremos los registros con los cuales trabajaremos para realizar la multiplicación.

Como registro donde guardaremos al primer operando esta R5 al cual definiremos de la siguiente manera para escribir OP1 a lo largo del programa y no R5

#define OP1 R5

Para el segundo operando requerimos dos registros ya que con los corrimientos, en un caso extremo puede llegar a tener el doble de la longitud. Por lo cual definiremos a R6 y R7 como OP2L (parte baja "low") y OP2H (parte alta "high")

#define OP2L R6#define OP2H R7

El resultado en varios casos puede resultar ser mayor a 16 bits por lo cual también estará formado por dos registros, es decir R8 y R9 por lo que los definiremos como RESL y RESH respectivamente con las siguientes directivas del preprocesador.

#define RESL R8#define RESH R9

Como resultado del análisis hemos desarrollado un diagrama de flujo el cual explica de manera grafica el algoritmo el cual hay que seguir para obtener la multiplicación. El diagrama lo mostramos a continuación.

Ya realizadas las definiciones correspondientes comenzaremos a traducir nuestro algoritmo en instrucciones que la CPU pueda interpretar. Este algoritmo estará en una subrutina la cual podremos llamar con la instrucción CALL, al final crearemos un programa que implemente esta subrutina. Primero debemos borrar o inicializar los registros que utilizaremos, es decir RESL, RESH y OP2, los demás registros no son borrados ya que antes de llamar a la subrutina debemos de cargarlos con los operandos correspondientes.

MULT CLR RESLCLR RESHCLR OP2H

Como podemos notar además de borrar los registros declaramos la etiqueta llamada MULT la cual nos servirá cuando empleemos la instrucción CALL.

Comprobaremos el valor del bit menos con la instrucción BIT la cual realiza una operación and entre la fuente y el destino sin modificar los valores, esto para únicamente alterar las banderas. Esta instrucción la utilizaremos en conjunto con un salto condicional JZ el cual se efectuara si al bit menos significativo es 0, de lo contrario (que sea 1) no se ejecuta el salto y el programa continua ejecutando la siguiente instrucción. A continuación mostramos las instrucciones que harán lo antes mencionado.

ET_02 BIT #1,OP1JZ ET_01

Auxiliándonos del diagrama de flujo podemos ver que si el bit es uno entonces debemos añadir el operando 2 al resultado, de lo contrario solo ejecutaremos los corrimientos correspondientes, además de que en cualquier caso los corrimientos se llevaran a cabo.

Así si el bit menos significativo es 1 la CPU no ejecuta el salto por lo tanto a continuación de las instrucciones anteriores debemos colocar las instrucciones correspondientes para llevar a cabo la suma del operando 2 con el resultado así:

ET_02 BIT #1,OP1JZ ET_01ADD OP2L,RESLADDC OP2H,RESH

Si el bit es cero entonces se ejecuta el salto y los corrimientos se llevan a cabo por lo cual completaremos la rutina de la siguiente manera:

MULT CLR RESLCLR RESHCLR OP2H

ET_02 BIT #1,OP1JZ ET_01ADD OP2L,RESLADDC OP2H,RESH

ET_01 RLA OP2LRLC OP2HRRC OP1JNZ ET_02RET

Esta es la forma final de la subrutina donde podemos ver las etiquetas para los saltos condicionales, además los corrimientos tanto del operando 2 (dos instrucciones ya que es de 32 bits de largo) como del operando 1 (hacia la derecha).

Por ultimo vemos que después del corrimiento del operando 1 encontramos otro salto condicional el cual nos ayudara a saber cuando debe terminar la subrutina. Esta terminara cuando el operando 1 haya sido desplazado completamente hasta estar vacio, lo cual ocurrirá en el caso extremo a las 16 iteraciones. Para nuestro ejemplo solo serán 7 veces.

EL PROGRAMA DE APLICACIÓN

Como podemos ver esta subrutina altera nuestros operandos después de que la multiplicación se llevo a cabo, por lo regular el operando dos es muy diferente al introducido inicialmente y el operando 1 termina siendo cero, así que tomando esto en cuenta crearemos un programa el cual a partir de un valor inicial y un incremento generara el cuadrado de cada valor en la serie colocándolo en la RAM, por ejemplo si ponemos como valor inicial a 1 y un incremento de 1 obtendremos 1, 4 ,9 , 16, 25, 36 y así en lo sucesivo.

Para comprender mejor el proceso que llevara a cabo nuestro programa te mostramos a continuación su diagrama de flujo.

A continuación mostramos el programa completo con la descripción correspondiente.

01|#include "msp430f2013.h"02|03|#define inicioSP 027Fh // Locacion en la RAM para la pila04|#define inicioRAM 200h // Lugar de inicio de la RAM

05|#define finRAM 270h // Lugar donde termina la RAM06|07|#define TEST R4 // Registro para la posicion08|#define OP1 R5 // Primer operando de 16 bits09|#define OP2L R6 // Segundo operando de 16 bits10|#define OP2H R7 // Parte alta del segundo operando11|#define RESL R8 // Resultado parte baja12|#define RESH R9 // Resultado parte alta13|14|#define valinicial 0FFh // Valor inicial para la serie15|#define incremento 0Ah // Incremento entre cada valor16|17|main18|19|;-------------------------------------------------------------------------------20| ORG 0xF800 ; Direccion de inicio del programa21|;-------------------------------------------------------------------------------22|RESET MOV #inicioSP,SP ; Inicio de la pila23| MOV #WDTPW+WDTHOLD,WDTCTL ; Apaga el perro guardian24|25| CLR R15 ; Inicializa el indice a cero26| MOV #valinicial,OP1; Primer operando27|CUAD MOV OP1,OP2L ; Segundo operando = Primer operando28| PUSH OP1 ; Guarda una copia del OP1 en la pila29| CALL #MULT ; Llamada a la rutina de multiplicacion30| POP OP1 ; Recupera la copia de OP131| ADD #incremento,OP1; Añade el incremento a OP132|33| MOV RESL,inicioRAM(R15) ; Resultado parte baja a la RAM34| INCD R15 ; Siquiente localidad de la RAM35| MOV RESH,inicioRAM(R15) ; Resultado parte altaa la RAM36| INCD R15 ; Siquiente localidad de la RAM37|38| CMP #finRAM-inicioRAM,R15 ; ¿Se ha terminado de llenar la RAM?39| JNZ CUAD40|41| BIS #CPUOFF,SR42| NOP43|;-------------------------------------------------------------------------------44|; Rutina que realiza la multiplicacion45|;-------------------------------------------------------------------------------46|MULT CLR RESL ; Borrar el registro de resultado parte baja47| CLR RESH ; Borrar el registro de resultado parte alta48| CLR OP2H ; Borrar la parte alta del operando49|ET_02 BIT #1,OP1 ; ¿Es 1 o 0 el bit menos significativo?50| JZ ET_01 ; Si es cero continua en ET_01

51| ADD OP2L,RESL ; Suma el operando 2 a resultado52| ADDC OP2H,RESH ; tanto parte baja como parte alta53|ET_01 RLA OP2L ; Realizar corrimiento para la siguiente54| RLC OP2H ; iteracion55| RRC OP1 ; Corrimiento a la derecha para el bit siguiente56| JNZ ET_02 ; ¿Termino?57| RET58|59|;-------------------------------------------------------------------------------60|; Vectores de Interrupción y Reset61|;-------------------------------------------------------------------------------62| ORG 0xFFFE ; Vector para el RESET63| DW RESET ; Etiqueta correspondiente64|65| END

Podemos ver que se han definido los valores inicioRAM y finRAM en las líneas 4 y5 los cuales indicaran a nuestro programa a partir de donde podrán iniciar a escribir la información y cuando deberán detenerse.

Después en el mismo bloque de definiciones se encuentran los identificadores correspondientes para realizar la multiplicación los cuales ya conocemos (líneas 7-12). Adicionalmente definimos las constantes que nos permitirán controlar la serie de números a los cuales obtendremos su cuadrado, es decir un valor inicial y un incremento.

Posteriormente se encuentran las partes indispensables de un programa las cuales ya conocemos y son la palabra main, la dirección de inicio de programa (ORG 0xF800 ), la etiqueta de RESET junto con las instrucciones para asignar a la pila en la RAM y apagar el perro guardián en las líneas 20-23.

Ahora vemos que en la línea 25 borramos el contenido de R15, esto porque lo utilizaremos como índice para poder grabar los resultados en la RAM de manera correcta y ordenada.

Como nuestra subrutina realiza la multiplicación de dos números, entonces requiere de dos parámetros, es decir OP1 y OP2L, pero como el programa que estamos desarrollando obtiene el cuadrado de una serie de números entonces utilizaremos la subrutina de multiplicación para este objetivo colocando tanto en OP1 como en OP2L el mismo número así que primero cargamos a OP1 con el valor inicial en la línea 26 y después copiamos OP1 en OP2L en las líneas 27 y 28.

Como mencionamos anteriormente la subrutina que realiza la multiplicación altera nuestros operandos (que en este caso son iguales) por lo cual debemos de respaldarlos, ya que son iguales basta con respaldar a OP1, una manera rápida de realizar esta acción es colocar a OP1 en la pila con la instrucción PUSH que vemos en la línea 28, después llamamos a la subrutina MULT lo cual altera a ambos operandos (OP1 se hace cero y OP2L termina con un valor impredecible) pero a través de la operación POP OP1 en la línea 30 logramos recuperar el valor de OP1.

Como podemos ver utilizamos una instrucción POP por cada instrucción PUSH como recomendamos cuando se realiza cualquier manipulación de la pila. Si posteriormente utilizamos este programa en otra aplicación y en esta aplicación utilizamos interrupciones debemos tener en cuenta que si nuestra ISR utiliza a la pila, entonces debemos seguir esta misma recomendación, es decir por cada instrucción POP utilizar una instrucción PUSH, ya que de lo contrario puede ocurrir que el flujo del programa sea impredecible entrando este en descontrol.

Ya que se recupero el valor de OP1 entonces le sumamos el incremento en la línea 31, así se preparan las condiciones para la próxima iteración.

Por último antes de repetir el mismo proceso para el siguiente valor, debemos de enviar los resultados a la RAM, esto porque es parte del objetivo del programa, lo cual hacemos con las líneas 33-36 donde utilizamos el registro índice para indicar cuantas posiciones a partir del inicio de la RAM se guardara la información, utilizamos incrementos dobles en el registro índice R15 ya que cada localidad de la RAM es de 8 bites por lo cual para apuntar a la próxima palabra (word) debemos de incrementar el índice en 2. Cuando se realiza la multiplicación de 8 bits veremos que solo se requiere incrementar el índice en 1.

Ya que se realizo la multiplicación y además se enviaron los resultados a la RAM solo queda verificar si es que ya se ha llegado al límite de la RAM para entonces terminar las iteraciones, de lo contrario seguir con el siguiente valor lo cual hacemos en las líneas 38-39 en la cual restamos el valor del fin de la RAM con el de inicio y después comparamos este valor con el registro índice, es decir comparamos el número de localidades disponibles con el número de localidades que y hemos llenado. Si la comparación resulta ser cero entonces significa que debemos de terminar, si no resulta ser cero entonces aun hay espacio disponible para poder seguir calculando los valores.

Como podemos notar la RAM no termina en la dirección que asignamos, es decir 270h, ya que la RAM de nuestro MSP430F2231 termina en la posición 027Fh, la razón principal de que no hayamos utilizado este valor para la constante finRAM es porque la pila esta localizada en la RAM, por lo cual declaramos el fin de la ram antes para que el programa no altere a la pila, como ya hemos mencionado el alterar a la pila puede traer consecuencias desastrosas para nuestras aplicaciones así que con esto damos cierto margen de error para que la pila pueda incrementarse hasta en 7 niveles mas.

Obtener codigo fuente

PUERTOS DIGITALES DE ENTRADA Y SALIDA

La parte más importante de nuestro microcontrolador es la de los puertos de entrada y salida ya que a partir de ellos este se podrá comunicar con el exterior con dispositivos que generen o acepten señales digitales, además de importante es de lo más básico que se debe de saber utilizar en cualquier tipo de microcontrolador, en esta sección describiremos el uso y configuración de los puertos.

Al terminar esta sección serás capaz configurar los puertos de entrada y salida, manejaremos el concepto de interrupción y otros conceptos algo básicos y muy útiles. Ahora comenzaremos a describir el funcionamiento de los puertos de entrada y salida.

FUNCIONAMIENTO Y NOTACION

Cada puerto de entrada y salida de todos los dispositivos de la familia MSP430™ están formados por grupos de 8 bits, donde cada bit representa físicamente a un pin del encapsulado, algunos de los dispositivos de la familia MSP430 cuentan con hasta 8 puertos, es decir 64 pines de entrada y salida e incluso más.

En nuestro caso el modelo de la familia MSP430™ que utilizaremos cuenta con dos puertos de entrada y salida, pero el segundo puerto solo tiene dos pines, es decir que en lugar de tener 16 pines, solo tenemos 10 pines disponibles para que sean usados como entradas y salidas digitales.

La notación utilizada para hacer referencia a cada pin es Pn.m; donde n es el numero de puerto y m es el bit especifico del puerto, así en la siguiente imagen se puede ver como están distribuidos los 10 pines de entrada y salida para el MSP430G2231.

Encerrados en rojo podemos ver los pines del puerto 1 (P1.m) donde m va desde el 0 hasta el 7, en total 8 bines.

De color verde podemos ver los únicos dos pines que pertenecen al puerto 2, cero podemos notar que la numeración no comienza con P2.0 y P2.1 si no que en lugar de eso tenemos P2.7 y P2.8, esto es cuestión del fabricante. Las demás notaciones que aparecen en el PinOut de este microcontrolador son otras funciones que tiene cada pin, las cuales se seleccionan dependiendo de nuestras necesidades.

Podemos usar un pin por ejemplo para que sea la entrada del temporizador, o para conectar un cristal de cuarzo o para introducir una señal analógica para que sea convertida o también podemos obtener una frecuencia del oscilador interno u obtener un voltaje de referencia para circuitos analógicos externos, pero todo esto depende no solo del pin, ya que no todos tienen estas funciones secundarias de las que hablamos, sino que también depende de configurar ese pin para que cumpla la función específica que hayamos seleccionado.

La parte importante de los puertos de entrada y salida es la configuración, ya que en algunos casos esta configuración solo se hace una ves al inicio de cada programa y muy pocas veces se ve alterada. Para la configuración básica los puertos existen 5 registros para ello y en algunos casos son 6 y son:

PXSEL y PXSEL2 Se utiliza para la selección de función de cada pin, PXSEL2 no esta disponible en todos los dispositivos como en el caso del MSP430G2231

PXDIR Nos será útil para poder seleccionar como es que funcionaran los pines de cada puerto, es decir como entradas o como salidas

PXIN En caso de que hayamos seleccionado un pin como entrada podremos leer su estado con este registro

PXOUT Cuando se selecciono un pin como salida, es con este registro con el cual podemos escribir estados lógicos en el pin seleccionado

PXREN Este nos sirve para elegir si habilitamos las resistencias PULL-UP o PULL-DOWN

Cabe mencionar que todos los registros aquí mencionados son de 8 bits, gracias a esto se puede relacionar la posición de cada bit individual con un pin del encapsulado. Como ejemplo el bit 7 de cualquier registro de los mencionados antes representa a el pin denominado PX.7, donde X es el puerto al que corresponde dicho pin.

Por lo tanto si tenemos dos puertos de entrada y salida, entonces tendremos dos de cada unos de estos registros, es decir uno por cada puerto:

P1SEL, P2SEL, P1DIR, P2DIR, P1IN, P2IN, P1OUT, P2OUT, P1REN, P2REN.

Y cada uno de esos registros tendrá 8 bits correspondientes a cada uno de sus pines.

SELECCIÓN DE FUNCION

Como lo dice el titulo de esta sección, estos registros nos serán útiles para seleccionar la función la cual tendrá cada uno de los pines de cada uno de los puertos, ya que cada pin del encapsulado del microcontrolador tiene como mínimo 2 funciones.

A continuación te mostramos como esta estructurado este registro de 8 bits de manera grafica y la función de cada uno de sus bits la cual explicaremos mas adelante.

Así modificando este registro lograremos establecer la función de cada pin, por ejemplo el pin denominado P1.0 tiene tres funciones, esto porque en el PinOut tiene escrito lo siguiente P1.0/TA0CLK/ACLK (Ovalo Rojo), la función por defecto es la que aparece al principio, en este caso P1.0 ósea entrada/salida digital.

Para el caso de P2.7 se puede ver que tiene escrito lo siguiente: XOUT/P2.7 (Ovalo Azul). Esto quiere decir que la función por defecto es la de XOUT, ósea que podemos conectar un oscilador externo entre P2.7 y P2.6 ya que P2.6 tiene escrito lo siguiente: XIN/P2.6/TA0.1 (Ovalo Verde).

De aquí obtenemos como conclusión que la función principal es la que esta descrita al principio de cada renglón (Subrayadas en morado) , la notación que sigue separada por diagonales son otras funciones que pueden ser configuradas a través de las combinaciones entre PXSEL y PXDIR.

Como esta sección esta dedicada a el uso de los pines como entradas y salidas digitales simplemente haremos que todos los bits de este registro tanto para el puerto 1 y 2 sean 0 con las siguientes instrucciones:

CLR.B &P1SEL CLR.B &P2SEL

En realidad solo es necesaria la segunda instrucción ya que como podemos ver las funciones por defecto de los pines de puerto 1 son de entrada y salida digital.

Observemos también que hemos utilizado el modificador ".B", esto es porque como ya hemos mencionado nuestros registros son de 8 bits, si hiciéramos cualquiera de los dos casos siguientes obtendríamos un error.

CLR.W &P1SEL CLR &P1SEL

Esto porque estamos tratando de borrar un registro de 16 bits cuando físicamente nuestro registro solo tiene 8. También hay que notar el "&" el cual como lo mencionamos en la sección de MODOS DE DIRECCIONAMIENTO este modo (absoluto) siempre se usara cuando en cualquier instrucción se haga referencia a algún registro de cualquier periférico.

Este microcontrolador al tener un numero muy reducido de pines disponibles y de pocos periféricos no requiere de un registro PXSEL2, ya qu como mencionamos con

anterioridad, las funciones de cada pin se pueden seleccionar por completo con dos bits en 2 registros (PXDIR y PXSEL), pero en caso de que exista el registro PXSEL podremos encontrar en el datasheet de el dispositivo a emplear las tablas para la selección de funciones.

Te invitamos a ver los ejemplos de puertos de entrada y salida tanto en C/C++ como en ASM (Ensamblador) para que puedas aplicar y entender mejor lo que aquí te explicamos.

LOS REGISTROS I/O

Para configurar como entrada haremos uso del mismo registro llamado PxDIR en el cual ahora pondremos en 0 los bits que deseemos utilizar como entradas.

Así si por ejemplo en el puerto 2 queremos que los bits 6 y 7 sean entradas haremos lo siguiente:

BIS.B #BIT6+BIT7,&P1DIR

O bien:

BIS.B #11000000b,&P1DIR

Ahora para la lectura de los bits utilizaremos un registro llamado PxIN mostrado a continuación:

Ya que un bit de un puerto ha sido seleccionado como entrada, a partir de este registro podemos leer el estado actual de la entrada lógica, dado a esto el registro es de solo lectura.

Para leer el estado directo de la entrada lógica utilizaremos instrucciones de testeo o comparación. Por ejemplo para leer el BIT6 utilizamos la siguiente instrucción:

BIT.B #BIT6,&P1IN

Para saber su estado podemos implementar el siguiente salto condicional:

BIT.B #BIT6,&P1INJZ ES-UNO

ES-CERO ....

ES-UNO ....

En electrónica digital existen dos circuitos para la generación de estados lógicos a través de un botón, tanto normalmente abierto como normalmente cerrado, de acuerdo a su configuración el botón puede generar 1 en estado de reposo y 0 al ser presionado o bien de manera contraria es decir 0 en estado de reposo y 1 al ser presionado, a continuación se muestran las 2 combinaciones para cuando se utilizan interruptores normalmente abiertos.

Para nuestro caso en especifico esta sería la manera de conectar un interruptor a cualquier terminal configurada como entrada , en el caso PULL-DOWN cuando el botón no se presione se estaría generando un cero, al oprimir el botón se generaría un uno lógico. Para el caso PULL-UP si no se oprime el botón se esta generando un uno lógico, al presionar el botón se genera un cero.

Cuando tenemos un botón normalmente cerrado las condiciones se invierten, es decir para la configuración PULL-DOWN al no presionar el botón se tiene un uno, al oprimirlo tenemos un cero. En la configuración PULL-UP al no oprimir el botón tenemos un cero, al oprimirlo tenemos un uno lógico.

El objetivo de todo esto es mostrarte como configurar estos circuitos de manera interna en los microcontroladores MSP430™ ya que disponen de este hardware. Para configurar las resistencias PULL-UP/DOWN haremos uso de dos registros, uno de ellos es PxOUT y el otro es PxREN.

Para que el registro PxOUT obtenga su segunda función es importante que se seleccionen los bits correspondientes como entrada, así si por ejemplo el bit 6 del puerto 2 fue seleccionado como entrada, entonces si queremos implementar una resistencia PULL-UP con un interruptor normalmente cerrado para que al presionarlo genere un uno lógico, entonces en el registro P2OUT en la posición llamada BIT6 colocaremos un 1 así:

BIS.B #BIT6,&P2OUT

De esta manera la resistencia esta seleccionada pero no habilitada, para ello haremos uso del registro PxREN mostrado a continuación:

El cual se encarga de habilitar las resistencias PULL-UP/DOWN en bits seleccionados como entradas únicamente, así para continuar con el ejemplo si queremos habilitarla solo hay que poner un uno en la posición llamada BIT6 así:

BIS.B #BIT6,&P2REN

Así con las configuraciones adecuadas podemos tener los siguientes circuitos de manera simplificada, lo cual ayuda al reducir la circuitería necesaria para comenzar a realizar aplicaciones.

CONFIGURAR COMO SALIDA

Para poder enviar datos digitales al exterior utilizaremos dos registros de los antes mencionados para configurar ya sean solo bits o puertos enteros para trabajar como salida de datos digitales. Estos registros necesarios los presentamos a continuación:

En este proceso de configuración para enviar datos lo primero que debes de hacer es configurar la dirección de los datos, ya que los bits de un puerto pueden trabajar tanto entrada o salida, para decidir con cual de las dos formas funcionara utilizaremos el registro PxDIR, en la tabla vemos que si queremos que por ejemplo seleccionar todo el puerto uno utilizamos la siguiente instrucción:

MOV.B #11111111b,&P1DIR

Lo cual hace que todos los bits en el registro P1DIR sean 1, lo cual indica que todos los bits en el puerto 1 son seleccionados como salida que es precisamente lo que queremos.

Con esto solo le hemos indicado a los puertos como es que se comportaran si como entrada o salida, pero aun no podemos ver un estado lógico reflejado en la salida. Para esto haremos uso del registro mostrado en la siguiente tabla:

Este registro tiene una doble función: seleccionar estados lógicos de salida y selección de resistencias PULL-UP/DOUWN( mas adelante veremos que significa esto), en esta sección solo nos enfocaremos a la primera función. Con este registro modificaremos

directamente el estado de los pines relacionados a este registro los cuales hayan sido configurado como salida. Por ejemplo para poner en estado alto los 4 bits de mayor peso utilizaremos por ejemplo esta instrucción:

MOV.B #11110000b,&P1OUT

O bien:

BIS.B #11110000b,&P1OUT

En este caso como todos los pines en el puerto 1 se seleccionaron como salidas, entonces este registro P1OUT reflejara el estado actual de la salida digital.

INTERRUPCION EN LOS PUERTOS

Ya que las interrupciones nos son útiles para apagar la CPU del microcontrolador y encendarla solo cuando sea necesario, esto es como ya lo mencionamos de vital importancia para el diseño de aplicaciones de bajo consumo (ya que esta tan de moda), debido a esto los microcontroladores de la familia MSP430™ tienen dos puertos completos para generar interrupciones a la CPU, es decir 16 fuentes de interrupción, en nuestro caso ya que solo tenemos diez pines, 8 del puerto 1 y 2 para el puerto 2 solo tenemos 10 fuentes de interrupción por parte de los puertos.

Cada bit es configurable de manera independiente, si se desea que solo un pin del puerto 1 admita interrupciones se puede hacer o que todos los bits del puerto 1 y 2 admitan interrupciones también es posible.

Para los puertos solo se puede configurar las interrupciones por obvias razones a pines que hayan sido configurados anteriormente como entradas, al igual que los registros como PxIN, PxOUT, PxREN, PxDIR y PxSEL, hay tres registros mas para la configuración de las interrupciones en los puertos, estos sol los siguientes:

PxIFG En este registro se puede ver si se renero una interrupción o no. PxIES Es útil para seleccionar el flanco con el cual será generada nuestra interrupción. PxIE Con este registro seleccionaremos si permitimos localmente las interrupciones de

cada bit por puerto.

Cabe mencionar que las interrupciones no se generan con niveles estáticos si no mediante una transición de niveles lógicos, es decir de 0 a 1 o de 1 a 0 ósea si se generan flancos de subida o de bajada, de lo contrario la interrupción no ocurrirá.

CONFIGURAR LAS INTERRUPCIONES.

Para ello es necesario configurar previamente el bit correspondiente como entrada digital, cosa que ya sabemos hacer, también configurar las resistencias PULL-UP/DOWN si es que colocaremos un pulsador. Después de ello seleccionaremos

el flanco con el cual la interrupción será generada, esto se hace con el registro llamado PxIES mostrado a continuación.

Cuando se genera un cambio de estado bajo (0) a estado alto (1) se dice que se genera un flanco de subida, cuando se genera un cambio de estado alto (1) a estado bajo (0) se genera un flanco de bajada. Dependiendo de cada aplicación es el flanco que elegiremos, ya que por ejemplo si a la entrada digital conectamos un pulsador de acuerdo a su configuración la interrupción se generara cuando se oprima el botón o cuando lo soltemos.

Si a la entrada digital le conectamos un conductor por donde fluye información de forma serial, entonces es importante elegir el flanco de bajada ya que eso indica el inicio de la transmisión.

Después de haber seleccionado el flanco haremos algo muy importante antes de poder permitir que las interrupciones se generen, esto es borrar la bandera de interrupción, pero antes tenemos que saber que significa esto.

Una bandera de interrupción es un bit contenido en un registro cualquiera el cual indica el estado de la interrupción, es decir si ese bit contiene un 1 significa que hay una interrupción pendiente, si ese bit tiene 0 entonces quiere decir que no hay interrupciones pendientes, debemos recordar que muchas interrupciones se pueden generar al mismo tiempo .

BANDERA DE INTERRUPCION PARA LOS PUERTOS.

A continuación mostramos una imagen la cual podremos observar los 8 bits que la forman, así como los valores que puede tomar y la función que cumplirá dependiendo del valor tomado.

Es importante mencionar que las banderas de los puertos al ser múltiples no son borradas automáticamente si no que hay que borrarlas por software mediante este registro ya que de lo contrario el programa no seguirá su curso normalmente, si no que se quedara en la rutina de servicio a la interrupción.

Antes de permitir cualquier interrupción por primera vez es necesario borrar su bandera correspondiente ya que en ocasiones suelen estar colocadas a 1, esto por diversos factores. Si no borramos las banderas antes de permitir las interrupciones podemos llamar a la ISR en un momento no adecuado. Esto lo podemos hacer con la instrucción CLR.B así:

CLR.B &P1IFG

De esta manera hemos configurado el pin por donde entrara la bandera, además de ello podemos seleccionar el flanco con el cual se generara, además borrado su bandera de interrupción, lo que sigue es permitir la interrupción de manera local.

HABILITAR LA INTERRUPCION.

Para seleccionar que pines pueden o no generar interrupciones utilizaremos el registro llamado PxIE el cual se muestra a continuación:

Se puede seleccionar de manera individual si es que un pin configurado como entrada puede o no interrumpir a la CPU, ahora ya podemos configurar las interrupciones en los puertos, cuando estén configuradas todas las interrupciones incluso las de otros periféricos entonces estaremos listos para permitirlas de manera global con:

EINT

SI lo que deseamos es solo permitir las interrupciones pero si además de eso modificaremos otro bit del Registro de estado podemos utilizar la instrucción MOV como se muestra a continuación:

BIS #GIE+LPM2,SR

Donde además de permitir las interrupciones de manera global hacemos que el microcontrolador entre en el modo de bajo consumo 2.

DECLARANDO EL VECTOR PARA LOS PUERTOS

La configuración es algo que debemos de hacer cuando deseamos trabajar con interrupciones, después de configurarlas y permitirlas debemos definir su vector correspondiente así como su rutina de servicio a la interrupción ISR, según la siguiente tabla los vectores correspondientes para el puerto 1 y 2 son los siguientes:

Para P1 es 0FFE4h para P2 es 0FFFE6h, como ya hemos mencionado en la sección de arquitectura, la tabla especifica de los vectores de interrupción se encuentran en el datasheet del dispositivo a programar, aunque en muchos casos no son muy diferentes nunca esta de mas revisar el datasheet ya que además de los vectores de interrupción encontraremos ahí mas información importante.

Ahora definiremos estos vectores después del vector de reset en la parte final de programa de la siguiente manera:

;-------------------------------------------------------------------------------; Vectores de Interrupción y Reset;-------------------------------------------------------------------------------

ORG 0xFFFEDW RESET

ORG 0xFFE4DW ISR_P1

ORG 0xFFE6DW ISR_P2

END

Lo único que resta es definir las ISR las cuales comenzaran con las etiquetas definidas comoISR_P1 e ISR_P2, las cuales definirán que es lo que ocurre cuando se genere la

interrupción, lo cual definirás de manera individual en tus programas, pero no olvides que deben de terminar con RETI para evitar un mal funcionamiento de tu programa.

Te recomendamos que veas el ejemplo de aplicación donde te guiaremos en la construcción de un programa para que puedas comprender por completo lo descrito en esta sección y puedas ver cómo es que todo lo aquí mencionado se implementa.

APLICACIÓN DE EJEMPLO

Es momento de realizar una aplicación para aplicar los conocimientos obtenidos, en este caso realizaremos un secuenciador sencillo para así también utilizar algunos conceptos de secciones pasadas como las tablas, apuntadores y rutinas de retardo.

Lo que hará nuestro programa es en todo el puerto uno tendrá conectados leds, la activación de estos leds dependerá de cual de los dos botones conectados en el puerto 2 se oprima, así lo primero que debemos hacer es configurar el puerto uno como salida.

MOV.B #11111111b,&P1DIR

Después pondremos en estado bajo las salidas, ya que al ejecutar la instrucción anterior los estados de las salidas toman valores aleatorios cosa que debemos evitar en lo posible.

CLR.B &P1OUT

O bien:

MOV.B #00000000b,&P1OUT

Posteriormente configuraremos los bits del puerto 2, primero seleccionaremos su función de entrada y salida digital ya que como recordamos que vimos en la sección de FUNCIONAMIENTO Y NOTACION la función principal del P2.6 y P2.7 es la de tener conectado un cristal, así si borramos el contenido en P2SEL tendremos a ambos pines como entrada y salida digital.

CLR.B &P2SEL

Ahora seleccionaremos los dos bits del puerto 2 como entradas modificando los bits 6 y 7 del registro PxDIR.

BIC.B #BIT6+BIT7,&P2DIR

En este ejemplo pondremos interruptores normalmente abiertos configurados de tal manera que al ser oprimidos generen un 1, si no se oprimen se leerán como cero. Para ello requerimos una configuración de resistencias PULL-DOWN. Así que primero pondremos en el registro P2OUT que queremos resistencias PULL-DOWN poniendo los bits 6 y 7 a 0.

BIC.B #BIT6+BIT7,&P2OUT

Ya que tenemos seleccionadas las resistencias PULL-DOWN solo basta con habilitarlas, para esto haremos uso del registro P2REN poniendo los bits 6 y 7 a 1 para que queden habilitadas.

BIS.B #BIT6+BIT7,&P2REN

Así tenemos listas las configuraciones listas para poder comenzar con nuestro programa principal, como se menciona en el inicio de la sección de puertos, la configuración de los puertos suele hacerse solo una vez en todo el programa a menos que nuestra aplicación lo requiera.

Después de hacer las configuraciones de los puertos lo que haremos es que nuestro programa espere hasta que sea presionado cualquiera de los dos botones mediante el método de encuesta el cual consiste en leer continuamente el valor de PxIN en espera de que sea presionado un botón. Esto lo logramos de la siguiente manera:

NoPres TST.B &P2INJZ NoPres

Así la instrucción TST nos indica si hay algún valor en P2IN si no lo hay entonces se sigue ejecutando esta instrucción hasta que haya un valor en P2IN, cuando hay un valor en P2IN entonces la CPU sale de este ciclo y continua con la siguiente instrucción.

En este momento sabemos que un botón se oprimió, pero no sabemos cual, así que lo siguiente es averiguar cual de los dos fue oprimido. Para averiguar cual fue debemos primero copiar el contenido de PxIN en un registro de la CPU (R6) ya que este puede cambiar su estado a lo largo de este proceso.

Ahora realizaremos una resta, ya que solo hay dos opciones, es decir que R6 tenga 10000000 o 01000000 le restaremos 10000000 si el resultado da cero quiere decir que se oprimió el BIT7, de lo contrario fue BIT6 el que se oprimió.

SUB.B #BIT7,R6JNZ SEC1

Si BIT7 se presiono entonces el resultado de la resta será cero por lo tanto no se realizara el salto y la CPU continuara ejecutando el código después de la instrucción JNZ. Si se oprimió el BIT6 entonces saltara a donde este la etiqueta SEC1.

Con esto ya averiguamos cual de los dos botones ha sido oprimido, aunque hay una posibilidad que ignoramos la cual sucede cuando se oprimen ambos botones, en ese caso por la lógica de nuestra solución no se ejecutaría el salto. Ahora lo que resta es ejecutar las secuencias para cada caso, que es muy semejante, el proceso de mostrar las secuencias es a través de un apuntador el cual antes de cambiar de dirección mueve el contenido de la dirección apuntada al puerto 1 y se espera un tiempo, hasta que el apuntador tenga la dirección de la etiqueta FIN0, después de eso se realiza un salto incondicional al inicio de programa justo donde se espera a que un botón sea presionado.

SEC0 MOV #Sec0,R4ETQ0 MOV.B @R4+,&P1OUT

CALL #RETARDOCMP #FIN0,R4JNE ETQ0CLR.B &P1OUTJMP Inicio

Las tablas definidas casi al final del programa definen las dos secuencias que serán ejecutadas, así podemos seguir agregando valores como de la función SENO, o la COSENO para así realizar una conversión digital-analógico para sintetizar audio.

Aquí esta el diagrama de flujo de este programa, te invitamos a que veas mas ejemplos de como es que se utilizan los puertos, en realidad para un programa funcional no solo se utilizan una sola parte del microcontrolador si no que varias partes se combinan para lograr el objetivo deseado.

EL SISTEMA BASICO DE RELOJ

El principal motivo por el cual existe este periférico es por la flexibilidad requerida por la arquitectura, además de que los periféricos exigen este para su implementación con una mayor eficiencia.

En otro tipo de microcontroladores solo es necesario una fuente de reloj, es decir un oscilador de uno o varios tipos (RC, de cuarzo, etc.) conectado a dos de sus terminales. En nuestro caso tenemos tres fuentes de reloj las cuales proveerán tanto a la CPU como a los periféricos, de señales de reloj completamente independientes y configurables por software.

Estas tres fuentes de reloj son completamente internas y gracias a esto podemos ahorrar tanto en componentes como en espacio, ya que podemos comenzar a realizar aplicaciones con un numero mínimo de elementos externos.

El sistema básico de reloj es el que se encarga de la generación y distribución de señales de reloj tanto para los dispositivos como para los periféricos. Es muy importante conocer el funcionamiento de este periférico ya que solo así podremos implementar las soluciones de bajo consumo de energía así como obtener la mayor precisión en nuestras aplicaciones.

LAS FUENTES DE RELOJ

Todo dispositivo requiere de una señal periódica para funcionar, ya que de lo contrario este no podría generar mas que estados finitos e invariantes en el tiempo, estos microcontroladores no son la excepción. Existen tres fuentes de reloj las cuales alimentaran a las señales que este modulo puede entregar. Estas fuentes son VLOCLK, LFXT1CLK, DCOCLK.

VLO.- Oscilador de bajo consumo y frecuencia.

Cada dispositivo cuenta con un oscilador interno con un frecuencia de 12KHz el cual es de bajo consumo, cuando este se selecciona entonces LFXT1 es apagado para evitar consumos inesesarios de energía.

LFXT1.-Oscilador de alta o baja frecuencia.

Soporta un oscilador de baja frecuencia de 32,768Hz conectado en las terminales llamadas XIN y XOUT sin componentes externos ya que internamente tiene capacitores de 1, 6, 10 y 12.5 pF. Para ello se debe de seleccionar su modo de baja frecuencia.

Además pueden conectarse cristales de mayor frecuencia o resonadores mediante las mismas terminales en el modo de alta frecuencia, en este caso se deben de adicionar capacitores externos según las especificaciones del cristal.

De forma adicional se pueden introducir señales externas de reloj solo en el pin XIN en cualquier modo, para ello debemos de asegurarnos que la frecuencia de la señal externa

este dentro de los parámetros enunciados en el datasheet del dispositivo ya que de ser mayor el sistema de reloj la bloqueara para evitar que esta llegue a la CPU.

Este oscilador de puede inhabilitar desde uno de los bits del registro de estado llamado OSCOFF si este no se usa para MCLK o SMCLK, es decir que solo si se usa para ACLK este no se podrá apagar por software.

DCO.- Oscilador Controlado Digitalmente

Este oscilador puede generar frecuencias de hasta 16MHz las cuales son ajustadas por los bits llamados DCOx, MODx y RSELx en los registros de control de este modulo.

La característica mas importante de este oscilador es su rápida estabilización al encenderse, esto lo hace ideal para aplicaciones de bajo consumo de energía. Ya que es un oscilador controlado digitalmente, habrá unos registros los cuales nos servirán para controlar la frecuencia de este oscilador. Estos son los DCOCLK y BCSCTL1 cuando usamos el MSP430G2231 solo se puede llegar a 1MHz pero para otros dispositivos existe una tabla en el datasheet la cual proporciona los valores que deben de tomar estos bits para lograr obtener ciertas frecuencias.

En algunos dispositivos tienen constantes de calibración en el área de memoria de intormacion en el segmento A, estas constantes tienen los valores necesaros para lograr frecuencias especificas como 1MHz, 2MHz, 4MHz y para el caso de por ejemplo el MSP430F2013 se puede llegar a los 16MHz.

Podemos apagar este oscilador mediante el bit en el registro de estado llamado SCG0 si no es usado para MCLK o SMCLK, al igual que el oscilador anterior no se puede apagar si este es usado por ACLK.

LAS SEÑALES DE RELOJ

Existen tres señales que este modulo puede proporcionar a los periféricos que así lo requieran, estas son ACLK, MCLK, SMCLK, cada una de ellas tiene sus características especificas.

ACLK es el reloj auxiliar, este puede ser alimentado por LFXT1CLK o VLOCLK y ser dividida por 1,2,4 y 8. Es usado para los periféricos según sea seleccionado por software, como podemos notar este no se puede apagar mediante un modo de bajo consumo, por lo cual se usara para proveer a nuestros periféricos de una fuente de reloj cuando la CPU este apagada.

MCLK es el reloj principal el cual puede ser seleccionado por software como LFXT1CLK, VLOCLK o DCOCLK. Esta señal puede ser dividida por 1,2,4 y 8 y es usada por la CPU.

SMCLK es el reloj sub principal puede ser alimentado por LFXT1CLK o VLOCLK y ser dividido por 1,2,4 y 8. Es utilizado por los periféricos según su configuración por software.

A continuación mostramos un diagrama a bloques de cómo está formado este modulo en donde en ovalo rojo están las fuentes de reloj y en ovalo rojo están las señales de reloj.

Este modulo lo configuraremos al principio de aplicaciones mas complejas donde apliquemos soluciones de bajo consumo esto para que una ves configuradas las señales de reloj puedan ser usadas por los periféricos que la requieran .

EL TIMER A

El timer a es un temporizador/contador el cual utilizaremos para nuestras aplicaciones con distintos fines ya que con el podemos medir y generar intervalos de tiempo, utilizarlo como contador de eventos, generar PWM a distintas frecuencias, muestrear señales etc.

Para ello requerimos de conocer este periférico para poder configurarlo a convencía, para ello dividiremos esta sección en 2, una de ellas es el uso de el timer a como temporizador, la otra es el uso del timer a en modo captura comparación.

TIMER_A COMO TEMPORIZADOR

Si tenemos un contador de pulsos al cual le insertamos una señal cuadrada de cierto periodo conocido, entonces después de cierto tiempo al consultar la cuenta podremos calcular el tiempo que ha transcurrido desde que iniciamos la cuenta. En si este es el principio básico de este periférico.

Podemos ver en el diagrama a bloques del Timer_A que hay un multiplexor de 4 entradas y una salida el cual es controlado por TASSELx después de ello hay un divisor de frecuencias controlado por IDx el cual puede dividir la señal por 2, 4 y 8, después esta señal ya seleccionada y dividida pasa a alimentar al contador/temporizador de 16 bits almacenando la cuenta en el registro llamado TAR, además este contador/temporizador es controlado por los bits MCx los cuales se encargan de controlar el modo de cuenta del contador/temporizador.

También podemos ver que tanto al divisor de frecuencia como al contador/temporizador cuentan con un bit mas llamado TACLR el cual se encarga de resetear los valores tanto del TAR como del IDx. Por ultimo podemos ver que la única salida con la que cuenta este modulo es la TAIFG, es decir que depende como configuremos a este modulo en conjunto de en que momento será enviada la interrupción a la CPU. A continuación describiremos los bits específicos antes mencionados junto con los valores que pueden tomar.

TAR

En este modo existe un registro de 16 bits llamado TAR (Timer A Register) el cual es incrementado o decrementado por cada flanco ascendente de la señal cuadrada del reloj, es decir que en este registro se almacena la cuenta de pulsos de periodo conocido de la señal cuadrada que incide en el contador. Este registro es el mas importante de el timer a el cual se puede tanto leer como escribir en el.

TASSELx e IDx

El contador se puede alimentar de diferentes fuentes de reloj tanto internas como externas, la selección de esto se hace mediante los bits llamados TASSELx (Timer A Source Select) y además estas fuentes pueden ser divididas por 2, 4, 8 con los birs llamados IDx (Input Divider) ambos se encuentran en el registro llamado TACTLx

(Timer A Control Register) . Tanto TASSELx como IDx son conjuntos de 2 bits dentro de este registro. (Para mayor información con respecto a las fuentes de reloj visitar la sección del sistema de reloj).

TASSELx ocupa las posiciones 8 y 9 del registro de 16 bits TACTL y puede adquirir los siguientes valores.

00 TACLK Reloj del Timer_A (Timer_A Clock) 01 ACLK Reloj auxiliar (Auxiliary Clock) 10 SMCLK Reloj sub principal (Semi Master Clock) 11 INCLK No disponible para nuestro caso

IDx ocupa las posiciones 6 y 7 del registro de 16 bits TACTL y puede adquirir los siguientes valores.

00 Frecuencia de entrada/1 01 Frecuencia de entrada/2 10 Frecuencia de entrada/4 11 Frecuencia de entrada/8

MCx

El modo de cuenta es controlado por estos dos bits dependiendo del valor de estos dos bits podemos elegir entre los 4 modos de cuenta disponibles: detenido, ascendente, continuo, ascendente/descendente. Depende de los modos de cuenta el momento en el que la interrupción será generada, a continuación te mostramos una tabla con sus valores, después de ello su descripción individual mas detallada.

00 detenido 01 ascendente 10 continuo 11 ascendente/descendente

MODOS DE CUENTA

1.- MODO ASCENDENTE

En este modo el contador/temporizador contara desde cero hasta el valor almacenado en TACCR0, después de eso la cuenta se reinicia y continua de nuevo. En la siguiente imagen se puede ver mejor este modo de cuenta.

La interrupción se genera en el momento en el que la cuenta en TAR cambia de el valor de TACCR0 a 0. Imaginemos que tenemos una frecuencia de 4MHZ externa mediante un cristal de cuarzo conectado en las terminales del puerto dos, con esta señal alimentaremos a nuestro contador/temporizador, por lo cual TASSELx debe ser 01, además utilizaremos un divisor por 4 para obtener una frecuencia de 1MHz y así un periodo de 1us, para eso IDx debe ser 10.

Lo que deseamos es interrumpir a la CPU cada 1ms por lo que deben de transcurrir 1000 pulsos de la señal que hemos configurado para que esto ocurra, para ello cargamos 1000 en TACCR0 y por ultimo iniciaremos la cuenta al poner en MCx el valor de 01.

Lo único que resta es definir la rutina de servicio a la interrupción además del vector de interrupción correspondiente para por ejemplo encender y apagar un led cada 1ms.

2.- MODO CONTINUO

En este modo el contador/temporizador cuenta de manera repetida hasta el valor máximo permitido el cual es 0xFFFF y después regresa a cero, así la bandera de interrupción es colocada cuando la cuenta pasa desde 0xFFFF a 0x0, así podemos generar interrupciones con periodo de 65535(Tsrc) donde Tsrc es el periodo de la fuente que seleccionamos con su respectivo divisor de frecuencia. A continuación una imagen que ilustra de mejor manera este modo.

En el ejemplo anterior este Tsrc es de 1us por tanto con esas configuraciones se pueden generar interrupciones con un periodo de 65.535ms.

Además de generar estos periodos podemos hacer uso de los registros TACCR0 y TACCR1, con ellos podemos generar intervalos de tiempo independientes, posteriormente veremos como implementar esto para generar intervalos de tiempo independientes.

3.- MODO ASCENDENTE/DESCENDENTE

En este modo el contador/temporizador cuenta desde cero hasta el valor de TACCR0 de manera ascendente y después cuenta de manera descendente hasta cero. Esto nos será útil para la generación de pulsos simétricos, así el periodo será de el doble del valor almacenado en TACCR0. A continuación una imagen que muestra este modo de cuenta.

En este modo la interrupción se genera cuando la cuenta pasa de 0x0001 a 0x0000, como podemos ver en todos los casos la bandera de interrupción TAIFG es generada cuando la cuenta pasa por cero.

TIMER EN CAPTURA

Casi todos los dispositivos cuentan con tres de estos módulos de captura y comparación, en nuestro caso el microcontrolador MSP430G2231 solo cuenta con 2 (CCR0 y CCR1), lo mismo ocurre con los dispositivos mas pequeños de esta familia. Es bueno mencionar que independientemente del numero de módulos todos son idénticos.

El modo de captura nos servirá para realizar mediciones de tiempo, como por ejemplo para medir velocidades de computo o bien para medir periodos de tiempo generados por fuentes externas. La precisión de la medición depende de muchos factores como la interferencia que puede generar la CPU o el hardware con el que se realiza, así como de la fuente de reloj aplicada además de el numero de bits involucrados en la medición.

A continuación mostramos un diagrama a bloques de un modulo de captura y comparación, donde te explicaremos los bits que interfieren en la configuración de este modulo.

CAP

El bit CAP (Capture Mode) nos servirá para seleccionar este modo ya que el modulo en si puede trabajar en captura o comparación, este ocupa la posición 8 del registro llamado TACCTLx.

0 Modo de comparación 1 Modo de captura

El grupo de bits llamado CCISx (Capture Compare Input Select) nos ayudara a seleccionar de donde provendrá nuestra señal a medir, este esta en los bits 12 y 13 de TACCTLx.

00 Bit CCIxA del encapsulado 01 Bit CCIxB del encapsulado 10 GND 11 VCC

Nuestro dispositivo solo cuenta con CCI0A y CCI1A los cuales se ubican en los puertos P1.1 y P1.2, estos los configuramos para esta función a través del registro P1SEL poniendo a 1 los bits 1 y 2 de este registro.

CMx

Los bits CMx nos ayudaran a seleccionar el flanco de captura de la señal de entrada, ya sea flaco de bajada, de subida o ambos. Cuando una captura ocurre el valor del TAR es copiado en TACCRx y la bandera de interrupción llamada CCIFG es colocada, estos bits están en las posiciones 14 y 15 de TACCTLx

00 No hay captura 01 Captura con flanco ascendente 10 Captura en flanco descendente 11 Captura en ambos flancos

CCI

El bit CCI nos ayudara para leer en cualquier momento el nivel lógico de la entrada, este esta ubicado en la posición 3 del registro TACCTLx.

SCS

El bit llamado SCS nos ayudara a sincronizar la entrada con el reloj del contador/temporizador.

0 Captura asincrona 1 Captura síncrona

COV

Un sobre flujo lógico es provisto en cada registro de captura comparación para indicar que una segunda captura ha ocurrido antes de que el valor de la primera captura sea leído.

0 No ha ocurrido sobre flujo en la captura 1 Ocurrió sobre flujo en la captura

Como podemos ver el registro utilizado para la configuración de este modulo aun tiene muchos bits que no hemos usado, estos bits que no hemos mencionado serán utilizados para la configuración del modo de comparación.

TIMER EN COMPARACION

Este modo es seleccionado cuando CAP=1, este modo lo usaremos principalmente para generar PWM o interrupciones a intervalos específicos en el momento en que TAR cuente al valor de los registros TACCRx. A continuación mostramos un diagrama a bloques de los módulos de comparación y captura, para explicar esta sección usaremos el mismo diagrama que la sección anterior.

La unidad de salida esta presente en todo modulo de captura comparación esta es la que usaremos para generar señales PWM cada unidad cuenta con ocho modos de operación que generan diferentes señales de salida, estos modos de salida serán configurados por el grupo de tres bits llamados OUTMODx que se encuentran en TACCTLx. A continuación una lista con los valores que pueden tomar estos tres bits además de una descripción de la función que cumplen de acuerdo a cada valor asignado.

000.-Modo Salida. En este modo la salida es igual al contenido del bit OUTx en este mismo registro

001.-Modo Colocar. La salida pasa a 1 cuando el contador/temporizador cuenta al valor en TACCRx y permanece así hasta que el contador/temporizador sea reiniciado u otro modo de salida sea seleccionado.

010.-Modo Conmutar/Reiniciar.- La salida es conmutada cuando el contador/temporizador cuenta al valor en TACCRx y es reiniciada cuando el contador/temporizador cuenta al valor de TACCR0.

011.- Modo Colocar/Reiniciar.- La salida es puesta a 1 cuando en contador/temporizador cuenta al valor de TACCRx y es puesto a 0 cuando el contador/temporizador cuenta al valor de TACCR0.

100.- Modo Conmutar.- La salida es conmutada cuando el contador/temporizador cuenta al valor de TACCRx, el periodo de salida es el doble que el periodo del contador/temporizador

101.- Modo Reiniciar.- La salida es puesta a cero cuando el contador/temporizador cuenta al valor de TACCRx y permanece ahí hasta que otro modo de salida sea seleccionado.

110.- Modo Conmutar/Colocar.- La salida es conmutada cuando el contador/temporizador cuenta al valor de TACCRx, es puesta a 1 cuando el contador/temporizador cuenta al valor en TACCR0

111.- Modo Reiniciar/Colocar.- La salida es reiniciada cuando el contador/temporizador cuenta al valor en TACCRx, después es puesta a 1 cuando el contador/temporizador cuenta al valor de TACCR0

A continuación mostraremos unas imágenes donde podemos ver como es que esto afecta a la señal de PWM en la salida según cada modo de cuenta y su respectivo modo de salida.

MODO ASCENDENTE

MODO CONTINUO

MODO ASENDENTE/DESCENDENTE

A partir de conocer tanto el modo de cuenta como el modo de salida podremos obtener la señal de PWM que mejor nos convenga con el periodo y ciclo útil que queramos.

EL PERRO GUARDIÁN

Este periférico esta implementado en muchos microcontroladores ya que mas que un periférico el cual podamos utilizar para fines de desarrollo, es una medida de seguridad para nuestras aplicaciones ya que este temporizador forzara un reinicio del sistema cuando transcurra cierto tiempo, esto para evitar que nuestro microcontrolador se quede en espera de algún dato que nunca llegara por ejemplo.

Además de esto lo podemos configurar para que cada cierto tiempo genere una interrupción sin reiniciar el sistema. Este periférico solo será utilizado en muy escasas situaciones ya que en la mayoría de las aplicaciones se apagara para evitar que forcé un reinicio del sistema.

Debemos de apagarlo antes de que ocurra este intervalo del que hablamos, por lo regular es la segunda instrucción en la que realizamos esta acción.

Para configurar las opciones de este periférico se valdra de un registro llamdo WDTCTL el cual esta protegido por una contraseña la cual esta situada en su parte superior y tiene el valor de 05Ah para acceder a este registro se debe de proporcionar esta contraseña, de lo contrario el sistema se reiniciara.

El registro de 16 bits llamado WDTCNT es el que contara el tiempo necesario hasta que se efectué el reinicio del sistema, para ello se recomienda que la fuente de reloj que se seleccione sea igual o mayor que la de la CPU. Este modulo puede ser alimentado por las fuentes de reloj ACLK o SMCLK lo cual es seleccionado con el bit llamado WDTSSEL en el registro de control mostrado a continuación en la imagen. Además de esto el modulo de perro guardián tiene la posibilidad de configurar el pin llamado RST/NMI del encapsulado.

Como ya mencionamos el perro guardián tiene dos modos de operación:

MODO GUARDIÁN

En este modo se provocara un reinicio del sistema cuando pasen 32,768 ciclos del DCOCLK, es decir que se tienen precisamente este numero de ciclos para configurar, detener o borrar el perro guardián, en la mayoría de las aplicaciones lo detendremos con la siguiente instrucción la cual se situara después de configurar la pila.

MOV.W #WDTPW+WDTHOLD,&WDTCTL

En esta instrucción se suma la contraseña (WDTPW el cual es 05Ah) con el bit WDTHOLD (el cual vale 128) para así moverlos al registro de control, si no se añadiera la contraseña se generaría un reinicio de forma inmediata. Cualquier configuración que deseemos hacer a este periférico deberá ser dentro del intervalo antes mencionado de lo contrario el sistema será reiniciado.

MODO INTERVALOS

Para configurarlo en este modo lo debemos hacer antes de que los 32,768 ciclos ocurran, para esto configuraremos algunos bits del registro de control uno de los principales es el llamado WDTTMSEL el cual al ponerlo a 1 selecciona este modo.

También podremos seleccionar los intervalos a los cuales deseamos que sea generada la interrupción ya que solo tenemos 4 (64, 512, 8192, 32768 ciclos de la fuente seleccionada), así como la fuente de reloj que usaremos ya sea SMCLK si el bit WDTSSEL=0 o ACLK si WDTSSEL=1.

Cabe aclarar que cuando la cuenta expire no se producirá un reinicio del sistema, sino que se activara una bandera de interrupción para que posteriormente mediante una rutina de servicio a la interrupción podamos realizar alguna acción.

Además de las configuraciones realizadas en el registro WDTCTL debemos de permitir la interrupción en este modo a intervalos en el registro llamado IE1 mostrado a continuación, cabe aclarar que este registro tiene banderas para habilitar a otros dispositivos representados en la imagen por una X, los cuales poco a poco se conocerán e implementaran.

Además de este registro existe otro llamado IFG1 el cual contiene el estado de las interrupciones que fueron habilitadas en el registro anterior, este al igual que el anterior

contiene las banderas de interrupción para otros periféricos por lo cual debemos de tener cuidado de solo modificar los que necesitemos como lo indica la nota en la imagen.

OPERACIÓN SEGURA

El perro guardián está diseñado para operar de manera adecuada ante la falla de algún reloj ya sea SMCLK o ACLK, esto para asegurar que el reloj utilizado para alimentar este modulo no se pueda apagar, esto hace que en algunos casos no se puedan implementar ciertos modos de ahorro de energía.

Este mecanismo también es capaz de cambiar la fuente del perro guardián si es que ACLK o SMCLK fallan, en este caso la fuente del perro guardián será cambiada a MCLK, en caso de que MCLK sea un cristal externo y este falle entonces este mecanismo activa al DCO y lo utiliza para alimentar al perro guardián.

ACERCA DE IAR EMBEDDED WORKBENCH ®

Esta sección está dedicada a mostrar cómo es que se usa el IAR Embedded Workbench® para el desarrollo de nuestros ejemplos, proyectos y aplicaciones completas, así como para editarlos en C/C++ o en Ensamblador, también para realizar la descarga de nuestros programas en los microcontroladores y la detección de errores de lógica a través de la depuración (Debug).

Cabe aclarar que este es el principal componente de software que utilizaremos para desarrollo debido a sus características, posteriormente te mostraremos como es que se utiliza CCE Software que es proporcionado por la misma empresa Texas Instruments ™.

IAR Systems es una empresa dedicada en su mayoría a la creación de herramientas de software para sistemas empotrados (embedded) desarrollados por las empresas más reconocidas en este hambito, colaborando con estas empresas son capaces de ofrecer entornos de desarrollo integrado (IDE) muy potentes y flexibles.

Uno de sus objetivos es proporcionar compiladores que generen código eficiente logrando un alto grado de optimización y que sus herramientas sean agradables además de ser fáciles de usar.

IAR Embedded Workbench es como ya lo mencionamos un entorno de desarrollo integrado el cual tiene diferentes versiones, dependiendo el tipo de microcontroladores a usar como los AVR de Atmel, HCS12 de Freescale, PIC de Microchip, MSP430™ de Texas Instruments ™ y algunos mas no tan conocidos.

El que nosotros usaremos es el de MSP430™, en la parte izquierda de la web podrás encontrar un link para obtener una versión de prueba de 30 días (tienes que registrarte) o una versión limitada en código pero ilimitada en tiempo la cual recomendamos, cualquiera que elijas es gratuita y ambas nos servirán.

DESCARGA E INSTALACION DE IAR.

Antes de comenzar a editar programas es necesario tener un IDE adecuado, con IAR Embedded Workbench® además de un editor tenemos compiladores tanto de C, C++ y ensamblador así como otras herramientas muy útiles para crear hardware muy completo.

A continuación mostramos un video tutorial para que puedas seguir de manera mas didáctica la forma de descargar e instalar este programa, cualquier sugerencia, duda o problemas con tu instalación envíanos un mensaje en la sección de contáctanos.

Descarga e instalacion IAR - VIDEO

http://www.youtube.com/watch?feature=player_embedded&v=Dck8pC9E39o

Pasos:

1.- Seleccionar el link de "Descarga IAR" en el menú lateral. 2.- En la pagina que se abre ir casi al final y seleccionar el segundo botón de

"Download" que es el que dice "Code size limited Kickstart version download". 3.- Descomprimir en una carpeta conocida. 4.- Ejecutar FET_R604. 5.- Seleccionar SETUP. 6.- Clic en siguiente. 7.- Aceptar la Licencia y presiona siguiente. 8.- Siguiente a todo lo demás (a menos de que quieras cambiar el lugar donde se

instalara el programa).

Con esto queda instalado el IAR en tu disco duro, puedes ejecutarlo al terminar la instalación e ir al siguiente tutorial para configurarlo ya sea para que trabaje con C/C++ o el lenguaje ensamblador.

CREAR PROYECTO EN ENSAMBLADOR.

Ahora en este video tutorial te mostramos como configurar IAR Embedded Workbench para crear un proyecto en Ensamblador, el programa por defecto nos va a crear una plantilla, esta plantilla la ignoraremos, es decir la borraremos y en su lugar pondremos alguno de los ejemplos que se muestran en la web o algún programa propio ya que esta plantilla contiene instrucciones del preprocesador que no se requiere conocer a fondo para comenzar a desarrollar aplicaciones de pequeña escala.

Configuras IAR en Ensamblador - VIDEO

http://www.youtube.com/watch?feature=player_embedded&v=oKAbuVCLlHQ

Pasos:

1.- Ejecutar IAR Embedded Workbench. 2.- Ir a menu Proyect>Create New Proyect. 3.- En donde dice Project Templates Seleccionamos ASM para abrir la lista. 4.- Seleccionamos ASM y damos en OK. 5.- Seleccionamos una ruta donde guardar nuestro proyecto. 6.- Ya que seleccionamos la ruta, ahora creamos una carpeta donde se alojaran los

archivos de nuestro proyecto. 7.- Después de crear la carpeta, nombramos nuestro proyecto y oprimimos guardar.

Con esto tendremos en la parte izquierda de la pantalla el administrador de proyectos el cual nos muestra todos los archivos que forman parte de nuestro proyecto, en este caso el mas importante es el código fuente que tiene la extensión *.s43 (no es *.asm como con los PIC´s), posteriormente cuando creemos nuestras propias bibliotecas o librerías las podremos incluir y visualizar en esta parte.

En la parte derecha tenemos un editor de texto, el cual contiene una plantilla generada por IAR Embedded Workbench, la cual borraremos casi en su totalidad ya que contiene instrucciones del preprocesador y por ahora no tiene mucho sentido saber que hacen. En esta sección escribiremos nuestros programas como lo indica la sección de tutorial de teoría básica.

CREAR PROYECTO EN C++.

El proceso para crear un proyecto en C++ es muy similar a crear un proyecto en ensamblador. Es necesaria esta configuración para poder compilar nuestros programas ya que de lo contrario no tendremos esta opción.

Configurar IAR en C++ - VIDEO

http://www.youtube.com/watch?feature=player_embedded&v=2cKk-nOFF0k&noredirect=1

Pasos:

1.- Ejecutar IAR Embedded Workbench. 2.- Ir a menu Proyect>Create New Proyect. 3.- En donde dice Project Templates Seleccionamos C++ para abrir la lista. 4.- Seleccionamos main y damos en OK. 5.- Seleccionamos una ruta donde guardar nuestro proyecto. 6.- Ya que seleccionamos la ruta, ahora creamos una carpeta donde se alojaran los

archivos de nuestro proyecto. 7.- Después de crear la carpeta, nombramos nuestro proyecto y oprimimos guardar.

De igual manera obtenemos un administrador de proyectos en la parte izquierda donde podremos incluir otro tipo de código fuente y navegar por los archivos de nuestro proyecto, en la parte del editor de textos obtenemos una plantilla con la característica sintaxis de C/C++, a diferencia de la plantilla en ensamblador, esta si nos será útil, solo como base claro pero no hay necesidad de borrarla.

CONFIGURACION DEBUG/RELEASE.

Con los tutoriales anteriores ya estamos listos para editar nuestros programas pero aun no está configurado IAR para transferirlos al microcontrolador, tampoco lo está para simular ni emular. Es necesaria esta configuración para trabajar con un dispositivo conectado vía puerto USB, paralelo o serial (el Launchpad se conecta vía USB) .

A continuación el tutorial que muestra cómo hacerlo, cabe mencionar que esta configuración es igual para programas en C/C++ o en ensamblador.

Debug Release con IAR - VIDEO

http://www.youtube.com/watch?feature=player_embedded&v=wDLMnASBYVE

Pasos:

1.- Abrir o crear un proyecto. 2.- Menú Project>Options. 3.- En la categoría de General Options, en la parte donde dice device presionamos el

icono en la parte derecha del cuadro de texto y seleccionamos el dispositivo que usaremos y damos en Ok.

4.-En la pestaña del administrador de proyectos seleccionamos Release. 5.- Menú Project>Options. 6.- En la categoría de General Options, en la parte donde dice device presionamos el

icono en la parte derecha del cuadro de texto y seleccionamos de nuevo el dispositivo que usaremos.

7.- En la categoría de Debugger en la parte donde dice Driver seleccionamos la opción de FET Debugger.

8.- En la categoría de FET Debuger seleccionamos la pestaña de Download y activamos la casilla de Verify Download.

9.- Presionamos Ok

Así concluimos con las configuraciones necesarias para editar, simular y emular nuestros programas escritos en C/C++ o ensamblador.

¿PARA QUE CONFIGURAR DEBUG Y RELEASE?.

Estas configuraciones las hicimos primero que nada para seleccionar el dispositivo a usar y para asociar a IAR con alguna herramienta de emulación (Flash Emulation Tools) las cuales sirven para comunicar al microcontrolador con la PC vía puerto serial o USB.

En la sección de espacio de trabajo (Workspace) podemos seleccionar el modo en el que deseamos trabajar ya sea debug o release.

Debug lo configuramos para simular nuestro programa, esto nos permite detectar errores antes de transferir la información al microcontrolador ya que se nos permite correr el programa paso por paso, insertar puntos de ruptura, modificar registros, simular interrupciones, ver el mapa de memoria etc.

Release lo utilizamos para transferir nuestro programa al microcontrolador, en este modo también podemos correr el programa paso a paso y en el caso de tener conectado el hardware necesario podemos ver como se ejecuta cada una de las instrucciones, es importante mencionar que en este modo no podemos simular interrupciones, ya que en algunos casos deberán ser generadas por hardware.

También es importante mencionar que en el modo Release, después de que se estableció la comunicación esta no se puede interrumpir, es decir desconectar el cable USB ya que esto puede llegar a dañar tanto al puerto USB como a nuestra Launchpad. Para desconectar nuestro microcontrolador debemos finalizar la sesión de emulación.

EJEMPLOS EN ENSAMBLADOR DE MSP430™

El ensamblador proporciona un "control total" del dispositivo, ya que solo así podemos configurarlo de la manera más cómoda para nuestra aplicación, la lógica a veces suele ser un poco complicada pero dividiendo el trabajo en subrutinas el trabajo se vuelve más sencillo.

Con este lenguaje tenemos acceso a funciones e instrucciones que no son tan accesibles desde C/C++, eso si es un poco más largo el proceso de aprendizaje pero realmente vale la pena.

Aquí está disponible una lista de ejemplos sencillos para el uso de los microcontroladores MSP430™ con la herramienta de desarrollo LaunchPad, te recomendamos que visites la sección de tutoriales para ver como programar los microcontroladores utilizando el IAR Embedded Workbench.

Cabe mencionar que todos estos programas están bien documentados y son a prueba de errores, trataremos de incluir videos de los programas en ejecución para que veas la forma en que trabajan, posteriormente incluiremos también los diagramas de flujo correspondientes y los circuitos eléctricos en caso de que estos sean necesarios.

Arquitectura:

Practica 1: Tablas y apuntadores Practica 2: Corrimientos Practica 3: Sumas y Restas Practica 4: Multiplicacion 16x16

Puertos:

Practica 1: Encender un led al pulsar Practica 2: Encender un led, apagar otro al pulsar Practica 3: Encender un led por 10 segundos Practica 4: Secuencia de 8 leds Practica 5: PWM de 10% en 10% Practica 6: Cuenta de display de 0 a 99

Descargar todos en RAR.-puertos.rar

Timer_A:

Practica 1: Encender un led por 10 segundos Practica 2: Secuencia con corrimientos Practica 3: Secuencia cualquiera con tablas Practica 4: PWM automatico con Time_A y WDT

Descargar todos en RAR.-timera.rar

Perro Guardian

Practica 1: Conmutar un led cada 5s Practica 2: La entrada digital numero 11

Descargar todos en RAR.-wdt.rar

EJEMPLO 1: TABLAS Y APUNTADORES

Otro recurso de software muy importante es el de los apuntadores ya que a través de ellos podemos acceder a gran cantidad de información a partir de solo una dirección, haciendo la analogía con C/C++ podemos implementar arreglos de información.

Las tablas nos permiten almacenar información en la FLASH junto con el programa principal en el momento de la grabación, esta información puede ser útil o no dependiendo la manera en que la implementemos, pueden ser algoritmos, secuencias para motores paso a paso, valores de una función continua, valores de una función discreta, aproximaciones para el cálculo de funciones matemáticas, posiciones de objetos etc. Todo depende de nuestro hardware conectado y además de nuestro programa.

En esta sección te enseñaremos como declarar un apuntador y asociarlo a una tabla ya que a menudo utilizaremos estos conceptos en programas de ejemplo. Además de que será de gran ayuda conocer estas herramientas.

DEFINIENDO UNA TABLA

Para esto tenemos dos opciones, una de ellas es guardar datos de 8 bits o bien de 16 bits, tu decidirás cual es la que se ajusta más a tus opciones. Para ello seguiremos la siguiente sintaxis primero para 8 bits:

ETIQ DC8 00000001b,00000010b,00000100b,00001000bFINT DC8 0

ETIQ es el nombre de la tabla y para cada tabla este debe de ser diferente, el segundo renglón llamado FINT indica que la tabla ha acabado, esto hace fácil el proceso de añadir más elementos a la tabla además de que es útil al momento de programar para detectar el fin de la tabla.

La palabra clave DC8 es la que se encarga de indicarle al compilador que los datos que están a continuación deberán guardarse en la FLASH tal como están. También podemos ver que cada elemento de la tabla es separado por una coma.

En este ejemplo los datos se ingresan de manera binaria, pero también se pueden hacer de forma hexadecimal (valor máximo 0xFF), decimal (valor máximo 255) e incluso con caracteres los cuales serán codificados en la FLASH en código ASCII. Así se pueden definir tablas de la siguiente manera:

ETIQ DC8 10,20,30,40,50,60,70,80,90,100FINT DC8 0ETIQ1 DC8 0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0x100FINT1 DC8 0ETIQ2 DC8 'HOLA MUNDO CRUEL!!'FINT2 DC8 0

La palabra reservada DC8 solo aplica a un renglón, si se nos acaba el espacio disponible en el editor de IAR entonces debemos de poner otro DC8 y continuar con la definición de la tabla. Así si queremos agregar mas elementos a la tabla llamada ETIQ haremos lo siguiente:

ETQT DC8 00000001b,00000010b,00000100b,00001000bDC8 00010000b,00100000b,01000000b,10000000b

FINT DC8 0

Para definir tablas con datos de 16 bits lo único que debemos hacer es cambiar DC8 por DC16 y entonces comenzar a definir los datos de forma binaria(no muy recomendada por la longitud de los datos al momento de la edición), decimal (valor máximo 65,535), hexadecimal (valor máximo 0xFFFF) o con caracteres de la misma forma que lo hicimos con la tabla con datos de 8 bits.

DECLARANDO UN APUNTADOR

Para crear un apuntador primero requerimos una dirección a la cual apuntara, esa dirección puede ser la de la tabla llamada Sec0 declarada a continuación:

Sec0 DC8 'Copiando letra por letra a la RAM'DC8 'Copia finalizada!!'

FIN0 DC8 0

Así para asignar un apuntador a esa tabla (arreglo de datos haciendo una analogía con C/C++) haremos la siguiente instrucción:

MOV #Sec0,R4

Recordemos que los registros de la CPU pueden ser utilizados para guardar tanto datos como direcciones, en el caso de guardar direcciones entonces serian considerados como apuntadores. Lo que estamos haciendo con esta instrucción es convertir a R4 en un registro apuntador ya que estamos copiando la dirección de la tabla llamada Sec0 en su interior.

Ahora lo que haremos es mover el contenido de la tabla a la RAM solo como ejemplo. La RAM para el MSP430G2231 inicia en la posición 0x200 así que comencemos definiendo la constante inicioRAM con un valor de 0x200 así:

#define inicioRAM 0x200

Ya que tenemos el registro el cual apunta a nuestra tabla necesitamos uno que nos indique a partir de que dirección iniciara la copia, este será R5 el cual hay que inicializar.

CLR R5

Utilizaremos la siguiente instrucción para mover el contenido de la dirección apuntada (el primer elemento de la tabla) a la primera posición de la RAM

MOV.B @R4+,inicioRAM(R5)

El apuntador R4 tiene la dirección del siguiente elemento de la tabla pero R5 tiene la misma dirección, por lo cual para hacer que apunte a la próxima posición en la RAM debemos incrementar a R5 con la siguiente instrucción:

INC R5

Si esto lo combinamos con un ciclo el cual pare hasta que se llegue al fin de la tabla entonces tendremos lo que hemos estado buscando, donde R4 apunta al dato de la tabla y R5 apunta a la dirección donde será copiado el dato. Este ciclo quedaría definido así:

ETQ0 MOV.B @R4+,inicioRAM(R5)INC R5CMP #FIN0,R4JNE ETQ0

Podemos notar que después del incremento comparamos la dirección de fin de la tabla con la dirección que contiene R4, si no son iguales significa que aun no se ha finalizado la copia de la tabla, cuando la dirección del fin de la tabla sea igual a la dirección contenida por R4 significara que se ha concluido la transferencia.

Veras que esto de los apuntadores y las tablas nos será de gran utilidad, además con este programa podemos copiar cualquier posición de la memoria a la RAM lo cual será útil cuando escribamos en la FLASH o bien para implementar un administrador de memoria en un sistema operativo o para que tu apliques tus propias variaciones para tus aplicaciones.

EJEMPLO 2: CORRIMIENTOS A LA IZQUIERDA

Los corrimientos son importantes para crear algoritmos útiles, entre sus aplicaciones mas destacadas están las de multiplicación, división, registros de corrimiento para comunicaciones seriales, secuencias de multiplexaje y otras más que puedes descubrir a medida que desarrollas aplicaciones.

En esta sección haremos introducción a el concepto de los corrimientos, así como también te enseñaremos la flexibilidad de esta arquitectura para extender el tamaño de sus operandos. Esta arquitectura tiene 4 tipos de corrimientos en sus set de instrucciones, ya sean emuladas o no, de estas cuatro dos son para realizar corrimientos a la izquierda y dos mas para realizar corrimientos a la derecha.

Comenzaremos con los corrimientos a la izquierda, el set de instrucciones de los MSP430™ cuenta como acabamos de mencionar con dos instrucciones con las cuales se pueden realizar corrimientos hacia la izquierda, estas son las siguientes:

RLA(.B) dstRLC(.B) dst

La primera es el corrimiento aritmético el cual coloca un cero en la posición cero del registro de destino, después el bit que antes estaba en la posición 0 pasa a la posición 1, el bit que estaba en la posición 1 pasa a la posición 2 y así hasta que el bit en la posición numero 15 pasa a la bandera de acarreo. La imagen siguiente ejemplifica el proceso de manera grafica.

Esto si se realiza la instrucción con 16 bits, es decir sin el modificador .B si elegimos realizar esta instrucción con solo 8 bits entonces ignoraremos los 8 bits mas altos así:

Se le conoce como corrimiento aritmético debido a que esta instrucción realiza una multiplicación aritmética dst x 2. Para demostrar esto un ejemplo.

Suponiendo que en el registro R15 de la CPU tenemos el siguiente valor binario: 0011011100101101, el cual tiene el valor decimal de 14125, al realizar la siguiente instrucción:

RLA R15

El valor en R15 es 0110111001011010 el cual tiene un valor binario de 28250 el cual como podemos notar es el numero contenido en R15 de manera inicial multiplicado por dos. Ademas de esto si realizamos esta instrucción ya sea 16 (sin el modificador .B) u 8 veces(con el modificador .B) entonces nuestro registro se encontrara vacio.

La otra instrucción de corrimiento a la izquierda es RLC la diferencia principal entre esta instrucción y la vista anteriormente es que en lugar de añadir un cero en el bit 0 se añade el contenido del acarreo. A continuación mostramos el proceso para ambas versiones de esta instrucción.

Para 8 bits.

Esta instrucción sirve como complemento a la primera ya que en la primera el máximo de bits con los cuales se puede realizar un corrimiento es 16, pero utilizando dos registros podemos hacer un corrimiento con un numero de 32 bits con solo combinar estas dos instrucciones de la siguiente manera:

RLA R14RLC R15

Con lo que gráficamente obtendríamos lo siguiente:

Como podemos ver el acarreo que genera el bit 15 es rescatado por la segunda instrucción la cual en lugar de introducir un cero, introduce el valor del acarreo. De esta manera podemos incrementar la longitud del corrimiento hasta el valor que deseemos o que requiramos, por ultimo veremos que para un corrimiento de 64 bits lo único que debemos hacer es añadir dos instrucciones RLC mas.

RLA R12RLC R13RLC R14RLC R15

El resultado estará contenido entonces por 4 registros de 16 bits los cuales para este caso han sido R12,R13,R14 Y R15 como veremos en secciones posteriores esto puede ser útil para realizar operaciones con más de 16 bits e incluso para operaciones con números menores a 16 bits.

CORRIMIENTOS A LA DERECHA

En principio este tipo de corrimientos son muy parecidos a los mostrados anteriormente, es decir en lugar de desplazar los bits a la izquierda los desplazan a la derecha.

Las dos instrucciones correspondientes para realizar este tipo de corrimientos son RRA y RRC, la sintaxis es la misma que para los corrimientos hacia la izquierda, en realizad tienen funciones simétricas a excepción de RRA la cual actúa de la siguiente manera:

Como podemos ver el bit 15 permanece sin cambio, pero en la posición 14 se copia el valor del bit 15, esto para conservar el signo, así en lugar de realizar una multiplicación por 2 binaria realiza la división entre 2.

Esto no es en realidad cierto si el bit mas significativo es 1, ya que este bit representa el signo de un numero por ejemplo en el caso de 1000100101101001 puede ser interpretado como 35177 en decimal o bien como -33129 por lo cual si aplicamos un corrimiento de este tipo obtendremos el siguiente numero: 1100010010110100 el cual puede ser interpretado como 50356 en decimal o bien como -17588 el cual es el primer numero dividido entre -2, para realizar una división entre 2 con 16 bits recomendamos la otra instrucción de corrimiento la cual presentaremos a continuación o bien después

de ejecutar esta instrucción verificar si la bandera N fue colocada, si este es el caso aplicaremos la siguiente instrucción:

BIC #80h,dst

Donde dst es el registro o localidad de memoria donde fue ejecutada la instrucción RRA previamente, esta instrucción borra el bit mas significativo del registro o localidad de memoria de 16 bits. Esto también puede ser interpretado como quita el signo.

Para la versión a 8 bits de la instrucción a través del modificador (.B) obtenemos el mismo resultado.

El set de instrucciones incluye de igual manera una instrucción de corrimiento a la derecha con acarreo, esta nos es útil para realizar divisiones entre dos sin necesidad de verificar si el resultado es positivo o negativo. A continuación una imagen.

Para 8 bits.

Como podemos ver esta instrucción es igual a RLC solo que los bits cambian de posición en sentido contrario, es decir hacia le derecha en lugar de a la izquierda, también se pueden combinar las dos instrucciones para poder realizar corrimientos a la derecha de 16, 36, 64 bits y hasta mas, dependiendo de nuestras necesidades.

EJEMPLO 3: SUMA Y RESTA A 32 BITS

En esta sección solo te demostramos como realizar sumas y restas con operandos de mas de 16 bits de longitud si es que algún día lo requieres, además es útil para demostrar la flexibilidad que nos brinda el set de instrucciones. Utilizaremos 6 identificadores para esta sección los cuales al final asignaremos a registros de la CPU mediante las directivas define.

Dos identificadores serán para almacenar el primer operando de 32 bits, estos son OP1L y OP2H. Otros dos serán para almacenar el segundo operando de 32 bits y estos son

OP2L y OP2H, además de almacenar el segundo operando estos identificadores almacenaran el resultado una ves que se ejecute la suma.

Comenzaremos entonces por realizar sumas de 32 bits con el uso de solo dos instrucciones:

ADD OP1L,OP2LADDC OP1H,OP2H

La primera instrucción suma la parte baja de ambos operandos y guarda el resultado en OP2L, si se genera un acarreo en esta suma entonces a través de la siguiente instrucción consideraremos este acarreo para obtener un resultado correcto ya que ADDC suma los dos operandos junto con el acarreo y el resultado es almacenado en OP2H, así el resultado de la suma se encontrara en OP2L y OP2H.

Para realizar una resta de 32 bits utilizaremos los mismos identificadores de manera que las instrucciones que realizan una resta de 32 bits son las siguientes:

SUB OP1L,OP2LSUBC OP1H,OP2H

Como podemos notar solo sustituimos la instrucción ADD por SUB y la instrucción ADDC por SUBC, el resultado es almacenado en OP2L y OP2H.

SUMA Y RESTA A 64 BITS

Para guardar un números de 64 bits requerimos 4 registros de 16 bits por lo que para realizar tanto sumas como restas con números de 64 bits requerimos 8 registros en total.

Para ello utilizaremos identificadores como en la sección anterior, para almacenar el operando 1 utilizaremos OP1_0, OP1_1, OP1_2 y OP1_3, para el operando 2 y resultado utilizaremos los siguientes OP2_0, OP2_1, OP2_2 u OP2_3.

Ya definidos los identificadores veremos que realizar una suma o resta de 64 bits es mas sencillo de lo que parece. A continuación el código necesario para ejecutar la suma:

ADD OP1_0,OP2_0ADDC OP1_1,OP2_1ADDC OP1_2,OP2_2ADDC OP1_3,OP2_3

Así si entre cada 16 bits se genera un acarreo este será considerado por la instrucción ADDC ya que esta suma ambos operandos junto con el acarreo para depositar el resultado en el Segundo operando.

La resta como en el caso de 32 bits se hace solo sustituyendo instrucciones ADD por SUB e instrucciones ADDC por SUBC para obtener lo siguiente:

SUB OP1_0,OP2_0SUBC OP1_1,OP2_1SUBC OP1_2,OP2_2

SUBC OP1_3,OP2_3

Como podemos ver es fácil implementar sumas, restas y corrimientos con valores mayores a los 16 bits esto gracias al set de instrucciones que proporciona soluciones fáciles a problemas fáciles.

PROGRAMA DE APLICACIÓN

Realizaremos un programa el cual realice sumas y restas tanto con 32 como 64 bits para demostrar el uso de estas subrutinas, además como extra de la sección mostraremos un video donde te enseñamos a verificar tus algoritmos mediante el uso de IAR Embedded Workbench® a través de la herramienta de simulación que este IDE contiene.

A continuación te mostramos el código que hemos desarrollado para esta sección.

01|#include "msp430f2013.h"02|03|#define inicioSP 027Fh // Locacion en la RAM para la pila04|// Operando 1:05|// |Parte3||Parte2||Parte1||Parte0|06|#define OP1_0 R8 // Operando 1 parte 007|#define OP1_1 R9 // Operando 1 parte 108|#define OP1_2 R10 // Operando 1 parte 209|#define OP1_3 R11 // Operando 1 parte 310|// Operando 2:11|// |Parte3||Parte2||Parte1||Parte0|12|#define OP2_0 R12 // Operando 2 parte 013|#define OP2_1 R13 // Operando 2 parte 114|#define OP2_2 R14 // Operando 2 parte 215|#define OP2_3 R15 // Operando 2 parte 316|17|main18|19|;-------------------------------------------------------------------------------20| ORG 0xF800 ; Direccion de inicio del programa21|;-------------------------------------------------------------------------------22|RESET MOV #inicioSP,SP ; Inicio de la pila23| MOV #WDTPW+WDTHOLD,WDTCTL ; Apaga el perro guardian24|25|;**************************** Operaciones con 32 bits***************************26|27| MOV #0xAF70,OP1_0 ; El numero 0x11FAAF70 (301641584 decimal)28| MOV #0x11FA,OP1_1 ; es colocado en OP1_0 y OP1_129| MOV #0x00FA,OP2_0 ; El numero 0x1A0F00FA (437190906 decimal)30| MOV #0x1A0F,OP2_1 ; es colocado en OP2_0 y OP2_131| CALL #SUMA32 ; Se realiza la suma de estos dos numeros, el32| ; resultado 0x2C09B06A (738832490) se almacena33| ; en OP2_0 y OP2_134|

35| MOV #0xAF70,OP1_0 ; Se carga en OP1_0 y OP1_1 el mismo valor para36| MOV #0x11FA,OP1_1 ; obtener los valores iniciales37| CALL #RESTA32 ; Se realiza la resta como resultado obtenemos38| ; 0x1A0F00FA (437190906 decimal)39|40|;**************************** Operaciones con 64 bits***************************41|42| MOV #0xAF70,OP1_0 ; Cargamos en el operando 1 0x4000B00111FAAF7043| MOV #0x11FA,OP1_1 ; (4611879537070485360 en decimal) en los cuatro44| MOV #0xB001,OP1_2 ; registros correspondientes45| MOV #0x4000,OP1_346|47| MOV #0x00FA,OP2_0 ; Cargamos en el operando 2 0x500O21321A0F00FA48| MOV #0x1A0F,OP2_1 ; (360324469258911994 en decimal) en los cuatro49| MOV #0x2132,OP2_2 ; registros correspondiente50| MOV #0x5000,OP2_351| CALL #SUMA64 ; Al sumar obtenemos 0x4500D1332C09B06A52| ; (4972204006329397354 en decimal)53|54| MOV #0x00FA,OP2_0 ; Cargamos el operando 1 con los valores que55| MOV #0x1A0F,OP2_1 ; tenia desde el principio para que al realizar56| MOV #0x2132,OP2_2 ; la suma obtengamos en el operando 2 lo que57| MOV #0x500,OP2_3 ; teniamos antes de realizar la suma 58| CALL #RESTA64 ; es decir: 0x500O21321A0F00FA59| ; (4611879537070485360 en decimal)60|61|62| BIS #CPUOFF,SR63| NOP64|;-------------------------------------------------------------------------------65|; Suma Con Operandos De 32 bits66|;-------------------------------------------------------------------------------67|SUMA32 ADD OP1_0,OP2_068| ADDC OP1_1,OP2_169| RET70|71|;-------------------------------------------------------------------------------72|; Resta Con Operandos De 32 bits73|;-------------------------------------------------------------------------------74|RESTA32 SUB OP1_0,OP2_075| SUBC OP1_1,OP2_176| RET77|78|;-------------------------------------------------------------------------------79|; Suma Con Operandos De 64 bits

80|;-------------------------------------------------------------------------------81|SUMA64 ADD OP1_0,OP2_082| ADDC OP1_1,OP2_183| ADDC OP1_2,OP2_284| ADDC OP1_3,OP2_385| RET86|87|;-------------------------------------------------------------------------------88|; Resta Con Operandos De 64 bits89|;-------------------------------------------------------------------------------90|RESTA64 SUB OP1_0,OP2_091| SUBC OP1_1,OP2_192| SUBC OP1_2,OP2_293| SUBC OP1_3,OP2_394| RET95|96|;-------------------------------------------------------------------------------97|; Vectores de Interrupción y Reset98|;-------------------------------------------------------------------------------99| ORG 0xFFFE ; Vector para el RESET100| DW RESET ; Etiqueta correspondiente101|102| END

Primero debemos acordar algunas definiciones para hacer mas clara la programación y la legibilidad, es decir definir que registros de la CPU formaran parte del operando 1 y que registros forman parte del operando 2 para operaciones a 32 y 64 bits.

Para ello en las líneas 6-9 vemos que asignamos de la siguiente manera los registros que forman parte del operando 1, OP1_0 a R8, OP1_1 a R9, OP1_2 a R10 y OP1_3 a R11 de igual forma para el operando 2 definimos OP2_0 a R12, OP2_1 a R13, OP2_2 a R14 y por ultimo OP2_3 aR15.

Podemos ver también que las instrucciones vistas en secciones anteriores fueron convertidas en subrutinas con nombres muy representativos. En las líneas 67-69 se encuentra la subrutina que realiza una suma a 32 bits, en las líneas 74-76 se encuentra la resta a 32 bits, en las líneas 81-85 esta la suma a 64 bits y por ultimo en las líneas 90-94 se encuentra la resta a 64 bits.

El programa principal el cual utilizara estas subrutinas está definido desde la línea 22 hasta la 63, antes de mandar a llamar a cada subrutina cargamos valores tanto en el operando 1 como en el operando 2 a través de instrucciones MOV.

A continuación te mostramos un video en el cual realizamos la simulación mediante IAR para verificar que realmente el programa hace lo que debe. Como estas subrutinas son elementos puramente de software no podemos armar un circuito y comprobar que todo va bien, si no que debemos de simular a la CPU.

Obtener codigo fuente - suma-resta.s43

EJEMPLO 4: MULTIPLICACION DE 16X16 BITS

Las practicas de la sección de arquitectura te introduciremos al uso de algunos algoritmos útiles para la realización de otras aplicaciones o programas más complejos, te presentamos los algoritmos a manera de apoyo para que refuerces tus conocimientos, así como para que puedas adaptarlos a tus aplicaciones si así lo ameritan.

En esta página en especifico realizaremos la multiplicación de dos números de 16 bits sin signo, esto a manera introductoria para los demás algoritmos de multiplicación que continúan.

Antes de comenzar con el desarrollo de este programa hay que mencionar que una multiplicación binaria se realiza de igual forma que una multiplicación decimal. Para entender mejor el algoritmo realizaremos un ejemplo en el cual multiplicaremos de forma binaria los números 1011010111010011 y 1101100.

Primero hay que ordenar de cierta manera a los dos operandos, nosotros los hemos ordenado de esta manera ya que así el algoritmo es más corto pero recordemos que en la multiplicaciones el orden de los factores no altera el producto. Después de eso lo que haremos es recorrer el operando 1 que se encuentra en la parte inferior bit a bit.

Comenzando por el bit menos significativo del operando 1 remarcado en azul multiplicaremos este bit por el operando 2 y lo pondremos como resultado.

Ahora haremos lo mismo con el segundo bit, el cual para este caso es cero por lo cual obtendremos lo siguiente:

El procedimiento continua así hasta terminar con el bit mas significativo del operando 1

Ya que hayamos terminado de recorrer todos los bits del operando 1 entonces estaremos listos para realizar la suma que nos llevara a obtener el resultado correcto.

De esta manera es como se realiza la multiplicación binaria, al analizar el algoritmo descrito podemos notar algunos aspectos los cuales nos serán útiles al momento de realizar el algoritmos correspondiente. Esos aspectos se mencionan a continuación.

1.-En cada iteración se realiza un corrimiento a la izquierda. 2.-El bit del operando 1 que ya fue utilizado jamás en el proceso vuelve a ser utilizado.

Tomando esto en cuenta podemos realizar el algoritmo de la siguiente manera:

El primer bit es cero por lo cual haremos un corrimiento a la izquierda en el operando 2 y un corrimiento a la derecha en el operando 1

Como podemos notar en verde añadimos un cero como resultado del corrimiento a la izquierda en el operando 2, pero en el operando 1 eliminamos el cero que comprobamos, como ese bit era cero el resultado permanece en ceros. Ahora como el siguiente bit a comprobar también es cero haremos lo mismo, es decir un corrimiento a la izquierda al operando 2 y un corrimiento a la derecha en el operando 1.

Como podemos ver el resultado continua en ceros, esto debido a que los bits que hasta ahora hemos comprobado han sido cero, pero ahora vemos que es lo que ocurre cuando el bit a comprobar es un 1.

Primero sumamos el operando 2 a resultado.

Después hacemos lo mismo que cuando encontramos un cero, es decir realizar un corrimiento a la izquierda en operando 2 y uno a la derecha en operando 1. Esta es una forma distinta de ver el proceso de la multiplicación la cual nos será más útil.

DESARROLLO DE LA SUBRUTINA

Primero definiremos los registros con los cuales trabajaremos para realizar la multiplicación.

Como registro donde guardaremos al primer operando esta R5 al cual definiremos de la siguiente manera para escribir OP1 a lo largo del programa y no R5

#define OP1 R5

Para el segundo operando requerimos dos registros ya que con los corrimientos, en un caso extremo puede llegar a tener el doble de la longitud. Por lo cual definiremos a R6 y R7 como OP2L (parte baja "low") y OP2H (parte alta "high")

#define OP2L R6#define OP2H R7

El resultado en varios casos puede resultar ser mayor a 16 bits por lo cual también estará formado por dos registros, es decir R8 y R9 por lo que los definiremos como RESL y RESH respectivamente con las siguientes directivas del preprocesador.

#define RESL R8#define RESH R9

Como resultado del análisis hemos desarrollado un diagrama de flujo el cual explica de manera grafica el algoritmo el cual hay que seguir para obtener la multiplicación. El diagrama lo mostramos a continuación.

Ya realizadas las definiciones correspondientes comenzaremos a traducir nuestro algoritmo en instrucciones que la CPU pueda interpretar. Este algoritmo estará en una subrutina la cual podremos llamar con la instrucción CALL, al final crearemos un programa que implemente esta subrutina. Primero debemos borrar o inicializar los registros que utilizaremos, es decir RESL, RESH y OP2, los demás registros no son borrados ya que antes de llamar a la subrutina debemos de cargarlos con los operandos correspondientes.

MULT CLR RESLCLR RESHCLR OP2H

Como podemos notar además de borrar los registros declaramos la etiqueta llamada MULT la cual nos servirá cuando empleemos la instrucción CALL.

Comprobaremos el valor del bit menos con la instrucción BIT la cual realiza una operación and entre la fuente y el destino sin modificar los valores, esto para únicamente alterar las banderas. Esta instrucción la utilizaremos en conjunto con un

salto condicional JZ el cual se efectuara si al bit menos significativo es 0, de lo contrario (que sea 1) no se ejecuta el salto y el programa continua ejecutando la siguiente instrucción. A continuación mostramos las instrucciones que harán lo antes mencionado.

ET_02 BIT #1,OP1JZ ET_01

Auxiliándonos del diagrama de flujo podemos ver que si el bit es uno entonces debemos añadir el operando 2 al resultado, de lo contrario solo ejecutaremos los corrimientos correspondientes, además de que en cualquier caso los corrimientos se llevaran a cabo.

Así si el bit menos significativo es 1 la CPU no ejecuta el salto por lo tanto a continuación de las instrucciones anteriores debemos colocar las instrucciones correspondientes para llevar a cabo la suma del operando 2 con el resultado así:

ET_02 BIT #1,OP1JZ ET_01ADD OP2L,RESLADDC OP2H,RESH

Si el bit es cero entonces se ejecuta el salto y los corrimientos se llevan a cabo por lo cual completaremos la rutina de la siguiente manera:

MULT CLR RESLCLR RESHCLR OP2H

ET_02 BIT #1,OP1JZ ET_01ADD OP2L,RESLADDC OP2H,RESH

ET_01 RLA OP2LRLC OP2HRRC OP1JNZ ET_02RET

Esta es la forma final de la subrutina donde podemos ver las etiquetas para los saltos condicionales, además los corrimientos tanto del operando 2 (dos instrucciones ya que es de 32 bits de largo) como del operando 1 (hacia la derecha).

Por ultimo vemos que después del corrimiento del operando 1 encontramos otro salto condicional el cual nos ayudara a saber cuando debe terminar la subrutina. Esta terminara cuando el operando 1 haya sido desplazado completamente hasta estar vacio, lo cual ocurrirá en el caso extremo a las 16 iteraciones. Para nuestro ejemplo solo serán 7 veces.

EL PROGRAMA DE APLICACIÓN

Como podemos ver esta subrutina altera nuestros operandos después de que la multiplicación se llevo a cabo, por lo regular el operando dos es muy diferente al introducido inicialmente y el operando 1 termina siendo cero, así que tomando esto en

cuenta crearemos un programa el cual a partir de un valor inicial y un incremento generara el cuadrado de cada valor en la serie colocándolo en la RAM, por ejemplo si ponemos como valor inicial a 1 y un incremento de 1 obtendremos 1, 4 ,9 , 16, 25, 36 y así en lo sucesivo.

Para comprender mejor el proceso que llevara a cabo nuestro programa te mostramos a continuación su diagrama de flujo.

A continuación mostramos el programa completo con la descripción correspondiente.

01|#include "msp430f2013.h"02|03|#define inicioSP 027Fh // Locacion en la RAM para la pila04|#define inicioRAM 200h // Lugar de inicio de la RAM05|#define finRAM 270h // Lugar donde termina la RAM06|07|#define TEST R4 // Registro para la posicion08|#define OP1 R5 // Primer operando de 16 bits09|#define OP2L R6 // Segundo operando de 16 bits10|#define OP2H R7 // Parte alta del segundo operando11|#define RESL R8 // Resultado parte baja12|#define RESH R9 // Resultado parte alta13|14|#define valinicial 0FFh // Valor inicial para la serie15|#define incremento 0Ah // Incremento entre cada valor16|17|main18|19|;-------------------------------------------------------------------------------20| ORG 0xF800 ; Direccion de inicio del programa21|;-------------------------------------------------------------------------------22|RESET MOV #inicioSP,SP ; Inicio de la pila23| MOV #WDTPW+WDTHOLD,WDTCTL ; Apaga el perro guardian24|25| CLR R15 ; Inicializa el indice a cero26| MOV #valinicial,OP1; Primer operando27|CUAD MOV OP1,OP2L ; Segundo operando = Primer operando28| PUSH OP1 ; Guarda una copia del OP1 en la pila29| CALL #MULT ; Llamada a la rutina de multiplicacion30| POP OP1 ; Recupera la copia de OP131| ADD #incremento,OP1; Añade el incremento a OP132|33| MOV RESL,inicioRAM(R15) ; Resultado parte baja a la RAM34| INCD R15 ; Siquiente localidad de la RAM35| MOV RESH,inicioRAM(R15) ; Resultado parte altaa la RAM36| INCD R15 ; Siquiente localidad de la RAM37|38| CMP #finRAM-inicioRAM,R15 ; ¿Se ha terminado de llenar la RAM?39| JNZ CUAD40|41| BIS #CPUOFF,SR42| NOP43|;-------------------------------------------------------------------------------44|; Rutina que realiza la multiplicacion45|;-------------------------------------------------------------------------------46|MULT CLR RESL ; Borrar el registro de resultado parte baja

47| CLR RESH ; Borrar el registro de resultado parte alta48| CLR OP2H ; Borrar la parte alta del operando49|ET_02 BIT #1,OP1 ; ¿Es 1 o 0 el bit menos significativo?50| JZ ET_01 ; Si es cero continua en ET_0151| ADD OP2L,RESL ; Suma el operando 2 a resultado52| ADDC OP2H,RESH ; tanto parte baja como parte alta53|ET_01 RLA OP2L ; Realizar corrimiento para la siguiente54| RLC OP2H ; iteracion55| RRC OP1 ; Corrimiento a la derecha para el bit siguiente56| JNZ ET_02 ; ¿Termino?57| RET58|59|;-------------------------------------------------------------------------------60|; Vectores de Interrupción y Reset61|;-------------------------------------------------------------------------------62| ORG 0xFFFE ; Vector para el RESET63| DW RESET ; Etiqueta correspondiente64|65| END

Podemos ver que se han definido los valores inicioRAM y finRAM en las líneas 4 y5 los cuales indicaran a nuestro programa a partir de donde podrán iniciar a escribir la información y cuando deberán detenerse.

Después en el mismo bloque de definiciones se encuentran los identificadores correspondientes para realizar la multiplicación los cuales ya conocemos (líneas 7-12). Adicionalmente definimos las constantes que nos permitirán controlar la serie de números a los cuales obtendremos su cuadrado, es decir un valor inicial y un incremento.

Posteriormente se encuentran las partes indispensables de un programa las cuales ya conocemos y son la palabra main, la dirección de inicio de programa (ORG 0xF800 ), la etiqueta de RESET junto con las instrucciones para asignar a la pila en la RAM y apagar el perro guardián en las líneas 20-23.

Ahora vemos que en la línea 25 borramos el contenido de R15, esto porque lo utilizaremos como índice para poder grabar los resultados en la RAM de manera correcta y ordenada.

Como nuestra subrutina realiza la multiplicación de dos números, entonces requiere de dos parámetros, es decir OP1 y OP2L, pero como el programa que estamos desarrollando obtiene el cuadrado de una serie de números entonces utilizaremos la subrutina de multiplicación para este objetivo colocando tanto en OP1 como en OP2L el mismo número así que primero cargamos a OP1 con el valor inicial en la línea 26 y después copiamos OP1 en OP2L en las líneas 27 y 28.

Como mencionamos anteriormente la subrutina que realiza la multiplicación altera nuestros operandos (que en este caso son iguales) por lo cual debemos de respaldarlos,

ya que son iguales basta con respaldar a OP1, una manera rápida de realizar esta acción es colocar a OP1 en la pila con la instrucción PUSH que vemos en la línea 28, después llamamos a la subrutina MULT lo cual altera a ambos operandos (OP1 se hace cero y OP2L termina con un valor impredecible) pero a través de la operación POP OP1 en la línea 30 logramos recuperar el valor de OP1.

Como podemos ver utilizamos una instrucción POP por cada instrucción PUSH como recomendamos cuando se realiza cualquier manipulación de la pila. Si posteriormente utilizamos este programa en otra aplicación y en esta aplicación utilizamos interrupciones debemos tener en cuenta que si nuestra ISR utiliza a la pila, entonces debemos seguir esta misma recomendación, es decir por cada instrucción POP utilizar una instrucción PUSH, ya que de lo contrario puede ocurrir que el flujo del programa sea impredecible entrando este en descontrol.

Ya que se recupero el valor de OP1 entonces le sumamos el incremento en la línea 31, así se preparan las condiciones para la próxima iteración.

Por último antes de repetir el mismo proceso para el siguiente valor, debemos de enviar los resultados a la RAM, esto porque es parte del objetivo del programa, lo cual hacemos con las líneas 33-36 donde utilizamos el registro índice para indicar cuantas posiciones a partir del inicio de la RAM se guardara la información, utilizamos incrementos dobles en el registro índice R15 ya que cada localidad de la RAM es de 8 bites por lo cual para apuntar a la próxima palabra (word) debemos de incrementar el índice en 2. Cuando se realiza la multiplicación de 8 bits veremos que solo se requiere incrementar el índice en 1.

Ya que se realizo la multiplicación y además se enviaron los resultados a la RAM solo queda verificar si es que ya se ha llegado al límite de la RAM para entonces terminar las iteraciones, de lo contrario seguir con el siguiente valor lo cual hacemos en las líneas 38-39 en la cual restamos el valor del fin de la RAM con el de inicio y después comparamos este valor con el registro índice, es decir comparamos el número de localidades disponibles con el número de localidades que y hemos llenado. Si la comparación resulta ser cero entonces significa que debemos de terminar, si no resulta ser cero entonces aun hay espacio disponible para poder seguir calculando los valores.

Como podemos notar la RAM no termina en la dirección que asignamos, es decir 270h, ya que la RAM de nuestro MSP430F2231 termina en la posición 027Fh, la razón principal de que no hayamos utilizado este valor para la constante finRAM es porque la pila esta localizada en la RAM, por lo cual declaramos el fin de la ram antes para que el programa no altere a la pila, como ya hemos mencionado el alterar a la pila puede traer consecuencias desastrosas para nuestras aplicaciones así que con esto damos cierto margen de error para que la pila pueda incrementarse hasta en 7 niveles mas.

Obtener codigo fuente - multiplicacion.s43

PRACTICAS MANEJO DE PUERTOS

PRACTICA 1 - Encender un led al pulsar

Este primer programa realiza la conmutación de un led conectado en el bit P1.0 al oprimir un botón conectado en el bit P1.3, con este programa podemos poner en practica las configuraciones realizadas con los puertos así como ver como es que se configura el vector de interrupciones del puerto 1 y se crea la rutina de servicio a la interrupción.

También podemos ver un video el cual nos muestra el programa en ejecución.

CODIGO FUENTE ; Autor: Humberto Aparicio Osorio; Fuente: http:/todomcu.scienceontheweb.net; Enviar dudas a: [email protected]; "Haz Tuyo El Conocimiento y Difúndelo"

#include

#define midram 0240h#define time 4000 /* Constante para el retardo*/main;-------------------------------------------------------------------------------

ORG 0F800h;-------------------------------------------------------------------------------RESET MOV.W #midram,SP ; Configuracion de la pila

MOV.w #WDTPW+WDTHOLD,&WDTCTL ; WDT apagado

MOV.B &CALBC1_1MHZ,&BCSCTL1 ; Calibracion delMOV.B &CALDCO_1MHZ,&DCOCTL ; oscilador a 1MHz

CLR.B &P1SEL ; P1 como e/s digitalMOV.B #11110111b,&P1DIR ; Todo P1 como salida excepto

P1.3MOV.B #00001000B,&P1OUT ; Apagar P1 y resistencia Pull-

Up en P1.3BIS.B #BIT3,&P1REN ; Resistencia Pull-Up habilitadaBIC.B #BIT3,&P1IES ; Flanco de bajada en P1.3BIC.B #BIT3,&P1IFG ; Borrado de la bandera P1.3BIS.B #BIT3,&P1IE ; Interrupcion local permitida

MOV #GIE+CPUOFF,SR ; Interrupciones habilitadas yNOP ; CPU apagado

;-------------------------------------------------------------------------------P1_ISR; Rutina de Servicio a la Interrupción;-------------------------------------------------------------------------------

XOR.B #BIT0,&P1OUT ; Conmuta el estado del ledBIC.B #BIT3,&P1IFG ; Borrar bandera por software

para poder ; Salir de la interrupcion

RETI ; Instruccion para indicar que la rutina

; de servicio a la interrupcion termino

;-------------------------------------------------------------------------------; Vectores de Interrupcion y Reset;------------------------------------------------------------------------------- ORG 0FFFEh ; Reset DW RESET ; Etiqueta para Reset

ORG 0FFE4h ; Vector para la int del P1 DW P1_ISR ; Etiqueta de la RSI END main

Practica 1.flv - VIDEO http://www.youtube.com/watch?v=rRrhoKI3HbE&feature=player_embedded

PRACTICA 2 - Encender un led, apagar otro al pulsar

Este programa es similar al anterior pero en este hacemos uso de los dos leds disponibles en el LaunchPad, tras hacer dos pequeñas modificaciones en el programa anterior logramos este, el cual al oprimir el botón conectado en P1.3 hacemos que los leds conmuten su estado, es decir el led que estaba apagado se enciende y el que estaba encendido se apaga.

Al igual que en el anterior hacemos uso de las interrupciones por lo cual no requerimos de subrutinas de retardo para eliminar los rebotes.

CODIGO FUENTE ; Autor: Humberto Aparicio Osorio; Fuente: http:/todomcu.scienceontheweb.net; Enviar dudas a: [email protected]; "Haz Tuyo El Conocimiento y Difúndelo"

#include

#define midram 0240hmain;-------------------------------------------------------------------------------

ORG 0F800h;-------------------------------------------------------------------------------RESET MOV.W #midram,SP

MOV.w #WDTPW+WDTHOLD,&WDTCTL ; WDT apagado

MOV.B &CALBC1_1MHZ,&BCSCTL1 ; Calibracion delMOV.B &CALDCO_1MHZ,&DCOCTL ; oscilador a 1MHz

CLR.B &P1SEL ; P1 como e/s digitalMOV.B #11110111b,&P1DIR ; Todo P1 como salida excepto

P1.3MOV.B #00001001b,&P1OUT ; Apagar P1 y resistencia Pull-

Up en P1.3BIS.B #BIT3,&P1REN ; Resistencia Pull-Up habilitadaBIC.B #BIT3,&P1IES ; Flanco de bajada en P1.3BIC.B #BIT3,&P1IFG ; Borrado de la bandera P1.3BIS.B #BIT3,&P1IE ; Interrupcion local permitida

MOV #GIE+CPUOFF,SR ; Interrupciones habilitadas yNOP ; modo de ahorro de energia

;-------------------------------------------------------------------------------P1_ISR; Rutina de Servicio a la Interrupción;-------------------------------------------------------------------------------

XOR.B #BIT0+BIT6,&P1OUTBIC.B #BIT3,&P1IFGRETI

;-------------------------------------------------------------------------------; Vectores de Interrupcion y Reset;------------------------------------------------------------------------------- ORG 0FFFEh ; Reset DW RESET ; Etiqueta para Reset

ORG 0FFE4h ; Vector para la int del P1 DW P1_ISR ; Etiqueta de la RSI

END main

Practica 2.flv - VIDEOhttp://www.youtube.com/watch?v=4aDGxlQ2hBs&feature=player_embedded

PRACTICA 3 - Encender un led por 10 segundos

Aquí hacemos uso de las subrutinas y subrutinas de tiempo para lograr un retardo de 10 segundos, el cual podemos visualizar mediante el encendido de un led. Al igual que en programas anteriores hacemos uso de las interrupciones del puerto 1 para que esto sea posible, un ejemplo mas de interrupciones y vector de interrupción.

CODIGO FUENTE ; Autor: Humberto Aparicio Osorio; Fuente: http:/todomcu.scienceontheweb.net; Enviar dudas a: [email protected]; "Haz Tuyo El Conocimiento y Difúndelo"

#include

#define midram 0240h#define time 60000#define time1 55main;-------------------------------------------------------------------------------

ORG 0F800h ; Direccion de inicio del programa;-------------------------------------------------------------------------------RESET MOV #midram,SP ; Inicializacion del SP

MOV #WDTPW+WDTHOLD,&WDTCTL ; WDT apagado

MOV.B &CALBC1_1MHZ,&BCSCTL1 ; Calibracion del DCOMOV.B &CALDCO_1MHZ,&DCOCTL

CLR.B &P1SEL ; P1 como E/S digitalMOV.B #11110111B,&P1DIR ; P1.3 como entradaMOV.B #00001000B,&P1OUT ; Resistencia Pull-UpBIS.B #BIT3,&P1REN ; Resistencia habilitadaBIS.B #BIT3,&P1IES ; Flanco de bajadaBIC.B #BIT3,&P1IFG ; Borrar la bandera de

interrupcionBIS.B #BIT3,&P1IE ; Interrupciones locales

habilitadas

MOV #GIE+CPUOFF,SR ; Modo de bajo consumo eNOP ; interrupciones globales

habilitadas

;-------------------------------------------------------------------------------P1_ISR; Rutina de servicio a la interrupcion;-------------------------------------------------------------------------------

BIS.B #BIT0,&P1OUT ; Enciende el ledCALL #RETARDO ; Retraso aproximado de 10 segBIC.B #BIT0,&P1OUT ; Apaga el ledBIC.B #BIT3,&P1IFG ; Borra la bandera de la

interrupcionRETI

;-------------------------------------------------------------------------------; Sub-rutina de Retardo;-------------------------------------------------------------------------------RETARDO MOV #time,R4 ; 60000 a R4 para loop interno

MOV #time1,R5 ; 55 a R5 para loop externoINT DEC R4 ; R4--

JNZ INT ; ¿R4 es cero?DEC R5 ; R5--JNZ INT ; ¿R5 es cero?RET

;-------------------------------------------------------------------------------; Vectores de Interrupcion y Reset

;-------------------------------------------------------------------------------

ORG 0FFFEh ; Vector para el resetDW RESETORG 0FFE4h ; Vector para la interrupcion

del P1DW P1_ISREND main

Practica 3.flv - VIDEO http://www.youtube.com/watch?v=C26oWKynd54&feature=player_embedded

PRACTICA 4 - Secuencia de 8 leds

En este programa implementamos una secuencia en la cual si conectamos 8 leds en todo el puerto 1 entonces al oprimir un botón colocado en P2.7 entonces obtenemos una secuencia en la cual enciende el led conectado a P1.0, después el conectado en P1.1 y así hasta que se encienda el led conectado en P1.7 y entonces se encenderá el P1.6 después el P1.5 hasta llegar al P1.0.

En este programa implementamos una secuencia en la cual si conectamos 8 leds en todo el puerto 1 entonces al oprimir un botón colocado en P2.7 entonces obtenemos una secuencia en la cual enciende el led conectado a P1.0, después el conectado en P1.1 y así hasta que se encienda el led conectado en P1.7 y entonces se encenderá el P1.6 después el P1.5 hasta llegar al P1.0.

CODIGO FUENTE ; Autor: Humberto Aparicio Osorio; Fuente: http:/todomcu.scienceontheweb.net; Enviar dudas a: [email protected]; "Haz Tuyo El Conocimiento y Difúndelo"

#include "msp430x20x3.h"

#define posc R4 /* Variable para almacenar la posicion*/#define limizq 128 /* Constante para el limite a la izquierda*/#define limder 1 /* Constante para el limite a la derecha*/#define midram 0240h /* Constante para desirnar el lugar de la pila*/#define time 40000 /* Constante para el retardo*/main;------------------------------------------------------------------------------- ORG 0F800h ; Direccion de inicio el la flash;-------------------------------------------------------------------------------RESET mov.w #midram,SP ; Inicio del SP mov.w #WDTPW+WDTHOLD,&WDTCTL ; WDT apagado

mov.b &CALBC1_1MHZ,&BCSCTL1 ; Calibracion del mov.b &CALDCO_1MHZ,&DCOCTL ; oscilador a 1MHz

clr.b &P1SEL ; P1 como i/o digital bis.b #0FFh,&P1DIR ; Todo P1 como salida

clr.b &P1OUT ; P1 en estado bajo

clr.b &P2SEL ; P2.7 como puerto digital mov.b #01000000b,&P2DIR ; P2.7 como entrada bic.b #BIT7,&P2OUT ; Resistencia PULL-DOWN bis.b #BIT7,&P2REN ; P2.7 resistencias

habilitadas bis.b #BIT7,&P2IES ; Flanco de bajada en P2.7 bic.b #BIT7,&P2IFG ; Limpiar bandera de int bis.b #BIT7,&P2IE ; Int habilitadas en

P1.7

mov #GIE+CPUOFF,SR ; Modo de ahorro e interrupciones

nop ; globales habilitadas

;-------------------------------------------------------------------------------P2_ISR; Rutina de Servicio a la Interrupcion;-------------------------------------------------------------------------------INICIO mov.b #limder,posc ; R4= 00000001 bIZQ mov.b posc,&P1OUT ; R4 a P1

rla.b posc ; Corrimiento <- call #RETARDO ; Retardo cmp.b #limizq,posc ; Es 1000 0000 ? jne IZQ

DER clrc ; Limpiar C rrc.b posc ; Corrimiento -> mov.b posc,&P1OUT ; Corrimiento a P1 call #RETARDO ; Retardo cmp.b #0h,posc ; Es 0000 0000 ? jne DER

bic.b #BIT7,&P2IFG ; Borrar la bandera P2.7 reti ; Salir de la interrupcion

;-------------------------------------------------------------------------------; Subrrutina Retardo;-------------------------------------------------------------------------------RETARDO mov #time,R5 ; Constante time a R5CONT dec R5 ; R5 = R5-1

jnz CONT ; Es cero? RET

;-------------------------------------------------------------------------------; Vectores de Interrupcion y Reset;------------------------------------------------------------------------------- ORG 0FFFEh ; Reset DW RESET ; Etiqueta para Reset

ORG 0FFE6h ; Vector para la int del P2 DW P2_ISR ; Etiqueta de la RSI

END main

PRACTICA 5 - PWM de 10% en 10%

Con este programa realizamos el cambio de brillo de un led a través de PWM, esto sin utilizar el Timer_A para comprobar que es posible su implementación con conocimientos básicos, esto no es muy recomendado ya que empleamos la CPU en todo momento cosa que no ocurre si utilizamos el Timer_A, esto seria absolutamente necesario si deseamos implementar mas de dos PWM que es el máximo que podemos generar con el Timer_A.

Por lo pronto solo usamos rutinas de tiempo variables además de que implementamos el concepto de tablas el cual es muy útil para todo tipo de aplicaciones.

CODIGO FUENTE ; Autor: Humberto Aparicio Osorio; Fuente: http:/todomcu.scienceontheweb.net; Enviar dudas a: [email protected]; "Haz Tuyo El Conocimiento y Difúndelo"

#include

#define midram 0240h#define time 60000#define time1 55#define CUENTA R14#define AUX R15main;-------------------------------------------------------------------------------

ORG 0F800h ; Programa Principal;-------------------------------------------------------------------------------RESET MOV #midram,SP ; Inicializacion del SP

MOV #WDTPW+WDTHOLD,&WDTCTL ; WDT apagado

MOV.B &CALBC1_1MHZ,&BCSCTL1 ; Calibracion del DCOMOV.B &CALDCO_1MHZ,&DCOCTL

CLR.B &P1SEL ;Puerto 1 como e/s digitalMOV.B #00000001b,&P1DIR ; P1.0 como salida, los demas

como entradasMOV.B #BIT3,&P1OUT ; P1.3 con resistencia PULL-UPBIS.B #BIT3,&P1REN ; Resistencia PULL-UP habilitadaBIS.B #BIT3,&P1IES ; Flanco de subidaBIC.B #BIT3,&P1IFG ; Borrar la bandera de

interrupciónEINT ; Interrupciones globales

habilitadas

ETQ0 BIT.B #BIT3,&P1IN ; ¿Esta presionado el Boton?

JNZ ETQ0BIS.B #BIT3,&P1IE ; Interrupcion local permitida

MOV #T1,R4 ; Direccion de la tabla 1 a R4MOV #T2,R5 ; Direccion de la tabla 2 a R5

ETQ1 BIS.B #BIT0,&P1OUT ; Prende P1.0CALL #SUB_TON ; Retraso segun tabla TonBIC.B #BIT0,&P1OUT ; Apaga P1.0CALL #SUB_TOFF ; Retraso segun tabla ToffCMP FIN,0(R4) ; ¿Es el fin de la tabla?JNE ETQ1JMP ETQ0

;-------------------------------------------------------------------------------P1_ISR; Rutina de servicio a la interrupcion;-------------------------------------------------------------------------------

INCD R4 ; Incrementa direccion del apuntador1

INCD R5 ; Incrementa direccion del apuntador2

BIC.B #BIT3,&P1IFG ; Borra la bandera de la interrupcion

RETI

;-------------------------------------------------------------------------------SUB_TON; S-Rutina Ton;-------------------------------------------------------------------------------

MOV @R4,AUX ; Elem x de la tabla1 en R_AUXETQ3 DEC AUX ; AUX--

JNZ ETQ3 ; ¿AUX es cero?RET

;-------------------------------------------------------------------------------SUB_TOFF; S-Rutina Toff;-------------------------------------------------------------------------------

MOV @R5,AUX ; Elem x de la tabla2 en R_AUXETQ4 DEC AUX ; AUX--

JNZ ETQ4 ; ¿AUX es cero?RET

;-------------------------------------------------------------------------------; Sección de tablas;-------------------------------------------------------------------------------T1 DC16 500,1000,1500,2000,2500,3000,3500,4000,4500FIN DC16 0x00T2 DC16 4500,4000,3500,3000,2500,2000,1500,1000,500

;-------------------------------------------------------------------------------; Vectores de Interrupción y Reset;-------------------------------------------------------------------------------

ORG 0FFFEh ; Vector para el resetDW RESET

ORG 0FFE4h ; Vector para la interrupcion del P1

DW P1_ISREND main

Practica 5.flv - VIDEO http://www.youtube.com/watch?v=6liYWg_x6tU&feature=player_embedded

PRACTICA 6 - Cuenta de display de 0 a 99

Este programa implementamos un circuito el cual puede realizar una cuenta de 0 a 99, esto lo mostramos en un display de 2 dígitos para lo cual utilizamos el multiplexaje de los displays, en realidad solo uno esta encendido a la vez, pero debido a la naturaleza de nuestro ojo humano es que podemos ver que los dos dígitos están encendidos a la ves, con los 10 puertos que tenemos es posible ampliar el numero de dígitos a 4 con la misma técnica, esto lo usaremos en programas posteriores para crear un sensor de temperatura.

CODIGO FUENTE ; Autor: Humberto Aparicio Osorio; Fuente: http:/todomcu.scienceontheweb.net; Enviar dudas a: [email protected]; "Haz Tuyo El Conocimiento y Difúndelo"

/* Descripcion: Despliega en un display de dos digitos una cuenta desde 1 hasta 99 al oprimir un boton situado en P1.7*/

#include

#define midram 0240h /*Constante para el inicio de la RAM*/#define ti1 100 /*Cte para el tiempo por caracter*/#define ti2 700 /*Cte para el multiplexaje*/#define APPT1_0 R4 /*Apuntador a la tabla1 unidades*/#define APPT1_1 R5 /*Apuntador a la tabla1 decenas*/#define UNID R6 /*Cuenta las unidades*/#define DECN R7 /*Cuenta las decenas*/#define TIME R14 /*Variable para el tiempo por digito*/#define AUX R15 /*Registro auxiliar*/main;-------------------------------------------------------------------------------

ORG 0F800h;-------------------------------------------------------------------------------RESET MOV #midram,SP

MOV #WDTPW+WDTHOLD,&WDTCTL

MOV.B &CALBC1_1MHZ,&BCSCTL1MOV.B &CALDCO_1MHZ,&DCOCTL

CLR.B &P1SEL ; Puerto1 como E/S digitalMOV.B #01111111B,&P1DIR ; P1.7 entrada otros bits como

salidaMOV.B #10000000B,&P1OUT ; Apaga salidas y en P1.7 Pull-

UpBIS.B #BIT7,&P1REN ; P1.7 resistencia habilatadaBIS.B #BIT7,&P1IES ; Flanco de bajada para P1.7BIC.B #BIT7,&P1IFG ; Borrar bandera de la

interrupcionBIS.B #BIT7,&P1IE ; Interrupcion local permitida

CLR.B &P2SEL ; Puerto2 como E/S digitalBIS.B #BIT6+BIT7,P2DIR ; P2.6 y P2.7 como salidasMOV.B #BIT6,&P2OUT ; P2.7 en bajo P2.6 en alto

MOV #GIE+CPUOFF,SR ; Interrupciones globales habilitadas

NOP ; y modo de bajo consumo

;-------------------------------------------------------------------------------P1_ISR; Rutina de servivio a la interrupcion;-------------------------------------------------------------------------------

MOV #T1,APPT1_0 ; Mueve la direccion de T1 a R4MOV #T1,APPT1_1 ; Mueve la direccion de T1 a R5CLR UNID ; Unidades = 0CLR DECN ; Decenas = 0

ETIQ2 MOV #ti1,TIME ; TIME=100

ETIQ1 MOV.B @APPT1_0,&P1OUT ; DATO->P1XOR.B #BIT6+BIT7,&P2OUT ; Visualiza dato en posicion 0CALL #RETARDO ; Retardo para diferenciar los

digitosMOV.B @APPT1_1,&P1OUT ; DATO->P1XOR.B #BIT6+BIT7,&P2OUT ; Visualiza dato en posicion 1CALL #RETARDO ; Retardo para diferenciar los

digitos

DEC TIME ; Decrementa TIME (Tiempo por digito)

JNZ ETIQ1 ; ¿TIME es cero?

INC UNID ; Unidades = Unidades + 1INC APPT1_0 ; Direccion del apuntador0 + 1CMP #10,UNID ; ¿Unidades es 9?JNE ETIQ2

CLR UNID ; Unidades = 0MOV #T1,APPT1_0 ; Mueve la direccion de T1 a R4

INC DECN ; Decenas = Decenas + 1INC APPT1_1 ; Direccion del apuntador1 + 1CMP #10,DECN ; ¿Decenas es 9?JNE ETIQ2

MOV.B #10000000B,&P1OUT ; Para apagar el display al terminar

; y para que el ciclo siga correctamente

BIC.B #BIT7,&P1IFG ; Limpia la bandera de interrupcion

RETI

;-------------------------------------------------------------------------------RETARDO; Surrituna de retardo;-------------------------------------------------------------------------------

MOV #ti2,AUX ; AUX = 700ETIQ3 DEC AUX ; AUX--

JNZ ETIQ3 ; ¿AUX es cero?RET

;-------------------------------------------------------------------------------T1; Tabla de 7 segmentos;-------------------------------------------------------------------------------

; 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9DC8 0BFh,86h,0DBh,0CFh,0E6h,0EDh,0FDh,87h,0FFh,0E7h

;-------------------------------------------------------------------------------; Vectores de interrupcion y reset;-------------------------------------------------------------------------------

ORG 0FFFEh ; Vector de resetDW RESETORG 0FFE4h ; Vector de interrupcion para P1DW P1_ISR

END main

Practica 6.flv - VIDEO http://www.youtube.com/watch?v=Dcq6Gbyb9mY&feature=player_embedded

Timer_A

PRACTICA 1 - Encender un led por 10 segundos

Con este programa configuramos el Timer_A para que al oprimir un botón situado en P1.3 encienda un led conectado en P1.0 durante 10 segundos, después de esto el led se apaga.

Podemos ver que utilizamos el VLO de 12 KHz, existe un pequeño problema con este programa y es que al principio dura 10 segundos y después dura 5, 7 , 8 segundos, es decir no se repite el tiempo del intervalo, estamos tratando de corregir este error que posiblemente se origina por el desborde del Timer_A, otra posible causa es la inestabilidad del oscilador ante los cambios de temperatura, para comprobar esto

debemos de revisar bien el datasheet del dispositivo y realizar mediciones, aunque lo mas probable es que sea un problema de software.

CODIGO FUENTE ; Autor: Humberto Aparicio Osorio; Fuente: http:/todomcu.scienceontheweb.net; Enviar dudas a: [email protected]; "Haz Tuyo El Conocimiento y Difúndelo"

#include "msp430x20x3.h"

#define midram 240h /* Lugar donde comenzara la PILA*/main;-------------------------------------------------------------------------------

ORG 0F800h ; Direccion de inicio el la flash;-------------------------------------------------------------------------------RESET MOV.W #midram,SP ; Inicio del apuntador a la pila

MOV.W #WDTPW+WDTHOLD,&WDTCTL ; WDT apagado

MOV.B &CALBC1_1MHZ,&BCSCTL1 ; Calibracion delMOV.B &CALDCO_1MHZ,&DCOCTL ; oscilador a 1MHz

MOV.B #LFXT1S_2,&BCSCTL3 ; VLO (12KHz) para ACLKMOV.B #DIVA_3,&BCSCTL1 ; Frecuencia de ACLK / 8 =

1.5KHz

MOV.B #11110111b,&P1DIR ; P1.3 como entrada los demas como salida

MOV.B #BIT3,&P1OUT ; Resistencia PULL-UP en P1.3 y apaga los demas

BIS.B #BIT3,&P1IE ; Habilita interrupcion para P1.3BIS.B #BIT3,&P1IES ; Flanco descendente para la

interrupcionCLR.B &P1IFG ; Borra bandera de interrupcion

MOV.W #CPUOFF+GIE,SR ; Apaga CPU y permite las interrupciones ; de manera global

NOP

;-------------------------------------------------------------------------------P1_ISR; Rutina de Servicio a la Interrupcion para P1;-------------------------------------------------------------------------------

BIS.B #BIT0,&P1OUT ; Enciende el ledMOV.W #CCIE,&CCTL0 ; Permite la interrupcion de TACCR0MOV.W #15000,&CCR0 ; TACCR0=15,000 para obtener un periodo

de 10sMOV.W #TASSEL_1+MC_1,&TACTL ; Alimentamos al timer con

; ACLK, en modo ascendenteBIC.B #BIT3,&P1IFG ; Borramos la bandera de interrupcion ya

que ; no se borra automaticamente como en

RETI ; otros perifericos

;-------------------------------------------------------------------------------TACCR0_ISR; Rutina de Servicio a la Interrupcion para WDT;-------------------------------------------------------------------------------

BIC.B #BIT0,&P1OUTBIC.W #TACLR+TAIFG,&TACTL ; Detiene el Timer_ARETI

;-------------------------------------------------------------------------------; Vectores de Interrupcion y Reset;-------------------------------------------------------------------------------

ORG 0FFFEh ; Vector de resetDW RESET ; Etiqueta para Reset (Inicio del

programa)ORG 0FFF2h ; Vector para la interrupcion de TACCR0

CCIFGDW TACCR0_ISR ; Etiqueta de la rutina de servicio a la

; interrupcionORG 0FFE4h ; Vector para la interrupcion del Puerto

2DW P1_ISR ; Etiqueta de la rutina de servicio a la

; interrupcionEND main

Timer_A Practica 1.flv - VIDEO http://www.youtube.com/watch?v=Uc8I5NkLmHs&feature=player_embedded

PRACTICA 2 - Secuencia con corrimientos

Utilizando de nuevo el Timer_A podemos ver el concepto de corrimiento, pero en esta vez en el programa no utilizamos sub rutinas de tiempo si no que a través de la interrupción del puerto 2 configuramos el Timer_A para que funcione de manera ascendente y genere interrupciones cada segundo.

La interrupción que el Timer_A hace un corrimiento en un valor almacenado en R15 y después de hacer esto el resultado lo refleja en el Puerto 1 que previamente ha sido configurado como salidas.

CODIGO FUENTE ; Autor: Humberto Aparicio Osorio; Fuente: http:/todomcu.scienceontheweb.net; Enviar dudas a: [email protected]; "Haz Tuyo El Conocimiento y Difúndelo"

#include "msp430x20x3.h"

#define midram 240h /* Lugar donde comenzara la PILA*/main

;-------------------------------------------------------------------------------

ORG 0F800h ; Direccion de inicio el la flash;-------------------------------------------------------------------------------RESET MOV.W #midram,SP ; Inicio del apuntador a la pila

MOV.W #WDTPW+WDTHOLD,&WDTCTL ; WDT apagado

MOV.B &CALBC1_1MHZ,&BCSCTL1 ; Calibracion delMOV.B &CALDCO_1MHZ,&DCOCTL ; oscilador a 1MHz

MOV.B #LFXT1S_2,&BCSCTL3 ; VLO (12KHz) para ACLKMOV.B #DIVA_3,&BCSCTL1 ; Frecuencia de ACLK / 8 =

1.5KHz

MOV.B #0xFF,&P1DIR ; Todo P1 como salidaCLR.B &P1OUT ; Apagar las salidas en P1

CLR.B &P2SEL ; P2 como E/S digitalMOV.B #BIT7,&P2DIR ; P2.7 como salida, P2.6 como entradaMOV.B #BIT6,&P2OUT ; Resistencia PULL-UP en P2.6 y apaga

P2.7BIS.B #BIT6,&P2IE ; Habilita interrupcion para P2.6BIS.B #BIT6,&P2IES ; Flanco descendente para la

interrupcionCLR.B &P2IFG ; Borra bandera de interrupcion

MOV.W #CPUOFF+GIE,SR ; Apaga CPU y permite las interrupciones ; de manera global

NOP

;-------------------------------------------------------------------------------P2_ISR; Rutina de Servicio a la Interrupcion para P1;-------------------------------------------------------------------------------

MOV.B #1,R15 ; Inicio de la secuenciaBIS.B R15,&P1OUT ; Inicio de la secuencia en puerto 1MOV.W #CCIE,&CCTL0 ; Permite la interrupcion de TACCR0MOV.W #800,&CCR0 ; TACCR0=800 para obtener un periodo

aprox de 1sMOV.W #TASSEL_1+MC_1,&TACTL ; Alimentamos al timer con

; ACLK, en modo ascendenteBIC.B #BIT6,&P2IFG ; Borramos la bandera de interrupcion ya

que ; no se borra automaticamente como en

RETI ; otros perifericos

;-------------------------------------------------------------------------------TACCR0_ISR; Rutina de Servicio a la Interrupcion para WDT;-------------------------------------------------------------------------------

CMP.B #128,&P1OUT ; ¿Es el fin de la secuencia?JNE NO

; Si es el fin:BIC.W #MC_0,&TACTL ; Detiene el Timer_ACLR.B &P1OUT ; Apaga las salidas de P1OUTBIC.W #TAIFG,&TACTL ; Borra la bandera de interrupcionRETI

; No es el fin:NO RLA.B R15 ; Realiza corrimiento

MOV.B R15,&P1OUT ; Refleja el corrimiento en la salidaBIC.W #TAIFG,&TACTL ; Borra la bandera de interrupcionRETI

;-------------------------------------------------------------------------------; Vectores de Interrupcion y Reset;-------------------------------------------------------------------------------

ORG 0FFFEh ; Vector de resetDW RESET ; Etiqueta para Reset (Inicio del

programa)ORG 0FFF2h ; Vector para la interrupcion de TACCR0

CCIFGDW TACCR0_ISR ; Etiqueta de la rutina de servicio a la

; interrupcionORG 0FFE6h ; Vector para la interrupcion del Puerto

2DW P2_ISR ; Etiqueta de la rutina de servicio a la

; interrupcionEND main

Timer_A Practica 2.flv - VIDEO http://www.youtube.com/watch?v=anseNiyW2kE&feature=player_embedded

PRACTICA 3 - Secuencia cualquiera con tablas

Haciendo uso del programa anterior modificamos únicamente la sub rutina de servicio a la interrupción del Timer_A llamada TACCR0_ISR para que en lugar de hacer solo corrimientos haga una secuencia almacenada en una tabla, esta secuencia es la misma que en la practica del WDT solo que ahora esta implementada de una manera diferente.

CODIGO FUENTE ; Autor: Humberto Aparicio Osorio; Fuente: http:/todomcu.scienceontheweb.net; Enviar dudas a: [email protected]; "Haz Tuyo El Conocimiento y Difúndelo"

/* Descripcion: */

#include "msp430x20x3.h"

#define midram 240h /* Lugar donde comenzara la PILA*/main;-------------------------------------------------------------------------------

ORG 0F800h ; Direccion de inicio el la flash

;-------------------------------------------------------------------------------RESET MOV.W #midram,SP ; Inicio del apuntador a la pila

MOV.W #WDTPW+WDTHOLD,&WDTCTL ; WDT apagado

MOV.B &CALBC1_1MHZ,&BCSCTL1 ; Calibracion delMOV.B &CALDCO_1MHZ,&DCOCTL ; oscilador a 1MHz

MOV.B #LFXT1S_2,&BCSCTL3 ; VLO (12KHz) para ACLKMOV.B #DIVA_3,&BCSCTL1 ; Frecuencia de ACLK / 8 =

1.5KHz

MOV.B #0xFF,&P1DIR ; Todo P1 como salidaCLR.B &P1OUT ; Apagar las salidas en P1

CLR.B &P2SEL ; P2 como E/S digitalMOV.B #BIT7,&P2DIR ; P2.7 como salida, P2.6 como entradaMOV.B #BIT6,&P2OUT ; Resistencia PULL-UP en P2.6 y apaga

P2.7BIS.B #BIT6,&P2IE ; Habilita interrupcion para P2.6BIS.B #BIT6,&P2IES ; Flanco descendente para la

interrupcionBIC.B #BIT6,&P2IFG ; Borra bandera de interrupcion

MOV.W #CPUOFF+GIE,SR ; Apaga CPU y permite las interrupciones ; de manera global

;-------------------------------------------------------------------------------P2_ISR; Rutina de Servicio a la Interrupcion para P1;-------------------------------------------------------------------------------

MOV.W #TABLA1,R15 ; Inicia apuntador a la tablaMOV.W #CCIE,&CCTL0 ; Permite la interrupcion de TACCR0MOV.W #800,&CCR0 ; TACCR0=800 para obtener un periodo

aprox de 1sMOV.W #TASSEL_1+ID_1+MC_1,&TACTL ; Alimentamos al timer

con ; ACLK / 2 = 750Hz, en

modo ; ascendente

BIC.B #BIT6,&P2IFG ; Borramos la bandera de interrupcion ya que

; no se borra automaticamente como en RETI ; otros perifericos

;-------------------------------------------------------------------------------TACCR0_ISR; Rutina de Servicio a la Interrupcion para WDT;-------------------------------------------------------------------------------

CMP.W FIN,0(R15) ; ¿Es el fin de la tabla?JNE NO

; Si es el fin:BIC.W #MC_0,&TACTL ; Detiene el Timer_ACLR.B &P1OUT ; Apaga las salidas de P1OUTBIC.W #TAIFG,&TACTL ; Borra la bandera de interrupcionRETI

; No es el fin:

NO MOV.B @R15,&P1OUT ; Mueve el contenido de la tabla apuntado por R15

INC R15 ; Desplaza el apuntador a la proxima posicion

BIC.W #TAIFG,&TACTL ; Borra la bandera de interrupcionRETI

;-------------------------------------------------------------------------------TABLA1; Definicion de la secuencia a seguir;-------------------------------------------------------------------------------

DC80,00011000b,00100100b,01000010b,10000001b,01000010b,00100100bDC8 00011000b,0

FIN DC8 0

;-------------------------------------------------------------------------------; Vectores de Interrupcion y Reset;-------------------------------------------------------------------------------

ORG 0FFFEh ; Vector de resetDW RESET ; Etiqueta para Reset (Inicio del

programa)ORG 0FFF2h ; Vector para la interrupcion de TACCR0

CCIFGDW TACCR0_ISR ; Etiqueta de la rutina de servicio a la

; interrupcionORG 0FFE6h ; Vector para la interrupcion del Puerto

2DW P2_ISR ; Etiqueta de la rutina de servicio a la

; interrupcionEND main

Timer_A Practica 3.flv - VIDEO http://www.youtube.com/watch?v=8fMfjEHk71I&feature=player_embedded

PRACTICA 4- PWM automatico con Time_A y WDT

En este programa realizamos el cambio de brillo de un led de manera automática y a través de la técnica conocida como PWM, para ello hacemos uso de dos temporizadores, uno de ellos es el WDT en modo de intervalos el cual a través de su rutina de servicio a la interrupción podemos aumentar el brillo del LED conectado a P1.2 al modificar el valor almacenado en TACCR1.

En el caso del Timer_A solo lo configuramos en el modo de salida numero 6 alimentado por ACLK en el modo de cuenta ascendente, así el valor en CCR0 define la frecuencia del pulso (100Hz para nuestro ejemplo) y CCR1 define el ciclo útil por lo que al modificar CCR1 modificamos entonces el coclo útil de nuestra señal de PWM.

Como conclusión de esta practica podemos notar que utilizando el modulo del Timer_A para generar señales de PWM es mucho mas fácil aplicarlo que con subrutinas de tiempo.

En el video no se nota muy bien el cambio de luminosidad del led ya que este es muy sutil a diferencia de la practica de la sección de puertos, así que te invitamos a que lo pruebes tu mismo.

CODIGO FUENTE ; Autor: Humberto Aparicio Osorio; Fuente: http:/todomcu.scienceontheweb.net; Enviar dudas a: [email protected]; "Haz Tuyo El Conocimiento y Difúndelo"

/* Descripcion: */

#include "msp430x20x3.h"

#define midram 240h /* Lugar donde comenzara la PILA*/main;-------------------------------------------------------------------------------

ORG 0F800h ; Direccion de inicio el la flash;-------------------------------------------------------------------------------RESET MOV.W #midram,SP ; Inicio del apuntador a la pila

MOV.W #WDTPW+WDTTMSEL+WDTIS0+WDTSSEL,&WDTCTL; Modo intervalo cada

; 32768 ciclos del ACLKBIS.B #WDTIE,&IE1 ; Interrupcion del modo intervalo

permitida

MOV.B &CALBC1_1MHZ,&BCSCTL1 ; Calibracion delMOV.B &CALDCO_1MHZ,&DCOCTL ; oscilador a 1MHz

MOV.B #LFXT1S_2,&BCSCTL3 ; VLO (12KHz) para ACLK

BIS.B #BIT2,&P1DIRBIS.B #BIT2,&P1SEL

MOV.W #120,&TACCR0MOV.W #OUTMOD_6,&CCTL1MOV.W #10,&TACCR1MOV.W #TASSEL_1+MC_1,&TACTL

MOV.W #CPUOFF+GIE,SR ; Apaga CPU y permite las interrupciones ; de manera global

NOP

;-------------------------------------------------------------------------------WDT_ISR; Rutina de Servicio a la Interrupcion para WDT;-------------------------------------------------------------------------------

ADD.W #10,&TACCR1reti

;-------------------------------------------------------------------------------; Vectores de Interrupcion y Reset;-------------------------------------------------------------------------------

ORG 0FFFEh ; Vector de resetDW RESET ; Etiqueta para Reset (Inicio del

programa)ORG 0FFF4h ; Vector para la interrupcion del WDTDW WDT_ISR ; Etiqueta de la rutina de servicio a la

; interrupcionEND main

Timer_A Practica 4.flv - VIDEO http://www.youtube.com/watch?v=P8KYCbHUA_M&feature=player_embedded

PERRO GUARDIAN

PRACTICA 1 - Conmutar un led cada 5s

En este programa aprendemos a utilizar el perro guardián como generador de interrupciones por intervalos, además de eso configuramos el ACLK con una frecuencia provista internamente de 12KHz, con lo cual podemos ver como es que se utiliza tanto el ACLK como el WDT en este modo.

El perro guardián interrumpe a la CPU aproximadamente cada 5 segundos, pudiendo ser el periodo máximo de interrupción de casi 22 segundos, según la configuración seleccionada.

CODIGO FUENTE ; Autor: Humberto Aparicio Osorio; Fuente: http:/todomcu.scienceontheweb.net; Enviar dudas a: [email protected]; "Haz Tuyo El Conocimiento y Difúndelo"

#include "msp430x20x3.h"

#define midram 240h /* Variable para almacenar la posicion*/main;-------------------------------------------------------------------------------

ORG 0F800h ; Direccion de inicio el la flash;-------------------------------------------------------------------------------RESET MOV.W #midram,SP ; Inicio del SP

MOV.B #LFXT1S_2,&BCSCTL3 ; ACLK= 12KHzMOV.B #DIVA_2,&BCSCTL1 ; Frecuencia de ACLK/2=6KHz

MOV.W #WDTPW+WDTTMSEL+WDTIS0+WDTSSEL,&WDTCTL; Modo intervalo cada

; 32768 ciclos del ACLKBIS.B #WDTIE,&IE1 ; Interrupcion del modo intervalo

permitidaBIS.B #BIT0,&P1DIR ; P1.0 como salidaBIC.B #BIT0,&P1OUT ; Apaga P1.0

MOV #GIE+CPUOFF,SR ; Modo de ahorro e interrupciones; globales habilitadas

;-------------------------------------------------------------------------------WDT_ISR; Rutina de Servicio a la Interrupcion para WDT;-------------------------------------------------------------------------------

XOR.B #BIT0,&P1OUT ; Conmuta el ledreti ; Salir de la interrupcion

;-------------------------------------------------------------------------------; Vectores de Interrupcion y Reset;-------------------------------------------------------------------------------

ORG 0FFFEh ; Vector de resetDW RESET ; Etiqueta para Reset (Inicio del

programa)ORG 0FFF4h ; Vector para la interrupcion del WDTDW WDT_ISR ; Etiqueta de la rutina de servicio a la

; interrupcionEND main

Perro guardián practica1.flv - VIDEO http://www.youtube.com/watch?v=_iS9yjtRdqo&feature=player_embedded

PRACTICA 2 - La entrada digital numero 11

A través de la configuración del perro guardián, se puede generar un puerto digital exclusivamente de entrada el cual genera una interrupción de casi máxima prioridad, esto lo podemos aplicar en el caso en donde los 10 puertos digitales de entrada y salida nos sean insuficientes y asignar así esta entrad a algún botón con el cual se inicie alguna acción (rutina de servicio a la interrupción) importante.

En el programa principal hacemos que un led conectado en P1.0 conmute indefinidamente y para probar que es una interrupción no enmascarable, nunca modificamos el bit GIE en el registro de estado. Al oprimir el botón conectado al pin llamado RST/MNI/SBWTDIO se genera y atiende la interrupción.

La rutina de servicio a la interrupción es un secuenciador de 8 canales con el cual atraves de apuntadores y tablas puede generar cualquier secuencia, en este caso la secuencia es la misma que en la practica 4 del capitulo de los puertos.

CODIGO FUENTE ; Autor: Humberto Aparicio Osorio; Fuente: http:/todomcu.scienceontheweb.net; Enviar dudas a: [email protected]; "Haz Tuyo El Conocimiento y Difúndelo"

#include "msp430x20x3.h"

#define midram 240h /* Lugar donde comenzara la PILA*/#define TIME 62500 /* Cte para que la subrutina de tiempo dure

aproximadamente 0.5 segundos*/main;-------------------------------------------------------------------------------

ORG 0F800h ; Direccion de inicio el la flash;-------------------------------------------------------------------------------RESET MOV.W #midram,SP ; Inicio del SP

MOV.W #WDTPW+WDTHOLD+WDTNMI,&WDTCTL ; WDT apagado, Interrupcion no

; enmascarable activada en flanco ascendente

MOV.B &CALBC1_1MHZ,&BCSCTL1 ; Calibracion delMOV.B &CALDCO_1MHZ,&DCOCTL ; oscilador a 1MHz

MOV.B #0XFF,&P1DIR ; Todo P1 como salidaCLR.B &P1OUT ; Los pines de P1 a estado bajo

BIS.B #NMIIE,&IE1 ; Permite la interrupcion localmente

CICLO1 XOR.B #BIT0,&P1OUT ; Conmuta a P1.0CALL #RETARDO ; Llama a retardo para que sea visible

el cambioJMP CICLO1 ; del led en un ciclo

;-------------------------------------------------------------------------------NMI_ISR; Rutina de Servicio a la Interrupcion para WDT;-------------------------------------------------------------------------------

MOV #TABLA1,R15 ; Crea un apuntador a la tablaCICLO INC R15 ; Incrementa en apuntador

MOV.B @R15,&P1OUT ; Mueve el contenido de la tabla a P1OUTCALL #RETARDO ; Llama a retardo para poder visualizarCMP.W FIN,0(R15) ; Es el fin de la tabla?JNZ CICLO ; Si lo es continua, si no salta a ciclo

BIC.B #NMIIFG,&IFG1 ; Borra la bandera de interrupcion NMIIFG

BIS.B #NMIIE,&IE1 ; Permite de nuevo la interrupcion

RETI

;-------------------------------------------------------------------------------RETARDO; Rutina de Retardo

;-------------------------------------------------------------------------------

MOV #TIME,R14 ; TIME se carga en R14 para durar 0.5 sETIQ3 NOP ; consume 2 ciclos de reloj

NOP ; consume 2 ciclos de reloj masDEC R14 ; Decrementa R14JNZ ETIQ3 ; R14 es cero?RET

;-------------------------------------------------------------------------------TABLA1; Definicion de la secuencia a seguir;-------------------------------------------------------------------------------

DC8 1,2,4,8,16,32,64,128,1FIN DC8 0

;-------------------------------------------------------------------------------; Vectores de Interrupcion y Reset;-------------------------------------------------------------------------------

ORG 0FFFEh ; Vector de resetDW RESET ; Etiqueta para Reset (Inicio del

programa)ORG 0FFFCh ; Vector para la interrupcion no

enmascarableDW NMI_ISR ; Etiqueta de la rutina de servicio a la

; interrupcionEND main

Perro guardian practica 2 version 1.flv - VIDEOhttp://www.youtube.com/watch?v=dHRljmrKPDg&feature=player_embedded

La secuencia mostrada en el video se genera a traves del programa anterior, veremos que con una leve modificación podemos generar cualquier secuencia en los 8 bits del puerto 1.

Esta secuencia es diferente a la anterior, a conrinuacion mostramos el cambio que debes de efectuar en el programa anterior para obtener esta secuencia.

Cambiar esto:

;-------------------------------------------------------------------------------TABLA1; Definicion de la secuencia a seguir;-------------------------------------------------------------------------------

DC8 1,2,4,8,16,32,64,128,1FIN DC8 0

Por esto:

;-------------------------------------------------------------------------------TABLA1; Definicion de la secuencia a seguir;-------------------------------------------------------------------------------

DC80,00011000b,00100100b,01000010b,10000001b,01000010b,00100100bDC8 00011000b,0

FIN DC8 0

Perro guardian practica 2 versión 2.flv - VIDEOhttp://www.youtube.com/watch?v=2GBLklHs95o&feature=player_embedded

En este caso introducimos los datos de forma binaria y no en hexadecimal lo cual es mas flexible, para cambiar las secuencias lo que resta es modificar estos valores, hasta que la memoria lo permita. En cada nuevo renglon es pertiente agregar DC8 al inicio como en este caso.

Esto es util por ejemplo para guardar los valores de la funcion seno o cualquier otra función y los 8 bits concetarlos a un convertidor digital analogico para asi obtener un generador de funciones de bajo costo.