image
image

images

© Universidad Peruana de Ciencias Aplicadas (UPC)

Primera publicación: setiembre de 2015

 

Edición:

Corrección de estilo:

Diseño de cubierta:

Diagramación:

Diana Félix

Luigi Battistolo

Christian Castañeda

Diana Patrón Miñán / Christian Castañeda

Editor del proyecto editorial

Universidad Peruana de Ciencias Aplicadas S.A.C.

Av. Alonso de Molina 1611, Lima 33 (Perú)

Teléf: 313-3333

www.upc.edu.pe

Primera edición: setiembre de 2015

Versión ebook 2015

Digitalizado y Distribuido por Saxo.com Perú S.A.C.

image
www.saxo.com/es
yopublico.saxo.com
Telf: 51-1-221-9998
Dirección: Av. 2 de Mayo 534 Of. 304, Miraflores
Lima-Perú

Universidad Peruana de Ciencias Aplicadas (UPC)
Centro de Información

Salas Arriarán, Sergio. Todo sobre sistemas embebidos. Arquitectura, programación y diseño de aplicaciones prácticas con el PIC18F

Lima: Universidad Peruana de Ciencias Aplicadas (UPC), 2015

ISBN de la versión impresa: 978-612-318-033-1

ISBN de la versión pdf: 978-612-318-034-8

ISBN de la versión epub y mobi: 978-612-318-035-5

Conceptos básicos - Arquitectura del microcontrolador PIC18F - El compilador para PIC18F. El MPLAB X IDE - El lenguaje ensamblador del PIC18F - Rutinas típicas en lenguaje ensamblador - Interrupciones -Los puertos de entrada y salida - El lenguaje ANSI C - Los módulos de temporización - El convertidor analógico digital - El módulo mejorado de comunicación serial síncrona asíncrona (EUSART) - La interfaz serial periférica - La interfaz serial I2C - El módulo USB.

006.22 SALA

Todos los derechos reservados. Esta publicación no puede ser reproducida, ni en todo ni en parte, ni registrada en o transmitida por un sistema de recuperación de información, en ninguna forma ni por ningún medio, sea mecánico, fotoquímico, electrónico, magnético, electroóptico, por fotocopia o cualquier otro, sin el permiso previo, por escrito, de la editorial.

El contenido de este libro es responsabilidad del autor y no refleja necesariamente la opinión de los editores.

A mis alumnos, quienes con su interés, a través de constantes preguntas e
inquietudes, me animaron al desarrollo de esta obra.

A mis excolegas del INICTEL-UNI, por su compañerismo y las
experiencias compartidas.

A mis padres, por las enseñanzas a lo largo de toda la vida.

Contenido

Prólogo

Introducción

Capítulo 1. Conceptos básicos

1.1 Definiciones básicas

1.2 Sistemas embebidos

1.3 Lenguajes de programación

1.4 La familia PIC18F4X de Microchip

1.5 Herramientas de desarrollo para Microchip

1.6 Características específicas del PIC18F4550

Capítulo 2. Arquitectura del microcontrolador PIC18F

2.1 La Unidad central de proceso (CPU)

2.2 Las unidades de memoria

2.3 Almacenamiento de las instrucciones en la memoria de programa

2.4 Las interfaces de entrada y salida (E/S)

2.5 El Reset

2.6 Temporización y opciones de reloj

2.7 Modos de ahorro de energía

2.8 El Perro guardián

Capítulo 3. El compilador para PIC18F. El MPLAB X IDE

3.1 IDE

3.2 Creación de un nuevo proyecto en MPLAB X usando el compilador MPASM

3.3 Elaboración de un programa sencillo. Partes del código y reglas básicas

3.4. Simulación de un programa en lenguaje ensamblador

3.5 Los archivos de configuración

3.6 El compilador MPLAB XC8

3.7 Creación de un nuevo proyecto en MPLAB usando el compilador MPLAB XC8

3.8 Proceso de grabación del microcontrolador PIC18F4550

Capítulo 4. El lenguaje ensamblador del PIC18F

4.1 El conjunto de instrucciones

4.2 Modos de direccionamiento

4.3 El Puntero de programa

4.4 La pila de direcciones

4.5 Instrucciones para el manejo de tablas en la memoria de programa

4.6 Acceso a la memoria EEPROM de datos

4.7 Directivas para el lenguaje ensamblador

Capítulo 5. Rutinas típicas en lenguaje ensamblador

5.1 Diseño de un diagrama de flujo

5.2 Rutinas básicas de retardo de tiempo

5.3 Conversión de bases

5.4 Operaciones matemáticas

5.5 Detección de teclas pulsadas en un teclado matricial

Capítulo 6. Interrupciones

6.1 El concepto de interrupción

6.2 El vector de interrupción

6.3 La prioridad de una interrupción

6.4 Latencia de una interrupción

6.5 Ejemplo de configuración de una interrupción externa

Capítulo 7. Los puertos de entrada y salida

7.1 Los puertos de entrada y salida del PIC18F4550

7.2 Ejemplo de control de un teclado matricial mediante la interrupción de cambio de estado del Puerto B

7.3 Manejo de un módulo LCD alfanumérico basado en el controlador HD44780

Capítulo 8. El lenguaje ANSI C

8.1 Historia del lenguaje ANSI C

8.2 La estructura de un programa en lenguaje C

8.3 Los tipos de datos

8.4 Los operadores en ANSI C

8.5 Sentencias condicionales e iterativas

8.6 Funciones y librerías

8.7 Arreglos y punteros

8.8 Estructuras y uniones

8.9 Tipos de variables compuestos

8.10 Uso del lenguaje ensamblador dentro de ANSI C

8.11 Manejo de interrupciones en MPLAB XC8

8.12 Las directivas del preprocesador

8.13 Ejemplos de aplicaciones con lenguaje ANSI C

Capítulo 9. Los módulos de temporización

9.1 Los temporizadores del PIC18F4550

9.2 Diseño de un semáforo sincronizado con el 0

9.3 Diseño de un reloj en tiempo real con el Timer 1

9.4 El módulo de entrada de captura

9.5 El modo de comparación de salida

9.6 El modo de modulación por ancho de pulso (PWM)

Capítulo 10. El convertidor analógico digital

10.1 Fundamentos de un sistema de adquisición de datos

10.2 La conversión analógica digital

