Haz una pregunta
  Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos
Foros Registrarse ¿Olvidaste tu contraseña?

Temas similares

28/11/2011 #1

Avatar de anilandro

Programando la Placa de Desarrollo Mini-STM32 - I
Presentación de la Mini-STM32 y borrado del programa Demo


Realizar proyectos con placas de desarrollo siempre ha sido mi asignatura pendiente, y hace poco me decidí a comenzar con este tema. Para ello busqué información en la red y al final me decanté por una Mini-STM32, equipada con un microcontrolador STM32. Según un compañero italiano de un foro de física era potente y fácil de programar, con un muchas ayudas disponibles y completas herramientas de software a su disposición ...O al menos ésta era la teoría, porque después de recibir la la placa, y a pesar de haber estudiado y trabajado en temas informáticos durante muchos años, no supe ni por donde empezar.

Esto fue ni más ni menos lo que me ocurrió hace una semana, cuando recibí la flamante Mini-STM32, que pese a ser un modelo de gran venta, la realidad es que apenas hay información de nivel básico disponible en Internet, y menos aún si nos remitimos al mundo hispanohablante. Por suerte, en los primeros intentos de programación recibí la ayuda de Francisco Javier y de Melchor, dos compañeros expertos en el tema que conocí a través de la red y cuyos consejos me permitieron superar el bloqueo en que me encontraba. Y tal vez para devolver una parte de este gesto he decidido comenzar una relación de mis experiencias con la Mini-STM32, en la esperanza que puedan servir a otros para andar más rápidos por el mismo camino.

El realizar esta especie de tutorial básico también constituye para mí un proceso de aprendizaje. Por tanto iré paso a paso y sólo hablaré de aquellas cosas que o bien conozca de otros dispositivos parecidos o haya podido probar en éste, y como aún así corro el riesgo de interpretar algo de forma equivocada, agradeceré cualquier comentario al respecto.


La placa de desarrollo Mini-STM32

Realizadas estas aclaraciones, diré que la placa o módulo de desarrollo Mini-STM32 es una placa de bajo precio y buenas prestaciones construida alrededor de un microcontrolador STM32F103VC Cortex M3, de 32 bits, fabricado por ST Electronics. Dichos microcontroladores pertenecen a la popular familia de los ARM, con los cuales son compatibles, y son utilizados habitualmente en multitud de sistemas industriales, domésticos y de automoción.

Vista de la Mini-STM32 reproduciendo el programa de demostración




Diferencias entre un microcontrolador y un microprocesador

¿Y cual es la diferencia entre un microcontrolador y un microprocesador, como por ejemplo el Pentium que equipa nuestros ordenadores? Pues la diferencia es básicamente el grado de integración de elementos dentro del mismo chip. Un microprocesador puede procesar datos digitales de acuerdo a un programa, pero necesita de una memoria externa RAM, de una ROM y de otra memoria para programas en flash o en disco duro. El microprocesador precisa además de otros chips de entradas y salidas (denominados normalmente PIO - Port Input / Output) que le permitan comunicarse con otros módulos, tanto de la misma placa como exteriores al ordenador, como una tarjeta grafica para la pantalla, un chip especial para las comunicaciones serie, otro chip de sonido, etc. En el microprocesador las funciones de cada uno de sus pines suele estar muy definido, agrupándose en forma de buses de datos, de direcciones y de control.

Un microcontrolador en cambio es casi como un pequeño ordenador y lo integra todo en el mismo chip, además de la unidad de proceso, contiene su propia memoria RAM, su ROM con un sistema de carga de datos y la memoria de almacenamiento de programas, normalmente de tipo Flash. En cuanto a sus pines, un alto porcentaje de ellos pueden ser configurados de forma indistinta como entradas o salida de tipos muy diferentes, ya que pueden por ejemplo controlar directamente un servo tipo radiocontrol, o el circuito driver de una sirena de alarma, o un display de LEDS, o leer el estado de un contacto o medir la tensión analógica de un sensor de temperatura.


El microcontrolador STM32F103VC

En nuestro caso concreto, el STM32F103VC es un pequeño chip de forma cuadrada tipo SMD alimentado a 3,3 volts. Dispone de 100 pines e integra en su interior 48 Kbytes de memoria RAM, 256 KBytes de memoria flash y funciona a una frecuencia de reloj de hasta 72 Mhz.

Como es habitual en los microcontroladores actuales, la mayoría de los pines pueden ser programados para que realicen distintas funciones, especialmente los que están agrupados en los cinco puertos (PA, PB, PC, PD y PE), de 16 líneas cada uno. Aparte de los pines utilizados por la propia placa que no están disponibles para el usuario, hay 2 de ellos que activan sendos LEDS de uso general y 2 a pulsadores también utilizables para cualquier función. Hay 30 pines no conectados y por tanto disponibles y configurables como entradas o salidas de distintos tipos, 16 de ellos pueden además actuar como entradas analógicas con conversor ADC de 12 bits, 2 como salidas analógicas tipo DAC, y también hay un cierto número de salidas de impulsos PWM modulados en duración, temporizadores y muchas otras funciones especiales que ya iremos descubriendo.
Por otra parte, los pines del microcontrolador, con o sin uso, están todos disponibles entre los conectores E/S superior e inferior.

De todas formas, si a alguien le empuja la impaciencia puede hallar una descripción más detallada de este micro en el manual de referencia del STM32, disponible en la web de ST Microelectronics, pero advierto que tiene alrededor de 1.000 páginas y su contenido es mucho más técnico que el nivel que de momento pretendemos asumir. También podríamos obtener información adicional de la placa en su conjunto acudiendo a la web del fabricante, en las direcciones: http://www.poweravr.com y http://www.powermcu.com , pero para ello necesitaríamos entender los caracteres chinos o confiar tal vez demasiado en la traducción automática de Google entre idiomas tan diferentes.

Por todo lo anteriormente expuesto ya intuimos que el controlador STM32 tiene una potencia y una versatilidad realmente notable para su tamaño, pero sobre todo esta placa se distingue de otras parecidas en que dispone de origen de un display LCD sensible al tacto de 320 x 240 pixels, capaz de representar 262.000 colores (64 niveles para cada color básico RGB).