10.3 El teorema del muestreo

10.4 El convertidor analógico digital del PIC18F4550

10.5 Ejemplos de aplicaciones con el convertidor analógico digital del PIC18F4550 Timer

Capítulo 11. El módulo mejorado de comunicación serial síncrona asíncrona (EUSART)

11.1 Nociones básicas de la comunicación serial

11.2 La tasa de bit y el formato NRZ

11.3 El estándar RS232

11.4 El módulo EUSART del PIC18F4550

11.5 Ejemplos de aplicación con el EUSART del PIC18F4550

Capítulo 12. La interfaz serial periférica

12.1 Fundamentos de la comunicación serial síncrona SPI

12.2 Pines del SPI

12.3 Formatos de transmisión del bus SPI

12.4 El módulo SPI del PIC18F4550

12.5 Ejemplos de aplicación con el bus SPI del PIC18F4550

Capítulo 13. La interfaz serial I2C

13.1 Características del protocolo I2C

13.2 Transferencia de datos en el protocolo I2C

13.3 Arbitrariedad

13.4 Direccionamiento de periféricos

13.5 Formato de transferencia de datos

13.6 Registros de configuración del PIC18F4550

13.7 Programación del módulo MSSP en modo I2C

13.8 Ejemplos de aplicación con el módulo I2C del PIC18F4550

Capítulo 14. El módulo USB

14.1 Fundamentos del bus USB

14.2 Modos de transferencia

14.3 El proceso de enumeración

14.4 Las clases de descriptores

14.5 El módulo USB del PIC18F4550

14.6 La librería MLA (Microchip Library Application) para dispositivos USB de Microchip

14.7 Ejemplo de comunicación entre el PIC18F4550 y un computador a través del puerto USB

Bibliografía

Image

Foto: Milagros Segura Zurita

Sergio Salas Arriarán es ingeniero electrónico de la Universidad Peruana de Ciencias Aplicadas y Magíster en Ingeniería Biomédica por la Pontificia Universidad Católica del Perú (PUCP). Se ha desempeñado como Investigador y Desarrollador Tecnológico en el INICTEL-UNI. Ha ejercido la docencia en la Universidad de San Martín de Porres, la Universidad Tecnológica del Perú y la Escuela Naval. Asimismo, cuenta con experiencia como catedrático en la Maestría en Ciencias con mención en Telecomunicaciones de la Universidad Nacional de Ingeniería (UNI). Actualmente, es Profesor a Tiempo Completo de la escuela de Ingeniería Electrónica de la Universidad Peruana de Ciencias Aplicadas (UPC).

Prólogo

Escribir un libro académico es dejar una huella para siempre. Decidir hacerlo no solamente conlleva capacidad, conocimientos, experiencia, dedicación y sacrificio, sino también la intención de que quienes lo lean y lo utilicen puedan aprender su contenido de una manera más fácil y comprensible. Ello constituye un gran desafío, que únicamente puede tener éxito cuando el autor domina el tema y cuando el estilo utilizado para transmitir el conocimiento es muy motivador, utilizando adecuadamente las herramientas audiovisuales disponibles.

En el presente libro, titulado Todo sobre sistemas embebidos, Sergio Salas, su autor, ha logrado de manera efectiva compendiar, en sus catorce capítulos, todos los elementos necesarios para la cabal comprensión de dichos sistemas y de sus aplicaciones, a través de ejemplos prácticos. La ruta propuesta para ello comienza por tratar los conceptos básicos acerca de los sistemas de numeración utilizados en la electrónica digital, lo que le sirve de soporte para poder explicar la arquitectura del microcontrolador PIC18F, el cual ha sido elegido en el texto por ser uno de los más populares en la actualidad. Contando con dicha base, procede a explicar el compilador MPLAB X IDE, así como el lenguaje ensamblador con sus rutinas típicas. Introduce luego el concepto de interrupciones en un microcontrolador, y a continuación describe en forma detallada los puertos de entrada y salida del microcontrolador PIC18F4550. Luego justifica la utilidad del lenguaje ANSI C, y lo explica mostrando en todo momento aplicaciones prácticas actuales. Cumplido lo anterior, trata el importante tema de la temporización y sus elementos. A esta altura del camino, el punto siguiente sobre la conversión analógica digital permite apreciar cómo adquirir datos a partir de un sensor y cómo convertirlas de su formato analógico original a uno digital, lo cual hace posible el desarrollo de soluciones para aplicaciones específicas que se puedan necesitar de acuerdo con la identificación de un problema real. Como el microcontrolador debe intercambiar datos con el mundo exterior, el texto completa su esquema desarrollando el módulo mejorado de comunicación serial asíncrona (EUSART), el protocolo de comunicación serial síncrono half dúplex SPI (Serial Peripheral Interface), y, por último, el módulo USB (Universal Serial Bus). A lo largo de cada capítulo, es de destacar la exposición clara y pedagógica, apoyada en la utilización de videos y en preguntas de repaso que, sin duda, distinguen este libro de otros disponibles en la literatura, y que además posibilita y pone en práctica uno de los paradigmas del modelo educativo de la Universidad Peruana de Ciencias Aplicadas (UPC): el de adquirir nuevos conocimientos haciendo las cosas por uno mismo.

El libro está dirigido a estudiantes de pregrado, y es directamente aplicable al curso Sistemas Embebidos de la UPC, ya sea de las carreras de Ingeniería Electrónica, Ingeniería de Telecomunicaciones y Redes, e Ingeniería Mecatrónica. Pero también genera interés en carreras afines, así como en ingenieros que deseen introducirse o actualizarse en este importante tema que, dicho sea de paso, nos encamina al fascinante mundo de internet de las cosas, donde tendremos cada vez más aplicaciones y soluciones para todo tipo de problemas en todos los escenarios que podamos imaginar.

Sin duda alguna, esta obra constituye un valioso aporte para el diseño y la implementación de aplicaciones innovadoras en todos los proyectos de ingeniería que incluyan sistemas embebidos, y contribuye de manera eficaz al desarrollo tecnológico propio que tanto se requiere para la mejora del bienestar y de la competitividad del país.

Carlos R. Valdez Velásquez-López, Dr. Eng.
Director de la Escuela de Ingeniería Electrónica
Universidad Peruana de Ciencias Aplicadas (UPC)

Introducción

En la enseñanza de sistemas embebidos, tanto para estudiantes universitarios como para alumnos a nivel técnico, no se encuentran materiales bibliográficos que involucren temas de arquitectura de sistemas embebidos, lenguajes de programación en ensamblador y ANSI C, que expliquen el funcionamiento y las características de los módulos periféricos de un microcontrolador y que muestren aplicaciones reales basadas en estos dispositivos. Todos estos temas se encuentran de forma separada y en su mayoría, la bibliografía está en idioma inglés. Por esta razón, se decidió tomar todo el material y la experiencia utilizada para la enseñanza de un curso sobre sistemas embebidos y volcarlos en un libro de texto que presente esta información de forma ordenada y simple.

Este libro se ha desarrollado pensando en estudiantes que se introducen al mundo de los sistemas embebidos por primera vez, o que cuentan también con cierta experiencia y desean profundizar conceptos para conocer nuevos ejemplos de aplicaciones con microcontroladores. De la misma manera, el libro está orientado a ingenieros que tengan cierta experiencia en el desarrollo de hardware digital o a docentes en el campo de sistemas embebidos que deseen ingresar al mundo de los micro-controladores de la familia PIC18F de Microchip.

Se ha tomado como base para el desarrollo del libro el curso de microcontroladores que se ofrece en las carreras de Ingeniería Electrónica, Ingeniería de Telecomunicaciones y Redes e Ingeniería Mecatrónica de la Facultad de Ingeniería de la Universidad Peruana de Ciencias Aplicadas de Lima, Perú.

Para mostrar ejemplos aplicados se utiliza el PIC18F4550, ya que es uno de los microcontroladores más populares de la empresa Microchip, se encuentra fácilmente en el mercado nacional a un costo bastante accesible y permite desarrollar un sinnúmero de aplicaciones prácticas para soluciones de problemas reales, ya sea en la industria electrónica de consumo o electrónica médica, entre otras. Todos los ejemplos mostrados en el libro se basan en el microcontrolador propuesto. Sin embargo, la gran mayoría de estos se pueden migrar fácilmente a cualquier otro modelo de microcontrolador de la misma familia, ya que los lenguajes de programación utilizados y la arquitectura son compatibles.

Adicionalmente, el PIC18F4550 es uno de los pocos microcontroladores de la familia PIC18F que cuenta con un módulo USB interno, el cual permite que sea conectado al computador a través de este protocolo a velocidades de 1.5Mpbs y 12Mbps, lo que abre las puertas a una serie de aplicaciones relacionadas a interfaces de comunicación con el computador. Es por esta razón que el libro contiene un capítulo dedicado a este tema tan interesante, además de un ejemplo real.

El presente libro pretende ser lo más claro y explicativo posible, a fin de que el lector pueda obtener el máximo provecho. De esta manera, en el aula los alumnos tendrán un mejor entendimiento sobre los temas a tratar en el curso sobre sistemas embebidos, y podrán convertir una sesión de clase explicativa en un debate entre el profesor y los estudiantes, lo cual enriquecerá el nivel de los proyectos propuestos que se puedan producir como resultado de la asignatura.

Cada capítulo del libro trata un tema diferente, pero a la vez necesario para poder entender los capítulos siguientes. Los ejemplos que presentan están listos para que el lector los pueda utilizar directamente en la programación del sistema embebido. Todos estos programas han sido probados en módulos de desarrollo y su funcionamiento se encuentra completamente verificado. El contenido de cada capítulo ha sido dividido de tal manera que el lector primero aprenda a programar en lenguaje ensamblador, entendiendo la arquitectura del microcontrolador y sus modos de acceso a memoria y uso de periféricos de entrada y salida. La segunda parte explica el lenguaje ANSI C, con lo cual algunos ejemplos suben en complejidad, en virtud de la facilidad que conlleva el uso de un lenguaje de alto nivel.

En el primer capítulo se presentan aspectos básicos de los sistemas de numeración binaria, conversión entre bases, las operaciones aritméticas y lógicas en el sistema binario y la representación de cifras decimales, BCD y ASCII. Luego, se explica claramente el concepto de sistema embebido y las herramientas que ofrece Microchip para poder programar y depurar los microcontroladores de la familia PIC18F y otros más. Finalmente, se analizan los elementos más importantes de esta familia y se detallan las características particulares del microcontrolador modelo de este libro: El PIC18F4550.

Posteriormente, el segundo capítulo muestra los detalles de la arquitectura del PIC18F. Se presentan las características del microprocesador, sus registros internos y unidad aritmética lógica. Luego, se explican las distintas unidades de memoria que existen en la familia de microcontroladores PIC18F y las interfaces de entrada y salida, las opciones de Reset, los módulos de temporización, las características del funcionamiento del reloj y los modos de bajo consumo.

En el tercer capítulo se muestra la herramienta de desarrollo: El MPLAB X IDE. Se explica con ejemplos cómo crear un nuevo proyecto, editar un programa, simularlo y grabarlo en la memoria FLASH del microcontrolador. Primero se realiza la demostración con el lenguaje ensamblador y luego se hace lo propio con el lenguaje ANSI C. Esta metodología deberá ser usada por el lector para la verificación del resto de ejemplos presentados en el libro.

El cuarto capítulo detalla las instrucciones del lenguaje ensamblador del PIC18F. Cada instrucción se presenta con un ejemplo que ayuda a entender su forma de operación. A continuación se presentan las directivas del lenguaje ensamblador, las cuales también han sido ejemplificadas, con el objetivo de mostrar claramente su función.

En el quinto capítulo se explica la metodología para plantear un programa en lenguaje ensamblador. Se plantean rutinas básicas que son útiles para la mayoría de aplicaciones, como retardo de tiempo, conversión de bases y operaciones matemáticas. Finalmente, se muestra una técnica para detectar las teclas pulsadas de un teclado matricial conectado al microcontrolador a través de uno de sus puertos.

Seguidamente, el sexto capítulo aborda el tema de las interrupciones. Se explica el concepto y luego se analiza la estructura de las interrupciones ofrecidas por el PIC18F. Luego se muestra un ejemplo sencillo en el que se configurará la interrupción externa 0 del PIC18F4550 para detectar flancos generados por un pulsador.

En el séptimo capítulo se presentan los puertos de entrada y salida del PIC18F4550. Mediante estos conceptos, se muestran ejemplos de configuración y control de un teclado matricial y un módulo LCD alfanumérico.