Comprando la Mini-STM32

Y si buenas parecen las características de la placa en su conjunto, igual de bueno es su precio, ya que puede encontrarse en Internet por unos 30 €, como por ejemplo en la tienda on-line Micro4you (http://www.micro4you.com/store/mini-...lcd-board.html), radicada en Tailandia, a lo que deberemos añadir unos 5 € por el envío aéreo hasta España.

El pago puede efectuarse por tarjeta de crédito o bien por Paypal, siendo ésta la opción que considero más segura porque te permite un lapso de 45 días para efectuar reclamaciones ante problemas imprevistos. Por el bajo importe del envío no hay retención por parte de aduanas, y sin ser rápido raramente tarda más de 15 días, lo cual entra dentro de lo razonable.

Y hechas las presentaciones de rigor, pasemos a ver nuestra pequeña maravilla:


Mostrando las partes de la Mini-STM32

En la imagen que viene a continuación, en que la placa a aparece con un tamaño un 20% inferior al real, podemos ver los bordes de la placa base y la pantalla LCD en primer término. En la parte alta hay dos bases mini-USB, pero sólo el de la izquierda es un USB 2.0 real, ya que el de la derecha es en realidad una entrada serie RS-232 que usa la tecnología USB para pasar las señales entre la placa y el ordenador.

Las versiones anteriores de esta placa venían equipadas con el típico conector serie DE9, de 9 pines, montado en un lateral, pero resulta que aparte de la deficiente estética funcional por su tamaño, hoy en día ya no se venden ordenadores con salida RS-232 y también son cada vez menos los que quedan funcionando en nuestras casas. Por este motivo, en la parte del ordenador se utiliza una solución de compromiso que consiste en convertir uno de sus USB en un puerto COM virtual, y por tanto generador de señales RS-232, siendo la recepción en la placa Mini-STM32 un conector también USB pero que conduce la señal a un chip convertidor PL2303HX, cuya misión es traducir de nuevo las señales de falso USB en las normales RS-232, las cuales ya son aprovechables directamente por el microcontrolador.

Descripción de los elementos de la placa




Esta conexión RS232-USB entre el ordenador y la placa la utilizaremos para borrar los programas contenidos en la memoria flash y sustituirlos por otros que deseemos.

Aparte de este detalle, distinguimos 4 LEDS situados en las cuatro esquinas, y serigrafiados de LD1 a LD4, cuya función es la siguiente:

LD1 Pertenece al USB, puede utilizarse para pruebas, aunque su labor normal es indicar la transferencia de datos a por el USB
LD2 LED de Power. Se enciende siempre que la placa tenga tensión de 5 volts, presente en uno de los pines del conector USB
LD3 LED de uso general, conectado a una salida del chip como indicador de lo que deseemos
LD4 Igual que el anterior, LED de uso general

En la franja inferior podemos ver cuatro pequeños botones. Comenzando por la derecha son:

Reset Efectúa un reset al microcontrolador. Si estaba en modo de carga de programa, pasa a modo de ejecución
Boot Abreviatura de "Boot Loader". Apretado junto con el al botón anterior, coloca la placa en modo de "carga de programa"
KeyB Pulsador de uso general, perteneciente al puerto B, para introducir órdenes en el programa
KeyA Pulsador de uso general, perteneciente al puerto A, para introducir órdenes en el programa

Parte trasera de la Mini-STM32




En la parte trasera de la placa principal sólo es distinguible el conector para una tarjeta de memoria MiniSD, del mismo tipo que utilizamos en las tablets y en las cámaras de fotos digitales, capaz de almacenar una gran cantidad de datos.

A parte de los elementos que hemos descrito en la primera imagen, aquí también son visibles tanto arriba como abajo de la placa las líneas E/S (entradas salidas) del microcontrolador, donde de acuerdo al programa que corra en su interior, deberemos conectar el resto del hardware que la placa pretenda controlar en nuestros proyectos, como sensores, motores, etc.

Si ahora quitamos los cuatro tornillos que sujetan la placa del LCD y la extraemos con cuidado de no doblarla ni forzar los contactos (ya que su único conector de 34 pines está situado en su parte izquierda), podemos ver la totalidad de la placa principal, donde descartando los elementos periféricos que ya hemos descrito, distinguimos el microcontrolador central y otros componentes SMD. A la izquierda vemos el alojamiento para una pila de litio tipo DL1220, de 3 volts, destinada a mantener el funcionamiento del reloj interno en tiempo real, y en la derecha el chip PL2303HX que "traduce" los datos USB en RS232, y un conector denominado JTAG, acrónimo de Joint Test Action Group, y que puede servir desde la comprobación en fábrica de la integridad de la propia placa hasta como sistema de depuración de código, aunque en estos momentos no sabría dar más información al respecto.

La tensión de alimentación del microcontrolador, así como de la mayoría de elementos del circuito es de 3,3 Volts, pero en las pruebas normales la obtendremos a partir de los 5 Volts del USB del ordenador. La reducción la efectúa un integrado estabilizador, que tiene la forma de un pequeño transistor, situado al lado del conector JTAG.

El microcontrolador y algunos elementos de la placa base




La placa del LCD no tiene muchos secretos, a parte del propio display de cristal líquido, distinguimos un diminuto integrado asociado al mismo y una serie de contactos sin soldar denominados CNB que son una continuación de los contactos, pin a pin del conector de entrada CNA que une esta placa a la principal.

Parte trasera de la placa del LCD




Ejercicio 1 -- Borrando el programa Demo


Bien, ya hemos visto un poco por encima la placa Mini-STM32 que acabamos de recibir, y como estamos impacientes por ver que hace. Tomamos el corto cable USB que la acompaña como único accesorio y lo enchufamos al conector CN3 (el tipo min-USB situado en la esquina superior derecha). Después, tomamos el otro extremo del cable y lo insertamos en una base USB de nuestro ordenador.

Al instante veremos como la pantalla se ilumina en rojo y nos pide que pulsemos en una serie de puntos para efectuar una calibración. Para pulsar usaremos algo tipo lápiz de material plástico duro, semejante al que utilizan las tablets o los ordenadores de mano tipo PAD. Nunca se deben utilizar herramientas metálicas o que puedan rayar la pantalla.

La calibración debe efectuarse porque el sistema de reconocimiento táctil es de tipo resistivo, cuya precisión no es tan buena como el capacitivo, y necesita encontrar los puntos de referencia correctos antes de comenzar a trabajar.

Después se iniciará un programa de demostración que nos muestra las posibilidades gráficas de la placa, con texto, barras de colores colores, cuadrados, círculos, ventanas tipo Windows y demás. Todo muy bonito para mostrar lo que hemos comprado, pero como nuestro interés es comenzar a programar la placa y entender sus entresijos, lo que de verdad debemos hacer es quitar dicho programa y entrar los nuestros, aunque de momento está claro que no tendrán comparación posible en cuento a vistosidad.


El software para comenzar a trabajar

Antes de comenzar con la primera prueba consistente el borrar el programa de demostración contenido en la placa, necesitamos una serie de programas que vamos a bajar:

1) Vamos a la web del vendedor de la placa, y en concreto a la pantalla de nuestro producto, Micro4you y en el apartado "Software" pulsamos sobre "PL2303 USB to Serial Driver", lo cual nos lleva a la web de Prolific y de allí nos descargamos dos pequeños programas que guardaremos en una carpeta:

PL2303_Prolific_DriverInstaller_v1417.zip
PL2303DRemover_v1001.zip

El primero de ellos es un driver que una vez instalado en el ordenador reconocerá la placa cuando la conectemos a un USB y nos creará un puerto COM virtual, que puede ser cualquier número disponible (en uno de mis ordenadores ha sido el COM 7 y el otro el COM 4). El segundo programa, como su propio nombre indica, solo sirve como desinstalador del primero.

Hagamos entonces la prueba, instalamos el programita, conectamos la placa al ordenador y si abrimos el Mi PC > Propiedades > Hardware > Administrador de Dispositivos, deberemos ver como el el apartado "Puertos (COM y LPT)" ha aparecido el COM adicional.

Conectando el mini USB-RS232 de la placa con el USB normal del ordenador



2) Ahora debemos bajar e instalar otro programa llamado "Flash Loader Demo", de ST Microelectronics, que puede conseguirse sin problemas en la propia web de la marca y en otros muchos sitios de Internet con sólo introducir el nombre en el Google. En caso de que si por alguna otra causa resulta difícil hallar dichos programas, pueden bajarse los dos de una vez, empaquetados en un archivo .rar, desde la siguiente dirección:

STM32setup.rar

3) Ahora colocaremos la placa Mini-STM32 en modo Boot-Loader, o de carga exterior. Para ello apretamos simultaneamente los pulsadores "Boot" y "RST", y manteniendo el primero pulsado, soltamos el segundo. Observaremos como en el display desaparece el programa demo que estaba corriendo y la pantalla se queda en un blanco de baja luminosidad.

4) Como ya tenemos instalado el Flash Loader Demo, lo arrancamos y ha de aparecernos la siguiente imagen:



En "Port name" seleccionaremos el port virtual que nos haya creado el programa anterior, dejando sin cambiar el resto de cuadros. Apretamos "Next" y saltamos a la siguiente pantalla:




Si el pequeño semáforo aparece en verde es que todo ha ido bien y se ha establecido la comunicación entre la placa y el ordenador. Pulsamos de nuevo "Next"




Aquí nos aparece una pantalla de selección e información sobre la memoria flash de la placa, datos que por ahora no vamos a usar. Apretamos "Next"




En esta página están las acciones a realizar. La que está resaltada por defecto es la de "Erase", o borrado de la memoria, que puede ser total o de una parte que hayamos seleccionado. Bien, como de momento no tenemos necesidades demasiado específicas, procederemos a borrarla en su totalidad, dejando el botón "All" seleccionado. Pulsamos de nuevo "Next"



Esta última página nos informa si el proceso se ha realizado con éxito, con la frase "Erase operation finished succesfully" o ha habido algún problema.

Problemas de reconocimiento de la placa con Windows 2000

En mi caso, este procedimiento ha funcionado bien y al primer intento en mi ordenador normal equipado con Windows XP y en otro con Windows 7, pero en cambio no he conseguido que andara más que una o dos veces de las veinte que lo he probado en otros dos ordenadores con Windows 2000. Aún no he podido determinar si el problema está en el sistema operativo con los COM virtuales o en alguna pijadita de configuración del hardware. Con los W-2000 he bajado la velocidad de los COMs para aumentar la seguridad de la transmisión y he probado las demás opciones de paridad, eco, etc, y sigue sin funcionar, y ya en la segunda página me aparece el semáforo en rojo y la indicación "Unrecognaized device...".

Pero bueno, en casa y con mi ordenador principal andando con XP me funciona, y como supongo que la mayoría ya dejasteis aparcado el W-2000 hace años, también debería funcionar en la vuestra. Si habéis llegado a la última pantalla del Flash Loader con la indicación de que el borrado se ha efectuado de forma satisfactoria, en la placa podéis pulsar el botón RST de la esquina inferior derecha, y con ello saldrá del modo "Boot Loader" y se colocará en ejecución, aunque en este caso, al haber borrado el programa, no va ha hacer absolutamente nada.


Descargando más software e información de utilidad