Luego, en el octavo capítulo se aborda la sintaxis completa del lenguaje ANSI C. Se explican sus instrucciones con ejemplos sencillos y se muestra la forma de creación de librerías haciendo uso del compilador XC8. Se mencionan temas más específicos, como el uso de ensamblador dentro del ANSI C, el manejo de interrupciones y el uso de directivas del preprocesador. Finalmente, se muestran programas de ejemplo, aplicados haciendo uso del lenguaje C y de los periféricos del microcontrolador.

En el noveno capítulo se emprende el tema de los módulos de temporización del microcontrolador. Aquí se presenta la teoría y el mecanismo de funcionamiento de un temporizador, además de diversos ejemplos de funcionamiento. Posteriormente, se explican los modos de Entrada de captura, comparación de salida y generador de PWM, los cuales se ejemplificarán con aplicaciones reales que requieren el uso de servomotores y sensores infrarrojos para su puesta a prueba.

El décimo capítulo toca el tema del convertidor analógico digital del PIC18F. Se presenta la teoría básica de digitalización de señales analógicas y algunos aspectos importantes, como el teorema del muestreo. Luego, se explica el módulo ADC del PIC18F4550 y el método de configuración. Finalmente, se muestran dos ejemplos aplicados para medir el voltaje de forma digital y la temperatura ambiente haciendo uso de un sensor LM35.

Más adelante, en el decimoprimer capítulo se aborda el tema de la comunicación serial asíncrona y el estándar RS232. Se analiza el módulo EUSART del PIC18F y su forma de configuración. Luego, se muestran ejemplos aplicados para obtener una comunicación entre el PIC18F4550 y un computador a través del puerto RS232 y otra aplicación médica muy interesante: el diseño de un oxímetro de pulso para medir el nivel de saturación de oxígeno y pulso cardiaco de un paciente.

En el decimosegundo capítulo se presenta la interfaz serial periférica (SPI), la cual corresponde a uno de los módulos de comunicación síncrona del microcontrolador bastante utilizada por muchos dispositivos periféricos en estos días. Se explica el módulo MSSP del microcontrolador y los registros de configuración. Luego, se muestran dos ejemplos de aplicación: un reloj en tiempo real haciendo uso del circuito integrado DS1305 y el diseño de una matriz de LED basada en el circuito integrado MAX6952.

Posteriormente, el decimotercer capítulo trata de la interfaz serial síncrona I2C. Se explican las características del protocolo y los métodos de intercambio de información entre dos o más dispositivos conectados mediante esta interfaz. Luego, se explica el módulo MSSP del microcontrolador configurado en modo I2C y el método de configuración. Se analiza la librería “i2c” del MPLAB XC8 y se muestran dos ejemplos aplicados: uno para obtener la temperatura de un sensor digital como el DS1621 y el acceso de lectura y escritura sobre una memoria EEPROM modelo 24LC08.

El último capítulo toca el tema de la interfaz USB. Se explican de forma general los fundamentos del bus, los métodos de transferencia, el proceso de enumeración y las clases de dispositivo. Luego, se analizan las características más relevantes del módulo USB del PIC18F4550 y se presenta la librería MLA de Microchip, que permite manipular el módulo USB del microcontrolador a través de funciones amigables que manejan los detalles de la configuración, facilitando la elaboración de aplicaciones. Al finalizar el capítulo, se muestra un ejemplo de comunicación entre el PIC18F4550 y el computador a través del bus USB usando la clase CDC.

Capítulo 1. Conceptos básicos

Para la correcta comprensión del contenido del presente capítulo y de los capítulos siguientes, es necesario tener en claro ciertos conceptos básicos acerca de los sistemas de numeración utilizados en la electrónica digital (básicamente, el sistema binario y el hexadecimal), los tipos de operaciones matemáticas relacionadas con estas bases numéricas y las diversas interpretaciones que se pueden obtener de las cifras binarias.

1.1 Definiciones básicas

A continuación se presenta una serie de conceptos importantes sobre electrónica digital; los tipos de base numérica binaria, decimal y hexadecimal; los métodos aritméticos para obtener los cambios de base, operaciones lógicas y aritméticas en estos sistemas numéricos; y los formatos de numeración BCD y ASCII, que son sumamente utilizados en las aplicaciones con sistemas embebidos.

1.1.1 El sistema de numeración binario y hexadecimal

En el mundo de los dispositivos lógicos digitales, las operaciones realizadas siempre involucran patrones numéricos en formato binario. La unidad mínima de este formato es el bit. Un bit se representa por dos niveles o estados lógicos: ‘1’ o ‘0’. Normalmente, un nivel ‘1’ lógico viene a estar físicamente representado por una magnitud en voltios, y el nivel ‘0’, en otra magnitud de voltaje. Por ejemplo, en la tecnología TTL1, el nivel lógico ‘1’ se encuentra determinado en el rango entre 2 V y 5.5 V, mientras que el nivel ‘0’ está entre 0V y 0.8 V. Cualquier nivel de voltaje fuera de este rango (entre 0.8 y 2 V) es considerado como un estado indeterminado o ‘X’, con el cual será imposible realizar operaciones lógicas a nivel digital.

Las cifras binarias, por lo general, no se componen de un solo bit. Normalmente, están compuestas por una cantidad múltiplo de ocho bits. En el gráfico 1.1 se muestran los tipos de arreglos binarios más utilizados en la electrónica digital.

Gráfico 1.1. Arreglos binarios más comunes usados en la electrónica digital

 

Tamaño

Valor mínimo y máximo

Denominación

1 bit

0 – 1

Bit

4 bits

0000 – 1111

Nibble

8 bits

0000 0000 – 1111 1111

Byte

16 bits

0000 0000 0000 0000 –
1111 1111 1111 1111

Word

32 bits

0000 0000 0000 0000
0000 0000 0000 0000 –
1111 1111 1111 1111
1111 1111 1111 1111

Double Word

Elaboración propia.

Una cifra binaria posee la siguiente nomenclatura: (código binario)2, donde el subíndice 2 indica la base. Por ejemplo, la cifra 010100002 es un byte con un valor equivalente al número 80 en base decimal (base 10). La nomenclatura para la base hexadecimal se representa antecediendo un 0x sobre el código hexadecimal. Por ejemplo, la cifra mostrada se puede representar como 0x50 en la base hexadecimal. El bit ubicado en el extremo derecho de la cifra en base binaria es conocido como el bit LSB2 y representa el valor menos significativo. De la misma manera, el bit del extremo izquierdo es considerado el bit MSB3 o más significativo. Al igual que en el sistema de numeración decimal, una cifra ubicada en la posición de las centenas o millares (izquierda) presenta mayor significancia que una cifra ubicada en la posición de las decenas o unidades (derecha).

En el sistema binario, la base numérica utilizada es 2. Esto significa que cada bit puede estar representado únicamente por dos cifras: ‘0’ o ‘1’. La posición del bit dentro de la cifra especifica un valor formado por la cifra 2 elevado a una potencia y multiplicado por el valor del bit (‘0’ o ‘1’). El valor de dicha potencia es la posición del bit en la cifra. Por ejemplo, si se observa el* gráfico 1.2, en el byte de la figura, el bit LSB tiene un aporte de 20 (ya que 0 es la posición menos significativa), mientras que el bit MSB aporta con 27. Esto implica que el valor de la cifra es el siguiente:

valor = 27 × 0 + 26 × 1 + 25 × 0 + 24 × 1 + 23 × 0 + 22 × 0 + 21 × 0 + 20 × 0

Como se puede observar, el valor obtenido es 64+16 = 80, cifra equivalente en base decimal. Conforme se agreguen más dígitos binarios a esta cifra, el exponente de la base binaria se incrementará en uno. Por ejemplo, si una cifra binaria posee 11 bits, el bit MSB tendrá un peso equivalente de 210.

Al igual que en el caso de las cifras decimales, donde existen prefijos como kilo (103), Mega (106) o Giga (109), entre otros que son usados para abreviar magnitudes elevadas, existen también los mismos prefijos para definir grandes magnitudes en cifras binarias formadas por longitudes con base en 8 bits (1 byte). Es así que para el sistema binario:

1 kB (Se pronuncia un kilo byte) = 210 bytes o 1024 bytes

1 MB (Se pronuncia un mega byte) = 210 kB o 1024 kB

1 GB (Se pronuncia un giga byte) = 210 MB o 1024 MB

Gráfico 1.2. Ejemplo sobre los pesos de cada bit de una cifra binaria

Image

Elaboración propia.

Al igual que en el sistema de numeración binario, se emplean otros sistemas numéricos para representar cifras en otras bases. Uno de los más usados en la programación de sistemas embebidos es la base hexadecimal4. En ella cada cifra tiene un peso, dependiendo de una potencia en base 16. En este sistema existen 16 cifras diferentes (valores de 0 a 15) para representar una magnitud. Por ejemplo, para las cifras del 0 al 9 se utilizan los mismos dígitos que en el sistema decimal. Para completar los 6 dígitos restantes se utilizan letras del alfabeto, como el siguiente caso:

Image

En el número hexadecimal mostrado en el gráfico 1.3, cada cifra representa un nibble, dado que se tienen 16 posibles valores diferentes y esto equivale a una combinación de 4 bits (24 estados). Cada dígito representa una potencia de 16, según su posición en la cifra. En el ejemplo, el valor decimal equivalente del número hexadecimal mostrado es el siguiente:

valor = 163 × 10 + 162 × 3 + 162 × 4 + 160 × 12

De esta manera, el valor decimal equivalente es 40 960 + 768 + 64 + 12 = 41 804. Como se puede observar, esta cifra pudo haber sido representada en el sistema binario con el siguiente código: 10100011010011002, lo cual habría resultado en una cifra más larga, al estar conformada por 16 dígitos. En cambio, en el sistema hexadecimal se utilizan únicamente 4 dígitos para representar la misma cifra numérica, lo cual permite abreviar valores de magnitudes muy extensas.

El sistema de numeración hexadecimal es el preferido cuando se quiere representar magnitudes superiores a 28 y, al mismo tiempo, se desea mantener la visualización del código binario. Esto permite obtener una mejor comprensión del orden de la cifra sin perder de vista su forma a nivel binario (ya que es fácilmente visible el código binario a partir de cada nibble o dígito hexadecimal).

Gráfico 1.3. Ejemplo sobre los pesos de cada cifra hexadecimal

Image

Elaboración propia.

1.1.2 Conversiones entre bases

La base decimal es el formato más utilizado por los seres humanos para interpretar las cifras numéricas que operan diariamente para sus tareas cotidianas. Las personas comunes y corrientes han aprendido a realizar operaciones aritméticas en base a este sistema de numeración. Entonces, la pregunta que cae por su propio peso es la siguiente: «¿por qué el programador debe conocer otros sistemas de numeración, como el binario y el hexadecimal?» La respuesta a esta pregunta es obvia: porque al programar un sistema embebido no se debe pensar como seres humanos sino como un computador, y el sistema de numeración utilizado por estas máquinas es, por naturaleza, el binario.

Durante la programación de un sistema embebido no es necesario que el programador realice las conversiones de bases en el código ingresado. Para el software de programación de sistemas embebidos, el uso de una base u otra es indiferente. La conversión de una base es un proceso automáticamente efectuado por el compilador en el momento de generar el código de salida del programa. Sin embargo, el programador debe conocer las diferentes bases para poder interpretar las cifras mentalmente y así agilizar la implementación de su algoritmo. La base decimal es por excelencia la más sencilla de interpretar por cualquier ser humano. Por tal motivo, se toma como referencia en las conversiones de base.

Convertir una cifra de base binaria a decimal es bastante simple y ya se explicó en el subcapítulo 1.1.1. Solo basta con multiplicar cada dígito binario (‘0’ o ‘1’) por su correspondiente peso (base dos elevado a la posición del dígito) y sumar todos los dígitos resultantes. Por ejemplo, si se tiene la cifra binaria 101010102, la transformación a la base decimal se haría de la siguiente manera:

valor decimal = 27 × 1 + 26 × 0 + 25 × 1 + 24 × 0 + 23 × 1 + 22 × 0 + 21 × 1 + 20 × 0

De tal modo, el valor decimal equivalente obtenido es 128 + 32 + 8 + 2 = 170.