En la próxima entrega intentaremos realizar nuestro primer programa, cargarlo y ejecutarlo, pero de momento no estaría de más repasar todo lo anterior mientras regresamos a la web del vendedor Micro4you (http://www.micro4you.com/store/mini-...lcd-board.html) y descargamos el software y la información que tan amablemente nos regala y que nos será útil en el futuro:

Del software descargaremos:

- Keil RealView MDK (Potente entorno IDE de programación en C, aunque es una versión de evaluación limitada a programas de 34 Kbytes)
- PL2303 USB to Serial Driver (que ya tenemos por haberlo descargado antes)
- Sample Code (ejemplos de código para las distintas opciones del microcontrolador)
- Update Sample Code 2011 (V1.5) (actualización de los ejemplos)
- Update Sample Code 2011 (1.18) (actualización de los ejemplos)

En la documentación en PDF:

- Mini STM32 STM32F103 TFT LCD Board Schematic (esquema completo de la placa)
- 3.2 TFT LCD Schematic (esquema del módulo LCD)
- TSC2046 Datasheet
- SSD1289 Datasheet
- All Chip Datasheet


Continuará...

NOTA: Este escrito podéis verlo también en forma de página web en http://sites.google.com/site/anilandro/06150-mstm21-01 (después del trabajo efectuado primero para redactar y luego para adecuar este texto al foro, espero que el moderador no considere esta referencia a mi web como spam ni una autopromoción condenable que merezca el borrado, como una vez, y de forma que considero bastante injusta, me sucedió en una intervención en otro apartado este foro)
28/11/2011 #2
Moderador

Avatar de Chico3001

Que padre tutorial!!! tendre que conseguirme una de esas placas...
28/11/2011 #3


yo también estoy estudiando ese micro solo que de otro fabricante por lo que supongo que las librerías cambiarán. Pero la metodología de programación será la misma no?
28/11/2011 #4

Avatar de anilandro

De este tutorial tengo acabadas más entregas. Ya iré colgándolas en el foro de tanto en cuanto.

Sobre las instrucciones, no creo que cambien por ser un micro de un fabricante u otro, mientras sean, naturalmente chips compatibles. Ahora bien, cambiarán un poco si los modelos no coinciden, y sobre todo si en vez de assembler se utiliza el C y distintas librerías en el compilador, ya que muchas funciones serán distintas.
No obstante, las mayores diferencias se deberán no al micro, sino a la placa en sí, ya que está condicionada por el tipo de hardware que está montado.

Todo mi trabajo de programación con esta placa lo realizo en C. Hace años programaba en assembler y me cansé de los berejenales en que me metía el dichoso código. En cuando al programa IDE compilador-linkcador y pese a que en el tutorial cito el Coocox IDE (que es un proyecto de código libre GNU), prácticamente todo lo hago con el Keil uVisión, que es un programa más serio y potente de la propia ARM, la casa matriz de las versiones iniciales de los micros Cortex 3.

Un saludo
29/11/2011 #5

Avatar de anilandro

Programando la placa de desarrollo Mini-STM32 - II
Los entornos IDE y haciendo parpadear los LED


Conseguir el par
padeo de uno o varios LED suele ser de las primeras pruebas que se llevan a cabo cuando se aprende a programar una placa microcontrolada, y en eso vamos a meternos en esta página, pero antes es necesario hablar un poco sobre programación, recordar cuatro generalidades y también presentar el programa que utilizaremos para llevarla a cabo.

Otra cosa que debemos tener en cuenta es que una placa de desarrollo no se parece demasiado a un ordenador corriente, del cual los usuarios podemos desconocer por completo su estructura interna y en cambio manejar a la perfección los programas a través del teclado y la pantalla. Un módulo de este tipo es totalmente dependiente de la circuitería asociada, de tal forma que para realizar el simple ejercicio de encender un LED será imprescindible saber donde y cómo está conectado, y tanto en las pruebas como en el desarrollo de proyectos más de una vez será necesario diseñar y construir pequeños circuitos auxiliares para adaptar los sensores o los actuadores a las características y limitaciones del microcontrolador.

Por todos estos motivos, es necesario que quien quiera meterse en el tema conozca los rudimentos de la programación en C, pero también deberá tener algunos conocimientos de electrónica y de manejo de las herramientas e instrumentos asociados a esta disciplina.

================================================== ====

Consideremos por un momento que hemos resuelto el problema de la conexión del LED y sabemos perfectamente a que pin de salida del microcontrolador está conectado, y pensemos ahora como podía ser un programa capaz de hacerlo parpadear. Sin duda deberemos escribir una orden para dar tensión a dicho pin, mantenerla durante un cierto tiempo, tras este lapso quitarle la tensión, esperar el mismo tiempo y volver a repetir el ciclo desde el principio.

Secuencia de un programa para hacer parpadear un LED

Orden --- Acción --- Resultado
1 --- Suministrar tensión al LED (
El LED se enciende)
2 --- Esperar un poco (
El LED permanece encendido)
3 --- Cortar tensión al LED (
El LED se apaga)
4 --- Esperar un poco (
El LED permanece apagado)
5 --- Regresar al punto 1 (
Se repite todo el ciclo anterior)

Estas órdenes son lógicas y fáciles de entender para nosotros... pero por desgracia no hay manera de cargarlas en la placa para que el microcontrolador las ejecute, ya que estos chips poseen un juego de órdenes muy determinado y mucho más preciso que nuestras formas corrientes de expresión. Las órdenes o instrucciones que puede ejecutar un dispositivo semejante se agrupan en lo que llamamos un "lenguaje de programación".

¿Y cómo sería programar con un lenguaje semejante...? Pues en la práctica como entrar en la Torre de Babel, ya que cada modelo de microcontrolador tiene el suyo propio, que a lo sumo será similar entre chips evolucionados de modelos anteriores, pero puede ser muy diferente al cambiar de tipo, de marca o de tecnología de fabricación.

Esto podría ser algo preocupante, y es el problema con que se encontraban los programadores de los primeros ordenadores. Por este motivo se trabajó para encontrar una solución hasta desarrollar los denominados "compiladores". Expliquemos cuatro cosas al respecto.

================================================== ====

Lenguajes de bajo y alto nivel

Hay muchos lenguajes de programación. Seguro que todos habréis oído hablar en alguna ocasión del Código Máquina, del Asembler, del Fortran, del Basic, del Visual Basic, del Pascal, del Java o del C, pero hay un factor determinante que diferencia los dos primeros de todos los demás.

El Código Máquina y el Asembler son calificados como lenguajes de bajo nivel, y están formados por órdenes muy escuetas, operaciones de deplazamiento en números binarios, conteos ascendentes o descendentes, escritura o lectura de bits en memorias-registro, comparaciones booleanas tipo OR, AND o NOT, etc. De hecho el Código Máquina y el Asembler son lo mismo, simplemente que el primero adopta la forma de listas interminables de números binarios y el segundo los sustituye por una representación algo más amable mediante iniciales, palabras abreviadas y números hexadecimales, que conocemos como lenguaje Asembler o Ensamblador.

Ejemplo de un corto fragmento de lenguaje ensamblador correspondiente a un microcontrolador PIC

org 0x00 ;
aquí comienza el micro.-
goto Inicio ;
salto a inicio del programa.-
org 0x05 ;
origen del código del programa.-
bsf STATUS,RPO ;
pasamos de Banco 0 a Banco 1
movlw b' 11111' ;
Muevo 11111 a W.-
movwf TRISA ;
cargo en TRISA
movlw b' 11111'
movlw TRISB
bcf STATUS,RPO ;
Paso del Banco 1 al Banco 0
bcf PORTB,Led ;
Comienza el apagado

Estos lenguajes no entienden de frases escritas ni procesadores de texto, ni de operaciones con números decimales o de mover una imagen en una pantalla o conectarse a Internet, sólo tratan con bits de información, con señales en un punto que representan un 1 si hay tensión eléctrica y un 0 si no la hay.

El Código Máquina y su alter ego el Asembler son los lenguajes primarios de los microprocesadores y microcontroladores, y la dificultad que implica su uso no sólo deriva de la complejidad o la extensión de sus programas cuando necesita efectuar funciones gráficas o matemáticas, sino también porque son exclusivos para cada modelo de chip. En contrapartida, su ventaja es la gran velocidad y el ahorro de memoria que permiten. Si necesitamos que un microcontrolador procese muy rápido la información que le entra, como por ejemplo la procedente de señales de audio o de vídeo, es necesario que no pierda tiempo en operaciones o comprobaciones inútiles, y eso se consigue con un código máquina eficiente y lo más reducido posible.

El resto de los lenguajes citados, desde el Fortran al C, son llamados "lenguajes de alto nivel", y poseen instrucciones capaces de realizar funciones muy complejas, como cargar un fichero desde un disco a una memoria, mostrar una imagen a color en una pantalla, o permitir que el usuario le entre un número, multiplicarlo por pi, efectuar su raíz cuadrada y escribir el resultado final en la ventana de un programa. Y aunque estos lenguajes también tienen sus dificultades, muchas de sus órdenes adoptan la forma de palabras que describen la acción, aunque por supuesto en inglés:

================================================== ====
Ejemplos de instrucciones de lenguajes de alto nivel

Instrucciones y acción que realizan

Load (
Carga un archivo completo)
Save (
Guarda un archivo completo)
Let A = 3 (
Deja que la variable A tenga el valor 3)
IF X<6 Then Print "Hola" (
Si X es menor que 6, entonces imprime "Hola")

La consecuencia es que mientras los lenguajes de bajo nivel están casi exclusivamente reservados a expertos, ya que su programación llega a ser compleja, tediosa y muy proclive a contener errores, los lenguajes de alto nivel pueden ser utilizados por la mayoría de las personas con una mínima formación.

Sin embargo, ya hemos dicho que sólo el lenguaje máquina es entendido por el microcontrolador, y por tanto, cualquier programa de alto nivel, que también llamaremos "código fuente", deberá ser "traducido" a bajo nivel antes de ser cargado. Esta función la efectúa el "compilador", con la ventaja adicional que no deberemos preocuparnos por los diferentes códigos máquina, porque el propio compilador ya dispone en su interior de los "diccionarios" adecuados para traducir el código fuente de entrada al código máquina de cada tipo de microcontrolador.

En la programación de alto nivel destinada a microprocesadores se utilizan todos los lenguajes antes citados y una veintena más para usos más específicos, pero en el caso de los microcontroladores el lenguaje utilizado es casi en exclusiva el C.

¿Y porqué en C y no en Visual Basic o en Pascal? Pues porque el C es un lenguaje algo especial, mediante el cual, con órdenes sencillas podemos cargar no sólo una imagen en pantalla o crear matrices de datos, sino que también efectuar funciones típicas del Código Máquina, como trabajar con bits individuales, con operaciones booleanas y acceder directamente a elementos del hardware o a posiciones de memoria. El C es potente y rápido a la vez, tal es así que muchos otros lenguajes están escritos interiormente en C, así como la mayor parte de los sistemas operativos como el Windows, el Linux o el Unix.

================================================== ====
Los IDE o Entornos Integrados de Desarrollo

Para programar en C utilizaremos programas llamados IDE (Entorno Integrados de Desarrollo), que consisten en una serie de herramientas unidas en un mismo paquete, que nos permiten escribir el código en C, corregir la sintaxis, añadir la librerías necesarias, compilar y depurar el código asembler resultante, e incluso cargarlo en el microcontrolador.

Hay bastantes programas IDE, la mayoría de pago, como el Keil uVision, el Atollic TrueStudio o el CrossWorks, aunque también pueden encontrarse soluciones de código libre como el Coocox o el Yagarto.

Para esta práctica del tutorial utilizaré el Keil microVisión en su versión gratuita de evaluación, que pese a estar reducida a compilaciones de 34 KBytes, nos basta perfectamente para nuestros propósitos, y el motivo es que todos los ejemplos de software que suministra el vendedor de la placa están en este formato de proyectos. Otro IDE que también veremos en futuras páginas será el Coocox, más sencillo de utilizar y que además suministra mucha información útil sobre órdenes y librerías.

================================================== ====

Instalación del Keil uVisión V4.22

El Keil uVision es otro de los archivos que habremos bajado de la web de Micro4you en el "Ejercicio 1", en concreto el archivo "mdk422.exe", de 414 Mbytes. Este considerable tamaño, teniendo incluso en cuenta que es un fichero comprimido autoextraible, es debido a que contiene muchas herramientas, información y librerías para los distintos microcontroladore ARM.

Sin perder más tiempo clicamos sobre el fichero mdk422.exe y procedemos a instalarlo en nuestro ordenador.

Anagrama de arranque del IDE Keil uVision 4.22


Una vez instalado, vemos que la interface es clásica y discreta, pero eso es tan engañoso como puede serlo en el Photoshop, ya que el uVision V4 es un programa complejo y de grandes posibilidades, la mayoría de las cuales no utilizaremos pero otras las iremos descubriendo a lo largo de las próximas páginas. Así que ahora no vamos a meternos en grandes explicaciones, porque lo siguiente será cargar el primer ejemplo y comenzar a trabajar.

================================================== ====

Cargando el primer ejemplo

Los ejemplos están contenidos en los archivos...

- Mini STM32 V4 Code.rar
- Mini STM32 V4 2011.1.5.rar
- Mini STM32 V4 2011.1.18.rar

...Que también habíamos bajado en la página anterior de este tutorial. De ellos elegiremos el Mini STM32 V4 2011.1.5.rar que parece el más actualizado, lo descomprimimos y abrimos la carpeta resultante HY-MiniSTM32V 2011.1.5, cuyo contenido son las 19 subcarpetas siguientes:

- WWDG, USB-Mass_Storage-SD Card, USART, uCOSII2.91+UCGUI3.90A(FSMC), uCOSII2.91, TouchPanel, TIM, Temp, SysTick, RTC+USART, PWR, IWDG, ID, GPIO, FreeRTOSV6.1.0, Flash, FATFS V0.08A-SD Card, EXTI+USART

Elegiremos la GPIO, la abrimos, seleccionamos MDK-ARM y el archivo Project.uvproj. Al instante se nos abrirá el Keil uVision mostrándonos una estructura de carpetas a la izquierda y otra mucho más ancha a la derecha con un fichero de texto ilegible. Esto no nos ha de preocupar, porque posiblemente dicho archivo está escrito originalmente en ideogramas chinos y nuestro sistema no lo sabe interpretar, así que lo cerramos apretando sobre la pestaña superior "readme.txt", con botón derecho del ratón y Close. Después, en la columna de la izquierda abrimos la carpeta USER y el archivo main.c , el cual nos aparecerá con su propia pestaña en la ventana derecha.

Interface del Keil uVisión 4.22, con el primer programa de ejemplo que hará parpadear un LED


La palabra "main", en inglés, significa "principal" y de hecho el listado así denominado representa el "programa principal" que va a ejecutarse, aunque este "main.c" también depende de otros archivos que contienen las definiciones de las órdenes que va a usar. Estos archivos se denomina "librerías" y tienen la forma de un nombre seguido de la extensión .h

A causa de esta dependencia, cuando se escribe un "main" en necesario incluir las librerías de que depende. Por ejemplo, en el "main" que estamos viendo, la instrucción #include "stm32f10x.h" indica en esta librería están las órdenes que después van a usarse, de manera que cuando arranquemos la compilación, no sólo va a procesarse el "main", sino también el "stm32f10x.h" , y ambos serán después "linkados" o unidos para formar el archivo ejecutable final.

Sigamos. El texto completo de "main.c",después de limpiarlo un poco de comentarios (escritos en verde entre los indicadores /* y */) para que no nos ocupe tanto espacio, tiene el siguiente aspecto.

======================================


#include "stm32f10x.h"
/*--------------Private functions ---------------*/
void GPIO_Configuration(void);
void Delay (uint32_t nCount)
{
for(; nCount != 0; nCount--);
}
/*----------------------- main -------------------------*/
int main(void)
{
GPIO_Configuration();
/* Infinite loop */
while (1)
{
/* LED1-ON LED2-OFF */
GPIO_SetBits(GPIOB , GPIO_Pin_0);
GPIO_ResetBits(GPIOB , GPIO_Pin_1);
Delay(0xfffff);
Delay(0xfffff);
Delay(0x5ffff);
/* LED1-OFF LED2-ON */
GPIO_ResetBits(GPIOB , GPIO_Pin_0);
GPIO_SetBits(GPIOB , GPIO_Pin_1);
Delay(0xfffff);
Delay(0xfffff);
Delay(0x5ffff);
}
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB , ENABLE);
/* LED1 -> PB0 LED2 -> PB1 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
#ifdef USE_FULL_ASSERT

======================================

Sin meternos ahora en explicaciones del cómo y el porqué, veo que este programa activará y desactivará de forma alternativa los Pins 0 y 1 del bus B del STM32. Entonces, abrimos el archivo "Mini STM32 STM32F103 TFT LCD Board V4.pdf" que contiene el esquema de la placa Mini-STM32 (archivo que ya habíamos bajado anteriormente de la web del vendedor), y en la parte del diagrama de las páginas 2 y 3 que reproducimos debajo, observamos que estos pins están conectados respectivamente a las etiquetas LED1 y LED2, que a su vez, a través de sendas resistencias alimentan los leds serigrafiados en la placa como LD3 y LD4, los cuales, evidentemente, también centellearán.

Parte del esquema de la placa Mini-STM32, que muestra las conexiones desde los Pines 0 y 1 del bus B, hasta los leds LD3 y LD4




Ahora que ya sabemos que hace, vamos a compilar el programa y después lo cargaremos en la placa siguiendo esta secuencia:

1) De la etiqueta Projet apretamos Build Target (o F7). Vemos que se abre una ventana en la parte inferior y comienza a compilar una serie de ficheros.

2) La primera vez tarda bastante, ya que no solo ha de hacerlo con el main.c sino con todas las librerías que éste utiliza. Después, cuando acaba, la penúltima fila nos indica "FromELF: creating hex file..." y la última si ha habido errores o avisos, en este caso "0" en ambas cosas.
El compilador nos ha creado un archivo ejecutable para el microcontrolador y lo ha guardado en la carpeta Obj del proyecto que hemos abierto. Antes de compilar por primera vez, esta carpeta estaba vacía, pero ahora hay muchos archivos, y entre ellos uno denominado Project.hex, que es ni más ni menos el ejecutable que hemos de cargar en nuestra placa.

3) Ahora conectamos nuestra MiniSTM32 al ordenador, la colocamos en modo de carga de programas (ver la página anterior para hacerlo) y abrimos el Flash Loader Demostrator.

4) Las dos primeras pantallas de la ventana del programa serán iguales que cuando borramos el programa Demo de la Mini-STM32, pero al llegar a la tercera hemos de marcar "Download to device" y después seleccionar ficheros tipo ".hex" y en concreto " el fichero Project.hex que hemos creado antes.





5) Le damos al "Next". La siguiente pantalla nos indicará el origen y tamaño del archivo cargado (1,2 KB) y la indicación en verde "Download operation successfuly" que la carga ha sido correcta.



6) Ahora apretaremos el botón Reset de la placa y... Oh maravilla... ya tenemos a los dos LEDS de la parte inferior destelleando de forma alternativa.

================================================== ====
Mejorando lo presente, vamos a crear nuestro primer programa

Antes he dicho que el programa anterior me parecía enrevesado, y no es que sea incorrecto bajo el punto de vista de un programador, es solamente que como ejemplo parece hecho a propósito para despistar a quienes no tengan un buen nivel de C. Por este motivo, sin que en ningún momento tenga interés en iniciar un curso de programación de este lenguaje, he decidido crear mi propio programa para luego poder explicar más fácilmente algunas órdenes concretas para manejar este microcontrolador.

Borro el contenido de main.c y escribo este nuevo listado:

======================================

/*Mini-STM32 encendido alternativo de dos leds*/
/* by Anilandro, octubre 2011*/

#include "stm32f10x.h" /*incluye la librería "stm32f10x.h"*/
GPIO_InitTypeDef GPIO_InitStructure;

int main(void){ /*inicio del programa principal*/

int cont; /*definimos una variable llamada "cont", de tipo entero*/

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*establece velocidad a 50 Mhz*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /*establece modo de salida digital*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; /*aplicar lo anterior a PIN 0 y 1*/
GPIO_Init(GPIOB, &GPIO_InitStructure); /*cerrar*/

while (1){ /*bucle infinito*/
GPIO_SetBits(GPIOB , GPIO_Pin_0); /*coloca el PIN 0 a valor alto (enciende el LED 1)*/
GPIO_ResetBits(GPIOB , GPIO_Pin_1); /*coloca el PIN 0 a valor bajo (apaga el LED 2)*/
for(cont=0; cont<1000000; cont++); /*bucle de espera que cuenta un millón de pasos*/
GPIO_ResetBits(GPIOB , GPIO_Pin_0); /*coloca el PIN 0 a valor bajo (apaga el LED 1)*/
GPIO_SetBits(GPIOB , GPIO_Pin_1); /*coloca el PIN 0 a valor alto (enciende el LED 2)*/
for(cont=0; cont<1000000; cont++); /*bucle de espera que cuenta un millón de pasos*/
} /*final de bucle "while" que vuelve al principio*/
} /*final del programa principal*/

======================================

Una vez acabado, coloco la placa en modo boot-loader, arranco el Flash Loader Demonstrator y cargo el nuevo programa, que funciona a la primera. Los leds parpadean de forma alternativa, aunque con una cadencia algo más rápida que la anterior debido a los diferentes valores de los bucles de espera.

Para quien desee repetir la prueba, lo cual aconsejo si sigue este tutorial, bastará que seleccione el texto del recuadro y lo copie en su espacio "main.c" una vez borrado el texto anterior. Como estos ficheros son sólo de texto, a partir de este momento es igual que si lo hubiéramos escrito directamente en la ventana del Keil

================================================== ====

Explicando el funcionamiento del nuevo programa

Con los comentarios contenidos entre /*...*/ del programa anterior creo que ya es posible hacerse una idea de cómo actúa el programa, pero la cosa estará más clara si concretamos un poco más.

El programa está escrito en varios bloques claramente diferenciados:

#include "stm32f10x.h"
GPIO_InitTypeDef GPIO_InitStructure;
int main(void){


La primera línea incluye la librería que contiene las órdenes a usar, la segunda una llamada a una estructura de órdenes y la tercera el comienzo de la rutina principal. La primera instrucción "#include "stm32f10x.h" incluye la librería donde están las órdenes que vamos a utilizar, aunque ello no significa que tales órdenes estén físicamente dentro de esta librería, porque a su vez ésta también puede tener otros "#include". La línea GPIO_"InitTypeDef GPIO_InitStructure;" se refiere a una estructura de variables (no preguntemos ahora que es una estructura), las cuales serán utilizadas a continuación. Y "int main(void){" inicia la parte principal del programa.

int cont;

A continuación viene la declaración de variables. En este caso una sola que llamaremos "cont", y que es de tipo "int" o entera. Lo cual significa que dicha variable podrá contener números enteros entre -2.147.483.648 a 2.147.483.647. Dicha variable la utilizaremos como puntero de los contadores que nos permitirán establecer un tiempo de encendido y otro de apagado de los leds.

Ahora viene la parte que configura los "pins" del microcontrolador:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
GPIO_Init(GPIOB, &GPIO_InitStructure);

El STM32 dispone de 3 buses utilizables para periféricos:

- Advanced High-Performance Bus (AHB)
- Advanced Peripheral Bus (APB1) de velocidad hasta 36 MHz
- Advanced Peripheral Bus (APB2) de velocidad hasta 72 MHz

Normalmente estos buses están desconectados para que no consuman corriente. En este caso sólo usaremos pines del APB2, y para ello introduciremos la orden "RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);" que proporciona la adecuada señal de reloj.
Las tres siguientes órdenes establecen la velocidad a 50 Mhz, que el pin actuará como una salida en Push-Pull, y la tercera a que pines afectarán estos parámetros, en concreto vemos que afecta a Pin = GPIO_Pin_0|GPIO_Pin_1; , es decir, al Pin_0 y al Pin_1.

Esta parte se cierra con GPIO_Init(GPIOB, &GPIO_InitStructure); tras la cual ya no podemos seguir asignando pines, excepto que de nuevo cerremos con la misma instrucción, por ejemplo, las órdenes:

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; /*asigna pin 0 y 1*/
GPIO_Init(GPIOB, &GPIO_InitStructure); /*cierra*/

Son equivalentes a:

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; /*asigna pin 0*/
GPIO_Init(GPIOB, &GPIO_InitStructure); /*cierra*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; /*asigna pin 1*/
GPIO_Init(GPIOB, &GPIO_InitStructure); /*cierra*/

Y finalmente encontramos las órdenes que encienden y apagan los LED, encerradas dentro de un bucle while (1){.......} que se repite infinitamente

while (1){
GPIO_SetBits(GPIOB , GPIO_Pin_0);
GPIO_ResetBits(GPIOB , GPIO_Pin_1);
for(cont=0; cont<1000000; cont++);
GPIO_ResetBits(GPIOB , GPIO_Pin_0);
GPIO_SetBits(GPIOB , GPIO_Pin_1);
for(cont=0; cont<1000000; cont++);
}

Aquí vemos las órdenes de encendido tipo GPIO_SetBits .... y las órdenes de apagado tipo GPIO_ResetBits . Formando dos grupos que encienden un LED y apagan el otro, e intercaladas entre los grupos la línea for(cont=0; cont<1000000; cont++); Que es un contador desde 0 a 1.000.000, y el tiempo que tarda en hacerlo es el que permanece encendido un LED y apagado el otro.

La sentencia for(cont=0; cont<1000000; cont++); hace lo siguiente:

1) Toma la variable cont y le asigna el valor 0 (cont=0 )
2) Comprueba si el valor de la variable es menor de 1.000.000 (cont<1000000 ), si es menor, pasa al paso 3), si es igual o mayor sale del "for" y salta a la siguiente instrucción
3) Le suma 1 a cont y salta de nuevo al paso 2) (cont++)