Para realizar la conversión de una cifra binaria a hexadecimal, el procedimiento también resulta sumamente sencillo. Si se toma como ejemplo el valor binario 0101110000112, primero se deberá separar la cifra en el número total de nibbles que lo componen. Para este caso son tres: 01012, 11002 y 00112. Cada nibble posee su equivalente en cifra hexadecimal. Por ejemplo, 01012 es 0x5, 11002 es 0xC (doce) y 00112 es 0x3. Por lo tanto, la cifra hexadecimal equivalente es 0x5C3.

El proceso de conversión de decimal a binario es ligeramente más complejo que en los casos anteriores. Consiste en realizar divisiones sucesivas entre 2 hasta lograr que el cociente final de la división sea 1. Si se desea convertir el valor decimal 17 a código binario, se deben realizar las siguientes operaciones sucesivas:

Image

La cifra binaria equivalente se forma al tomar el último cociente como bit MSB y los residuos restantes como los dígitos ordenados de izquierda a derecha. La cifra binaria, entonces, estará compuesta de 5 dígitos y será el valor 100012.

Si se repite el ejercicio con una cifra decimal par, se podrá notar que el bit LSB siempre será ‘0’, ya que la primera división entre 2 de un número par dará como residuo 0. El dígito MSB siempre será ’1’ para cualquier cifra. Por ejemplo, para convertir el número 18 a base decimal se tiene la siguiente operación:

Image

Como resultado se obtiene el código binario 100102, del cual se puede observar que el bit LSB es ‘0’.

La conversión de base hexadecimal a decimal es muy parecida a la de binario a decimal, con la diferencia de que cada elemento tiene asociada una potencia en base 16. Por ejemplo, se tiene un número hexadecimal cuyo valor es 0xFA28. Para convertirlo a su equivalente en base decimal, se debe observar que el número en base 16 estará compuesto por 4 cifras:

0xF = 15 (nibble más significativo),

0xA = 10,

0x2 = 2 y

0x8 = 8 (nibble menos significativo)

La cifra 0xF es la de mayor significancia (MS5), por lo cual le corresponde un peso de 163, mientras que la cifra 0x8 es la menos significativa (LS6) y, por lo tanto, le corresponde el menor peso, de 160. Posteriormente, se multiplica cada cifra por su respectiva potencia de 16 según el orden:

valor = 163 × 15 + 162 × 10 + 161 × 2 + 160 × 8

De esta manera, el valor decimal da como resultado 61 440 + 2560 + 32 + 8 = 64 040. Cada cifra es múltiplo de 16; sin embargo, es posible expresar cualquier magnitud entera en base hexadecimal.

Para pasar de una base decimal a hexadecimal el procedimiento también resulta ser similar al caso de la conversión decimal a binaria. La diferencia radica en que las divisiones sucesivas se realizan sobre un divisor de 16. Suponiendo que se tiene el número 39 481 en base decimal y se desea transformar a base hexadecimal, el procedimiento sería el siguiente:

Image

El resultado de la conversión de 39 481 a hexadecimal es, entonces, 0x9A39. La división sucesiva deberá detenerse cuando el último cociente obtenido sea un valor menor a 15 (0xF).

Un proceso mucho más sencillo y que no requiere de cálculos aritméticos es la conversión binaria a hexadecimal. Como ejemplo, se cuenta con el número binario 11100110110000102 y se desea transformar a base hexadecimal. El primer paso de este proceso es dividir el número binario en grupos de cuatro bits o nibbles. Si no se cuenta con un número de bits múltiplo de cuatro, se deberán agregar varios ‘0’ a la izquierda para completar los dígitos. Entonces, el número binario se divide de la siguiente manera:

 

Nibble MS:

11102 = 0xE

Segundo nibble:

01102 = 0x6

Tercer nibble:

11002 = 0xC

Nibble LS:

00102 = 0x2

Por tanto, la cifra hexadecimal equivalente es 0xE6C2.

La conversión hexadecimal a binario es un proceso muy similar al anterior. Simplemente se deberá tomar cada cifra del número hexadecimal, para convertirla al nibble correspondiente en código binario. Por ejemplo, se tiene el número hexadecimal 0xABCD2 y se desea convertirlo a binario. El procedimiento es como se muestra:

 

Nibble MS:

0xA = 10102

Segundo Nibble:

0xB = 10112

Tercer Nibble:

0xC = 11002

Cuarto Nibble:

0xD = 11012

Nibble LS:

0x2 = 00102

De esta manera, el resultado de la conversión es 101010111100110100102. Se puede observar que no es conveniente expresar una cifra de esta magnitud en base binaria, ya que resulta muy larga y difícil de interpretar. Durante la programación de sistemas embebidos, el programador es libre de utilizar cualquiera de las tres bases vistas (base binaria, decimal y hexadecimal). Sin embargo, muchos programadores optan por utilizar la combinación de las tres bases en sus programas, ya que, para ciertas circunstancias, algunas bases se adecúan mejor que otras. Por lo general, un programador opta por la base decimal cuando realiza operaciones matemáticas. La base hexadecimal se utiliza para manejar direcciones de memoria (que usualmente son magnitudes elevadas) o cargar códigos binarios a registros, y la base binaria suele ser utilizada para la asignación de estados a los puertos de entrada y salida (E/S) del sistema embebido.

Si bien es cierto que existen otras bases, como la octal (base 8), estas son poco utilizadas, debido a que no son versátiles y no resultan atractivas para la mayoría de programadores (al parecer, conocer tres bases numéricas ya es suficiente). No obstante, la mayoría de compiladores siguen aceptando este tipo de base.

1.1.3 Operaciones lógicas

En el mundo digital existen dos maneras de operar las cifras binarias (o en la base en que se interpreten, pues finalmente todo número es manejado de forma binaria en un sistema embebido). Cada cifra puede ser operada en modo aritmético o en modo lógico. El modo aritmético se presentará en el siguiente subcapítulo. A continuación se muestra el modo lógico.

El modo lógico se basa en las operaciones lógicas. Estas se obtienen mediante la manipulación de los patrones binarios en base a las reglas creadas por George Boole7 a mediados del siglo XIX, las cuales constituyen el álgebra de Boole. El álgebra de Boole opera sobre variables que pueden ser verdaderas o falsas. Las reglas de esta álgebra son actualmente utilizadas en las operaciones lógicas binarias en los sistemas digitales, ya que cada cifra binaria puede ser tratada como verdadero (nivel binario ‘1’) y falso (nivel binario ‘0’)8.

Las operaciones lógicas típicas más empleadas en los sistemas embebidos son las siguientes:

NOT

OR

AND

XOR

SWAP

SHIFT

Cabe señalar que las operaciones lógicas son fundamentales en la programación de sistemas embebidos, ya que permiten la implementación de una serie de operaciones vitales para el funcionamiento del programa. Por ejemplo, invertir el estado de un pin de entrada y salida de un sistema embebido, configurar un registro interno, realizar operaciones de conversión binario BCD o implementar el proceso de división, entre otras. Estos son ejemplos en los cuales se requiere hacer uso intensivo de las operaciones lógicas.

La operación lógica más simple de todas es la NOT (negación). Esta operación simplemente invierte un estado verdadero a falso y viceversa. En el caso binario, negar un bit significa cambiar su estado de ‘1’ a ‘0’ o de ‘0’ a ‘1’. Por ejemplo, se tiene una variable de nombre A que representa un bit. Por lo tanto, A puede tomar dos valores: ‘0’ o ‘1’. Si se niega el valor de A, entonces Ā (se denomina a esta variable ‘A negado’. En otras literaturas se considera A´ también como ‘A negado’) denota la negación. El símbolo para la compuerta lógica que realiza la negación se muestra en el gráfico 1.4, junto con su tabla de verdad.

Gráfico 1.4. a) Tabla de verdad de la operación lógica NOT. b) Símbolo de la compuerta NOT

Image

Elaboración propia.

También es posible realizar la operación lógica NOT sobre un conjunto de bits, que podrían ser un nibble o un byte. Si la variable A equivale al siguiente valor:

A = 101100112

Entonces:

Ā = 010011002

La operación lógica OR, también conocida como OR inclusiva (IOR), es otra de las operaciones básicas del álgebra de Boole. Su lógica es muy similar a la suma, excepto cuando ambos operandos son ‘1’9. En una operación OR deben existir al menos dos operandos, y basta que uno de ellos sea ‘1’ para que el resultado de la operación sea ‘1’. En el gráfico 1.5 se observa la tabla de verdad y el símbolo de la compuerta lógica OR.

La operación OR se realiza normalmente en conjuntos binarios. Por ejemplo, en el caso de que la variable A = 100000112 y la variable B = 000111112, el resultado de la operación OR sería el siguiente:

A OR B = A + B = 100000112 + 000111112 = 100111112

También es posible combinar las operaciones. Por ejemplo, se puede negar la operación OR entre A y B, lo cual se conoce como la operación NOR. Esto daría el siguiente resultado para los valores dados de A y B:

Image

Gráfico 1.5. a) Tabla de verdad de la operación lógica OR. b) Símbolo de la compuerta OR

Image

Elaboración propia.

En muchos sistemas embebidos, la operación NOR no forma parte del conjunto de instrucciones. Por lo cual, para su implementación, se deben ejecutar las operaciones OR y NOT de manera combinada.

La operación lógica AND toma dos variables binarias y realiza un proceso muy similar al de la multiplicación, sin tomar en cuenta el acarreo. En esta operación basta que uno de los operandos sea ‘0’ para que todo el resultado de la operación dé ‘0’. En el gráfico 1.6 se muestra la tabla de verdad y el símbolo de la compuerta lógica AND.

Gráfico 1.6. a) Tabla de verdad de la operación lógica AND. b) Símbolo de la compuerta AND

Image

Elaboración propia.

En el caso de que la variable A = 110011002 y la variable B = 010010112, el resultado de la operación AND será el siguiente:

A AND B = A.B = 110011002.010010112 = 010010002

En el resultado se puede observar que solo aquellos bits que poseen la cifra ‘1’ en la misma posición mantienen su valor ‘1’. El resto son ‘0’. También es posible agregar una tercera variable, de nombre C, a la operación. Si se tiene que C = 000011112, entonces la operación AND de las tres variables generará el siguiente resultado:

A AND B AND C = A.B.C = 110011002.010010112.000011112.000010002

También se puede combinar la operación lógica AND con la NOT para obtener un operador NAND. Este tipo de operación tampoco es muy común en el conjunto de instrucciones de sistemas embebidos con arquitectura tipo RISC10. Por ejemplo, la operación NAND de las variables A y B se muestra a continuación:

Image

Hasta el momento se han analizado las tres operaciones lógicas fundamentales. Si se combinan estos tres operadores, se logrará obtener una nueva operación lógica que se encuentra disponible en la arquitectura de la gran mayoría de sistemas embebidos: el operador XOR (OR exclusivo). Este operador genera un resultado verdadero solo si una de las entradas es verdadera y la otra es falsa. Pero si ambas entradas a la operación XOR son iguales, el resultado será falso.

Si A y B son dos variables binarias, entonces la operación XOR se denota de la siguiente manera:

A XOR B = A ⊕ B = A.B + Ā.B

En el gráfico 1.7 se muestra la tabla de verdad de la operación lógica XOR y el símbolo de su compuerta.

La operación XOR es muy utilizada para verificar si dos números son iguales. Por ejemplo, la variable A = 100011102 y la variable B = 100011102. Ambas variables tienen asignados el mismo código binario. Entonces, la operación XOR dará el siguiente resultado:

A ⊕ B = 100011102 ⊕ 100011102 = 000000002

Gráfico 1.7. a) Tabla de verdad de la operación lógica AND. b) Símbolo de la compuerta XOR

Image

Elaboración propia.

Como se puede observar, al ser todos los bits iguales en cada posición, el resultado de la operación XOR da 000000002. Este resultado será el mismo cada vez que los operandos sean iguales. Si, en cambio, se alterase un bit de la variable B y su nuevo valor fuera B = 100111102, entonces el resultado de la operación XOR sería el siguiente:

A ⊕ B = 100011102 ⊕ 100111102 = 000100002

El valor obtenido es diferente de 000000002, lo cual será siempre así si es que ambos operandos no son iguales.

La operación SWAP no posee un símbolo lógico. Si bien es cierto, no es una operación lógica propiamente dicha sino el resultado de la combinación de operaciones básicas, muchos sistemas embebidos utilizan una instrucción de nombre swap para alterar el contenido de un byte de información.