Entonces, si nosotros alteramos el valor de la comparación de (cont<1000000 ), y ponemos 2.000.000 ó 500.000, el tiempo de conteo, y por tanto de encendido de un LED y de apagado de otro, subirá al doble o bajará a la mitad.

La secuencia total de esta parte es:

1) - Activamos Pin_0 y por tanto encendemos el LED_1
2) - Desactivamos el Pin_1 y por tanto apagamos el LED_2
3) - Esperamos el tiempo de conteo
4) - Desactivamos Pin_0 y por tanto apagamos el LED_1
5) - Activamos el Pin_1 y por tanto encendemos el LED_2
6) - Esperamos el tiempo de conteo
7) - Volvemos al paso 1)

================================================== ==

Probando algunas variaciones

Las órdenes GPIO_SetBits(GPIOB , GPIO_Pin_x); y GPIO_ResetBits(GPIOB , GPIO_Pin_x); (siendo "x" cualquier número de Pin válido) No son las únicas posibles para poner los pins a 0 y a 1, también podemos utilizar:

GPIO_WriteBit(GPIOB, GPIO_Pin_x,Bit_SET); /*coloca el PIN 0 a valor alto (enciende el LED 1)*/
GPIO_WriteBit(GPIOB, GPIO_Pin_x,Bit_RESET); /*coloca el PIN 0 a valor bajo (apaga el LED 1)*/

A la vez, la librería "stm32f10x.h" es muy general, pero también podemos utilizar las librerías particulares para las órdenes GPIO, y por tanto podemos sustituir la orden #include "stm32f10x.h" por:

#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"

Aplicando estos cambios, nuestro programa "main.c" quedaría como:

======================================
/*Mini-STM32 encendido alternativo de dos leds*/
/* by Anilandro, octubre 2011*/

#include "stm32f10x_gpio.h" /*incluye la librería "stm32f10x_gpio.h"*/
#include "stm32f10x_rcc.h" /*incluye la librería "stm32f10x_rcc.h"*/
GPIO_InitTypeDef GPIO_InitStructure;

int main(void){ /*inicio del programa principal*/

int cont; /*definimos una variable llamada "cont", de tipo entero*/

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*establece velocidad a 50 Mhz*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /*establece modo de salida digital*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; /*aplicar lo anterior a PIN 0 y 1*/
GPIO_Init(GPIOB, &GPIO_InitStructure); /*cerrar*/

while (1){ /*bucle infinito*/
GPIO_WriteBit(GPIOB, GPIO_Pin_0,Bit_SET); /*coloca el PIN 0 a valor alto (enciende el LED 1)*/
GPIO_WriteBit(GPIOB, GPIO_Pin_1,Bit_RESET); /*coloca el PIN 0 a valor bajo (apaga el LED 2)*/
for(cont=0; cont<1000000; cont++); /*bucle de espera que cuenta un millón de pasos*/
GPIO_WriteBit(GPIOB, GPIO_Pin_0,Bit_RESET); /*coloca el PIN 0 a valor bajo (apaga el LED 1)*/
GPIO_WriteBit(GPIOB, GPIO_Pin_1,Bit_SET);; /*coloca el PIN 0 a valor alto (enciende el LED 2)*/
for(cont=0; cont<1000000; cont++); /*bucle de espera que cuenta un millón de pasos*/
} /*final de bucle "while" que vuelve al principio*/
} /*final del programa principal*/
======================================

En la próxima entrega de este tutorial mostraremos otro entorno de programación IDE, el Coocox, veremos como utilizar botones para entrar órdenes al programa y montaremos alguna experiencia práctica algo más útil que encender y apagar un par de LEDs.

Continuará...

NOTA: este texto puede verse también en forma de página web en ni sitio, cuya dirección figura al pie de esta página
03/11/2013 #6


Hola amigo anilandro, estoy por comprar una pantalla TFT de 4.3" con el controlador ssd1963 pero también me gustaría tener una más pequeña como un TFT 3.2" pero éstas tienen el controlador ssd1289, mi petición sería saber si tienes y quieres pasarme rutinas para manejar la pantalla TFT con el controlador ssd1289? yo ya estoy leyendo y entendí como usar las TFT más grandes de 4.3 y 7". yo estoy usando lenguaje ansi C con Atmel y freescale. No importa si es de STM32 u otro micro con que sea C puedo darme maña jeje Gracias!! Saludos!.
Respuesta
¿Tienes una mejor respuesta a este tema? ¿Quieres hacerle una pregunta a nuestra comunidad y sus expertos? Registrate

Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos

Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO ©2011, Crawlability, Inc.