En la operación swap, los nibbles de un byte son intercambiados de posición. Con una variable A = 110001012, se observa que el nibble más significativo es 11002, mientras que el nibble menos significativo es 01012. Si se realiza la operación swap sobre A, el nuevo resultado será A = 010111002. Como se puede constatar, simplemente se han intercambiado de posición los nibbles del byte.

Otra de las operaciones clásicas realizadas por todo sistema embebido es la operación shift o de desplazamiento binario. En una cifra binaria, cada bit posee una posición. Con el operador shift es posible realizar un cambio de posición de cada bit, ya sea para la derecha o para la izquierda.

Nuevamente, la operación shift no es una compuerta, sino un conjunto de operaciones que involucran el movimiento de los bits en un registro. Esta operación está incluida en el conjunto de instrucciones de todo sistema embebido y resulta muy útil para una gama de aplicaciones en las cuales se requiere multiplicar, dividir o convertir de binario a BCD, entre otras.

En la operación shift se utilizan los símbolos >> o <<, para denotar un corrimiento binario hacia la derecha o hacia la izquierda, respectivamente. Por ejemplo, si se tiene que la variable A = 100110002, entonces, al realizar la operación A>>3, los bits de la variable A se desplazarán tres posiciones a la derecha, quedando de la siguiente manera: A = 000100112. Al realizar esta operación han aparecido tres bits de valor cero (b’000’) al lado izquierdo del bit que solía ser el MSB de la cifra. Estas tres posiciones en realidad son reemplazadas por bits fuera de las ocho posiciones del byte. Por defecto, cuando se realiza el corrimiento, estos nuevos valores son siempre ceros.

Ahora, en el caso de que la variable A = 000100112 sufre un corrimiento a la izquierda con la siguiente operación: A<<4, el resultado quedaría de la siguiente forma: A = 00110002. En este caso se puede observar que uno de los bits ‘1’ de la variable A ha desaparecido (el bit en la posición 4). Esto en realidad no ha ocurrido, sino que este bit ha tomado la posición 8 o se ha convertido en el noveno bit, el cual no se muestra, ya que el valor a tratar es un byte y solo tiene 8 posiciones (la novena posición, verdaderamente, solo estará en la mente del programador).

1.1.4 Operaciones aritméticas

Otra de las formas que existen para manipular los números binarios a nivel digital es a través de operaciones aritméticas. Las operaciones aritméticas típicas que involucran a los sistemas embebidos de mediano rango son las siguientes:

Suma

Resta

Multiplicación

Las reglas de la aritmética que se conocen para el sistema decimal son muy similares al sistema binario. La diferencia es que el sistema binario es más simple y las reglas que hay que aprender para efectuar una suma, por ejemplo, son más sencillas que en el caso de la base decimal. En general, para llevar a cabo una sumatoria en el sistema binario se deben tener en cuenta únicamente tres reglas:

Image

El acarreo es una parte fundamental en la suma. Por ejemplo, en la suma decimal es común que se produzca un acarreo cuando la sumatoria supera el valor de nueve. Se empieza sumando las cifras menos significativas y se termina cuando la última suma involucra a las dos cifras más significativas de los operandos (o a solo uno de ellas). Si se analiza la siguiente suma decimal: 137 + 26, sucederá lo siguiente:

 

1. 7 + 6

= 3 (acarreo1 = 1)

2. (acarreo1) + 3 + 2

= 6 (acarreo2 = 0)

3. (acarreo2) + 1

= 1

Resultado = 163

En general, para la base decimal el acarreo es un número entre 0 y 1. Para el caso de la base binaria, el acarreo también será una cifra entre 02 y 12, ya que la suma de dos dígitos binarios solo puede dar ‘0’, ‘1’ o 102. En el caso de que se quiera realizar la suma de los siguientes dígitos binarios: 011011002 y 100110102, primero, se comienza sumando las cifras menos significativas, de la siguiente manera:

1. ‘0’ + ‘0’ = ‘0’ (acarreo1 = ‘0’)

2. (acarreo1) + ‘0’ + ‘1’ = ‘1’ (acarreo2 = ‘0’)

3. (acarreo2) + ‘1’ + ‘0’ = ‘1’ (acarreo3 = ‘0’)

4. (acarreo3) + ‘1’ + ‘1’ = ‘0’ (acarreo4 = ‘1’)

5. (acarreo4) + ‘0’ + ‘1’ = ‘0’ (acarreo5 = ‘1’)

6. (acarreo5) + ‘1’ + ‘0’ = ‘0’ (acarreo6 = ‘1’)

7. (acarreo6) + ‘1’ + ‘0’ = ‘0’ (acarreo7 = ‘1’)

8. (acarreo7) + ‘0’ + ‘1’ = 102

Resultado = 1000001102

Como se puede observar, el resultado posee un bit más (9 bits en total) que los dos operandos. Esto se debe al acarreo que se ha ido arrastrando desde la cuarta operación. En el ejemplo anterior, el primer operando 011011002 representa la cifra decimal 108, y el segundo operando 100110102 representa la cifra decimal 154. El resultado es 1000001102, cuyo valor decimal es 262, y corresponde a la suma de 108 + 154.

Uno de los formatos utilizados por los sistemas embebidos para poder operar números positivos y negativos es el complemento a 2. Las cifras binarias pueden interpretarse de dos formas: positivas o negativas. Por ejemplo, la cifra 100100112 puede interpretarse de dos maneras: como 147 en base decimal o –109 (complemento a 2).

En el formato complemento a 2, una cifra se puede interpretar como positiva o negativa. En este formato, el bit MSB representa el signo. Si este bit es ‘1’, entonces el número tendrá una representación negativa. Para obtener el valor negativo de una determinada magnitud en código binario, se debe obtener su complemento a 2. Esto se logra realizando los siguientes pasos:

1. Escribir la cifra binaria.

2. Realizar la operación NOT sobre toda la cifra.

3. Sumar el bit 12 a la cifra negada.

4. Si la cifra inicial representa una magnitud positiva, el resultado será la representación negativa en complemento a 2. Si la cifra inicial es una magnitud negativa, el resultado será la representación positiva en complemento a 2.

De esta manera, para determinar el valor representado por la cifra 100100112 en complemento a 2, el primer paso consiste en invertirla y transformarla en el siguiente valor negado: 011011002. La siguiente fase consiste en sumar el bit ‘1’, con lo cual cambia al siguiente estado: 0110110122