Está en la página 1de 258

Machine Translated by Google

CAPITULO 2

La programación en C
Idioma
C
C. El lenguaje que a todos nos encanta odiar. Hemos visto C++, Java, C#, Go, Python
y muchos otros lenguajes ir y venir. Sin embargo, C permanece. C fue, es y será. El
ensamblador solía ser el lenguaje elegido para programar microcontroladores de 8
bits. Sin embargo, los microcontroladores PIC® más nuevos tienen una arquitectura

optimizada para C y mucha memoria. El ensamblaje tiene su lugar y, a veces, todavía


se necesita para optimizar el código. Los programas en C suelen ocupar más espacio
de código que uno equivalente en ensamblador. En este libro, hago un esfuerzo por
mantener los principios de KISS; por lo tanto, usamos la solución más simple, que es
C. Así que veamos algunos C básicos.
Este capítulo se puede omitir si usted es un gurú de la programación C, sin
embargo, para cualquier otra persona, es mejor que lea este capítulo.

Programación en C
El lenguaje de programación C fue diseñado en un momento en que el poder de
cómputo era una fracción de lo que es hoy. Olvídese de los gigabytes de memoria,
había kilobytes. Olvídese de los gigahercios de velocidad informática, aquí estamos
hablando de megahercios. Suena familiar, ¿no? kilobytes de

15
© Armstrong Subero
2018 A. Subero, Programación de microcontroladores
PIC con XC8, https://doi.org/10.1007/978-1-4842-3273-6_2
Machine Translated by Google

CAPÍTULO 2 EL LENGUAJE DE PROGRAMACIÓN C

memoria y una velocidad medida en megahercios. De hecho, suena como un


microcontrolador PIC®, ¿no es así? Esa es esencialmente la razón por la cual C
es ideal para programar microcontroladores.

Estructura del programa C

Los programas en C tienen una estructura que deben seguir. El listado 2-1 es
un programa C típico.

Listado 2-1. Programa típico de C

/* Este es un comentario que normalmente contiene información como el nombre del


autor, fecha y nombre del programa y detalles */

// Aquí es donde se incluyen los archivos y se llevan a cabo las directivas del
preprocesador

#include <stdio.h> // Este es un ejemplo de un archivo de encabezado

// Esta es la función principal, todos los programas en C tienen una función


principal y

// Aquí es donde comienza la ejecución del programa

int principal (vacío)


{ // paréntesis de apertura muy importante
printf("¡Hola mundo!"); // se ejecuta algún código

devolver 0; // no se ejecuta ningún código después de una declaración de retorno

} // cerrar paréntesis

Como puede ver, el programa C típico tiene un bloque de comentarios, archivos


de inclusión y una función principal. A medida que examinemos otros programas,
notará que se mantiene esta plantilla.

dieciséis
Machine Translated by Google

CAPÍTULO 2 EL LENGUAJE DE PROGRAMACIÓN C

Comentarios

Los comentarios se utilizan en su programa para describir líneas de código. Los


comentarios son muy útiles porque te ayudan a recordar lo que hace tu código.
Los comentarios se pueden usar según sea necesario, ya que el compilador
los ignora por completo. El lenguaje C usa comentarios que se pueden escribir
usando barras diagonales y asteriscos (vea el Listado 2-2).

Listado 2-2. Comentarios usando barras diagonales y asteriscos

/* Esto es un comentario
eso puede ser usado

para abarcar varias líneas */

Los comentarios también se pueden escribir con dos barras diagonales y estos

ocupa una línea (vea el Listado 2-3).

Listado 2-3. Comentarios usando dos barras diagonales

// Este comentario ocupa una linea

Variables y constantes

Una variable en C es un nombre que se usa para referirse a alguna ubicación


en la memoria y permite al programador asignar un valor a esa ubicación. Las
variables se pueden cambiar durante la ejecución de un programa a menos que
se declaren explícitamente como constantes. Las variables deben declararse antes
de que se usen en un programa (vea el Listado 2-4).

Listado 2-4. Declaración de una variable

// Esta es una variable declarada


int A;

17
Machine Translated by Google

CAPÍTULO 2 EL LENGUAJE DE PROGRAMACIÓN C

Después de ser declarada, una variable se puede inicializar, es decir, se le


puede asignar un valor inicial (ver Listado 2-5).

Listado 2-5. Inicializar una variable

// Esta es una variable que tiene un valor asignado


A = 10;

Las variables también se pueden declarar e inicializar al mismo tiempo

(vea el Listado 2-6).

Listado 2-6. Declaración e inicialización de una variable

// Esta es una variable que se declara e inicializa al mismo tiempo.

int A = 10;

En el lenguaje C, las variables pueden ser de diferentes tipos. Por ejemplo,


las variables que se usan para almacenar letras son diferentes de las que se usan para almacenar

números. La tabla 2-1 muestra algunos de los tipos de variables comunes


disponibles en el lenguaje C.

18
Machine Translated by Google

CAPÍTULO 2 EL LENGUAJE DE PROGRAMACIÓN C

Tabla 2-1. Variables comunes

Variable Definición Ejemplo

carbonizarse Este tipo de variable se utiliza para 1 carácter A = 'A'

almacenar caracteres individuales.

En t Este tipo de variable almacena números enteros. 1 entero A = 1;

flotador Un flotador se utiliza para almacenar decimal 1 flotador A =

números y por lo general tiene hasta 6.1234567890...23

23 *cifras significativas.

doble Estos se utilizan para almacenar decimales 1 doble A =

números y normalmente tienen hasta 01234567890123456789...52

52 *cifras significativas.

Constantes Las constantes se pueden considerar 1 const int A = 10;

como variables especiales cuyo

valor no se puede cambiar. Las

constantes se declaran usando la palabra clave const.

Matrices, punteros y estructuras


arreglos

En C, una matriz es un tipo de estructura de datos que puede almacenar varios elementos,

conocidos como elementos, de la misma matriz. Los arreglos son muy útiles en C y

programación integrada. El uso de un arreglo es fundamental cuando se trabaja con PIC®

microcontroladores Una matriz se puede declarar con o sin un tamaño específico.

Ejemplo:

temperaturas int[5] = {29, 25, 26, 25, 28};

La misma secuencia se puede escribir de la siguiente manera:

temperaturas int[] = {29, 25, 26, 25, 28};

19
Machine Translated by Google

CAPÍTULO 2 EL LENGUAJE DE PROGRAMACIÓN C

Se accede a los elementos de una matriz con el primer elemento que tiene un
índice de 0. A estos elementos se accede de la siguiente manera:

int lunes = temperatura[0]; // el lunes tendrá valor 29

También puede asignar un valor a un solo elemento de una matriz usando lo


siguiente:

temperaturas[2] = 27; // el elemento 2 ahora tiene el valor de 27

Punteros

el puntero Mucha gente tiene dificultad para comprender la proposición simple.


Los punteros son poderosos. Aunque en este libro utilizo punteros con moderación,
son uno de los conceptos de C más importantes.
La mayoría de la gente está confundida en cuanto a lo que es un puntero y su propósito.

Un puntero es solo otra variable. Piense en punteros como int, char o float.
Sabemos que un int almacena números, char almacena caracteres individuales
y float almacena números decimales. Sin embargo, no dejes que el asterisco y
el ampersand te asusten.
Un puntero es simplemente una variable que almacena la dirección de
memoria de otra variable. Es bastante simple de entender. El listado 2-7 muestra
un ejemplo de cómo declarar un puntero y una asignación común.

Listado 2-7. Declarar un puntero

// una declaración entera


numero int;

// un puntero a un entero
int *numero_puntero;

// el puntero ahora tiene la dirección de memoria del entero 'num'


puntero_numero = &num;

20
Machine Translated by Google

CAPÍTULO 2 EL LENGUAJE DE PROGRAMACIÓN C

¿Ves lo simples que son los punteros para usar? Si aún tiene
dificultades para entenderlos, investigue un poco más. Hay libros enteros
dedicados al uso de punteros.

Estructuras

Puede arreglárselas con la programación C más simple simplemente usando matrices.


Sin embargo, cuando desee almacenar varios tipos de datos, debe utilizar un
estructura.

La palabra clave struct se utiliza para declarar estructuras. El listado 2-8


muestra cómo declarar una estructura.

Listado 2-8. Declaración de una estructura

Velocidad de estructura{

byte lento;
byte normal;
byte rápido;
};

Para usar una estructura, declara un tipo de estructura (vea el Listado 2-9).

Listado 2-9. Declaración de un tipo de estructura

// Declarar MotorSpeed de tipo velocidad


estructura Velocidad Velocidad del motor;

Luego accede a un miembro de una estructura con un punto (.) como el miembro
operador de acceso de la siguiente manera:

MotorSpeed.slow = 10;

Las estructuras son muy útiles cuando se programan microcontroladores.

21
Machine Translated by Google

CAPÍTULO 2 EL LENGUAJE DE PROGRAMACIÓN C

Operadores

Las matemáticas y la lógica son lo que prospera en una CPU.


En C, hay muchos símbolos que permiten que el microcontrolador
realice funciones lógicas y matemáticas. Los repaso brevemente en
los Listados 2-10 al Listado 2-12.

Listado 2-10. Ejemplos de operadores aritméticos

// La operación de suma agrega operandos


X+Y;

// La operación de resta resta operandos


X-Y;

// Multiplicación múltiplos de operandos


X * Y;

// La división divide operandos


X/Y;

// Módulo encuentra el resto después de la división


X % Y;

// Incremento aumenta el valor en uno


X++;

// Decremento disminuye el valor en uno


Y--;

Listado 2-11. Ejemplos de operadores relacionales

// Comprueba la igualdad
X == Y;

22
Machine Translated by Google

CAPÍTULO 2 EL LENGUAJE DE PROGRAMACIÓN C

// Comprueba que los valores no son


iguales X != Y;

// Determina si el primer operando es mayor que el segundo


X > Y;

// Determina si el primer operando es menor que el segundo


X <Y;

// Comprueba si el operando de la izquierda es mayor o igual que el de la


derecha
X >= Y;

// Las comprobaciones del operando de la izquierda son menores o iguales


que el de la derecha
X <= Y;

Listado 2-12. Ejemplos de operadores lógicos

// Operador lógico Y
X && Y;

// Operador OR lógico
X || Y;

// Operador lógico NOT !(X)

Control del flujo del programa


si declaración

La sentencia if se usa para tomar decisiones dentro de un


programa (vea el Listado 2-13).

23
Machine Translated by Google

CAPÍTULO 2 EL LENGUAJE DE PROGRAMACIÓN C

Listado 2-13. Ejemplo de una sentencia if

if (velocidad ==
200) { turnLightOn(); }

otra declaración

La sentencia else le permite al programador realizar otra acción y es un


complemento de la sentencia if (vea el Listado 2-14).

Listado 2-14. Ejemplo de declaración else

if(velocidad ==
200)
{ enciendeLuz(); }

demás

{ mantenerLuzApagada(); }

otra cosa si Declaración

A veces necesitamos probar más de dos condiciones del programa y


ahí es cuando usamos una sentencia else if (vea el Listado 2-15).

Listado 2-15. Ejemplo de una sentencia else if

if(velocidad ==
200)
{ enciendeLuzRoja(); }

24
Machine Translated by Google

CAPÍTULO 2 EL LENGUAJE DE PROGRAMACIÓN C

else if (velocidad == 150)


{ enciendeLuzAmarillo(); }

demás

declaración de cambio

La sentencia switch se usa cuando necesitamos comparar una variable con diferentes
valores (vea el Listado 2-16). Se utiliza en situaciones en las que se habrían utilizado
demasiadas declaraciones if y else if. Debes recordar

incluir declaraciones de ruptura dentro de los casos; de lo contrario, el flujo caería a

los casos subsiguientes hasta una declaración de interrupción. El caso predeterminado


se usa cuando ninguno de los otros casos es verdadero.

Listado 2-16. Ejemplo de una declaración de cambio

cambiar (velocidad)
{
caso 100:

bipUnaVez();
descanso;

caso 150:

bipDosVeces();
descanso;

caso 200:

caso 250:

apagarMotor();
descanso;

25
Machine Translated by Google

CAPÍTULO 2 EL LENGUAJE DE PROGRAMACIÓN C

descanso:

mantener el motor en marcha

(); }

en bucle

El ciclo for se usa cuando necesita ejecutar una secuencia de sentencias varias
veces (vea el Listado 2-17).

Listado 2-17. Ejemplo de un bucle for

for(int x = 0; x<= 10; x++)


{ spi_send(0x01);

retraso_ms(1000); }

mientras bucle

El ciclo while repite un grupo de sentencias mientras la condición


especificada sea verdadera (vea el Listado 2-18). Los bucles while son muy
importantes en los sistemas integrados y normalmente se utilizan para crear un
bucle infinito, ya que normalmente no hay un sistema operativo para mantener
el programa en ejecución. Todos los programas de este libro utilizan un ciclo while infinito.

Listado 2-18. Ejemplo de un ciclo while

while(1)

{ leerSensor();
verificarbateria();
actualizarPantalla(); }

26
Machine Translated by Google

CAPÍTULO 2 EL LENGUAJE DE PROGRAMACIÓN C

hacer bucle

El bucle do funciona igual que el bucle while, excepto que comprueba las
condiciones del bucle después de la ejecución y se ejecutará al menos una vez.
Consulte el Listado 2-19.

Listado 2-19. Ejemplo de bucle do

hacer { temp = leerTemperatura(); }


mientras (temperatura < 40);

declaración de ruptura

La sentencia break se usa para terminar un bucle y, cuando se usa, se ejecuta


la sentencia que sigue inmediatamente al bucle (vea el Listado 2-20).

Listado 2-20. Ejemplo de una declaración de ruptura

si (temperatura > 35)


{ descanso; }

continuar declaración

La instrucción continuar hace que se salte el resto de la iteración actual del ciclo
(vea el Listado 2-21).

Listado 2-21. Ejemplo de una declaración de continuación

para (i = 0; i < 1023; i++) { si (i >


100 && i < 400)

27
Machine Translated by Google

CAPÍTULO 2 EL LENGUAJE DE PROGRAMACIÓN C

{
Seguir;
}

spi_send(0x02);
}

ir a Declaración
La sentencia goto es vista con vergüenza. Sin embargo, hay casos
en los que un salto incondicional es útil. Aunque usando el goto
declaración a menudo conduce a un código de espagueti, es útil comprender
cómo funciona.
La declaración goto simplemente transfiere el flujo del programa a un
punto en el programa que tiene una etiqueta (vea el Listado 2-22). La única
vez que puede ser necesario usar un bucle goto es cuando hay bucles for
profundamente anidados o sentencias if.

Listado 2-22. Ejemplo de una instrucción goto

miEtiqueta:
encenderAlgo();

ir a miEtiqueta;

Directivas del pre procesador


Antes de discutir las directivas del preprocesador, tomemos un tiempo
para pensar un poco sobre los IDE y los compiladores. El IDE (Entorno
de desarrollo integrado) es básicamente un programa como su editor de
texto, navegador o videojuego. La diferencia es que el programa IDE tiene un propósito especial.
Contiene todo lo que necesita para desarrollar el programa que se
ejecutará en su microcontrolador. Eso significa que consta de varias partes, como un

28
Machine Translated by Google

CAPÍTULO 2 EL LENGUAJE DE PROGRAMACIÓN C

editor de código donde escribes tu código, un depurador que te ayuda a buscar errores

en tu código y muchas otras cosas que simplifican todo el proceso de desarrollo.

Una de esas partes en el IDE es el compilador. Un compilador convierte tu código

(en este caso escrito en C) en instrucciones que el microcontrolador entenderá. Cuando se

compila este código, se convierte en algo llamado archivo de objeto. Después de este paso,

básicamente un componente llamado enlazador toma estos archivos de objetos y los

convierte en el archivo final que será ejecutado por su microcontrolador. Puede haber otros

pasos en este proceso de generar el archivo hexadecimal final (programa que se escribirá en

el microcontrolador), pero esto es todo lo que necesita saber.

Ahora podemos entender qué es una directiva de preprocesador. los

El preprocesador es otra parte del IDE que usa directivas, lo que hace que el programa C

se edite antes de la compilación.

Estas directivas de preprocesador comienzan con un símbolo de etiqueta hash. En

XC8, encontrará muchas directivas de preprocesador, especialmente con bibliotecas

diseñadas para apuntar a más de un chip.

#definir
La directiva #define es la primera que veremos. La instrucción #define en

C define macros. Esta declaración se usa mucho en la programación integrada y es muy útil.

En lugar de tener que seguir escribiendo alguna constante, es más fácil usar la directiva
#define. Esto también es útil en casos en los que

Es posible que sea necesario cambiar las constantes.

Por ejemplo, si estamos escribiendo un controlador para una pantalla LCD que viene en dos

variantes compatibles (128x64 y 128x32) entonces, en lugar de tener que escribir

constantemente esos números, ya que las dimensiones de la pantalla LCD seguirían siendo

las mismas, es más fácil escribirlo como se muestra en el Listado 2-23.

29
Machine Translated by Google

CAPÍTULO 2 EL LENGUAJE DE PROGRAMACIÓN C

Listado 2-23. Definir macros usando #define

#define LCD_HEIGHT 128


#define LCD_WIDTH 64

Sin embargo, una pequeña advertencia: recuerde omitir el punto y coma


después de la macro, ya que generará errores de compilación. Otro uso importante
de la directiva #define es en la creación de macros similares a funciones. Estos son
macros que se pueden usar para crear una pequeña "función" y son útiles para el

creación de pequeñas funciones que pueden aparecer muchas veces en su código.


Consulte el Listado 2-24.

Listado 2-24. Ejemplo de instrucción #define

#define MAX(x, y) ((X) > (Y) ? (X) : (Y))

El uso más importante de tales funciones que he encontrado en la práctica es


que no requieren un tipo específico y pueden usar cualquier tipo genérico. En el
ejemplo del Listado 2-24, no importa si los parámetros son int, float o double, igual
se devolvería el máximo. Aprender a usar la directiva #define ya que es muy
importante. A veces puede ver que esto se conoce como una función lambda.

#if, #ifdef, #ifndef, #elif y #else


Estas directivas de preprocesador se utilizan para la compilación condicional en el
programa. Estas directivas son importantes. Estas directivas se usan comúnmente
para depurar y desarrollar bibliotecas que apuntan a múltiples chips.
Son sencillos. El Listado 2-25 muestra cómo se usan las directivas.

Listado 2-25. Ejemplos de directivas de preprocesador en uso


#ifdefFOTO16F1717
#define VELOCIDAD 200

#elif definido (__PIC24F__)

30
Machine Translated by Google

CAPÍTULO 2 EL LENGUAJE DE PROGRAMACIÓN C

#define VELOCIDAD 300


#demás

#define VELOCIDAD 100

#terminara si

Tenga en cuenta que las directivas condicionales deben terminar con un #endif

declaración.

#pragma
Esta es una directiva de C que en la programación de propósito general se usa para

directivas específicas de máquinas o sistemas operativos. Esta directiva se encuentra

más comúnmente para establecer los bits de configuración del PIC®

microcontrolador (ver Listado 2-26).

Listado 2-26. Ejemplo de #pragma

#pragma config PLLDIV = 2

Ensamblaje contra C

Hay personas que piensan que Assembly es mejor para el diseño de microcontroladores

de 8 bits. Este puede haber sido el caso hace varios años, pero ahora que los

microcontroladores tienen una arquitectura C optimizada, la necesidad de tener ensamblado

escrito a mano es menos importante ahora que antes. El único caso en el que puede usar

Assembly es si necesita generar código eficiente en la versión gratuita del compilador XC8,

tiene un chip en un diseño heredado que solo puede usar Assembly o, por supuesto, desea

aprender la arquitectura de el microcontrolador en un nivel más profundo. Sin embargo, en

este libro omito el uso de Asamblea.

31
Machine Translated by Google

CAPÍTULO 2 EL LENGUAJE DE PROGRAMACIÓN C

Conclusión
Este capítulo contiene una descripción general básica del lenguaje de programación C.
Con solo los conceptos presentados aquí, puede hacer mucho, ya que cubrimos
las palabras clave más importantes para nuestros propósitos. Sin embargo, el
simple hecho de conocer las palabras clave de un idioma no ayuda a dominarlo.
Se necesita práctica. Si no domina el lenguaje C, lo animo a buscar libros y
recursos de Internet para ayudarlo en su viaje con el lenguaje de programación C.
Si eres completamente nuevo en la programación en general, te recomiendo que
aprendas los conceptos básicos. El libro que personalmente recomiendo es
Beginning C, 5th Edition de Ivor Horton, disponible en Apress®. También hay
muchos recursos gratuitos en la web que enseñan conceptos completos de
programación para principiantes.

32
Machine Translated by Google

CAPÍTULO 3

Electrónica Básica
para Embebidos
Sistemas
Electrónica
La diferencia entre los diseñadores de sistemas integrados y los ingenieros
de software o técnicos de TI es el conocimiento profundo del hardware que poseen
los diseñadores integrados. Los diseñadores integrados deben tener conocimientos
de electrónica para diseñar sistemas integrados de manera eficaz. Debemos recordar,
por encima de todo, que las computadoras son simplemente dispositivos electrónicos
complejos y los microcontroladores son simplemente computadoras en miniatura.
Las resistencias, los capacitores, los diodos y los transistores son algunos de los
componentes básicos del hardware de la computadora. Para comprender estos
dispositivos más complejos, es importante comprender los componentes electrónicos
básicos a partir de los cuales se construyen estos dispositivos.

resistencias
Una resistencia se usa en electrónica para imponer resistencia en los circuitos. Las
resistencias se clasifican por la cantidad de ohmios, que es esencialmente una
medida de la cantidad de resistencia que proporcionan.

33
© Armstrong Subero
2018 A. Subero, Programación de microcontroladores
PIC con XC8, https://doi.org/10.1007/978-1-4842-3273-6_3
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Los resistores se utilizan para reducir el flujo de corriente en un circuito y para reducir

el voltaje. También se utilizan para dividir voltajes y extraer líneas de E/S.


Los resistores vienen en una variedad de paquetes, incluido un paquete axial, un
paquete radial, un paquete de montaje en superficie y un tipo de paquete único en línea
(SIL) llamado conjunto de resistencias. Las resistencias son componentes pasivos y son
uno de los tipos de dispositivos más simples que encontrará.
Las resistencias tienen clasificaciones de vataje que no se deben exceder. Típicamente,
las clasificaciones van desde 1/8 watt a 2 watts. Las resistencias de 1/4 de vatio
son las más comunes utilizadas en el diseño de sistemas integrados. La variedad de
montaje en superficie que se encuentra comúnmente suele tener una clasificación de 1/16 y 1/10 vatios.
Sin embargo, es mejor consultar la hoja de datos de la resistencia que está planeando.
usar.

Una hoja de datos es un documento que le informa un poco sobre la técnica


especificaciones de un producto. Por ejemplo, la hoja de datos de una resistencia

incluye características eléctricas como la tolerancia y la curva de funcionamiento, así


como las dimensiones de la pieza. Esta información es muy útil cuando está diseñando
una placa de circuito impreso o PCB. Para el microcontrolador, una hoja de datos
incluye el diagrama de bloques (como verá en un capítulo posterior), así como mucha
otra información útil. Las hojas de datos son tus amigos y siempre debes tenerlas a
mano. Puede obtener las hojas de datos del sitio web del fabricante. Algunos proveedores
de componentes, como Digi-Key y Mouser, también enumeran las hojas de datos en sus
páginas de productos.
La resistencia se mide en ohmios, como se muestra en la Figura 3-1.

Figura 3-1. símbolo de ohmios

34
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

La mayoría de las resistencias tienen cuatro bandas. Las dos primeras bandas son las más

dígitos significantes. La tercera banda te dice la potencia de 10 por la que tienes que multiplicar

y la banda final es la tolerancia de la resistencia. Por lo general, la tolerancia se puede ignorar;

sin embargo, para algunas aplicaciones, la tolerancia debe estar dentro de un rango muy

estrecho.

Las resistencias de montaje en superficie suelen utilizar las marcas de tipo E24 o

E96. El E24 tiene tres números. Los primeros dos números son los dígitos significativos y

el tercero es el índice de base 10 para multiplicar. Por ejemplo, una resistencia marcada con

104 sería 10x10ˆ4, que son 100 kiloohmios.

La Figura 3-2 muestra el símbolo esquemático de la resistencia y la Figura 3-3 muestra una
resistencia real.

Figura 3-2. Símbolo esquemático de resistencia

Figura 3-3. Resistor

35
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Potenciómetro
Un potenciómetro es un componente electrónico utilizado para variar la
cantidad de resistencia en un circuito. El potenciómetro también se conoce
como "pot" y contiene tres terminales. Una olla no es más que un divisor de
voltaje que el usuario puede ajustar. Un reóstato es otro dispositivo que puede
encontrar, y es simplemente una resistencia ajustable. El joystick de dos ejes
que se encuentra comúnmente en los controladores de juegos y los botones
de ajuste de volumen son aplicaciones comunes de los potenciómetros en el
mundo real. La Figura 3-4 muestra el símbolo esquemático del potenciómetro y la Figura 3-5 muestra un

Figura 3-4. Símbolo esquemático del potenciómetro

Figura 3-5. Potenciómetro

36
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Potenciómetro digital
Un potenciómetro digital o digipot es una versión digital de un potenciómetro.
Electrónicamente hablando, realiza las mismas funciones que un potenciómetro.
La ventaja del digipot es que los microcontroladores pueden ajustar su
resistencia utilizando algún protocolo de interfaz digital, como SPI o I2C,
mediante software.

Dado que se pueden controlar mediante software a diferencia de sus


contrapartes mecánicas, es posible ajustar el valor de formas distintas a la
lineal (normalmente de forma logarítmica). Esto le da a los potenciómetros
digitales aplicaciones adicionales, como el escalado y el recorte de señales
analógicas. El digipot tiene una apariencia diferente a la de un potenciómetro
normal y están empaquetados para parecerse a cualquier otro IC. El potenciómetro
digital MCP 4131 que usaremos en nuestros proyectos se muestra en la Figura
3-6. La figura 3-7 muestra el símbolo esquemático del potenciómetro digital.

Figura 3-6. PCM 4131

37
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

PCM 4131

CS VDD
SCK POB
IDE prisionero de guerra

POA de VSS

Figura 3-7. Símbolo esquemático de Digipot

fotorresistencia
Una fotorresistencia, también conocida como resistencia dependiente
de la luz (LDR) o fotocélula, es un tipo de resistencia en la que la resistencia
cambia con la intensidad de la luz. La Figura 3-8 muestra el símbolo
esquemático del fotorresistor y la Figura 3-9 muestra un fotorresistor real.

Figura 3-8. Símbolo esquemático de fotorresistencia

38
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Figura 3-9. fotorresistencia

Condensador
Los capacitores se utilizan para almacenar energía eléctrica en un circuito
electrónico (vea la figura 3-12). Los condensadores vienen en paquetes axiales, radiales y SMT.
Consisten en dos placas de metal separadas por un aislante, llamado
dieléctrico. Este material dieléctrico está hecho de muchos materiales, incluidos
papel, cerámica, plástico e incluso aire. La capacitancia se mide en faradios (F),
aunque los microfaradios y picofaradios son las unidades de medida más utilizadas
en el uso diario.
El tipo de dieléctrico influye en las propiedades del condensador y
determina si el condensador está polarizado o no polarizado. Figura 3-10
muestra los símbolos esquemáticos del gorro polarizado y la Figura 3-11 muestra
los símbolos esquemáticos del gorro no polarizado.
El condensador más comúnmente encontrado es el condensador
electrolítico. Esto se debe a que almacenan una capacitancia relativamente grande
en relación con su tamaño. Están polarizados y se debe tener cuidado de no
conectarlos al revés. Vienen en dos variedades: tantalio y aluminio.
Los capacitores de aluminio son fácilmente reconocibles ya que generalmente
vienen en latas cilíndricas. Los capacitores de tantalio tienen una mayor relación
entre capacitancia y peso que los capacitores de aluminio y, por lo general, son más caros.

39
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Los condensadores cerámicos son otro tipo de condensador que se


encuentra comúnmente en el diseño de sistemas integrados. A diferencia de los
condensadores electrolíticos, tienen la ventaja de no estar polarizados. Sin embargo,
tienen una capacitancia más baja.
El uso más destacado de los capacitores en el espacio integrado es filtrar la
salida de las fuentes de alimentación. Muchos microcontroladores requieren
condensadores de filtrado en sus pines de alimentación. Los capacitores de
desacoplamiento actúan como una fuente de voltaje temporal para los
microcontroladores y son muy importantes para suprimir el ruido de alta frecuencia
en la fuente de alimentación. Cuando se usan de esta manera, los capacitores de
desacoplamiento también se conocen como capacitores de derivación, ya que evitan
la fuente de alimentación. Es importante consultar la hoja de datos para determinar el valor de los capacitores d
Hay muchas ocasiones donde muchos problemas intermitentes en su
los circuitos se pueden atribuir a tener una fuente de alimentación ruidosa. Una
fuente de alimentación es ruidosa cuando hay ondas en el riel de alimentación. Estas
ondas son esencialmente fluctuaciones en el voltaje de suministro. Si observa la salida
de CC de una fuente de alimentación con un osciloscopio, notará estas ondas. Si son
demasiado grandes, pueden causar muchos problemas en su circuito y pueden
provocar operaciones no deseadas y, en algunos casos, daños al IC y otros componentes
electrónicos sensibles.

Figura 3-10. Símbolos esquemáticos de gorra polarizada

40
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Figura 3-11. Símbolos esquemáticos de gorras no polarizadas

Figura 3-12. algunos capacitores

Inductor
Los inductores se utilizan para resistir los cambios en la corriente eléctrica que
fluye a través de ellos (vea la figura 3-14). El uso más común de los inductores es
en filtros, ya que un inductor deja pasar señales de baja frecuencia y resiste las de alta frecuencia.
El Henry (H) se utiliza para medir la inductancia. El nanohenrio, el
microhenrio y el milihenrio son las unidades más comunes.
La Figura 3-13 muestra los símbolos esquemáticos del inductor.

41
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Figura 3-13. Símbolos esquemáticos del inductor

Figura 3-14. Inductor

Transformadores
Un transformador es un dispositivo utilizado para aumentar o reducir
voltajes en dispositivos electrónicos.

Los transformadores requieren una corriente alterna para funcionar. La Figura


3-15 muestra los símbolos esquemáticos del transformador y la Figura 3-16 muestra un
transformador real.

42
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Figura 3-15. Símbolos esquemáticos del transformador

Figura 3-16. Transformador

Diodo
Un diodo es un dispositivo utilizado para permitir que la corriente fluya en una dirección particular.
Cuando el diodo tiene polarización directa, la corriente puede fluir. Cuando el diodo

tiene polarización inversa, la corriente no puede fluir. Si se aplica cierto voltaje en la


dirección inversa, el diodo se romperá y permitirá que la corriente fluya en la dirección

opuesta. Los diodos son extremadamente importantes en aplicaciones integradas.

43
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

dispositivos, ya que son imprescindibles para suprimir los picos de voltaje que
pueden estar presentes cuando se conducen cargas inductivas. La figura 3-17
muestra el símbolo esquemático del diodo.

Figura 3-17. Símbolo esquemático de diodo

Diodo Zener
Los diodos Zener son dispositivos que funcionan en la región de tensión de ruptura
y se utilizan para la estabilización y regulación de tensión y como referencia de tensión.
La figura 3-18 muestra el símbolo esquemático del diodo Zener. En la Figura 3-19, verá
el diodo Zener (cuerpo de vidrio) debajo de un diodo normal (cuerpo negro). Debe
tener en cuenta que los diodos normales también pueden tener cuerpos de vidrio.

Figura 3-18. Símbolo esquemático del diodo Zener

44
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Figura 3-19. Zener y diodo regular

Diodo emisor de luz


Un diodo emisor de luz (LED) es un tipo de diodo que emite luz cuando se le aplica un
voltaje. Los diodos vienen en una variedad de colores y tamaños. Los tipos encontrados
son infrarrojo, rojo, naranja, amarillo, verde, azul, violeta, púrpura, rosa, ultravioleta y
blanco. También hay LED bicolores y LED RGB. Hay LED de montaje en superficie y, por
supuesto, estándar de 3 mm.

y LED de 5 mm que se utilizan en la mayoría de los proyectos. Los LED de siete


segmentos, dieciséis segmentos y matriz de puntos también se utilizan en una variedad de proyectos.
La Figura 3-20 muestra los símbolos esquemáticos de los LED y la Figura 3-21
muestra un LED.

Figura 3-20. Símbolos esquemáticos LED

45
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Figura 3-21. LED

Diodo láser
El diodo láser (consulte la figura 3-22) es otro tipo de diodo común en
los sistemas integrados. Son de bajo costo y pesan muy poco, lo que los
hace muy útiles para una variedad de proyectos.

Figura 3-22. Diodo láser

46
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

transistores
Los transistores son posiblemente los dispositivos más revolucionarios jamás inventados.
Los dispositivos modernos no serían posibles sin el transistor. Los transistores se
utilizan principalmente para conmutación y rectificación en circuitos electrónicos.
Los transistores vienen en una variedad de tipos, que se discutirán brevemente en las
siguientes secciones.

Transistores de unión bipolar


El transistor de unión bipolar (BJT) viene en dos variedades y puede estar basado en
NPN o PNP. Estos nombres provienen de la designación del material semiconductor del
que está construido. un semiconductor con

electrones adicionales es de tipo N y uno con menos electrones es de tipo P. Si ese


semiconductor se apila en el orden de tipo N, tipo P, tipo N, entonces obtiene la
variedad NPN. De manera similar, si se apila tipo P, tipo N, tipo P, entonces se crea la
variedad PNP.
Como se mencionó, vienen en dos variedades: basadas en NPN y basadas en PNP.
Estos dos tipos de transistores se pueden diferenciar por la dirección de la flecha en
el pin del emisor en los dibujos esquemáticos. El transistor tipo PNP tiene la flecha
apuntando hacia adentro, mientras que la variedad NPN tiene la flecha apuntando
hacia afuera (vea la Figura 3-23).
Los transistores son dispositivos de tres pines: el colector (C), la base (B) y el
emisor (E). El transistor se utiliza ampliamente para la amplificación de señales y la
conmutación electrónica. Cuando se utilizan para amplificación, los transistores
convierten una señal de baja potencia en una de mayor potencia. El nombre que recibe
el tipo de amplificador de transistores viene determinado por el pin por el que entra y
sale la señal a amplificar.

47
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

El tipo más común de amplificador es el amplificador de tipo emisor común.


En este modo, el emisor está atado a tierra, el punto de entrada de la señal es la base
y el punto de salida es el colector. Este tipo de amplificador se usa comúnmente para
amplificar señales de audio, ya que realiza una amplificación de voltaje.

El colector común es el otro tipo de configuración de amplificador del transistor.


En este modo, el colector está conectado a tierra y la señal entra en la base y sale por
el emisor. Este tipo de amplificador se utiliza para el almacenamiento en búfer de
voltaje y la amplificación de corriente.
El último tipo de amplificador que veremos es el de base común.
configuración, que rara vez se utiliza en la práctica. La base está conectada a tierra
con el emisor como entrada y el colector como salida.
Tiene aplicaciones como amortiguador de corriente. La Figura 3-23 muestra los
símbolos esquemáticos de los transistores y la Figura 3-24 muestra algunos transistores NPN comunes.

Figura 3-23. Símbolos esquemáticos de transistores

48
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Figura 3-24. Transistores NPN de uso común

Transistor Darlington
Un transistor Darlington consta de dos transistores conectados de tal manera
que la salida de corriente del primer transistor es amplificada aún más por el
segundo. El par Darlington usa dos transistores PNP o dos NPN y un Darlington
complementario usa un transistor NPN y otro PNP.
Actúan como un solo transistor con una alta ganancia de corriente. Esta
propiedad es importante en las aplicaciones integradas, ya que en los circuitos
basados en microcontroladores, pueden usar una pequeña cantidad de corriente
del microcontrolador para ejecutar una carga mayor. Esto les da muchos usos,
como controladores de pantalla y control de motores y solenoides.

Otro transistor Darlington que quizás deba usar es el transistor


Photodarlington. Este transistor consta de dos transistores como un Darlington
normal. Sin embargo, se diferencian en que el primer transistor actúa como
fotodetector y su emisor está acoplado con la base del segundo transistor. La
figura 3-25 muestra los símbolos esquemáticos del transistor Darlington.

El Photodarlington tiene una alta ganancia pero es más lento que los
fototransistores ordinarios.

49
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Figura 3-25. Símbolos esquemáticos del transistor Darlington

El ULN2003, que se usará para impulsar pequeños motores paso a paso


en este libro, consta de una matriz de transistores Darlington. La Figura 3-26
muestra el símbolo esquemático ULN2003.

Figura 3-26. Símbolo esquemático ULN2003

50
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Transistor de efecto de campo

Los transistores de efecto de campo o FET pueden ser de canal N o de canal P

basado y operar de manera similar a los transistores bipolares.

Efecto de campo de semiconductores de óxido de metal

Transistores (MOSFET)

El transistor fue el pionero de la electrónica digital moderna. Sin embargo, con el


paso del tiempo, el transistor de efecto de campo semiconductor de óxido de metal
(MOSFET) se ha hecho cargo de muchas aplicaciones del transistor y se utiliza para
amplificación y conmutación y en circuitos integrados modernos.
El MOSFET consta de tres pines: puerta (G), fuente (S) y drenaje (D),
que son el equivalente de la base, el emisor y el colector, respectivamente, del
transistor. También hay un cuarto pin llamado cuerpo o sustrato, pero generalmente
está conectado internamente.
Los MOSFET vienen en las variedades de canal N y canal P. MOSFET

tienen una gran ventaja sobre los BJT, ya que requieren menos voltaje para encenderse.
Así, mientras que los transistores son dispositivos basados en corriente, los

MOSFET están basados en voltaje.

Los MOSFET deben manejarse con cuidado, ya que se dañan fácilmente con
electricidad estática. La figura 3-27 muestra el símbolo esquemático MOSFET.

51
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Figura 3-27. símbolo esquemático MOSFET

Transistor de efecto de campo de unión

El transistor de efecto de campo de unión (JFET) se utiliza para conmutación,

amplificación y como resistencia controlada por voltaje. Los JFET no se usan comúnmente en el

diseño de circuitos normales, pero encuentran uso en circuitos analógicos especiales.

Los BJT o MOSFET pueden hacer la mayor parte de lo que se requiere.

El JFET también encuentra uso como un interruptor controlado por voltaje y como un interruptor.

La figura 3-28 muestra el símbolo esquemático JFET.

Figura 3-28. Símbolo esquemático JFET

52
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Amplificador operacional
El amplificador operacional u op-amp es uno de los componentes básicos de la

electrónica analógica. Incluso iría tan lejos como para decir que un amplificador

operacional es para la electrónica analógica lo que un transistor es para los digitales.

Después de aprender sobre la tecnología de microcontroladores, le recomiendo que

eche un vistazo en profundidad a los amplificadores operacionales. Con conocimientos de

amplificadores operacionales y microcontroladores, puede diseñar sistemas integrados

muy potentes. La figura 3-29 muestra el símbolo esquemático del amplificador operacional.

Figura 3-29. Símbolo esquemático del amplificador operacional

Como su nombre lo indica, el amplificador operacional se utiliza para la amplificación de señales de CC.

También se utiliza para filtrar y acondicionar señales, así como para integración,
diferenciación, resta y suma.

Al mirar los símbolos esquemáticos del amplificador operacional, además de la potencia

pines de suministro (que generalmente se omiten), verá dos terminales, uno con el

signo menos y el otro con el signo positivo. La entrada con el signo positivo se conoce

como entrada no inversora y la que tiene el

53
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

El signo menos se llama entrada inversora. Hay un tercer pin en el vértice del símbolo del

amplificador operacional de forma triangular, conocido como puerto de salida, y este pin

puede permitir que el voltaje o la corriente fluyan hacia el dispositivo, lo que se denomina

sumidero, o suministrar corriente desde el dispositivo, lo que se denomina suministro. .

Algunas aplicaciones comunes de los amplificadores operacionales en el

diseño de sistemas integrados son como un búfer para la salida de referencias de

voltaje del divisor de voltaje, amplificadores de instrumentación para pares diferenciales,

filtros activos de paso bajo y paso alto, amplificación de fotodiodos y más. De hecho, ¡se

puede escribir un libro completo sobre los amplificadores operacionales y sus aplicaciones!

Hay cientos de amplificadores operacionales para elegir y te recomiendo

prototipo con TL081CP, KIA324, MCP6001 y MCP6002. Estos amplificadores operacionales

son excelentes para la creación rápida de prototipos. Una vez que tenga un sistema en

funcionamiento, puede determinar el mejor amplificador para sus necesidades.

Electrónica digital
Las puertas lógicas son los componentes básicos de los circuitos digitales. Cuando

combina varios transistores, obtiene puertas lógicas. Le dejo a usted leer sobre las

complejidades de la electrónica digital con respecto a aspectos específicos de los

circuitos secuenciales y combinacionales. Algunas puertas básicas se describen en las

siguientes secciones.

La puerta Y
La puerta AND es uno de los componentes básicos de la lógica digital.

La puerta AND funciona tratando dos entradas y salidas lógicas como un nivel lógico alto

solo si ambas entradas son altas. Si solo una de las entradas es alta, entonces la salida

será lógicamente baja. La figura 3-30 muestra el símbolo esquemático de la puerta AND.

54
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Figura 3-30. Y símbolo esquemático de puerta

La puerta OR
La puerta OR funciona emitiendo un alto lógico si cualquiera de sus entradas es
un alto lógico. Si ambas entradas son un nivel lógico alto, entonces la salida
también es un nivel lógico alto. La única vez que la puerta OR genera un nivel bajo
lógico es si ambas entradas son un nivel bajo lógico. La figura 3-31 muestra el símbolo esquemático de la p

Figura 3-31. O símbolo esquemático de puerta

La puerta NO
La puerta NOT, también conocida como puerta de inversión, produce
exactamente lo contrario de su entrada. Si la entrada es un alto lógico, entonces la
salida será un bajo lógico, y si la entrada es un bajo lógico, entonces la salida será un
alto lógico. La figura 3-32 muestra el símbolo esquemático de la puerta NOT.

55
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Figura 3-32. NO símbolo esquemático de puerta

La puerta NAND
La puerta NOT AND (NAND) es una puerta lógica que combina una puerta NOT y
una puerta AND. La única característica distintiva entre la puerta NAND y la puerta
AND es el pequeño círculo en el extremo que simboliza la inversión.
La puerta NAND solo da un bajo lógico si ambas entradas son altos lógicos.
La figura 3-33 muestra el símbolo esquemático de la puerta NAND.

Figura 3-33. Símbolo esquemático de puerta NAND

La puerta NOR
La puerta NOT OR (NOR) es una puerta lógica que combina una puerta NOT y una
puerta OR. La puerta NOR, como la puerta NAND, simplemente invierte la salida de
una puerta OR y tiene la misma característica distintiva. La figura 3-34 muestra el
símbolo esquemático de la puerta NOR.

56
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Figura 3-34. Símbolo esquemático de puerta NOR

La puerta de amortiguamiento

La puerta del búfer es simplemente dos puertas NO combinadas. La puerta del búfer

puede parecer inútil, pero en realidad tiene muchas aplicaciones con conversión de nivel

lógico, que se analizan en la siguiente sección. La figura 3-35 muestra el símbolo

esquemático de la puerta del búfer.

Figura 3-35. El símbolo esquemático de la puerta del búfer

La puerta XOR
La compuerta OR exclusiva (XOR) es una compuerta lógica que proporciona un valor

lógico bajo cuando ambas entradas son verdaderas o cuando ambas entradas son

falsas. Da un alto lógico cuando ambas entradas son lógicamente opuestas. La figura

3-36 muestra el símbolo esquemático de la puerta XOR.

57
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Figura 3-36. Símbolo esquemático de puerta XOR

Conversión de nivel lógico


Un concepto importante para comprender en el ámbito de la electrónica digital,
especialmente cuando se trata de microcontroladores de interfaz, es la conversión
de nivel lógico. Antes de discutir formas de convertir entre niveles lógicos, primero
debemos entender el concepto de un nivel lógico.
Como sabe, en los sistemas digitales, los datos se representan en formato
binario, con un 0 que representa apagado o bajo y un 1 que representa encendido o
alto. Si bien este conocimiento puede ser suficiente para la programación en general,
cuando usa hardware físico, debe comprender que bajo es 0 voltios y alto es el voltaje
que el sistema reconocerá como una señal alta en comparación con la tierra.

Los primeros sistemas de microcontroladores usaban 5 voltios como estándar, porque


este es el voltaje con el que operan el microcontrolador y cualquier módulo
externo. Recientemente, sin embargo, la tendencia ha sido usar 3.3v e incluso 1.8v
como voltaje para alimentar estos sistemas. Esto presenta un problema porque
muchos de los módulos existentes, como los LCD, por ejemplo, se fabricaron para
usar 5 voltios, mientras que los microcontroladores más nuevos generalmente usan 3.3v.
El problema también surge si tiene un módulo más nuevo que usa lógica de 3.3v y sus
sistemas funcionan con lógica de 5v.
Para resolver este problema, es necesaria la conversión a nivel lógico.
Los sistemas suelen tener cierta tolerancia con su nivel lógico. Lo que esto
significa es que si tiene un sistema de 5v, reconocerá una señal de 3.3v como lógica
alta. Sin embargo, no puede manejar un sistema de nivel lógico de 3.3v con 5 voltios, ya
que esto dañará el módulo.

58
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Para evitar esto, existen formas comunes de encubrir un sistema de nivel lógico de 5v
para ser interconectado con un sistema de nivel lógico de 3.3 voltios, discutido a continuación.

Ejecute todo el sistema en 3.3v


Aunque no es necesariamente una técnica de conversión de nivel lógico, ejecutar
su sistema en 3.3v eliminará cualquier componente adicional que se compre, lo que
reducirá los costos de su lista de materiales (BOM). Además, ejecutar todo el sistema
en 3.3v reducirá el consumo general de energía.
Por estas razones, se recomienda que, una vez que sea posible, reduzca el voltaje
operativo general de su sistema.
El PIC16F1717 y los microcontroladores más nuevos pueden funcionar a 3.3v o
5v. En este libro, uso 5v tanto como sea posible, simplemente porque muchos módulos
y sensores se adaptan a un sistema de 5v (aunque esto está cambiando lentamente). Si
es un usuario de Arduino, es posible que haya construido su arsenal electrónico con
componentes de 5v. Otra ventaja de los 5v es que son mucho menos susceptibles de
ser perturbados por el ruido que los de 3.3v, porque se necesita más ruido para
perturbar el funcionamiento del circuito de 5v.
Sin embargo, siéntase libre de ejecutar su sistema a 3.3v en su aplicación final.

Use un divisor de voltaje


El uso de un divisor de voltaje es otra forma de interfaz entre señales de nivel
lógico (vea la Figura 3-37). Como se mencionó, si su dispositivo de 3.3v está
transmitiendo a 3.3v, puede conectar directamente esta línea a la entrada del dispositivo de 5v.
Sin embargo, en el extremo transmisor del dispositivo de 5v, puede ser necesario
usar un divisor de voltaje para convertir el nivel lógico más alto en uno más bajo.
Una buena combinación de resistencias para este tipo de circuito es un par de 1k y 2k.
La salida estaría cerca de 3.3v. La desventaja de este sistema es que es más adecuado
para señales muy lentas. Si tiene un presupuesto ajustado, entonces este es el método
que recomiendo.

59
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Figura 3-37. Método del divisor de tensión

Use un cambiador de nivel lógico bidireccional


Cuando está interactuando entre niveles lógicos y se necesita realizar una
conversión de muy alta velocidad, es simple usar un cambiador de nivel lógico
bidireccional dedicado para convertir entre niveles de señal. Para fines de
creación de prototipos, recomiendo los omnipresentes módulos convertidores
de nivel lógico, ya que están diseñados para la integración y funcionan bien
(vea la figura 3-38). Para cambiar a una placa de circuito impreso, recomiendo
el 74LVC245, porque son fáciles de usar y funcionan muy bien.

Figura 3-38. Convertidor de nivel lógico común

60
Machine Translated by Google

CAPÍTULO 3 ELECTRÓNICA BÁSICA PARA SISTEMAS EMPOTRADOS

Conclusión
Este capítulo analizó los componentes electrónicos básicos que se
encuentran comúnmente en los sistemas integrados. Cubrimos varios
componentes, así como puertas lógicas básicas y métodos de conversión de
nivel lógico. Este capítulo es esencial para comprender cómo conectar dispositivos y sensores a
Fue una introducción muy básica; sin embargo, si comprende el contenido
aquí, debería poder construir sus propios circuitos. Si necesita más
información, hay libros disponibles que dan una descripción más detallada de
los componentes. También existe una aplicación llamada Logic Gates para
dispositivos Android que permite a los usuarios experimentar con compuertas lógicas.

61
Machine Translated by Google

CAPÍTULO 4

Microcontroladores PIC®
Descripción general de los microcontroladores PIC®

Microchip fabrica microcontroladores de 8, 16 y 32 bits. En este capítulo, analizamos

las familias de 8 bits. Los microcontroladores PIC® de 8 bits pertenecen a diferentes grupos

según los clasifica el microchip. Los grupos son línea de base, rango medio, rango medio

mejorado y alto rendimiento. Analizamos cada uno de ellos en este capítulo.

Microcontroladores PIC® de línea base


Estos están en la parte inferior de la cadena alimenticia de Microchip de 8 bits. PIC® de referencia

Los microcontroladores están formados por miembros de la familia PIC10, PIC12 y

PIC16. Estos dispositivos generalmente se usan en aplicaciones que necesitan un número

bajo de pines, requisitos de energía extremadamente bajos y contienen programas pequeños.

Algunos miembros de esta familia incluyen un oscilador integrado. ¡Hay miembros de

esta familia que tienen tan solo seis pines!

El PIC16F57 es un miembro de la familia de referencia que ha encontrado un uso

generalizado. El BASIC stamp I usa el PIC16C56 y el BASIC stamp II usa el PIC16F57

como sus microcontroladores.

63
© Armstrong Subero
2018 A. Subero, Programación de microcontroladores
PIC con XC8, https://doi.org/10.1007/978-1-4842-3273-6_4
Machine Translated by Google

CAPÍTULO 4 MICROCONTROLADORES PIC®

Microcontroladores PIC® de gama media


La familia de microcontroladores PIC® de gama media tiene miembros en
las familias PIC10, PIC12 y PIC16. Estos dispositivos se utilizan cuando
necesita más funciones, como periféricos de comunicación integrados y
posiblemente periféricos independientes del núcleo.
Los dispositivos como PIC16F877, 16F84A y 16F887 eran y siguen
siendo muy populares entre los entusiastas de los microcontroladores
y hay mucho código disponible para usar estos dispositivos. Sin
embargo, a menos que admita un diseño heredado, se recomienda utilizar los
microcontroladores de rango medio mejorados, que tienen muchas características útiles.

Microcontroladores PIC® de gama media mejorados


El núcleo de rango medio mejorado incluye miembros de las familias PIC12 y
PIC16. Este núcleo fue desarrollado por Microchip para ser compatible con los
dispositivos de rango medio y al mismo tiempo ofrece varias mejoras, que
incluyen más memoria de programa, más periféricos en el chip y, por supuesto,
la arquitectura C optimizada.
En este libro, nos enfocamos en la familia mejorada de
microcontroladores de rango medio. El chip que estamos usando, el
PIC16F1717, tiene muchos elementos útiles integrados, incluidos periféricos analógicos.

Microcontroladores PIC® de alto rendimiento


Estos son los miembros de mayor rendimiento de la familia PIC® de 8
bits y son miembros de la familia 18F. Cuentan con una gran memoria de
programa Flash, un conjunto de instrucciones ampliado y, por supuesto,
comunicaciones de protocolo integradas, como USB, CAN y Ethernet. Están
destinados a dispositivos de 8 bits de alto rendimiento y tienen multiplicadores de hardware.

64
Machine Translated by Google

CAPÍTULO 4 MICROCONTROLADORES PIC®

Si necesita usar USB, le recomiendo que use el PIC18F4553


para sus proyectos basados en USB. Aunque hay versiones más
nuevas de la familia PIC18, este chip tiene mucho código relacionado con
su uso para aplicaciones USB, ya que es idéntico al PIC18F4550. La
excepción es que el PIC18F4553 contiene un convertidor de analógico a digital de mayor reso
Sin embargo, generalmente diría que si necesita USB, un miembro de la
familia PIC24 o PIC32 proporciona funciones mucho más potentes.

Diagrama de bloques PIC® 16F1717


Ahora que ha aprendido acerca de los diferentes tipos de PIC®
familias y grupos de microcontroladores, veamos la arquitectura del
PIC16F1717 (consulte la Figura 4-1).

Programa
Memoria flash
RAM PORTA

PUERTOB
CLKOUT tiempo
Generacion

CLKIN HFINTOSC/
PUERTO
LFINTOGC
Oscilador
UPC

MCLR

suboficial

ZCD

amplificadores operacionales
PWM Temporizador0 Temporizador1 Temporizador2 MSSP Comparadores
DIENTE

Temperatura. ADC
RVF DAC PCC EUSART CLC
Indicador 10 bits

Figura 4-1. Diagrama de bloques PIC16F1717 (reimpreso con


permiso)

sesenta y cinco
Machine Translated by Google

CAPÍTULO 4 MICROCONTROLADORES PIC®

Mirando el diagrama de bloques que se muestra en la Figura 4-1, vemos que el

PIC16F1717 es muy complejo. Consta de una gran cantidad de periféricos, de los que
hablaremos en las próximas secciones.

Memoria flash del programa


La memoria Flash de programa es la memoria que almacena nuestro programa y está

hecha con tecnología de memoria Flash. Los chips más antiguos requerían luz ultravioleta

para borrar su memoria. Sin embargo, con la llegada de la tecnología basada en Flash, los

microcontroladores tienen un costo extremadamente bajo y se pueden reprogramar en

segundos. Flash también es una forma de memoria no volátil y presenta una retención de datos

prolongada. ¡La memoria flash PIC16F1717 tiene una retención de datos de aproximadamente

40 años!

El tamaño de la memoria Flash de los microcontroladores PIC® de 8 bits generalmente consiste

de varios kilobytes y, en el PIC16F1717, es de 14 KB de memoria de programa. Esto

puede almacenar bastantes instrucciones, como verá en este libro. Los sistemas de

microcontroladores generalmente nunca usan más de un par de megabytes de memoria de

programa.

Memoria de acceso aleatorio


La memoria de acceso aleatorio (RAM), como sabe, almacena las instrucciones del programa

para aumentar la velocidad de ejecución del programa. Hay dos tipos principales de RAM: RAM

estática (SRAM) y RAM dinámica (DRAM). Hay otros tipos de RAM, como FRAM y EERAM; sin

embargo, no se discutirán aquí.

En su computadora de uso general, encontrará DRAM en el rango de gigabytes que se

utiliza para la memoria. Sin embargo, en los microcontroladores, encuentra SRAM que se

utiliza para la memoria principal. Las CPU de uso general contienen SRAM; sin embargo,

generalmente se encuentra en el procesador y se usa para la memoria caché.

66
Machine Translated by Google

CAPÍTULO 4 MICROCONTROLADORES PIC®

memoria. Las principales diferencias son que SRAM retiene sus datos si se aplica
energía, mientras que DRAM necesita una actualización constante. SRAM también
es más rápido que DRAM.

El PIC16F1717 contiene 1024 bytes de SRAM. Ahora, antes de que te


quejes de la pequeña cantidad de RAM en este controlador, déjame decirte que es
bastante. Los programas de microcontroladores generalmente nunca requieren más
de unos pocos kilobytes de RAM.

Generación de tiempos
Si observa el diagrama de bloques en la Figura 4-1, verá un bloque titulado
"Generación de temporización". Este bloque contiene HFINTOSC y LFINTOSC, que
son el oscilador interno de alta frecuencia y el oscilador interno de baja frecuencia,
respectivamente. Además, no mencionado aquí, es el MFINTOSC (oscilador interno
de frecuencia media). El LFINTOSC funciona a 31 kHz y no está calibrado. El
MFINTOSC funciona a 500 kHz y viene calibrado de fábrica. El HFINTOSC deriva su
velocidad del MFINTOSC y funciona a una velocidad de hasta 16 MHz.

La velocidad máxima del PIC16F1717 es de 32 MHz, que puede ser


obtenido mediante el uso de Phase Locked Loop (PLL). Los PLL se utilizan para
generar algún múltiplo de la frecuencia de entrada. El que está a bordo del PIC16F1717
es un PLL 4x, lo que significa que dará una frecuencia de salida cuatro veces la
frecuencia de entrada.
Los PLL tienen un período de tiempo antes de que coincidan con la frecuencia y la fase
eso se espera de ellos y cuando esto se hace, se dice que el PLL está bloqueado.
El PLL del PIC16F1717 tiene un tiempo de bloqueo de 2 ms.

Es importante señalar que el HFINTOSC y MFINTOSC, aunque


calibrados, caen dentro de un margen del 2% de la frecuencia estipulada. Por lo
tanto, si necesita una sincronización extremadamente precisa, se requerirá un
oscilador externo. Sin embargo, en este libro bastaría con el oscilador interno.

67
Machine Translated by Google

CAPÍTULO 4 MICROCONTROLADORES PIC®

!MCLR
El pin !MCLR se utiliza para restablecer el microcontrolador PIC®. Cuando diseñe
circuitos, no deje este pin flotando. Este pin debe estar conectado a VDD si no
está en uso. El circuito utilizado para el !MCLR se muestra a continuación.

Puertos

Si observa el diagrama de bloques del microcontrolador, notará varios puertos


marcados como PORTA to PORTE. En un microcontrolador, hay varios pines
que sobresalen. Los pines se utilizan para conectar el microcontrolador al mundo
exterior. Sin embargo, dentro del microcontrolador, estos pines están controlados
por registros dentro del microcontrolador que están representados por puertos.

Periféricos a bordo
El microcontrolador PIC® consta de varios periféricos digitales. Estos
periféricos son de naturaleza digital o analógica. Microchip introdujo
recientemente una gran cantidad de periféricos independientes del núcleo.
Los periféricos independientes del núcleo no requieren la intervención de la CPU para mantener el funci
Veamos estos periféricos.

Conversor analógico a digital


El convertidor analógico a digital (ADC) se utiliza para convertir señales
analógicas en digitales. El convertidor ADC integrado en el PIC16F1717 tiene una
resolución de 10 bits. Lo que esto significa es que puede tomar una señal y
dividirla en 1023 "pasos", siendo el valor de un paso el voltaje de entrada dividido
por el número de pasos.

68
Machine Translated by Google

CAPÍTULO 4 MICROCONTROLADORES PIC®

Por ejemplo, si usamos una referencia de voltaje de 4.096v, entonces tenemos

una resolución de 4mV por bit. Para una lectura precisa de ADC, se recomienda tener una

fuente de alimentación limpia y una referencia de voltaje estable.

Convertidor digital a analógico


El convertidor digital a analógico (DAC) hace exactamente lo contrario del ADC. El

DAC convierte una señal analógica en una digital. El DAC se usa típicamente para

generar sonido y formas de onda. El PIC16F1717 tiene dos DAC. DAC1 tiene una resolución
de 8 bits y DAC2 tiene una resolución de 5 bits.

Modulación de captura/comparación/ancho de pulso


Módulo

La captura/comparación/PWM (módulo CCP) es un módulo importante en el microcontrolador


PIC®.

El modo de captura se utiliza para medir un número particular de flancos

descendentes o ascendentes de un temporizador y esencialmente permite la sincronización de un evento.

El modo de comparación permite comparar el valor del temporizador con un valor de

comparación preestablecido. El modo de modulación de ancho de pulso (PWM) genera una

onda cuadrada de frecuencia y ciclo de trabajo variables, que el usuario puede determinar.

Módulo de modulación de ancho de pulso

En la práctica, he encontrado que uno tiende a usar PWM con más frecuencia debido a su

uso en aplicaciones como iluminación y control de motores. Incluso Microchip se ha dado

cuenta de la importancia de PWM y proporciona un módulo PWM dedicado además de los

módulos CCP regulares. El módulo PWM del PIC16F1717 tiene una resolución de 10 bits.

69
Machine Translated by Google

CAPÍTULO 4 MICROCONTROLADORES PIC®

Temporizadores

Aunque puede ver la palabra "Timerx" en el diagrama de bloques del microcontrolador,


los temporizadores a bordo del PIC16F1717 también pueden funcionar como contadores y

realizar funciones de temporizador/contador. Los temporizadores se utilizan para medir el

tiempo, generar pulsos y contar pulsos, y también son retrasos de tiempo muy precisos. Por

lo tanto, aunque puede ver estos módulos simplemente denominados "temporizadores",

tenga en cuenta que realmente realizan funciones de temporizador/contador.

El PIC16F1717 tiene cuatro temporizadores de 8 bits y un temporizador de 16 bits. Temporizadores 0, 2,

4 y 6 son de 8 bits y el temporizador 1 es de 16 bits.

Comparadores
El comparador del PIC16F1717 compara dos voltajes y proporciona una salida digital para

indicar cuál es mayor. El comparador tiene una histéresis mínima de 20mV y máxima de 75mV.

También tiene un tiempo de respuesta de menos de 100 ns.

Referencia de voltaje fijo


La referencia de voltaje fijo (FVR) se utiliza para proporcionar un voltaje de referencia

estable al comparador, DAC o ADC. Al hacer esto, se elimina el costo de pagar una referencia

de voltaje externa.

Indicador de temperatura
Hay un indicador de temperatura a bordo del PIC16F1717 que tiene un rango de -40 a 85 grados

Celsius. Este indicador de temperatura es útil cuando no tiene espacio en la placa para un

sensor de temperatura o desea reducir el costo del sistema.

70
Machine Translated by Google

CAPÍTULO 4 MICROCONTROLADORES PIC®

EUSART
El módulo Enhanced Universal Synchronous Asynchronous Receiver Transmitter
(EUSART) se utiliza para comunicaciones en serie y muchos módulos externos
requieren esta interfaz para comunicarse con el microcontrolador.

CVX
La celda lógica configurable (CLC) es un módulo en el microcontrolador que
proporciona un poco de funciones lógicas secuenciales y combinatorias integradas.

MSSP
El módulo de puerto serie síncrono maestro (MSSP) proporciona dos modos de
funcionamiento que se configurarán para su uso, ya sea para la función de interfaz
periférica serie (SPI) o las funciones de circuito interintegrado (I2C).

suboficial

El oscilador controlado numéricamente (NCO) se utiliza para proporcionar


una frecuencia de resolución muy precisa y fina en un ciclo de trabajo. El NCO
en el PIC 16F1717 usa el desbordamiento de un acumulador de 20 bits para lograr esta función.

ZCD
El módulo de detección de cruce por cero detecta el punto cuando no hay
voltaje presente en la forma de onda de CA. El módulo ZCD se puede utilizar
para detectar la frecuencia fundamental de una forma de onda y para enviar
datos digitales a través de circuitos de CA, como se hace en los sistemas X10.
La detección de cruce por cero en el PIC16F1717 tiene un tiempo de respuesta de 1uS.

71
Machine Translated by Google

CAPÍTULO 4 MICROCONTROLADORES PIC®

DIENTE

El módulo generador de salida complementaria (COG) toma una señal


PWM y la convierte en dos señales complementarias.

Amplificadores operacionales

Los amplificadores operacionales (OPA) o los amplificadores operacionales son la piedra angular de

los sistemas analógicos. El PIC16F1717 incluye amplificadores operacionales integrados. Tienen un

producto de ancho de banda de ganancia de 2 MHz y una velocidad de respuesta de 3 V por EE. UU.,
suponiendo un VDD de 3,0 V.

Bloque Flash de alta resistencia

La celda High Endurance Flash (HEF) está diseñada para reemplazar la


EEPROM, que está presente en algunos microcontroladores. Mientras que
el flash normal en el PIC16F1717 puede soportar solo 10 000 ciclos de
borrado y escritura, el HEF puede soportar 100 000 ciclos de borrado y
escritura. El HEF tiene un tamaño de 128 bytes.

El núcleo de CPU de rango medio mejorado


Ahora que tiene una comprensión básica de los periféricos integrados del
microcontrolador, echemos un vistazo al núcleo de la CPU de 8 bits (vea la Figura 4-2).

72
Machine Translated by Google

CAPÍTULO 4 MICROCONTROLADORES PIC®

15
Configuración 15 8
Bus de datos
Contador de programa

Destello

Programa
Memoria Stock de 16 niveles
RAM
(15 bits)

Programa 14 Memoria de programa 12 RAM Agregar


Autobús

Leer (PMR)
Dirección MUX

Registro de instrucción
Indirecto
Dirección directa 7

5 Dirección 12 12

15 Reg. BSR

Registro FSR0

Registro FSR1

15
ESTADO Reg.
8

3
multiplexor
Encender
Temporizador

Instrucción Oscilador
Decodificar y Temporizador de puesta en marcha
ALU
Control
Encendido
OSC1/CLKIN 8
Reiniciar

Sincronización Perro de agua


OSC2/CLKOUT Generacion Wreg
Temporizador

Apagón
Reiniciar

Interno
Oscilador
Cuadra

vco vs

Figura 4-2. Diagrama central de PIC16F1717 (reimpreso


con permiso)

73
Machine Translated by Google

CAPÍTULO 4 MICROCONTROLADORES PIC®

Veamos de qué son responsables algunos de estos bloques en el núcleo.

No discutiremos cada detalle de la arquitectura; sin embargo, los componentes que

se pueden configurar en el software se describen en las siguientes secciones.

Temporizador de encendido

El temporizador de encendido es responsable de proporcionar un breve retraso para permitir

que la fuente de alimentación alcance el valor requerido. Una vez transcurrido el tiempo, el programa

puede comenzar a ejecutarse. La razón de esto es que es una precaución para evitar efectos

adversos en la ejecución del programa. El temporizador de encendido tarda entre 40 y 140 ms en


hacer esto.

Temporizador de puesta en marcha del oscilador

El temporizador de inicio del oscilador (OST) proporciona un retraso (además del que ofrece el

temporizador de encendido) para permitir que el reloj se estabilice antes de que comience la

ejecución del programa. El OST cuenta por un período de 1024 ciclos y es independiente de la

frecuencia del microcontrolador.

Restablecimiento de encendido

Mientras el temporizador de encendido y el temporizador de inicio del oscilador están

funcionando, el temporizador de reinicio de encendido mantiene el dispositivo en reinicio hasta


que la energía y el reloj se estabilizan.

Temporizador de vigilancia

El temporizador de vigilancia (WDT) restablece automáticamente el procesador después de

un período determinado definido por el usuario. Esto es extremadamente importante para permitir

que una aplicación escape de un bucle sin fin. Para mantener el programa

74
Machine Translated by Google

CAPÍTULO 4 MICROCONTROLADORES PIC®

en ejecución, se debe borrar el WDT o, de lo contrario, el programa no se ejecutará


según lo previsto. Por lo tanto, es importante apagar el WDT al configurar el
microcontrolador.

Restablecimiento de Brown-Out

El restablecimiento de caída de tensión se utiliza para detectar una condición de caída de tensión dentro del

microcontrolador Una condición de caída de voltaje es aquella en la que hay una


caída en el voltaje de la fuente de alimentación. El circuito de reinicio de caída de
tensión mantiene el microcontrolador en reinicio hasta que la fuente de alimentación
vuelve a un nivel aceptable. El restablecimiento por caída de tensión tiene un tiempo de
respuesta de entre 1 y 35 uS en el PIC16F1717 antes de que se active.

Conclusión
En este capítulo, examinamos brevemente el microcontrolador PIC®, que es el
tema principal de este libro. Aprenda la información presentada en este capítulo y
aprenda bien. El capítulo cubrió algunos de los periféricos más importantes a bordo del
microcontrolador y proporcionó una descripción general de algunas de las características
del núcleo.

75
Machine Translated by Google

CAPÍTULO 5

Conectando
y Creando
Empecemos
En este capítulo, analizamos el proceso de conexión de un microcontrolador
PIC® a un programador en serie en circuito, o ICSP. Algunas personas también
los llaman Depuradores en circuito, ya que también tienen capacidades de
depuración. Observamos el proceso de creación y ejecución de un nuevo
proyecto en MPLAB X, así como la creación de archivos fuente. Los principiantes
y los usuarios primerizos de microcontroladores básicos deben prestar especial
atención a este capítulo porque, a diferencia de Arduino y otras placas de
desarrollo, es necesario conectar el microcontrolador a un programador para
cargar su programa en el chip. El proceso no es tan "plug and play" como usar una placa de desar

Una mirada a los programadores


Como se explicó en el Capítulo 1, existen diferentes programadores que
puede usar para programar su microcontrolador PIC®. Los dos más populares
en este momento son el PICkit™ 3 y el MPLAB® ICD 3. (También hay un ICD
4; sin embargo, en el momento de escribir este artículo no es compatible con
todos los chips PIC® y no es tan popular como el programadores antes
mencionados). Independientemente de si compró un ICD 3 o un PICkit™ 3, el
proceso de conexión del programador a su microcontrolador es el mismo.

77
© Armstrong Subero
2018 A. Subero, Programación de Microcontroladores
PIC con XC8, https://doi.org/10.1007/978-1-4842-3273-6_5
Machine Translated by Google

CAPÍTULO 5 CONECTANDO Y CREANDO

No profundizaremos en la mecánica de cómo funcionan estos


programadores, porque en este libro, todo lo que veremos es usarlos
como programadores y no exploraremos sus capacidades de depuración.
Simplemente trataremos a los programadores como "cajas negras" que
le permiten cargar su programa en el chip. La Figura 5-1 muestra un primer plano del PICkit™ 3

Figura 5-1. Primer plano de PICkit 3

Si observa el primer plano de la Figura 5-1, verá una flecha.


Esta flecha es la posición donde colocas el cable que está conectado
al pin !MCLR de tu microcontrolador. Moviéndose hacia la izquierda,
los pines posteriores que se conectarán son el pin Vdd, el pin Vss, el
pin PGD (datos) y el pin PGC (reloj). También hay un pin LVP
(programación de bajo voltaje); sin embargo, podemos ignorarlo con seguridad por ahora.
Si está utilizando el ICD 3, le recomiendo encarecidamente que
compre un adaptador que convierta el conector tipo RJ-11 del
programador en una interfaz tipo ICSP. Como principiante, esto
hará que conectar el programador a sus diversos chips y placas de
desarrollo sea muy fácil, ya que simplemente podrá insertar un cable en
el conector y conectarlo a su chip. La Figura 5-2 muestra un ejemplo de cómo uno de estos RJ-

78
Machine Translated by Google

CAPÍTULO 5 CONECTANDO Y CREANDO

aspecto de los conectores. También te recomiendo repetir estos pasos o


conectar el chip al programador con el programador desconectado de tu
computadora para evitar percances.

Figura 5-2. Adaptador RJ-11 a ICSP

Una vez que haya configurado su programador, el siguiente paso es


conectar el programador al chip físico. Hay muchas maneras de hacer esto.
Sin embargo, la forma más sencilla es simplemente conectar un cable de puente
macho a macho desde el orificio del conector hasta el dispositivo de destino. La
Figura 5-3 muestra cómo conectar el cable puente macho al conector ISCP.
Después de realizar este proceso, puede conectar los cables puente al PIC16F1717,
como se muestra en la Figura 5-4.

79
Machine Translated by Google

CAPÍTULO 5 CONECTANDO Y CREANDO

Figura 5-3. Conexión de cables puente al conector ICSP

Figura 5-4. Conexión de ICSP a PIC16F1717


80
Machine Translated by Google

CAPÍTULO 5 CONECTANDO Y CREANDO

Una mirada a la programación


Después de haber conectado su programador a su chip, puede conectar el cable
USB de su programador a su computadora. Si no se libera humo mágico y tiene
su programador conectado al microcontrolador, el siguiente paso es escribir su
programa y descargarlo al microcontrolador.

Primero, abra MPLAB® X. Se le presentará la ventana que se muestra


en la Figura 5-5.

Figura 5-5. Pantalla de inicio de MPLAB® X

Elija Archivo ÿ Nuevo proyecto, como se indica en la esquina superior izquierda


del IDE que se muestra en la Figura 5-6.

Figura 5-6. Creando un nuevo proyecto

81
Machine Translated by Google

CAPÍTULO 5 CONECTANDO Y CREANDO

A continuación, elija Microchip Embedded seguido de Standalone Project, como se


muestra en la Figura 5-7.

Figura 5-7. Selección de un proyecto independiente

A continuación, seleccione su familia de dispositivos seguido de su dispositivo. En


este caso, será PIC16F1717. Escriba esto en el cuadro Dispositivo, como se muestra en la Figura 5-8.

Figura 5-8. Elegir tu dispositivo

Haga clic en Siguiente y luego en Siguiente nuevamente. Seleccione el


programador que utilizará en la opción Herramientas de hardware. En este caso,
seleccione el PICkit 3 o el ICD 3, como se muestra en la Figura 5-9.

82
Machine Translated by Google

CAPÍTULO 5 CONECTANDO Y CREANDO

Figura 5-9. Selección de su herramienta de hardware

Seleccione su compilador. Usaremos el compilador XC8 en este ejemplo,


así que asegúrese de que esta opción esté seleccionada, como se muestra en la Figura 5-10.

Figura 5-10. Elegir el compilador XC8

Seleccione un nombre para su proyecto y elija una ruta. Luego haga clic en el
botón Finalizar. Esto se representa en la Figura 5-11. ¡Felicidades! ¡Has creado un nuevo
proyecto!

83
Machine Translated by Google

CAPÍTULO 5 CONECTANDO Y CREANDO

Figura 5-11. Nombrando su proyecto y seleccionando una ruta

Debería ver su nuevo proyecto creado, como se muestra en la Figura 5-12.

Figura 5-12. Proyecto recién creado

84
Machine Translated by Google

CAPÍTULO 5 CONECTANDO Y CREANDO

Ahora está listo para escribir su programa. Para hacer esto, debe crear archivos de

encabezado y archivos fuente. Veamos cómo se crea un archivo fuente.

Haga clic en la carpeta Archivos de origen. A continuación, haga clic con el botón derecho en él y seleccione Nuevo.

Cree un nuevo archivo main.c, como se muestra en la Figura 5-13.

Figura 5-13. Creando un nuevo archivo principal

El proceso para crear un archivo de encabezado es el mismo. La diferencia es que

en lugar de hacer clic en la carpeta Archivos de origen, hace clic en la carpeta Archivos de
encabezado y crea un archivo de encabezado en lugar de un archivo de origen.

Su archivo será creado. No ejecutaremos un programa ahora.

Mire la parte superior del IDE y verá los dos íconos que usaremos. los

El icono con el martillo y la escoba es la opción Limpiar y construir y la flecha verde se

usa para ejecutar el proyecto principal (consulte la Figura 5-14). Usamos el botón Clean and

Build para verificar que nuestro programa está libre de errores. Al hacer clic en el icono

Ejecutar proyecto principal, el programa se cargará en el microcontrolador.

Figura 5-14. Limpiar y Construir y Ejecutar Iconos

85
Machine Translated by Google

CAPÍTULO 5 CONECTANDO Y CREANDO

Si intenta ejecutar el proyecto actual y descargarlo a su


microcontrolador, no pasará nada. Esto se debe a que no le hemos dado ninguna
instrucción al microcontrolador. En el próximo capítulo, veremos cómo escribir un
programa para hacer que el microcontrolador haga algo.

Trampas para principiantes

Cuando construye su proyecto, espera que se cargue en el chip. Sin embargo,


hay algunas trampas que causan problemas a los principiantes. La primera trampa
es que el PICkit® 3 o ICD 3 no proporciona energía a su microcontrolador por defecto
y le recomiendo que lo mantenga así. Por lo tanto, debe alimentar el circuito de destino
desde su propia fuente de alimentación. La razón de esto es que cuando comenzamos a
usar cargas inductivas o de alta corriente, como motores de CC y servos, por ejemplo,
podemos consumir más corriente de la que puede proporcionar el programador.

La otra trampa que debe tener en cuenta es la longitud de los cables desde
el programador al chip. Mantenga estos cables lo más cortos posible, lo que
garantizará que no experimente ningún error al intentar ejecutar su proyecto.

La trampa final con la que debe tener cuidado es tener una fuente de
alimentación ruidosa. Le recomiendo que use una fuente de alimentación dedicada,
ya que tendrá la menor cantidad de ruido. Incluso con una buena fuente de
alimentación, le recomiendo que siga usando algunos condensadores de suavizado
en los rieles de suministro. Innumerables problemas evitables se pueden atribuir a tener una fuente de alimentac
Recuerde que programar un chip es un proceso complejo y muchas cosas suceden
en segundo plano. Por lo tanto, cualquier cosa puede salir mal. Es muy importante que
prestes atención a la ventana de salida. Te ahorrará muchas horas de frustración.

Recuerde también verificar tres veces sus conexiones. A veces, accidentalmente


conectará las cosas de la forma en que no deberían estar conectadas. PIC®
Los microcontroladores son dispositivos resistentes y fáciles de usar, pero hay
algunas reglas a las que debe prestar atención.

86
Machine Translated by Google

CAPÍTULO 5 CONECTANDO Y CREANDO

información adicional
Si necesita más información sobre cómo se lleva a cabo la programación real
del microcontrolador PIC, le recomiendo que consulte la nota de la aplicación
DS30277. Microchip también proporciona mucha información en su sitio web
sobre el uso de microcontroladores PIC en general en www.microchip.com. Hay
muchos recursos adicionales en el sitio web del fabricante.

Conclusión
Este capítulo analizó el proceso de conexión de nuestro microcontrolador
a nuestro programador. También analizamos los procesos de creación de un
nuevo archivo de origen del proyecto, así como también cómo construiría y ejecutaría un proyecto

87
Machine Translated by Google

CAPÍTULO 6

Entrada y salida
Comencemos E/S
En el último capítulo, analizamos los periféricos disponibles para los usuarios de PIC®
microcontroladores Una de las cosas que vimos en el diagrama de bloques
fueron los puertos. Como se describió, los puertos son registros que brindan
acceso a los pines del microcontrolador. Los puertos del PIC16F1717 se
pueden usar para entrada o salida y pueden brindar acceso a muchos
periféricos integrados en el microcontrolador. En este capítulo, analizamos la
entrada y la salida, también escritas como E/S. Usamos E/S para interactuar con
LED, interruptores y pantallas de siete segmentos.
Antes de ver el código para que esto suceda, hay algunos registros
que debe comprender, incluido saber cómo configurarlos para usar E/S de
manera efectiva en el microcontrolador.

Registro TRIS
El primer registro que examinamos es el registro TRIState (TRIS). El registro
TRIS recibe su nombre del hecho de que puede estar en tres estados. Se
puede configurar para salida alta, salida baja o entrada. El registro TRIS se
utiliza para hacer que un puerto sea una entrada o una salida. Para convertir un
puerto en una salida, escribimos un 0 en el registro TRIS correspondiente de
ese puerto. Para que sea una entrada, escribimos un 1.

89
© Armstrong Subero
2018 A. Subero, Programación de microcontroladores
PIC con XC8, https://doi.org/10.1007/978-1-4842-3273-6_6
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

Por ejemplo, para configurar PORTB como puerto de salida, hacemos lo siguiente:

TRIB = 0;

De manera similar, si quisiéramos convertir ese mismo puerto en un puerto de entrada,

hacemos lo siguiente:

TRIB = 1;

Es importante administrar eficientemente las preciadas E/S ya que PIC®


Los microcontroladores no contienen un número infinito de pines. La versión DIP
del PIC16F1717 utilizada para la creación de prototipos contiene 40 pines. La razón
por la que afirmé este punto obvio es para reiterar el hecho de que las E/S deben
designarse correctamente. Por lo tanto, a veces es necesario asignar un pin en un puerto
en particular para cumplir una función de entrada o salida. Por ejemplo, para establecer
un bit individual (en este caso, BIT 0 en PORTB) como salida, hacemos lo siguiente:

TRISBbits.TRISB0 = 0;

De manera similar, si quisiéramos establecer un bit como entrada, escribimos:

TRISBbits.TRISB1 = 1;

Como puede ver en estas asignaciones, Microchip hace que sea muy fácil
acceder a las E/S individuales en los microcontroladores PIC® y configurar sus
registros asociados. No hay necesidad de meterse con funciones de puntero
esotéricas o lidiar con lógica bit a bit alucinante. De hecho, acceder a pines
individuales para operaciones de E/S en microcontroladores PIC® es más fácil en un
microcontrolador.

Es imperativo recordar que los datos no se moverán del registro del puerto a
los pines del microcontrolador a menos que le dé algún valor al registro TRIS apropiado.

Ahora veamos algunos otros registros importantes.

90
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

PUERTO Registro

Nos hemos referido a los puertos de los microcontroladores PIC® en varias


ocasiones. En el PIC16F1717, hay un total de cinco puertos que van de la A a la E.
Estos puertos tienen un ancho de 8 bits y, por lo tanto, generalmente estos puertos
tienen de 0 a 7 bits. La excepción a esto en el PIC16F1717 es PORTE, que es un 4
Puerto de entrada de 3 bits de ancho y puerto de salida de 3 bits de ancho.
El registro del puerto esencialmente lee los niveles de voltaje de los pines en
el dispositivo.

Registros de enganche de salida

Los registros de bloqueo de salida (LAT) son un tipo de registro importante y


pasado por alto relacionado con las E/S. Antes de las mejoras realizadas por
Microchip en la familia PIC16F, solo la familia 18F contenía registros LAT. Los
registros LAT son una mejora de los registros PORT para escribir datos en la salida.
El registro LAT mejora los problemas asociados con el registro PORT para escribir
datos en los pines. Tenga en cuenta que es recomendable enviar datos a los puertos
usando el registro LATx y leer datos usando el registro PORTx.
Esto se debe a que, como se indicó anteriormente, el registro LAT mejora
cualquier problema que pueda ocurrir simplemente al usar el registro PORT
para la salida de datos. La razón por la que usa el registro PORT para leer datos
de los pines de entrada es porque el registro PORT lee el nivel de voltaje real en el
pin, mientras que una lectura del registro LAT simplemente lee lo mismo sin tener
en cuenta el nivel de voltaje del pin asociado.

Registros de selección analógica

Los registros de selección analógica (ANSEL) se utilizan para habilitar o


deshabilitar las funciones de entrada analógica en un pin en particular. Cuando se
utiliza un pin de E/S en particular para la salida, no es necesario ajustar el registro ANSEL correspondien

91
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

ese poco Sin embargo, si desea utilizar un pin de E/S en particular como pin de
entrada analógica, debe configurar el registro ANSEL correspondiente.

dominada débil

Los puertos del PIC16F1717 tienen resistencias pull-up internas. Estos son
importantes ya que reducen el número de componentes al eliminar la necesidad
de una resistencia externa. El pull-up débil puede usarse como se ve en el Listado 6-1.

Listado 6-1. Ejemplo de pull-up débil

// Primero debemos habilitar pull-ups débiles globalmente

OPTION_REGbits.nWPUEN = 0;

// Luego lo configuramos para el pin individual, en este PINB0 5 WPUBbits.WPUB0


= 1;

Una vez completado esto, podemos conectar un interruptor al microcontrolador.


sin necesidad de una resistencia pull-up externa.
También hay opciones para otros registros asociados con el PUERTO,
incluidos los de control de nivel de entrada, drenaje abierto y control raro de rotación.

Hacer que un LED parpadee

¡Finalmente, llegamos a las partes buenas! Buscamos hacer que un LED


parpadee, que es esencialmente el "hola mundo" de la programación integrada.
Para hacer esto, primero necesitamos conectar el LED al pin que pretendemos
usar. Para este ejemplo, conectamos el LED al PIN RD1.
No olvide conectar una resistencia al LED o corre el riesgo de
dañarlo.

92
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

Revisemos los pasos para crear un proyecto en MPLAB X IDE.

1. Abra el IDE. Se le presentará el inicio


página.

2. Haga clic en el icono Crear nuevo.

3. Seleccione Microchip Embedded seguido de Standalone


Proyecto.

4. Seleccione su familia de dispositivos y dispositivo.

5. Seleccione su programador. En mi caso utilizo el ICD 3; sin


embargo, puede usar el PICkit™ 3 u otro programador de
su elección.

6. Seleccione su compilador. En este caso, es el XC8.

7. Dale a tu proyecto un nombre y una ubicación.

8. Después de crear su proyecto, haga clic derecho y seleccione


Nuevo seguido del archivo de su elección.

Si olvida cómo crear un nuevo proyecto, el Capítulo 5 proporciona un paso a paso


guía paso a paso del proceso.
Ahora puedes escribir algo de código. Con base en lo que ha aprendido, Ud.
puede usar los siguientes pasos para configurar el microcontrolador para I/0.
Repasemos lo que debemos hacer para que esto suceda:

1. Configure el registro TRIS para generar en un determinado


pasador de puerto

2. Apague el registro ANSEL asociado con ese


pin especial.

3. Configure el registro LAT para ese pin.

Sería bueno hacer esto solo, pero primero hay algunas cosas que debemos
hacer. Tan importante como es el software, el hardware es muy importante cuando se
diseña con microcontroladores. A veces, un programa se compilará y no se ejecutará
como se esperaba.
93
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

Primero, conecta el LED a través de una resistencia de 1K a PIND1, como se muestra en

Figura 6-1.

Figura 6-1. LED conectado al microcontrolador PIC®

94
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

Aunque el hardware está conectado, simplemente no puede escribir el


programa principal y hacer que el código funcione. Primero debe crear un
archivo para establecer los bits de configuración del microcontrolador. Escriba
el código primero, luego discutiremos lo que hace. Cree un archivo de encabezado llamado 16F1717
e ingrese el código que se muestra en el Listado 6-2.

Listado 6-2. Archivo de encabezado estándar PIC16F1717

/*
* Archivo: 16F1717_Internal.h
* Autor: Armstrong Subero
* FOTO: 16F1717 con X OSC @ 16MHz, 5v
*
Programa: archivo de encabezado para configurar PIC16F1717

* Compilador: XC8 (v1.35, MPLAX X v3.10)


*
Versión del programa 2.0
**Archivo separado en encabezado y archivo fuente C
**Comentarios y diseño modificados
*
*
Descripción del programa: este encabezado de programa permite
la configuración
* bits y proporciona rutinas para configurar interna
* oscilador e incluye todos los dispositivos y módulos MCU
*

* Creado el 9 de enero de 2016 a las 14:50


**************************************************** ************

***************/

/**************************************************** ************
****************
*Incluye y define
**************************************************** ************

***************/

95
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

// Ajustes de bits de configuración de PIC16F1717

// CONFIG1

#pragma config FOSC = INTOSC // Bits de selección de oscilador


(Oscilador INTOSC: función I/O

en pin CLKIN)

#pragma config WDTE = APAGADO // Habilitar temporizador de vigilancia


(WDT deshabilitado)

#pragma config PWRTE = APAGADO // Habilitar el temporizador de encendido

(PWRT deshabilitado)

#pragma config MCLRE = APAGADO // Selección de función de pin MCLR

(La función de pin MCLR/VPP es


MCLR)

#pragma config CP = APAGADO // Código de memoria del programa Flash

Protección (La protección del

programa\código de memoria está deshabilitada)

#pragma config BOREN = APAGADO // Habilitar restablecimiento de caída de tensión

(Brow-out Reset deshabilitado)

#pragma config CLKOUTEN = OFF // Habilitar salida de reloj (la función CLKOUT está

deshabilitada.
E/S o función de oscilador en el pin

CLKOUT)

#pragma config IESO = ENCENDIDO // Conmutación interna/externa

Modo (Interno/Externo

El modo de cambio está habilitado)

#pragma config FCMEN = APAGADO // Monitor de reloj a prueba de fallas

Habilitar (reloj a prueba de fallas)


El monitor está habilitado)

96
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

// CONFIG2

#pragma config WRT = APAGADO // Autoescritura de memoria flash


Protección (protección contra escritura desactivada)

#pragma config PPS1WAY = ON // Pin periférico Seleccione uno


control de modo (el bit PP\SLOCK no
se puede borrar una vez que se

establece por software)


#pragma config ZCDDIS = ON // Deshabilitar la detección de cruce por cero
(El circuito de detección de cruce por
cero está deshabilitado en POR y se

puede habilitar con el bit ZCDSEN).


#pragma config PLLEN = OFF // Phase Lock Loop habilitado (4x PLL está habilitado
cuando el software establece el bit

SPLLEN)
pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable
(Stack\Overflow o Underflow provocará
un reinicio)
#pragma config BORV = LO // Selección de voltaje de restablecimiento de
apagón (Apagón\Voltaje de reinicio (Vbor),
punto de disparo bajo seleccionado).
#pragma config LPBOR = OFF // Restablecimiento de Brown Out de baja potencia
(El BOR de bajo consumo está deshabilitado)

#pragma config LVP = APAGADO // Habilitar programación de bajo voltaje


(Se debe usar alto voltaje en MCLR/VPP
para la programación)

//XC8 estándar incluido


#incluir <xc.h>
#incluir <stdio.h>
#incluir <stdlib.h>

97
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

//Otro Incluye
#incluir <stdint.h>
#incluir <stdbool.h>
#incluir <stddef.h>
#incluir <matemáticas.h>

//Para rutinas de retraso


#define _XTAL_FREQ 16000000

//Módulos MCU incluidos

//Configuración del oscilador interno


vacío interno_32();
vacío interno_16(); //16MHz
vacío interno_8();
vacío interno_4();
vacío interno_2();
vacío interno_1();
vacío interno_31(); //31kHz

En este libro, utilizo un código muy comentado, por lo que no


se incluyen explicaciones línea por línea. Sin embargo, explico los aspectos
más importantes del código.
Este archivo configura el microcontrolador PIC® con opciones como
relojes, temporizadores de encendido, restablecimientos de apagón y
temporizadores de vigilancia, por nombrar algunos. Estas opciones se
conocen como los bits de configuración del microcontrolador. Si los bits de
configuración no están establecidos, el microcontrolador no se ejecutará. Puede
identificar los bits de configuración por el prefijo #pragma config. Si mira debajo de este bloque, verá vario
archivos El exclusivo del compilador XC8 es <xc.h> y se requiere para
que cada programa se escriba usando el compilador XC8.
Debajo de esta sección, verá una declaración de definición: _
#define XTAL_FREQ 16000000. Esta declaración define la velocidad a la que el

98
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

funciona el microcontrolador, que es de 16 MHz. Para asegurar la consistencia,


en este libro mantenemos esta frecuencia en todo momento.
Descendiendo, notará algunas declaraciones de funciones personalizadas.
Estas declaraciones permiten al usuario cambiar rápida y efectivamente la
velocidad del microcontrolador según sea necesario.
A continuación, miramos el archivo que contiene el cuerpo de las funciones.
Cree otro archivo llamado PIC16F1717_Internal.c e ingrese el código que se
muestra en el Listado 6-3.

Listado 6-3. Archivo fuente estándar PIC16F1717

/*
* Archivo: 16F1717_Internal.c
* Autor: Armstrong Subero
* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: archivo de biblioteca para configurar PIC16F1717
* Compilador: XC8 (v1.35, MPLAX X v3.10)
*
Versión del programa: 1.2
** Se agregaron comentarios adicionales
*
*
Descripción del programa: esta biblioteca le permite configurar un
FOTO16F1717
*

* Creado el 9 de enero de 2016 a las 18:45


*/

/**************************************************** ************
****************

*Incluye y define
**************************************************** ************

***************/
#incluye "16F1717_Internal.h"

99
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

/**************************************************** ************
****************

* Función: interno_32()
*

* Devoluciones: Nada
*
*
Descripción: Ajusta el oscilador interno a 32MHz
*
*
Uso: interno_32()
**************************************************** ************

***************/
//Establecer a
32MHz void internal_32(){
//Reloj determinado por FOSC en bits de configuración
SCS0 = 0;
SCS1 = 0;

// Bits de selección de frecuencia


IRCF0 = 0;
IRCF1 = 1;
IRCF2 = 1;
IRCF3 = 1;

//CONFIGURAR PLLx4 EN

SPLLEN =
1; }

/**************************************************** ************
****************

* Función: interno_16()
*

* Devoluciones: Nada
*

100
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

*
Descripción: Ajusta el oscilador interno a 16 MHz
*
*
Uso: internal_16()
**************************************************** ************

***************/
//Establecer a 16MHz

vacío interno_16(){
//Reloj determinado por FOSC en bits de configuración
SCS0 = 0;
SCS1 = 0;

// Bits de selección de frecuencia


IRCF0 = 1;
IRCF1 = 1;
IRCF2 = 1;
IRCF3 = 1;

//ESTABLECER PLLx4 APAGADO

SPLLEN =
0; }

/**************************************************** ************
****************

* Función: interno_8()
*

* Devoluciones: Nada
*
*
Descripción: Ajusta el oscilador interno a 8 MHz
*
*
Uso: interno_8()
**************************************************** ************

***************/

101
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

//Establecer a 8MHz

vacío interno_8(){
//Reloj determinado por FOSC en bits de configuración
SCS0 = 0;
SCS1 = 0;

// Bits de selección de frecuencia


IRCF0 = 0;
IRCF1 = 1;
IRCF2 = 1;
IRCF3 = 1;

//ESTABLECER PLLx4 APAGADO

SPLLEN =
0; }

/**************************************************** ************
****************

* Función: interno_4()
*

* Devoluciones: Nada
*
*
Descripción: Ajusta el oscilador interno a 4MHz
*
*
Uso: interno_4()
**************************************************** ************

***************/
//Establecer a
4MHz void internal_4(){
//Reloj determinado por FOSC en bits de configuración
SCS0 = 0;
SCS1 = 0;

102
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

// Bits de selección de frecuencia


IRCF0 = 1;
IRCF1 = 0;
IRCF2 = 1;
IRCF3 = 1;

//ESTABLECER PLLx4 APAGADO

SPLLEN =
0; }

/**************************************************** ************
****************

* Función: interno_2()
*

* Devoluciones: Nada
*
*
Descripción: Ajusta el oscilador interno a 2 MHz
*
*
Uso: interno_2()
**************************************************** ************

***************/
//Establecer a 2MHz

vacío interno_2(){
//Reloj determinado por FOSC en bits de configuración
SCS0 = 0;
SCS1 = 0;

// Bits de selección de frecuencia


IRCF0 = 0;
IRCF1 = 0;
IRCF2 = 1;
IRCF3 = 1;

103
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

//ESTABLECER PLLx4 APAGADO

SPLLEN =
0; }

/**************************************************** ************
****************

* Función: interno_1()
*

* Devoluciones: Nada
*
*
Descripción: Ajusta el oscilador interno a 1 MHz
*
*
Uso: interno_1()
**************************************************** ************

***************/
//Establecer a 1MHz

vacío interno_1(){
//Reloj determinado por FOSC en bits de configuración
SCS0 = 0;
SCS1 = 0;

// Bits de selección de frecuencia


IRCF0 = 1;
IRCF1 = 1;
IRCF2 = 0;
IRCF3 = 1;

//ESTABLECER PLLx4 APAGADO

SPLLEN =
0; }

104
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

/**************************************************** ************
****************

* Función: interno_31()
*

* Devoluciones: Nada
*
*
Descripción: Ajusta el oscilador interno a 31kHz
*
*
Uso: internal_31()
**************************************************** ************

***************/
//Establecer a
31kHz(LFINTOSC) void internal_31(){
//Reloj determinado por FOSC en bits de configuración
SCS0 = 0;
SCS1 = 0;

// Bits de selección de frecuencia


IRCF0 = 0;
IRCF1 = 0;
IRCF2 = 0;
IRCF3 = 0;

//ESTABLECER PLLx4 APAGADO

SPLLEN =
0; }

Este archivo implementa las funciones necesarias para establecer la


velocidad del reloj del microcontrolador PIC®.

Ahora viene la parte buena: hacer que el LED se encienda. Todos los
programas en C, como saben, deben contener una función principal.
Tradicionalmente, el archivo que contiene esta función también se llama main. Por
lo tanto, cree un nuevo archivo llamado main.c e ingrese el código, como se muestra en el Listado 6-4.

105
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

Listado 6-4. Archivo fuente de salida PIC16F1717

/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa:
00_Output * Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*
*
*
Descripción del programa: este programa permite que PIC16F1717
encienda un LED
*

* Descripción del hardware: un LED está conectado a través de una resistencia


de 10k al PIN D1
*

* Creado el 4 de noviembre de 2016 a las


13:00 */

/**************************************************** ************
****************

*Incluye y define
**************************************************** ************

***************/

#incluye "16F1717_Internal.h"

/**************************************************** ************
****************

* Función: void initMain()


*

* Devoluciones: Nada
*

106
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************

***************/

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

// Establecer PIN D1 como


salida TRISDbits.TRISD1 =
0; }

/**************************************************** ************
****************
* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************

***************/

vacío principal
(vacío) { initMain ();

while(1){ //
Establecer PIND1
High LATDbits.LATD1
= 1; }

regreso;

107
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

Compile el programa y ejecútelo. ¡El LED debería encenderse! Si el LED


no se enciende, asegúrese de haber probado sus conexiones correctamente.
Muchos problemas se pueden resolver simplemente asegurándose de que todo esté

cableado correctamente.

Genial, el LED se enciende. Sin embargo, queremos que el LED parpadee.


Para hacer esto, debe usar la macro de retardo integrada en XC8. Hay
opciones para retrasar ciclos de reloj, milisegundos o microsegundos. Para
hacer que el LED parpadee, usaremos la opción de milisegundos. Este código se muestra en el Listado

Listado 6-5. Archivo fuente flash PIC16F1717

/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: 01_Flash
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*

9 *
*
Descripción del programa: este programa permite que PIC16F1717
parpadee un LED en
* 50% ciclo de trabajo
*

* Descripción del hardware: un LED está conectado a través de una resistencia


de 10k al PIN D1
*

* Creado el 4 de noviembre de 2016 a las 13:08


*/

108
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

/**************************************************** ************
****************
*Incluye y define
**************************************************** ************

***************/

#incluye "16F1717_Internal.h"

/**************************************************** ************
****************
* Función: void initMain()
*
* Devoluciones: Nada
*
*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************

***************/

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

// Establecer PIN D1 como


salida TRISDbits.TRISD1 =
0; }

/**************************************************** ************
****************
* Función: Principal
*
* Devoluciones: Nada
*

109
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

*
Descripción: Punto de entrada del programa
**************************************************** ************

***************/

vacío principal (vacío) {


initPrincipal();

mientras(1){
// Alternar LED
LATDbits.LATD1 = ~LATDbits.LATD1;

// retraso 500ms
__retraso_ms(500);
}

regreso;

La macro __delay_ms le permite retrasar un período de tiempo particular.


Usamos el operador NOT bit a bit para alternar el LED.

Uso de un pulsador
Ahora que examinamos la salida, veamos la entrada. Como se mencionó
anteriormente, el registro TRIS debe configurarse para permitir que el pin de E/S actúe como una entrada.
También usamos el pull-up interno para evitar el uso de una resistencia externa.
Como hicimos con la salida, también hay un proceso para convertir el pin en
un pin de entrada. Estos son los pasos para configurar un pin como entrada
usando las resistencias pull-up débiles internas en el chip:

1. Configure el registro TRIS para ese pin como entrada.

2. Apague el ANSEL para ese pin en particular.

3. Habilite pull-ups débiles globalmente.

4. Habilite los pull-ups débiles para ese pin en particular.


110
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

El esquema de la Figura 6-2 muestra cómo conectamos el


interruptor y el LED. El LED queda conectado a RD1 y ahora conectamos el interruptor
a RB0.

Figura 6-2. LED con pulsador conectado a un PIC®


microcontrolador

111
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

El Listado 6-6 muestra el código principal. Los archivos de encabezado y los bits
de configuración son los mismos que en el último ejemplo.

Listado 6-6. PIC16F1717 Pulsador con pull-up débil interno


/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: 02_Internal_Pullups
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*
*
*
Descripción del programa: este programa permite que PIC16F1717 gire
en un LED basado
* en un pulsador
*

* Descripción del hardware: un LED está conectado a través de una


resistencia de 1k al PIN D1 y un
* el interruptor está conectado al PIN B0
*

* Creado el 4 de noviembre de 2016 a las 13:08


*/

/**************************************************** ************
****************

*Incluye y define
**************************************************** ************

***************/

#incluye "16F1717_Internal.h"

112
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

/**************************************************** ************
****************

* Función: void initMain()


*

* Devoluciones: Nada
*
*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************

***************/

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

// Establecer PIN D1 como


salida TRISDbits.TRISD1 = 0;

// Apagar LED
LATDbits.LATD1 = 0;

// Establecer PIN B0 como


entrada TRISBbits.TRISB0 = 1;

// Configurar ANSELB0
ANSELBbits.ANSB0 = 0;

// Habilitar pullups débiles


globales OPTION_REGbits.nWPUEN = 0;

// Habilitar pullup débil en PINB0


WPUBbits.WPUB0 = 1; }

113
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

/**************************************************** ************
****************
* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************

***************/

vacío principal (vacío) {


initPrincipal();

mientras(1){
// Activar LED en pulsador
LATDbits.LATD1 = ~PORTBbits.RB0;
}

regreso;

Puede haber momentos en los que sea necesario eliminar el rebote de su interruptor.
El rebote es cuando permite que el microcontrolador solo reconozca
que el interruptor se presionó una vez, incluso cuando se presiona varias veces.
Algunos interruptores de muy mala calidad pueden hacer múltiples
contactos con solo presionar un botón. Esto, a su vez, hace que el
microcontrolador registre varias veces que se presiona el interruptor.
Hay varias opciones para eliminar rebotes, incluidos los métodos de
hardware y software. Sin embargo, descubrí que en la práctica, los botones
mecánicos de alta calidad que se utilizan para crear prototipos de
aplicaciones no necesariamente necesitan eliminar el rebote, especialmente
para aplicaciones tan triviales como la nuestra. Sin embargo, si está
diseñando un producto comercial, se recomienda encarecidamente que agregue antirrebote a sus inte

114
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

Si necesita eliminar el rebote de su interruptor, puede hacerlo usando el software


y el método simple que se muestra en el Listado 6-7. Simplemente reemplace el
código después del comentario // Toggle LED on pushbutton en el Listado 6-6 con este código.

Listado 6-7. Fragmento antirrebote de botón

// Comprueba si el interruptor está presionado

si (RB0 == 0)
{
// breve retraso
__retraso_ms(100);

// si el interruptor sigue presionado


si (RB0 == 0)
{
// enciende el led
LATDbits.LATD1 = 1;
}
}

demás{

// mantener el LED apagado

LATDbits.LATD1 = 0;
}

Usamos el método de ingresar un breve retraso después de que se detecta la


presión inicial del botón, luego volvemos a verificar el interruptor antes de realizar
cualquier otra acción. Si el interruptor sigue cerrado, encendemos el LED. Tenga
en cuenta también que el tiempo de retraso real antes de volver a comprobar puede variar según el interr
Por lo tanto, debe probar el tiempo de retardo para asegurarse de que sea
compatible con su botón en particular.

115
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

También puede haber un momento en el que no desee utilizar la debilidad interna


levantar. En este caso, puede omitir todas las partes del código relacionadas
con la configuración de las resistencias pull-up débiles. Así es como lo haces.
Agrega una resistencia pull up externamente, que se conecta como se muestra
en el esquema de la Figura 6-3.

Figura 6-3. Conexión del interruptor con pull-up externo

116
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

Lo único que cambia en la configuración del hardware es la adición


de una resistencia pull-up. El valor estándar de la resistencia pull-up es 10k.
En cuanto al software, eliminaremos las partes del código que configuran
los pull-ups internos para su uso (vea el Listado 6-8).

Listado 6-8. PIC16F1717 Pulsador sin pull-up interno


/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: 03_Pushbutton
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*
*
*
Descripción del programa: este programa permite que PIC16F1717
encienda un LED
* basado en un pulsador
*

* Descripción del hardware: un LED está conectado a través de una


resistencia de 10k al PIN D1 y un
* el interruptor está conectado al PIN B0
*

* Creado el 4 de noviembre de 2016 a las


13:08 */

/**************************************************** ************
****************

*Incluye y define
**************************************************** ************

***************/

#incluye "16F1717_Internal.h"

117
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

/**************************************************** ************
****************

* Función: void initMain()


*

* Devoluciones: Nada
*
*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************

***************/

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

// Establecer PIN D1 como


salida TRISDbits.TRISD1 = 0;

// Apagar LED
LATDbits.LATD1 = 0;

// Establecer PIN B0 como


entrada TRISBbits.TRISB0 = 1;

// Configurar ANSELB0
ANSELBbits.ANSB0 = 0;

/**************************************************** ************
****************
* Función: Principal
*

* Devoluciones: Nada

118
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

*
*
Descripción: Punto de entrada del programa
**************************************************** ************

***************/

vacío principal (vacío) {


initPrincipal();

mientras(1){
// Alternar LED en el botón PUSH
LATDbits.LATD1 = ~PORTBbits.RB0;
}

regreso;

Pantallas de siete segmentos


Las pantallas LCD y OLED son, sin duda, las opciones más populares para
transmitir la salida a los usuarios de sistemas integrados. Agregar una pantalla
agregará costos a su sistema. Habrá momentos en los que querrá dar salida a
los usuarios y la mera salida LED no será suficiente. En tales casos, puede
utilizar una pantalla de siete segmentos para dar a los usuarios un poco más de información.
Las pantallas de siete segmentos son básicamente paquetes que
tradicionalmente contienen siete LED. Si cuenta el segmento de punto decimal
disponible en la mayoría de las pantallas de siete segmentos, en realidad son
ocho. Cada uno de los LED de este paquete se denomina segmento. De ahí el
nombre de pantalla de siete segmentos; consulte la Figura 6-4.
Estos LED pueden emitir dígitos hexadecimales en forma de dígitos
0-F. Estas pantallas también vienen en dos variedades, que pueden ser
de ánodo común o de cátodo común. En este libro, usamos la variedad de
cátodo común. La figura 6-4 muestra cómo se organizan los dígitos de un
LED de siete segmentos de cátodo común.

119
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

Figura 6-4. Un pinout de pantalla de siete segmentos

Como ves, cada pin está asociado con una letra AG, y también hay un pin
para el punto decimal marcado como DP. Hay dos pines marcados COM.
Esta es la abreviatura de "común" y se conectará a tierra.
Para mostrar números en la pantalla, los segmentos asociados con ese pin
están activados. Por ejemplo, para mostrar el número 8, todos los segmentos del
LED estarían encendidos. Estos pines luego se conectarían a un puerto particular en
el microcontrolador. Luego, los números se enviarían al puerto del microcontrolador
al que está conectada la pantalla de siete segmentos.
Dado que la pantalla de siete segmentos es, después de todo, un grupo de
LED en un solo paquete, debe conectar resistencias a cada segmento de las
pantallas para asegurarse de no dañarlas.
Tenga en cuenta que si está utilizando la variedad de ánodo común, el hexadecimal
los números enviados al puerto serán ligeramente diferentes. Esto se debe a que
en la variedad de ánodo común, todos los LED están conectados a la alimentación
en lugar de a tierra.

120
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

Ahora que tiene una idea clara de cómo funcionan estas pantallas, vamos a
mire el esquema para conectar la pantalla de siete segmentos al microcontrolador
(vea la Figura 6-5). Los pines están conectados a PORTD, con A conectado a RD0, B
conectado a RD1, y así sucesivamente, hasta que todos los pines estén conectados con
la excepción del pin del punto decimal. El común está conectado a tierra.

Figura 6-5. PIC16F1717 con siete segmentos conectados

Ahora escribimos el código requerido para usar una pantalla de siete segmentos,
como se muestra en el Listado 6-9.

121
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

Listado 6-9. PIC16F1717 Pantalla de siete segmentos

/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: I01_Seven_Segment
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*
*
Descripción del programa: este programa permite que PIC16F1717
controle una sola pantalla de siete segmentos, muestra el hexadecimal
*

* dígitos 0-F en la pantalla de siete segmentos.


*

* Descripción del hardware: una pantalla de siete segmentos de la


variedad de cátodo está * conectada al puerto D del microcontrolador a
través de resistencias de 1k *.

* Creado el 16 de febrero de 2017 a las


18:31 */

/**************************************************** ************
****************

*Incluye y define
**************************************************** ************

***************/

#incluye "16F1717_Internal.h"

Visualización de caracteres sin firmar (dígito de caracteres sin firmar);

122
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

/**************************************************** ************
****************

* Función: void initMain()


*

* Devoluciones: Nada
*
*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************

***************/

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

// Establecer PORTD como salida


TRISD = 0;
ANSELD =
0; }

/**************************************************** ************
****************
* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************

***************/

123
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

vacío principal (vacío) {

// variable de bucle
ent yo;

initPrincipal();

// Sigue mostrando los dígitos 0-F


// y actualizarlo cada segundo
mientras(1){
para (i = 0; i <= 15; i++){
// Ahora los valores hexadecimales para la matriz se derivan en función del
tipo de pantalla // de siete segmentos. En nuestro caso utilizamos la versión
de cátodo común.

// Por ejemplo, para mostrar el número '7', esto significa que debemos tener
los segmentos // a, b y c habilitados. Esto sería "0000111" en binario con
un '1' que significa // el segmento en particular. Esto equivaldría a 0x07 en
hexadecimal. Así que cuando

//'0x07' se escribe en el PORTD.


// basado en la iteración de la matriz por el ciclo for, mostramos cada
letra
// a PUERTO.

LATD = Pantalla(i);
__retraso_ms(1000);
}

regreso;

124
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

/**************************************************** ************
****************

* Función: visualización de caracteres sin firmar (dígito de caracteres sin firmar)


*

* Devoluciones: números de caracteres sin firmar


*
*
Descripción: Función que toma un número y devuelve su índice en
un arreglo
* correspondiente al dígito hexadecimal
**************************************************** ************

***************/

Visualización de caracteres sin firmar (dígito de caracteres sin firmar)

{
// variable que representa numeros
números de caracteres sin firmar;

// una matriz de los dígitos 0-F


carácter sin signo DIGITS[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D,
0x07, 0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71};

// asigna el índice dado por el usuario a la variable


números = DÍGITOS[dígito];

// devolverlo
números de retorno;
}

Multiplexación de pantalla de siete segmentos


Hay momentos en los que querrá usar más de una pantalla de siete
segmentos en su aplicación. Una pantalla de siete segmentos generalmente
usa un puerto completo de su microcontrolador (vea la Figura 6-6).
¡Conducir dos pantallas de siete segmentos usaría alrededor de 16 pines de su microcontrola

125
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

casi la mitad de los pines del PIC16F1717. Para evitar esto, puede usar un
microcontrolador con mayor número de pines, que cuesta más y aumenta el
costo total de su sistema, o puede usar multiplexación.

Figura 6-6. Pantalla multiplexada de siete segmentos PIC16F1717

La multiplexación de pantallas es el proceso de usar pantallas de tal


manera que no se enciende toda la pantalla al mismo tiempo. Lo que esto
significa para las pantallas de siete segmentos es que solo un dígito está
encendido a la vez. Sin embargo, el microcontrolador cambia entre actualizar
estas dos pantallas tan rápido que los usuarios no pueden detectarlo. Para
multiplexar estas pantallas, usamos transistores para encender y apagar las pantallas.
La principal ventaja de la multiplexación es que utiliza menos E/S en
el microcontrolador. Veamos cómo podemos multiplexar pantallas de siete
segmentos en el PIC16F1717 (vea el Listado 6-10).

126
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

Listado 6-10. Pantalla doble de siete segmentos PIC16F1717

/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: I02_Seven_Segment_Mul
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*
*
Descripción del programa: este programa permite que PIC16F1717 conduzca dos
* pantallas multiplexadas de siete segmentos, muestra los
* números del 0 al 99 en las pantallas dependiendo de *
cuál de los dos botones se presiona.
*

* Descripción del hardware: Las pantallas duales de siete


segmentos de la variedad de cátodos están * conectadas al puerto
D del microcontrolador a través de resistencias de 1k *. Hay dos
transistores conectados en
*
configuración de emisor común en los pines RB0 y
RB1* respectivamente. También hay dos pulsadores conectados
* a los pines RC4 y RC5.
*

* Creado el 16 de febrero de 2017 a las


21:55 */

/**************************************************** ************
****************

*Incluye y define
**************************************************** ************

***************/

127
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

#incluye "16F1717_Internal.h"

Visualización de caracteres sin firmar (dígito de caracteres sin firmar);

// habilitar dígito uno


#define DIGITONE LATB0

// habilitar dígito dos


#define DIGITTWO LATB1

/**************************************************** ************
****************

* Función: void initMain()


*

* Devoluciones: Nada
*
*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************

***************/

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

// Establecer PORTD como salida


// Analógico deshabilitado
TRISD = 0;
ANSELD = 0;

// Establecer PORTB como salida


// Analógico deshabilitado
TRIB = 0;
ANSELB = 0;

128
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

// Establecer RC4 y RC5 como


entrada TRISCbits.TRISC4 = 1;
TRISCbits.TRISC5 = 1;

// Activar analógico en C
ANSELC = 0;

// Habilitar pullups débiles globales


OPTION_REGbits.nWPUEN = 0;

// Habilitar pullup débil en RC4 y RC5


WPUCbits.WPUC4 = 1; WPUCbits.WPUC5
= 1; }

/**************************************************** ************
****************
* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************

***************/

vacío principal (vacío) {

// variable de conteo
conteo int = 0;

// dígito más significativo int


MSD;

// dígito menos significativo int


LSD;

initPrincipal();

129
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

// Sigue mostrando los dígitos 0-F // y


actualízalo cada segundo while(1){

// Si RC4 presionó incrementa el conteo


if(RC4 == 0){ __delay_ms(100);

si (RC4 == 0)
{ contar++; } }

// SI RC5 presionó cuenta decreciente si (RC5


== 0) { __delay_ms(100);

if(RC5 == 0)
{ contar--; } }

// Obtener MSD y LSD

MSD = recuento/10;
LSD = recuento% 10;

// Mostrar MSD
LATD = Pantalla (MSD);
DIGITO DOS = 1;
__retraso_ms(20);
DIGITO DOS = 0;

130
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

// Mostrar LSD
LATD = Pantalla (LSD);
DIGITONO = 1;
__retraso_ms(20);
DIGITONO = 0;

// Si el valor no es válido, se
establece en 0 si (cuenta > 99 ||
cuenta < 0){ cuenta = 0; }

__retraso_ms(1); }

regreso;

/**************************************************** ************
****************

* Función: visualización de caracteres sin firmar (dígito de caracteres sin firmar)


*

* Devoluciones: números de caracteres sin firmar


*
*
Descripción: Función que toma un número y devuelve su índice en
un arreglo * correspondiente al dígito hexadecimal

**************************************************** ************

***************/

visualización de caracteres sin signo (dígito de


caracteres sin signo) { // variable que representa
números números de caracteres sin signo;

131
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

// una matriz de los dígitos 0-F


carácter sin signo DIGITS[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07,
0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71};

// asigna el índice dado por el usuario a la variable


números = DÍGITOS[dígito];

// devolverlo

números de retorno;
}

Este programa muestra el dígito más significativo (MSD) dividiendo el


conteo actual por 10. El dígito menos significativo (LSD) se encuentra
encontrando el módulo del conteo y 10. Se usan dos botones para incrementar
y decrementar el conteo. Si el usuario intenta ingresar un conteo de más de 99

o menos de 0, el contador se restablece a 0. El programa se ejecuta en un bucle de 1


ms y se puede ver una ligera fluctuación en las pantallas de siete segmentos.

Proyecto: Temporizador de cuenta regresiva

Aunque no hemos cubierto mucho, todavía podemos construir un proyecto útil.


Usaremos el conocimiento que hemos adquirido hasta ahora para hacer un
cronómetro de cuenta regresiva básico. La idea es construir un temporizador
que pueda contar hacia atrás desde un valor de hasta 99 segundos según lo que
establezca el usuario. Usaremos un botón para aumentar el tiempo, uno para
disminuir el tiempo y otro botón para comenzar la cuenta regresiva. El esquema de este circuito se mues
y el código se muestra en el Listado 6-11.

132
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

Figura 6-7. Esquema del proyecto del temporizador de cuenta regresiva PIC16F1717

133
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

Listado 6-11. Código de proyecto del temporizador de cuenta regresiva PIC16F1717

/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: P01_Countdown_Timer
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*
*
Descripción del programa: este programa permite que PIC16F1717 realice
una cuenta regresiva desde un
* tiempo de hasta 99 segundos determinado por el
* usuario.
*

* Descripción del hardware: las pantallas duales de siete segmentos


de la variedad de cátodos son
* conectado al puerto D del microcontrolador a través de 1k
* resistencias. Hay dos transistores conectados en
*
configuración de emisor común en los pines RB0 y RB1
* respectivamente. También hay dos pulsadores conectados
* a los pines RC4 y RC5 utilizados para decrementar y
*
incrementando También hay un botón conectado a
* RC6 solía comenzar la cuenta atrás.
*

* Creado el 16 de febrero de 2017 a las 23:16


*/

/**************************************************** ************
****************

*Incluye y define
**************************************************** ************

***************/

134
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

#incluye "16F1717_Internal.h"

visualización de caracteres sin firmar (dígito de caracteres


sin firmar); void countDown (número de caracteres sin
firmar); void showNumber(número de caracteres sin firmar);

// puerto de
visualización #define DISPLAYPORT LATD

// habilitar dígito uno


#define DIGITONE LATB0

// habilitar dígito dos


#define DIGITTWO LATB1

/**************************************************** ************
****************

* Función: void initMain()


*

* Devoluciones: Nada
*
*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************

***************/

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

// Establecer PORTD como salida


// Analógico deshabilitado
TRISD = 0;
ANSELD = 0;

135
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

// Establecer PORTB como salida


// Analógico deshabilitado
TRIB = 0;
ANSELB = 0;

// Establecer RC4, RC5 y RC6 como


entrada TRISCbits.TRISC4 = 1;
TRISCbits.TRISC5 = 1;
TRISCbits.TRISC6 = 1;

// Activar analógico en C
ANSELC = 0;

// Habilitar pullups débiles


globales OPTION_REGbits.nWPUEN = 0;

// Habilitar pullup débil en RC4, RC5 y RC6


WPUCbits.WPUC4 = 1; WPUCbits.WPUC5 = 1;
WPUCbits.WPUC6 = 1; }

/**************************************************** ************
****************
* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************

***************/

vacío principal (vacío) {

136
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

// variable de conteo

recuento de caracteres sin firmar = 0;

initPrincipal();

mientras(1){

// Si RC4 presionó incrementa el conteo if(RC4


== 0){ __delay_ms(100);

si (RC4 == 0){ contar+


+; } }

// Si RC5 presionó decrementa la cuenta si (RC5


== 0) { __delay_ms(100);

if(RC5 == 0)
{ contar--; } }

// Si se presiona RC6 comienza la cuenta


regresiva if (RC6 == 0) { __delay_ms(100);

si (RC6 == 0){ cuenta

regresiva (cuenta); } }

137
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

// Si el valor no es válido, se
establece en 0 si (cuenta > 99 ||
cuenta < 0){ cuenta = 0; }

// mostrar el número en
pantalla showNumber(count);

__retraso_ms(1); }

regreso;

/**************************************************** ************
****************

* Función: visualización de caracteres sin firmar (dígito de caracteres sin firmar)


*

* Devoluciones: números de caracteres sin firmar


*
*
Descripción: Función que toma un número y devuelve su índice en
un arreglo * correspondiente al dígito hexadecimal

**************************************************** ************

***************/

visualización de caracteres sin signo (dígito de


caracteres sin signo) { // variable que representa
números números de caracteres sin signo;

// una matriz de dígitos 0-F unsigned


char DIGITS[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07,0x7F,
0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71};

138
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

// asigna el índice dado por el usuario a


números variables = DIGITS[digit];

// devolverlo
números de
retorno; }

/**************************************************** ************
****************

* Función: cuenta regresiva nula (número de caracteres sin firmar)


*

* Devoluciones: nada
*
*
Descripción: comienza una cuenta regresiva basada en el número
pasado a la función
**************************************************** ************

***************/

void countDown (número de caracteres sin


firmar) { // contador de bucle int i;

// comienza la cuenta
atrás para (i = número; i >= 0; i--)
{ showNumber(i);
__retraso_ms(1000); }

regreso;

139
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

/**************************************************** ************
****************

* Función: void shownumber (número de caracteres sin firmar)


*

* Devoluciones: nada
*
*
Descripción: Muestra un número en el puerto especificado
**************************************************** ************

***************/

void showNumber(número de caracteres sin


firmar) { // dígito más significativo MSD de
caracteres sin firmar;

// dígito menos significativo sin


signo char LSD;

// Obtener MSD y LSD

MSD = número/10;
LSD = número% 10;

// Mostrar MSD
DISPLAYPORT = pantalla (MSD);
DIGITO DOS =
1; __retraso_ms(20);
DIGITO DOS = 0;

// Mostrar LSD
DISPLAYPORT = pantalla (LSD);
DIGITONO = 1;
__retraso_ms(20);
DIGITONO = 0;

140
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

Si hubiéramos cubierto las interrupciones y los temporizadores, este proyecto habría sido
mucho más eficiente y eficaz. Actualmente, durante la cuenta regresiva, las pantallas
parpadean cada segundo. Esto se debe a que, como estamos usando la función de
retardo, durante un segundo el microcontrolador no hace nada. Cuando aprenda sobre
los temporizadores en el Capítulo 8, puede volver a visitar este proyecto y usar uno de
los módulos de temporizador integrados si lo desea.

Selección de pin periférico


Aunque no lo usaremos en este capítulo, echemos un vistazo rápido al módulo
Peripheral Pin Select (PPS). En los microcontroladores PIC® más antiguos, los
puertos de E/S tenían funciones fijas con respecto a qué pines accedían a los
periféricos. En los microcontroladores PIC® más nuevos, se introdujo PPS para
evitar este problema.
Como puede ver en la Figura 6-8, los pines del PIC16F1717 no tienen una entrada
y salida periférica fija. Esto proporciona enormes posibilidades con respecto a la
disposición de la placa y el diseño del circuito. Antes de tener PPS, los diseñadores
tenían que diseñar su circuito alrededor del chip. Si bien esto aún puede ser cierto hoy
en día, el requisito no es tan crítico, ya que es más fácil ajustar en qué pines del chip
coloca su salida o entrada periférica. Esto también hace posible reconfigurar a qué
pines accede el microcontrolador en tiempo de ejecución y también permite un camino
más fácil para la migración de diseños heredados a otros más nuevos. PPS es una
característica muy poderosa.

141
Machine Translated by Google

CAPÍTULO 6 ENTRADA Y SALIDA

Figura 6-8. Asignación de pines PIC16F1717

Conclusión
Este capítulo analizó cómo usar la entrada y salida en un PIC®
microcontrolador mientras observa sus aplicaciones de conducción de LED,
interruptores y pantallas de siete segmentos. Cubrimos la multiplexación de
pantallas y vio cómo crear un proyecto simple utilizando lo que ha aprendido hasta ahora.

142
Machine Translated by Google

CAPÍTULO 7

Actuadores de interfaz
Introducción a los actuadores
Hasta ahora, hemos cubierto la entrada y salida de los microcontroladores PIC®.
En este capítulo, aplicamos el conocimiento que aprendimos hasta ahora
para controlar tres actuadores comunes en sistemas integrados: el motor
de CC, el motor paso a paso y el servomotor. Examinamos de forma
incremental estos tres actuadores en función de su capacidad para ser
controlados. Comenzamos con el motor de CC, que tiene un control de
direccionalidad muy aproximado (hacia adelante o hacia atrás) y es el más
fácil de controlar. A continuación, observamos el servo, que tiene un mayor
grado de capacidad de control, ya que se puede colocar en uno de tres ángulos.
Finalmente, el motor paso a paso tiene el nivel más fino de granularidad y el control se reduce a un

Motor de corriente continua

Al introducir la actuación en sistemas integrados, los tres tipos más


comunes de actuadores son neumáticos, hidráulicos y eléctricos. De estos
tres, la actuación eléctrica es la más fácil y económica de diseñar y crear
prototipos. Una amplia gama de dispositivos, desde cerraduras electrónicas
hasta coches de juguete y robots, utilizan motores eléctricos. Antes de que
veamos el uso de un motor eléctrico, analicémoslo un poco. Hay dos tipos de motores eléctricos.
Los hay que funcionan con corriente alterna y los que funcionan con
corriente continua. Para las aplicaciones, veremos la variedad de CC,
específicamente el motor de CC con escobillas.

143
© Armstrong Subero
2018 A. Subero, Programación de microcontroladores
PIC con XC8, https://doi.org/10.1007/978-1-4842-3273-6_7
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

Los motores de CC funcionan según el principio de corriente que


fluye a través de un campo magnético, creando así una fuerza. Los motores
eléctricos se utilizan para convertir la energía eléctrica en energía mecánica. Los
motores de CC contienen dos terminales de entrada y la aplicación de un voltaje a
través de estos terminales hace que el eje del motor gire. Cuando se aplica voltaje
positivo, el motor gira en una dirección; cuando se aplica voltaje negativo, gira en la otra dirección.
Para conectar correctamente un motor de CC a un microcontrolador, podemos
usar relés, MOSFET o transistores. La razón es simple:

Si conecta un motor de CC directamente al pin de su microcontrolador,


¡lo dañará!

Eso sí, los microcontroladores PIC® son muy difíciles de destruir en


comparación con otros microcontroladores. He tenido microcontroladores PIC®
que echaban humo y luego funcionaron durante años después de que se solucionó
el problema, ¡y todavía funcionan! Sin embargo, para asegurarse de tener un
microcontrolador PIC® feliz, no conecte el motor directamente a un pin de E/S.
La razón por la que no puede conectar un motor directamente a un PIC®
microcontrolador es que una carga inductiva como un motor requiere una gran
cantidad de corriente. Los pines I/O de un microcontrolador PIC® son incapaces
de suministrar la corriente requerida por el motor. Para interconectar pequeños
motores de CC, como pequeños motores de pasatiempo o motores de vibración
que se usan comúnmente para la retroalimentación háptica en sistemas
integrados, recomiendo usar un transistor simple al crear prototipos. La razón es
que cuando se trabaja con MOSFET, se deben tomar precauciones adicionales para evitar daños por está
Entonces puede crear un prototipo con un transistor y usar un MOSFET para
su diseño final.
La figura 7-1 muestra cómo se conecta un motor de CC al microcontrolador.

144
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

Figura 7-1. Motor de accionamiento con PIC16F1717

El valor de la resistencia, el diodo y los capacitores varía según el


tamaño del motor. Para nuestros propósitos, la resistencia puede ser de 1k, el diodo

de 1N4001 estándar y el capacitor de tipo cerámico de 0.1uF. El transistor puede ser un


2n2222 o un 2n3904; sin embargo, se puede sustituir casi cualquier transistor NPN.
Asegúrese de consultar la hoja de datos de su motor.
El código es bastante simple, como se muestra en el Listado 7-1.

145
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

Listado 7-1. Control de motores PIC16F1717

/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa:
07_Motor * Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*
*
*
Descripción del programa: este programa permite que PIC16F1717 gire
en un motor
*

* Descripción del hardware: según los esquemas


*

* Creado el 4 de noviembre de 2016 a las


13:00 */

/**************************************************** ************
****************

*Incluye y define
**************************************************** ************

***************/

#incluye "16F1717_Internal.h"

/**************************************************** ************
****************

* Función: void initMain()


*

* Devoluciones: Nada
*

146
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************

***************/

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

// Establecer PIN D0 como


salida TRISDbits.TRISD0 = 0;

}
/**************************************************** ************
*******
* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************

******/

vacío principal
(vacío) { initMain ();

// Enciende el motor por 5


segundos while(1){ LATD0 = !
LATD0; __retraso_ms(5000);

regreso;
}

147
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

Esto debería ser suficiente para impulsar motores pequeños para aplicaciones triviales.

Si miramos el código, la línea que es responsable de encender el motor es LATD0 = !LATD0.

Al igual que en el programa LED, esta línea eleva el pin durante un período de cinco segundos,

lo que enciende el transistor.

Cuando el bucle while se ejecuta de nuevo, el pin tiene una salida baja, lo que apaga el

transistor durante un período de cinco segundos. Verá que incluso una aplicación simple,

como hacer parpadear un LED, se puede modificar para realizar otras tareas en el mundo real.

Este es el poder de los microcontroladores. El tiempo de encendido y apagado de cinco

segundos lo determina el usuario y usted puede modificarlo como mejor le parezca. Si desea

que el motor gire en la otra dirección, puede hacerlo modificando el circuito y simplemente

cambiando las terminales del motor. Para hacerlo, conecte el terminal positivo a tierra y conecte

el terminal negativo al emisor del transistor.

Sin embargo, como estamos usando un microcontrolador, te recomiendo que uses

controles inteligentes para modificar la dirección del motor. En un capítulo posterior,

cubriremos la modulación de ancho de pulso (PWM). En ese mismo capítulo, veremos cómo

controlar un motor usando el PWM en el PIC®


microcontrolador para controlar un controlador de motor.

Servo motor
Ahora que tiene una comprensión justa del motor de CC, veamos el servomotor. Hay

muchos tipos y tamaños diferentes de servos. Hay servos de CA que se usan normalmente

para aplicaciones industriales y servos de CC que se usan comúnmente para aplicaciones

más pequeñas. De hecho, hay servos que se usan exclusivamente para robots y se conocen

como servos robóticos. Tienen un torque ridículo para su tamaño.

148
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

Cuando hablamos de torque, estamos hablando de la fuerza máxima


el servo puede dar salida. El servo normalmente tiene tres cables. Un cable está
conectado a la alimentación, el otro a tierra y el último se conoce como cable de
señal y está conectado al pin del microcontrolador. No entraremos en las complejidades
internas de cómo se construyen los servomotores.
Para nuestros propósitos, todo lo que necesitamos saber es que un servo contiene
circuitos de control en su interior. Por lo tanto, todo lo que tenemos que hacer es
decirle a este circuito de control a qué posición mover el servomotor.
Para decirle al servomotor a qué posición debe ir, enviamos un pulso en el cable
de señal. De acuerdo con el ancho del pulso (básicamente cuánto dura el pulso alto),
el motor girará hacia la ubicación deseada. Un servomotor puede moverse a uno de
tres ángulos: 0 grados, 90 grados o 180 grados.

Hay una excepción a esto, que es el servo de rotación continua.


Puede girar 360 grados completos.
La técnica de variar el ancho de un pulso se conoce como modulación de ancho de
pulso y la discutiremos en capítulos posteriores. Por ahora, sepa que controlamos el
servo cambiando la duración del pulso en su cable de señal. Para aplicaciones sencillas,
recomiendo los servos de metal, ya que tienen más torque para su tamaño y son más
precisos y duraderos.
Conecte el servomotor como se muestra en la Figura 7-2.

149
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

Figura 7-2. Servo de conducción con PIC16F1717

Cree un archivo llamado Servo.h y use el código del Listado 7-2.

Listado 7-2. Archivo de encabezado de servo

/*
* Archivo: Servo.h
* Autor: Armstrong Subero
* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: Archivo de cabecera para controlar un servo
estándar * Compilador: XC8 (v1.38, MPLAX X v3.40)

150
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

*
Versión del programa 1.0
*
*
Descripción del programa: este encabezado de programa le permitirá
controlar un estándar
* servo
*
*

* Creado el 14 de enero de 2017 a las 21:15


*/

/**************************************************** ************
****************
*Incluye y define
**************************************************** ************

***************/
#incluye "16F1717_Internal.h"

vacío servoRotar0(); //0 Grado

vacío servoRotar90(); //90 grados

vacío servoRotar180(); //180 grados

Ahora debe crear un archivo fuente llamado Servo.c, que contiene


el código del Listado 7-3.
Listado 7-3. Archivo fuente de servos

/*
* Archivo: Servo.c
* Autor: Armstrong Subero
* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: archivo de biblioteca para configurar PIC16F1717
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*

151
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

*
Descripción del programa: esta biblioteca le permite controlar un
servo estándar
*

* Creado el 14 de enero de 2017 a las 22:41


*/

#incluye "16F1717_Internal.h"

/**************************************************** ************
****************
* Función: void servoRotate0()
*

* Devoluciones: Nada
*
*
Descripción: Gira el servo a la posición de 0 grados
*
**************************************************** ************

****************/

void servoRotate0()
{ unsigned int i;
para(i=0;i<50;i++) {

RD0 =
1; __delay_us(700);
RD0 =
0;
__delay_us(19300); } }

152
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

/**************************************************** ************
****************

* Función: anular servoRotate90()


*

* Devoluciones: Nada
*
*
Descripción: Gira el servo a la posición de 90 grados
*
**************************************************** ************

****************/

void servoRotate90() //90 Grados


{ sin firmar int i; para(i=0;i<50;i++)
{

RD0 =
1; __delay_us(1700);
RD0 =
0;
__delay_us(18300); } }

/**************************************************** ************
****************

* Función: anular servoRotate90()


*

* Devoluciones: Nada
*
*
Descripción: Gira el servo a la posición de 180 grados
*
**************************************************** ************

****************/

153
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

void servoRotate180() //180 grados


{ unsigned int i; para(i=0;i<50;i++) {

RD0 = 1;
__delay_us(2600);
RD0 = 0;
__delay_us(17400); }

El listado 7-4 proporciona el código principal.

Listado 7-4. Archivo principal del servo

/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: I02_Servo_Motor
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*
*
*
Descripción del programa: Esto demuestra el uso de un servo en una imagen
microcontrolador
*

* Descripción del hardware: un microservo MG90s está conectado al PIN


RD0

* Creado el 14 de enero de 2017 a las 22:30 */

154
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

/**************************************************** ************
****************

*Incluye y define
**************************************************** ************

***************/

#incluye "16F1717_Internal.h"
#incluye "Servo.h"
**************************************************** ************

****************
* Función: void initMain()
*

* Devoluciones: Nada
*
*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************

***************/

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();
/////////////////////
// Configurar
puertos ///////////////////

// Hacer salida D0
TRISDbits.TRISD0 = 0;

// Apagar analógico
ANSELD = 0;

}
155
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

/**************************************************** ************
****************
* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************

***************/

vacío principal
(vacío) { initMain ();

// Rotar servo 0 - 90 - 180 while(1)


{

servoRotar0();
servoRotar90();
servoRotar180();

regreso; } }

Una vez que todo va bien, el eje del servo se moverá a lo largo de un arco de 180
grados en incrementos de 90 grados, comenzando en 0 grados.
Una advertencia que debo mencionar sobre el uso real de servomotores es que
si compra la variedad barata, o incluso las de plástico de alta calidad, es
posible que en realidad no comiencen en 0 grados y terminen en 180 grados.

156
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

Motor paso a paso


El motor paso a paso es el próximo tema de nuestro trío de actuadores. Los motores paso
a paso son cruciales para las aplicaciones industriales y la robótica. Los motores paso a
paso se utilizan en muchos dispositivos, incluidas las impresoras y el control CNC, donde
se necesita un movimiento muy preciso y controlado.

El motor paso a paso tiene múltiples bobinas que, cuando se organizan juntas,
se llaman fases. Cada fase se enciende secuencialmente, lo que hace que el
motor paso a paso gire. La distancia entre cada paso se conoce como el ángulo de
paso. Existen dos devanados principales para las bobinas del motor paso a paso. Uno se
conoce como unipolar y el otro como bipolar. La diferencia básica entre los dos es que,
en el motor paso a paso unipolar, hay una bobina con una derivación central por fase,
mientras que un motor bipolar tiene un devanado por fase.
En este libro, nos enfocamos en la variedad unipolar.
Hay tres formas principales de conducir un motor paso a paso. ahí está la ola
impulso, impulso de paso completo y impulso de medio paso.
En el modo de accionamiento por ondas, solo se activa una sola fase a la vez. Esto
da como resultado que el modo de conducción por ondas use menos energía que otros
modos, pero a costa de la pérdida de par. El modo de conducción de medio paso alterna
entre dos fases encendidas y una sola fase encendida. Esto aumenta la resolución
angular pero reduce el par. El modo de conducción de paso completo permite que dos
fases estén encendidas a la vez, lo que permite un par máximo.
Por lo tanto, cuando se diseña con motores paso a paso, existe un equilibrio entre el
par, el consumo de energía y la resolución angular.
Sin embargo, el método popular para accionar motores paso a paso es utilizar el
modo de accionamiento de paso completo; por lo tanto, este es el método que usaremos en este libro.
Para impulsar el motor paso a paso, debemos usar un controlador para darle al motor
paso a paso la potencia que necesita. Para motores paso a paso pequeños, puede usar
puentes H o matrices de transistores Darlington. Usaremos la matriz de Darlington ya que,
según mi experiencia, son más simples de usar.

157
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

El IC que usaremos que contiene estos paquetes es el ULN2003A. los


ULN2003A contiene siete pares de Darlington y será adecuado para nuestros
propósitos. El ULN2003A incluye diodos de retorno y puede funcionar hasta 50
V con una sola salida que proporciona 500 mA. Estas especificaciones lo
convierten en una opción popular para impulsar pequeños motores paso a
paso. El motor que usaremos en este ejemplo es un motor paso a paso unipolar
de cuatro fases clasificado en 5v. El motor también tiene un par de retención de
110 g-cm y un ángulo de paso de 7,5 grados y requiere una corriente de 500 mA.
Los motores con especificaciones similares se pueden comprar de una variedad
de proveedores en línea; solo asegúrese de comprar uno donde se pueda acceder
fácilmente a la hoja de datos; de lo contrario, es posible que no sepa qué cable
hace qué. El circuito de la figura 7-3 indica cómo se conecta un motor paso a paso al microcontrolador.

158
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

Figura 7-3. Conexión del motor paso a paso

159
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

El código del Listado 7-5 es bastante sencillo y maneja el paso a paso en


modo de paso completo.

Listado 7-5. Archivo principal paso a paso

/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: I03_Servo_Motor
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*
*
*
Descripción del programa: Esto demuestra el uso de un motor
paso a paso unipolar con un
*
microcontrolador pic.
*

* Descripción del hardware: Un motor paso a paso unipolar de 4


fases Sinotech 25BY4801 * está conectado al PUERTO D del
microcontrolador con una matriz de transistores Darlington
ULN2003A utilizada como controlador * para el motor paso a paso.

* Las conexiones son las siguientes:


*

* El ULN2003A está conectado al microcontrolador como * se


muestra a continuación:
*
* IN1 --> RD0
* IN2 --> RD1
* IN3 --> RD2

160
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

* IN4 --> RD3


*

* El motor paso a paso se conecta al ULN2003A como


* sigue:
*
* Blanco = SALIDA1
* Negro = SALIDA2
* Rojo = SALIDA3
* Amarillo = SALIDA4
*

* Creado el 15 de enero de 2017 a las


00:05 */

/**************************************************** ************
****************

*Incluye y define
**************************************************** ************

***************/

#incluye "16F1717_Internal.h"

/**************************************************** ************
****************

* Función: void initMain()


*

* Devoluciones: Nada
*
*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************

***************/

161
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

/////////////////////
// Configurar
puertos ///////////////////

// Hacer salida D0
TRISD = 0;

// Apagar analógico
ANSELD = 0;

/**************************************************** ************
****************
* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************

***************/
vacío principal
(vacío) { initMain ();

mientras(1){
LATD = 0b00001001; // Paso 1
__delay_ms(500);
LATD = 0b00000101; // Paso 2
__delay_ms(500);

162
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

LATD = 0b00000110; // Paso 3


__retraso_ms(500);
LATD = 0b00001010; // Etapa 4
__retraso_ms(500);
}
regreso;
}

Si observa el ciclo while principal en el Listado 7-5, notará que los cuatro
bits inferiores de PORTD siguen cambiando. En caso de que se esté preguntando
qué está pasando aquí, así es como funciona. ¿Recuerda que dijimos que en el
modo de paso de conducción completa, el motor enciende dos fases a la vez?
Bueno, si revisa el esquema de la Figura 7-3, notará que cada fase del motor
paso a paso está conectada a un pin del microcontrolador. Ahora mencioné que
las bobinas están conectadas al centro en el motor paso a paso de variedad
unipolar y, si observa su esquema, esto se muestra en la Figura 7-3. Por lo tanto,
se deben encender dos fases a la vez, ya que en realidad la corriente solo fluye
en la mitad del devanado del motor paso a paso a la vez. Por lo tanto, si observa
el código, notará que dos pines de salida están altos a la vez. Esto asegura que
al energizar alternativamente los medio devanados de las dos bobinas dentro del
motor paso a paso, obtenga la rotación completa de 360 grados del motor.
Si todavía tiene problemas para entender cómo funciona esto, hay excelentes
recursos en la web que profundizan en las complejidades del funcionamiento
de los motores paso a paso. En este libro, sin embargo, puede ignorar con
seguridad todos los detalles de la operación. Siempre que verifique con su hoja
de datos que ha conectado el motor paso a paso como se muestra en la Figura
7-3, este código funcionará con motores paso a paso unipolares de cualquier tamaño.
No se preocupe si su motor paso a paso se calienta. Los motores paso
a paso usan mucha corriente, y usan la misma cantidad de corriente cuando
están parados y en funcionamiento, así que no se asuste; esto es completamente normal.

163
Machine Translated by Google

CAPÍTULO 7 ACTUADORES DE INTERFAZ

Conclusión
Este capítulo analizó la interfaz de los actuadores con el microcontrolador
PIC®, incluidos los motores de CC, los motores paso a paso y los servomotores.
Estos forman la base para las aplicaciones de los microcontroladores PIC® en
áreas como la robótica y el control de motores.

164
Machine Translated by Google

CAPÍTULO 8

Interrupciones, Temporizadores,

Contadores y PWM
Introducción a las interrupciones
Las interrupciones son uno de los conceptos más simples relacionados con los microcontroladores.

Permítanme explicar las interrupciones de la manera más simple posible haciendo referencia a la vida cotidiana.

Imagina que necesitas despertarte a las 6:00 am. Hay dos formas de saber
cuándo tienes que despertarte. Una forma es seguir mirando el reloj hasta
que sean las 6:00. Sin embargo, si hace eso, entonces no podrá
concentrarse en la tarea en cuestión, que es dormir. La otra cosa que
puedes hacer es poner tu reloj en alarma para avisarte que son las 6:00. En
ambos escenarios, sabrá cuándo son las 6:00; sin embargo, el segundo
método es más efectivo ya que puede concentrarse en la tarea en cuestión, que es dormir.
Volviendo esta analogía a los microcontroladores, el primer
método para verificar continuamente su reloj es el método de sondeo. El
segundo método del reloj que le avisa cuando ha llegado el momento es
el método de interrupción. A las interrupciones se les asignan prioridades.
Por ejemplo, si está hablando por teléfono con alguien y su pareja lo llama,
puede interrumpir su llamada, hablar con su pareja y luego reanudar su
llamada. Esto se debe a que su pareja es más importante para usted y, por
lo tanto, se le asigna una mayor prioridad.

165
© Armstrong Subero
2018 A. Subero, Programación de microcontroladores
PIC con XC8, https://doi.org/10.1007/978-1-4842-3273-6_8
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

De la misma forma, el microcontrolador asigna prioridades a cada interrupción.

Una interrupción con mayor prioridad tiene prioridad sobre una de menor prioridad. El

microcontrolador también puede enmascarar una interrupción, que es el nombre que se le da a la

forma en que un microcontrolador ignora una llamada de servicio de interrupción en particular.

La rutina de servicio de interrupciones, también conocida como controlador de interrupciones,

es esencialmente la pieza de código que el microcontrolador ejecuta cuando se invoca una

interrupción. El tiempo que tarda el microcontrolador en responder a la interrupción y

comenzar a ejecutar su código se conoce como interrupción.

latencia. Para el PIC16F1717, la latencia de interrupción es de tres a cinco ciclos de instrucción.

La interrupción podría tener muchas fuentes, es decir, cosas que pueden provocar que

la CPU se interrumpa, y esto puede incluir temporizadores y otros periféricos integrados,

incluso un pin externo.

Ahora podría entrar en muchos detalles sobre cómo funcionan las interrupciones. Hay

mucha información escrita al respecto y encontrará muchos recursos en Internet si está

interesado. En este libro, adopto un enfoque pragmático.

Veamos la interrupción en acción, que se muestra en el Listado 8-1. En este caso, consideramos

que la interrupción externa usa un botón pulsador para activar una interrupción (vea la Figura

8-1).

166
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

Figura 8-1. Circuito de interrupción externo

Listado 8-1. Código de interrupción externa

/*
* Archivo: Main.c
* Autor: Armstrong Subero
* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: 07_Interrupt_External *
Compilador: XC8 (v1.38, MPLAX X v3.40)

167
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

*
Versión del programa: 1.0
*
*
*
Descripción del programa: este programa permite que PIC16F1717 cambie
un LED basado
*
sobre el estado de una interrupción de botón pulsador
*
* Descripción del hardware: un LED está conectado a través de una
resistencia de 10k al PIN D1 y
* otro LED está conectado al PIN D2 y un interruptor está
* conectado al PIN B0
*
* Creado el 4 de noviembre de 2016 a las
20:10 */

/**************************************************** ************
****************
*Incluye y define
**************************************************** ************

***************/

#incluye "16F1717_Internal.h"

/**************************************************** ************
****************
* Función: void initMain()
*
* Devoluciones: Nada
*
*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()

168
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

**************************************************** ************

***************/

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

/////////////////////////
/// Configurar
puertos ////////////////////////

// Establecer PIN D1 y D2 como


salida TRISDbits.TRISD1 = 0;
TRISDbits.TRISD2 = 0;

// Apagar LED
LATDbits.LATD1 = 0;

// Establecer PIN B0 como


entrada TRISBbits.TRISB0 = 1;

// Configurar ANSELB0
ANSELBbits.ANSB0 = 0;

// desbloquear PPS

PPSLOCK = 0x55;
BLOQUEO PPS = 0xAA;

PPSLOCK = 0x00;

// Habilitar pullups débiles globales


OPTION_REGbits.nWPUEN = 0;

// Habilitar pullup débil en PINB0


WPUBbits.WPUB0 = 1;

//////////////////////////

169
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

/// Configurar
interrupciones /////////////////////////

// Establezca el pin de interrupción en


el pin B0 INTPPSbits.INTPPS = 0b01000;

// bloquear PPS
PPSLOCK = 0x55;
BLOQUEO PPS = 0xAA;

PPSLOCK = 0x01;

// Activar en flanco descendente


OPTION_REGbits.INTEDG = 0;

// Borrar bandera de interrupción


externa INTCONbits.INTF = 0;

// Habilitar interrupción externa


INTCONbits.INTE = 1;

// Habilitar interrupción global


ei(); }

/**************************************************** ************
****************
* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************

***************/

vacío principal
(vacío) { initMain ();

170
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

while(1)
{ LATDbits.LATD1 = ~LATDbits.LATD1;
__retraso_ms(500); }

regreso;

/**************************************************** ************
****************

* Función: anular interrupción isr (vacío)


*

* Devoluciones: Nada
*
*
Descripción: Interrupción disparada al presionar un botón
**************************************************** ************

***************/

void interrupt isr(void){ //


Borrar indicador de
interrupción INTCONbits.INTF = 0;

// Toggle led
LATDbits.LATD2 = ~LATDbits.LATD2; }

Ahora que tiene una comprensión justa de cómo funcionan las


interrupciones externas, podemos pasar a una interrupción activada por algún
mecanismo interno. En este caso, usaremos un temporizador integrado para
activar la interrupción. Sin embargo, primero debemos fijarnos en el funcionamiento de los temporizado

171
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

Uso de temporizadores

Un temporizador en un microcontrolador puede contar pulsos de reloj regulares (lo que lo

convierte en un temporizador) o puede contar pulsos de reloj irregulares (en este modo es un

contador). El PIC16F1717 tiene cinco temporizadores. Estos son el temporizador 0, el

temporizador 1 y los temporizadores 2, 4 y 6. El temporizador que usaremos es el temporizador

0. Usaremos este temporizador porque es omnipresente entre los microcontroladores PIC®


de 8 bits. Dado que los temporizadores también se pueden usar como contadores, a veces nos referimos a ellos como tem
contadores

El temporizador necesita un pulso de reloj para funcionar. Esta fuente de reloj puede
ser interna o externa al microcontrolador. Cuando nos alimentamos internamente

pulsos de reloj, el temporizador/contador está en modo de temporizador. Sin embargo,

cuando usamos un pulso de reloj externo, el temporizador está en modo contador. El


temporizador 0 en el PIC16F1717 se puede usar como un temporizador/contador de 8 bits.

Un temporizador 0 incrementará cada ciclo de instrucción a menos que se use un

preescalador. El prescaler es responsable de reducir la velocidad a la que cuenta el

temporizador 0. El temporizador tiene un valor de preescala seleccionable por software y tiene

ocho valores de 2 a 256.

Temporizador 0 en modo temporizador

Primero observamos el uso del temporizador 0 en el modo de temporizador. Para usar el

temporizador, es necesario realizar algunas tareas de limpieza. En este modo, necesitamos

borrar el bit TMR0CS del registro de opciones. Luego asignaremos un prescaler y para hacerlo,

necesitamos borrar el bit PSA del registro de opciones. En este ejemplo, usamos el

temporizador 0 para hacer parpadear un LED con precisión de 1 Hz. Para hacerlo, conecte el

LED al microcontrolador, como se muestra en la Figura 8-2 con RD1 conectado al LED a través
de una resistencia de 1k.

172
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

Figura 8-2. Circuito de flash LED preciso

El listado 8-2 muestra el código principal.

Listado 8-2. Temporizador 0 Modo Temporizador

/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa:
04_Timer0 * Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*
*

173
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

*
Descripción del programa: este programa permite que PIC16F1717 parpadee
un LED a 1 Hz
* en Timer0 desbordamiento
*
* Descripción del hardware: un LED está conectado a través de una resistencia
de 10k al PIN D1
*
* Creado el 4 de noviembre de 2016 a las
16:14 */

/**************************************************** ************
****************
*Incluye y define
**************************************************** ************

***************/

#incluye "16F1717_Internal.h"

// Variable de contador
conteo int = 0;
/**************************************************** ************
****************
* Función: void initMain()
*
* Devoluciones: Nada
*
*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************

***************/

174
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

////////////////////////
/// Configurar
puertos //////////////////////

// Establecer PIN D1 como


salida TRISDbits.TRISD1 = 0;

// Apagar LED
LATDbits.LATD1 = 0;

// Establecer PIN B0 como


entrada TRISBbits.TRISB0 = 1;

// Configurar ANSELB0
ANSELBbits.ANSB0 = 0;

////////////////////////
/// Configurar
Timer0 ///////////////////////

// Seleccione el modo de temporizador

OPTION_REGbits.TMR0CS = 0;

// Asignar Prescaler a TIMER0


OPTION_REGbits.PSA = 0;

// Establecer Prescaler a
256 OPTION_REGbits.PS0
= 1; OPCIÓN_REGbits.PS1
= 1; OPCIÓN_REGbits.PS2 = 1;

175
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

// Temporizador cero

RTM0 = 0; }

/**************************************************** ************
****************

* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************

***************/

vacío principal (vacío)


{ initMain ();

mientras(1){

// Cuando el temporizador se desborde, el indicador de interrupción TMR0


será igual a 1 while (INTCONbits.TMR0IF != 1);

// Restablece el indicador después del

desbordamiento INTCONbits.TMR0IF = 0;

// Cuenta de incrementos

contar++;

// Valor = fclk / (4 * 256 * 256 * salida)


//|-- Salida de frecuencia (en Hz)
//|-- Valor del prescaler //
Valor = 16 000 000 / (262 144)
// Valor =61.04 por 1 s

176
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

// Enciende el LED durante 1 segundo en el desbordamiento del temporizador

si (cuenta == 61){
LATDbits.LATD1 = 1;
cuenta = 0;
}

// De lo contrario, apaga el LED


demás {
LATDbits.LATD1 = 0;
}

regreso;
}

Temporizador 0 en modo contador

Ahora veremos cómo usar el temporizador en modo contador. Para usar el


temporizador en modo contador, necesitamos configurar el bit TMR0CS del registro
de opciones. Los pasos para asignar el prescaler son los mismos que para un
temporizador. Este código también es el primero en el libro en utilizar el PPS. El PPS en este caso se ut

designe qué pin se usará para contar los pulsos del reloj externo. La secuencia
para asignar un periférico a un pin usando PPS es la siguiente:

1. Desbloquee el PPS.

2. Asigne el periférico a los pines.

3. Bloquee el PPS.

Debe seguir estos pasos para utilizar correctamente el PPS. La


habilitación de interrupción global debe configurarse adecuadamente, como se
muestra en el código del Listado 8-3. También hay una función para leer el
temporizador 0. Cuando el contador del temporizador 0 alcanza un valor determinado, el LED se encien

177
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

Las conexiones son muy simples, como se muestra en el esquema en


Figura 8-3.

Figura 8-3. Circuito contador

El listado 8-3 proporciona el código.

Listado 8-3. Temporizador 0 Modo contador

/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v

178
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

*
Programa: 05_Contador
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*
*
*
Descripción del programa: este programa permite que PIC16F1717 gire
en un LED
después de que * el módulo de contador en Time0 alcanza un valor
especificado * que se detecta a partir de pulsos externos dados a
través de un * interruptor en RB0.
*

* Descripción del hardware: un LED está conectado a través de una


resistencia de 1k al pin RD1 y un interruptor está conectado al pin RB0
*
*

* Creado el 23 de febrero de 2017 a las


17:22 */

/**************************************************** ************
****************

*Incluye y define
**************************************************** ************

***************/

#incluye "16F1717_Internal.h"

/**************************************************** ************
****************

* Función: void initMain()


*

* Devoluciones: Nada
*

179
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************

***************/

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

////////////////////////
/// Configurar
puertos //////////////////////

// Establecer PIN D1 como


salida TRISDbits.TRISD1 = 0;

// Apagar LED
LATDbits.LATD1 = 0;

// Establecer PIN B0 como


entrada TRISBbits.TRISB0 = 1;

// Configurar ANSELB0
ANSELBbits.ANSB0 = 0;

////////////////////////
/// Configurar
Timer0 ///////////////////////

//Seleccionar modo contador


OPCIÓN_REGbits.TMR0CS = 1;

// Asignar Prescaler a TIMER0


OPTION_REGbits.PSA = 1;

180
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

estado booleano =
GIE; GIE = 0;
PPSLOCK = 0x55;
BLOQUEO PPS =
0xAA; PPSLOCKbits.PPSLOCKED = 0x00; // desbloquear PPS

T0CKIPPSbits.T0CKIPPS = 0x08; //RB0->TMR0:T0CKI;

PPSLOCK = 0x55;
BLOQUEO PPS =
0xAA; PPSLOCKbits.PPSLOCKED = 0x01; // bloquear PPS

GIE = estado;

// Temporizador cero

RTM0 = 0;

// Habilitar las interrupciones del temporizador 0 y borrar el indicador


de interrupción INTCONbits.TMR0IE = 1; INTCONbits.TMR0IF = 0; }

/**************************************************** ************
****************

* Función: int ReadTimer (vacío)


*

* Devuelve: int readVal;


*
*
Descripción: Devuelve el valor de Timer0
*
*
Uso: int x;
**************************************************** ************

***************/

181
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

uint8_t Temporizador de lectura0

(vacío) {
// Leer variable de valor
uint8_t readVal;

// Establecer variable en valor timer0


readVal = TMR0;

// valor devuelto
volver readVal; }

/**************************************************** ************
****************
* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************

***************/

vacío principal
(vacío) { initMain ();

// variable de conteo
uint8_t cuenta;

mientras(1){

// lee el temporizador con


cuenta cuenta = ReadTimer0();

// si el contador tiene valor de 5 if


(count == 5){

182
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

// enciende el LED

LATDbits.LATD1 = 1;

// breve retraso para ver el LED en


__delay_ms(2000);

// temporizador cero

RTM0 = 0; }

demás

{ // mantener el LED
apagado LATDbits.LATD1
= 0; } }

regreso; }

Temporizador 0 con interrupciones

Ahora miramos el uso del temporizador 0 con interrupciones. El código es muy simple
si ha estado siguiendo hasta este punto, y lo usaremos para hacer parpadear un LED
cada segundo mientras responde simultáneamente al botón para cambiar otro LED. Este
ejemplo demuestra una aplicación importante de las interrupciones, realizando una
acción de forma muy determinista.
conducta.

El circuito se muestra en la figura 8-4.

183
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

Figura 8-4. Circuito de interrupción del temporizador

El listado 8-4 proporciona el código.

Listado 8-4. Temporizador 0 con Interrupción

/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: 06_Interrupciones

184
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

* Compilador: XC8 (v1.38, MPLAX X v3.40)


*
Versión del programa: 1.0
*
*
*
Descripción del programa: este programa permite que PIC16F1717 flashee un
LED a un ritmo
* de 1 Hz mientras responde a una entrada de botón usando
*
una interrupción del temporizador 0
*
*

* Descripción del hardware: un LED está conectado a través de una


resistencia de 1k al PIN D1 y
* otro LED conectado al interruptor PIN D2 está conectado
* al PIN B0
*
* Creado el 4 de noviembre de 2016 a las
19:15 */

/**************************************************** ************
****************

*Incluye y define
**************************************************** ************

***************/

#incluye "16F1717_Internal.h"

/**************************************************** ************
****************

* Función: void initMain()


*

* Devoluciones: Nada
*

185
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************

***************/

void initMain()
{ //////////////////////
// Configurar
puertos /////////////////////

// Ejecutar a 16 MHz

interno_16();

// Establecer PIN D1, D2 como


salida TRISDbits.TRISD1 = 0;
TRISDbits.TRISD2 = 0;

// Apagar LED
LATDbits.LATD1 = 0;

// Establecer PIN B0 como


entrada TRISBbits.TRISB0 = 1;

// Configurar ANSELB0
ANSELBbits.ANSB0 = 0;

////////////////////////
// Configurar
Timer0 //////////////////////

// Seleccione el modo de temporizador

OPTION_REGbits.TMR0CS = 0;

// Asignar Prescaler a TIMER0


OPTION_REGbits.PSA = 0;

186
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

// Establecer Prescaler a
256 OPTION_REGbits.PS = 0b111;

// habilitar la interrupción del


Timer0 INTCONbits.TMR0IE = 1;

// habilitar interrupciones
globales ei(); }

/**************************************************** ************
****************
* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************

***************/

vacío principal
(vacío) { initMain ();

while(1){ //
Alternar LED en el botón PUSH
LATDbits.LATD1 = ~PORTBbits.RB0; }

regreso; }

/**************************************************** ************
****************

* Función: anular interrupción isr (vacío)


*

187
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

* Devoluciones: Nada
*
*
Descripción: Timer0 interrumpe a una velocidad de 1 segundo
**************************************************** ************

***************/

void interrupt isr(void)


{ static int count = 0;

// Restablece el indicador después del

desbordamiento INTCONbits.TMR0IF = 0;

RTM0 = 0;

// Cuenta de incrementos

contar++;

// Valor = fclk / (4 * 256 * 256 * salida)


// |-- Salida de frecuencia (en Hz)
// |-- Valor del
preescalador // Valor = 16 000 000 / (262 144)
// Valor = 61.04 por 1 s

// Enciende el LED durante 1 segundo en el desbordamiento


del temporizador if (count == 61){ LATDbits.LATD2 = 1;
cuenta = 0; }

// De lo contrario, mantenga el

LED apagado else

{ LATDbits.LATD2 = 0; }

188
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

Uso del módulo CCP


El PIC16F1717 viene con módulos integrados de captura/comparación/PWM (CCP).
El modo de captura cronometra la duración de un evento. El modo de comparación
activa un evento externo después de que haya pasado una cierta cantidad de tiempo.
Nos centraremos en el PWM. Si necesita utilizar funciones de captura o
comparación, consulte la hoja de datos.

En el último capítulo, examinamos brevemente el uso de PWM para controlar un


servo En esta sección, analizamos el uso de PWM con hardware dedicado.

Entendiendo PWM
La modulación de ancho de pulso (PWM) describe un tipo de señal que puede ser
producida por un microcontrolador. Sin embargo, para entender PWM, primero
debemos entender el concepto del ciclo de trabajo. Una señal digital puede ser 5v (alta) o
0v (baja). La cantidad de tiempo que una señal está alta se describe como el ciclo de
trabajo de esa señal. Esto se expresa como un porcentaje. Por ejemplo, si durante un
período de tiempo determinado, una señal está alta la mitad del tiempo y baja la otra
mitad, tendrá un ciclo de trabajo del 50 %.

Usando PWM
Veamos cómo usar el PWM en el módulo CCP. Se requiere un temporizador para usar el
módulo PWM. Dado que el temporizador 0 se usa para muchas cosas, usaremos el
temporizador 6 para que sea el temporizador PWM.

El módulo PWM es muy importante y tiene muchos usos. Los usos más populares
son la atenuación de la luz, el control de la velocidad del motor y la generación de una
señal modulada. En este ejemplo, usaremos el módulo PWM para atenuar un LED.
Haremos funcionar el LED al 50% del ciclo de trabajo.
La figura 8-5 muestra el circuito.

189
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

Figura 8-5. circuito PWM

El código se muestra en el Listado 8-5.

Listado 8-5. CCP PWM


/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa:
20_PWM * Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*
*

190
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

*
Descripción del Programa: Este Programa utiliza el módulo PWM del
FOTO16F1717
*
*

* Descripción del hardware: un LED está conectado a PINB0


*
* Creado el 7 de noviembre de 2016 a las
17:20 */

/**************************************************** ************
****************

*Incluye y define
**************************************************** ************

***************/

#incluye "16F1717_Internal.h"

/**************************************************** ************
****************

* Función: void initMain()


*

* Devoluciones: Nada
*
*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************

***************/

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

191
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

// Configurar PINB0 como


salida TRISBbits.TRISB0 = 0;

//////////////////////
// Configurar
Timer6 /////////////////////

// Seleccione el temporizador PWM como Timer6

CCPTMRSbits.C1TSEL = 0b10;

// Habilitar temporizador Incrementos cada 250 ns (reloj de 16 MHz)


1000/ (16/4)
// Periodo = 256 x 0,25 us = 64 us

// Frecuencia de cristal
// Frecuencia PWM = -----------------------------------------
// (PRX + 1) * (Prescaler TimerX) * 4

//Frecuencia PWM = 16 000 000 / 256 * 1 * 4 //


Frecuencia PWM = 15,625 kHz

// Preescala = 1
T6CONbits.T6CKPS = 0b00;

// Habilitar Temporizador6

T6CONbits.TMR6ON = 1;

// Establecer el período del temporizador

PR6 = 255;

// Configurar CCP1

// LSB del ciclo de trabajo de PWM =


00 CCP1CONbits.DC1B = 00;

// Selecciona el modo PWM

CCP1CONbits.CCP1M = 0b1100;

192
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

PPSLOCK = 0x55;
BLOQUEO PPS =
0xAA; PPSLOCKbits.PPSLOCKED = 0x00; // desbloquear PPS

// Establecer RB0 en PWM1

RB0PPSbits.RB0PPS = 0b01100;

PPSLOCK = 0x55;
BLOQUEO PPS =
0xAA; PPSLOCKbits.PPSLOCKED = 0x01; // bloquear
PPS }

/**************************************************** ************
****************

* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************

***************/

vacío principal
(vacío) { initMain ();

while(1){ //
Ejecutar al 50 % del ciclo de trabajo a 15,625
kHz CCPR1L = 127; }

regreso; }

El código también contiene una fórmula para calcular la frecuencia del


módulo PWM, que es importante para aplicaciones como el control de motores.

193
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

Proyecto: Uso de PWM con un controlador de motor

En el capítulo anterior sobre la interfaz de actuadores, vimos una forma sencilla de


accionar un motor. En esta sección, analizamos la forma típica de accionar un motor,
que consiste en utilizar un controlador de motor dedicado, IC. El uso de un IC dedicado
nos permite controlar fácilmente la velocidad y la dirección del motor y ofrece un mejor
control general del motor.
El controlador de motor que usaremos es el común SN754410, que tiene

dos puentes H a bordo y puede manejar hasta 36 voltios a 1A por conductor. Además
de tener especificaciones decentes, este controlador también es de bajo costo, lo que
lo convierte en una opción atractiva para aplicaciones de propósito general.
Cuando se enseña a alguien a hacer algo por primera vez, es agradable
proporcione mucho agarre de la mano. Después de todo, los principiantes
necesitan mucha mano para comprender correctamente los conceptos. En este
proyecto, sin embargo, te dejo hacer un poco de investigación para completarlo.
Proporciono las conexiones en el texto y en el código, y su trabajo es conectar el
controlador del motor y el motor al microcontrolador sin un esquema. Crees que puedes manejar eso?
¡Vamos a empezar!

El motor se conecta de la siguiente manera:

• 1: Habilita el motor uno, conecta a 5v

• 2: se conecta al canal PWM directo (motor 1)

• 3: Motor 1 +

• 4-5: TIERRA

• 6: Motor 1

• 7: se conecta al canal PWM inverso (motor 1)

• 8: Entrada de alimentación del motor +VE

• 12-13: TIERRA

• 16: 5v

194
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

Haremos funcionar el motor durante cinco segundos en una dirección, lo apagaremos

durante dos segundos y luego lo haremos funcionar de nuevo durante cinco segundos en la otra dirección.

El código se proporciona en el Listado 8-6.

Listado 8-6. Motor PWM


/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: I04_H_Puente
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*
*
*
Descripción del programa: Esto demuestra el uso de un H-
Bridge SN754410 con un
* Motor DC con microcontrolador PIC.
*

* Descripción del hardware: un motor de CC de hobby cepillado


genérico está conectado al
* SN754410 según conexiones estándar. Las señales PWM
*
emanan de RB0 y RB1 para avance y retroceso
* señales respectivamente.
*
*

* Creado el 15 de enero de 2017 a las 11:36


*/

195
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

/**************************************************** ************
****************

*Incluye y define
**************************************************** ************

***************/

#incluye "16F1717_Internal.h"

/**************************************************** ************
****************
* Función: void initMain()
*

* Devoluciones: Nada
*
*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************

***************/

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();
/////////////////////
// Configurar
puertos ///////////////////

// Establecer PIN B0 como


salida TRISBbits.TRISB0 = 0;

// Establecer PIN B1 como


salida TRISBbits.TRISB1 = 0;

196
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

// Apagar analógico
ANSELB = 0;

//////////////////////
// Configurar
Timer6 /////////////////////

// Seleccione el temporizador PWM como Timer6 para CCP1


y CCP2 CCPTMRSbits.C1TSEL = 0b10; CCPTMRSbits.C2TSEL
= 0b10;

// Habilitar temporizador Incrementos cada 250 ns (reloj de 16 MHz)


1000/ (16/4)
// Periodo = 256 x 0,25 us = 64 us

// Frecuencia de cristal
//Frecuencia PWM = -----------------------------------------
//(PRX + 1) * (Prescaler TimerX) * 4

//Frecuencia PWM = 16 000 000 / 256 * 1 * 4 //


Frecuencia PWM = 15,625 kHz

// Preescala = 1
T6CONbits.T6CKPS = 0b00;

// Habilitar Temporizador6

T6CONbits.TMR6ON = 1;

// Establecer el período del temporizador

PR6 = 255;

///////////////////////////
// Configurar
PWM /////////////////////////

// Configurar CCP1

197
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

// LSB del ciclo de trabajo de PWM = 00


CCP1CONbits.DC1B = 00;

// Selecciona el modo PWM

CCP1CONbits.CCP1M = 0b1100;

// Configurar CCP2

// LSB del ciclo de trabajo de PWM = 00


CCP2CONbits.DC2B = 00;

// Selecciona el modo PWM

CCP2CONbits.CCP2M = 0b1100;

///////////////////////////////

// Configurar
PPS /////////////////////////////

PPSLOCK = 0x55;
BLOQUEO PPS =
0xAA; PPSLOCKbits.PPSLOCKED = 0x00; // desbloquear PPS

// Establecer RB0 en PWM1

RB0PPSbits.RB0PPS = 0b01100;

// Establecer RB1 en PWM2

RB1PPSbits.RB1PPS = 0b01101;

PPSLOCK = 0x55;
BLOQUEO PPS =
0xAA; PPSLOCKbits.PPSLOCKED = 0x01; // bloquear PPS

198
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

/**************************************************** ************
****************

* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************

***************/

vacío principal (vacío)


{ initMain ();

while(1){ //
Ejecutar a aprox. Ciclo de trabajo del 20 % a 15,625 kHz durante 5 segundos

// Hacia adelante

CCPR1L = 192;
CCPR2L = 0;

__retraso_ms(5000);

CCPR1L = 0;
CCPR2L = 0;

__retraso_ms(2000);

// Contrarrestar

CCPR1L = 0;
CCPR2L = 192;

__retraso_ms(5000);

}
regreso; }

199
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

Proyecto: uso de CCP y PWM


dedicado con LED RGB
Como se mencionó anteriormente, un uso importante de PWM es en
aplicaciones de iluminación. En este proyecto, usaremos el PWM para
controlar un LED tricolor. Un LED tricolor (LED RGB) consta de tres LED en un solo paquete.
Variando la intensidad de cada uno de estos tres colores, se puede generar
cualquier otro color.
Usaremos el PWM para cambiar el voltaje promedio que fluye
cada LED individual y dejar que nuestra persistencia de visión haga el resto.
En el código del Listado 8-7, también utilizamos el módulo PWM integrado de
el microcontrolador PIC® y usamos un canal PWM3 dedicado.

Listado 8-7. PWM RGB


/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: I08_RGB_LED
* Compilador: XC8 (v1.41, MPLAX X v3.55)
*
Versión del programa: 1.0
*
*
*
Descripción del programa: Esto demuestra el uso de un LED RGB con
FOTO16F1717
*

* Descripción del hardware: un LED RGB se conecta de la siguiente manera:


* Rojo - RB0
* Verde – RB3
* Azul – RB2
*

200
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

* Creado el martes 18 de abril de 2017 a las 11:53 */

/**************************************************** ************
****************

*Incluye y define
**************************************************** ************

***************/

#incluye "16F1717_Internal.h"

/*
Valor para PWM1
*/
void PWM1_LoadDutyValue(uint16_t dutyValue) {
// Escribir en 8 MSB del ciclo de trabajo pwm en el registro CCPRL
CCPR1L = ((valor de servicio y 0x03FC) >> 2);

// Escribir en 2 LSB del ciclo de trabajo pwm en el registro CCPCON


CCP1CON = (CCP1CON y 0xCF) | ((valor de servicio y 0x0003) <<
4); }

/*
Valor para PWM2
*/
void PWM2_LoadDutyValue(uint16_t dutyValue) {
// Escribir en 8 MSB del ciclo de trabajo pwm en el registro CCPRL
CCPR2L = ((valor de servicio y 0x03FC) >> 2);

// Escribir en 2 LSB del ciclo de trabajo pwm en el registro CCPCON


CCP2CON = (CCP2CON y 0xCF) | ((valor de servicio y 0x0003) <<
4); }

201
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

/*
Valor para PWM3
*/
void PWM3_LoadDutyValue(uint16_t dutyValue) {
// Escribir en 8 MSB del ciclo de trabajo PWM en el registro PWMDCH
PWM3DCH = (valor de servicio y 0x03FC) >> 2;

// Escribir en 2 LSB del ciclo de trabajo PWM en el registro PWMDCL


PWM3DCL = (valor de servicio y 0x0003) <<
6; }

/*
Valor para LED
RGB */
void RGB_LoadValue(uint16_t rojo, uint16_t verde, uint16_t azul) {

PWM1_LoadDutyValue(rojo);
PWM2_LoadDutyValue(verde);
PWM3_LoadDutyValue(azul); }

/**************************************************** ************
****************

* Función: void initMain()


*

* Devoluciones: Nada
*
*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************

***************/

202
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

/////////////////////
// Configurar
puertos ///////////////////

// Establecer PIN B0 como


salida TRISBbits.TRISB0 = 0;

// Establecer PIN B1 como


salida TRISBbits.TRISB1 = 0;

// Establecer PIN B2 como


salida TRISBbits.TRISB2 = 0;

// Apagar analógico
ANSELB = 0;

//////////////////////
// Configurar
Timer6 /////////////////////

// Seleccione el temporizador PWM como Timer6 para CCP1


y CCP2 CCPTMRSbits.C1TSEL = 0b10; CCPTMRSbits.C2TSEL
= 0b10;

// Habilitar temporizador Incrementos cada 250 ns (reloj de 16 MHz)


1000/ (16/4)
// Periodo = 256 x 0,25 us = 64 us

// Frecuencia de cristal
//Frecuencia PWM = -----------------------------------------
//(PRX + 1) * (Prescaler TimerX) * 4

203
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

//Frecuencia PWM = 16 000 000 / 256 * 1 * 4 //


Frecuencia PWM = 15,625 kHz

// Preescala = 1
T6CONbits.T6CKPS = 0b00;

// Habilitar Temporizador6

T6CONbits.TMR6ON = 1;

// Establecer el período del temporizador

PR6 = 255;

///////////////////////////

// Configurar
PWM /////////////////////////

// Configurar CCP1

// LSB del ciclo de trabajo de PWM =


00 CCP1CONbits.DC1B = 00;

// Selecciona el modo PWM

CCP1CONbits.CCP1M = 0b1100;

// Configurar CCP2

// LSB del ciclo de trabajo de PWM =


00 CCP2CONbits.DC2B = 00;

// Selecciona el modo PWM

CCP2CONbits.CCP2M = 0b1100;

// Configurar PWM 3

// PWM3EN habilitado, PWM3POL activo alto


PWM3CON = 0x80;

204
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

// PWM3DCH127
PWM3DCH = 0x7F;

// PWM3DCL 192
PWM3DCL = 0xC0;

// Seleccionar temporizador6

CCPTMRSbits.P3TSEL = 0b10;

///////////////////////////////

// Configurar
PPS /////////////////////////////

PPSLOCK = 0x55;
BLOQUEO PPS =
0xAA; PPSLOCKbits.PPSLOCKED = 0x00; // desbloquear PPS

// Establecer RB0 en PWM1

RB0PPSbits.RB0PPS = 0b01100;

// Establecer RB1 en PWM2

RB1PPSbits.RB1PPS = 0b01101;

// Establecer RB2 en
PWM3 RB2PPSbits.RB2PPS = 0x0E;

PPSLOCK = 0x55;
BLOQUEO PPS =
0xAA; PPSLOCKbits.PPSLOCKED = 0x01; // bloquear PPS

205
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

/**************************************************** ************
****************
* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************

***************/

vacío principal
(vacío) { initMain ();

// Todos los canales inicialmente 0


PWM1_LoadDutyValue(0);
PWM2_LoadDutyValue(0);
PWM3_LoadDutyValue(0);

mientras(1){

// Rojo

RGB_LoadValue(512, 0, 0);
__retraso_ms(1000);

// Verde
RGB_LoadValue(0, 512, 0);
__retraso_ms(1000);

// Azul
RGB_LoadValue(0, 0, 512);
__retraso_ms(1000);

// Amarillo
RGB_LoadValue(192, 192, 0);
__retraso_ms(1000);

206
Machine Translated by Google

CAPÍTULO 8 INTERRUPCIONES, TEMPORIZADORES, CONTADORES Y PWM

// Púrpura
RGB_LoadValue(192, 0, 192);
__retraso_ms(1000);

// aguamarina
RGB_LoadValue(0, 512, 512);
__retraso_ms(1000);

}
regreso;
}

Conclusión
Esto concluye este capítulo, donde vimos algunos módulos integrados
más del microcontrolador PIC®. Examinamos las interrupciones, que permiten
que el microcontrolador salte instantáneamente a una tarea específica, los
temporizadores, que cuentan pulsos de reloj regulares, los contadores, que
cuentan pulsos irregulares y PWM, que es muy útil en aplicaciones de
microcontroladores como iluminación y control de motores.

207
Machine Translated by Google

CAPÍTULO 9

USART, SPI e I2C:


Comunicación serial
protocolos
En este capítulo, analizamos el uso de protocolos de comunicación en
serie. Los más ubicuos de estos son USART, SPI e I2C, que explicaré en
este capítulo. Este es un capítulo que no desea omitir, ya que cubrimos el
uso de sensores, GPS, GSM y muchas otras cosas. Entonces, toma una
botella de agua y siéntate. Este será largo.

Usando USART (Universal Synchronous


Transmisor receptor asíncrono)
El transmisor receptor universal síncrono asíncrono (USART) es mi
protocolo de comunicación favorito. La razón por la que es mi favorito es
porque es el más simple de usar. Es posible que un diseñador de sistemas
integrados entienda cada detalle del protocolo USART. A veces puede ver
que USART se escribe simplemente como "UART". Para nuestras
aplicaciones, hacen más o menos lo mismo. USART es solo un protocolo
UART mejorado, ya que la "S" faltante (síncrona) requiere que el reloj sea síncrono y

209
© Armstrong Subero
2018 A. Subero, Programación de microcontroladores
PIC con XC8, https://doi.org/10.1007/978-1-4842-3273-6_9
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

agrega un poco de complejidad a su diseño. Por lo tanto, utilizaremos el módulo USART de

forma asíncrona de conformidad con KISS.


El módulo USART integrado en el microcontrolador PIC® se puede utilizar

sincrónica o asincrónicamente. Cuando se usa de forma asíncrona, toda la comunicación

tiene lugar sin reloj. Esto ahorra un pin de E/S ya que en este modo solo se requieren las líneas

de transmisión y recepción. El modo asíncrono es el tipo de comunicación que utilizaremos. El

modo síncrono permite que el módulo se use con un reloj y no se usa tanto, por lo que no lo

discutiremos en este libro.

Una consideración importante para USART es la tasa de baudios. La velocidad en baudios

del USART especifica la velocidad a la que el USART transfiere datos. Una tasa de baudios de
2400 significa que el USART puede transferir un máximo de 2400 bits

por segundo.

LCD de caracteres en serie

Comenzamos nuestro uso de USART enviando señales a un módulo LCD en serie.

El módulo LCD serial que usaremos es el LCD Parallax 2x16 (vea la Figura 9-1 ). En este ejemplo,

escribimos texto y comandos en la pantalla LCD. La hoja de datos de Parallax proporciona

información sobre los comandos que deben enviarse a la pantalla LCD.


Este módulo LCD tiene velocidades de transmisión seleccionables de 2400, 9600 y 19200.

Esta pantalla LCD también incluye un altavoz piezoeléctrico incorporado y tiene luz de fondo.

Figura 9-1. LCD serie Parallax

210
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

Echemos un vistazo al código para configurar el módulo USART


(vea el Listado 9-1). Primero creamos un archivo de encabezado que contiene
varios prototipos de funciones. Después de ejecutar el código de esta sección,
descargue la hoja de datos de Parallax para la pantalla LCD y experimente con el altavoz piezoeléctric
Te garantizo que estarás usando USART como un profesional en poco tiempo.
Además, he omitido deliberadamente esquemas para interconectar estos
módulos para que descargue las hojas de datos y descubra cómo funcionan.
Todos estos módulos requieren la conexión de cuatro cables para que
funcionen y la pantalla LCD en serie requiere la conexión de tres. Vamos, eres
inteligente, ¡puedes resolverlo!
Hay una trampa para principiantes con USART. La línea TX está conectada
a RX y la línea RX está conectada a TX.

Listado 9-1. Cabecera EUSART

/*
* Archivo: EUSART.h

* Autor: Armstrong Subero


* FOTO: 16F1717 con X OSC @ 16MHz, 5v
*
Programa: archivo de encabezado para configurar PIC16F1717

* Compilador: XC8 (v1.35, MPLAX X v3.10)


*
Versión del programa 1.0
*
*
Descripción del programa: este encabezado configura el módulo EUSART
* Creado el 7 de noviembre de 2016 a las 19:00
*/

/**************************************************** ************
* Función Prototipo
**************************************************** ************/

char EUSART_Initialize(const long int baudrate);


uint8_t EUSART_Read(vacío);
char EUSART_Read_Char(char *salida);

211
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

vacío EUSART_Write(uint8_t txData);


void EUSART_Write_Text(char *texto);
void EUSART_Read_Text(char *Salida, longitud int sin signo);

Luego creamos el archivo fuente que implementa estas funciones, como


se muestra en el Listado 9-2.

Listado 9-2. Fuente EUSART


/*
* Archivo: EUSART.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: Archivo de biblioteca que contiene funciones para el
módulo EUSART
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.1
* * Se agregaron comentarios adicionales
*
*
Descripción del programa: esta biblioteca le permite utilizar la
Módulo EUSART del
* FOTO16F1717
*

* Creado el 7 de noviembre de 2016 a las 19:10


*/

/**************************************************** ************
*Incluye y define
**************************************************** ***********/

#incluye "16F1717_Internal.h"
#include "EUSART.h"

212
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

/**************************************************** ************

* Función: char EUSART_Initialize (const long int baudrate)


*

* Devoluciones: Nada
*
*
Descripción: Inicializa el módulo EUSART
*
*
Uso: EUSART_Initialize()
************************************************ ****************/

char EUSART_Initialize(const long int baudrate) { unsigned


int x; x = (_XTAL_FREQ - velocidad de transmisión*64)/
(velocidad de transmisión*64); si(x>255) {

x = (_XTAL_FREQ - velocidad de transmisión*16)/(velocidad de transmisión*16);

BRGH = 1;

} si(x<256)
{
SPBRG = x;
SINCRONIZACIÓN = 0;

GASTO = 1;
TRISC7 = 1;
TRISC6 = 1;
CREN = 1;
TXEN = 1;
devolver 1;

} devuelve 0;

213
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

/**************************************************** ************
* Función: char EUSART_Read (void)
*

* Devoluciones: Nada
*
*
Descripción: Lee el módulo EUSART
*
*
Uso: EUSART_Read()
******************************************** ****************/

uint8_t EUSART_Read(vacío)
{

RC1STAbits.SREN =
1; while(!PIR1bits.RCIF)
{}

si (1 == RC1STAbits.OERR)
{
//Error EUSART – reiniciar

RC1STAbits.SPEN =
0; RC1STAbits.SPEN = 1;
}

devolver RC1REG;
}

// Leer caracteres

char EUSART_Read_Char(char *Salida)


{
Salida = EUSART_Read();
Salida de retorno;
}

214
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

/**************************************************** ************
* Función: char EUSART_Write (uint8_t txData)
*

* Devoluciones: Nada
*
*
Descripción: Escribe en el módulo EUSART
*
*
Uso: EUSART_Write(x)
**************************************************** ***********/

vacío EUSART_Write(uint8_t txData)


{
while(0 == PIR1bits.TXIF) { }

TX1REG = txDatos; // Escribe el byte de datos en el USART.


}

void EUSART_Read_Text(char *Salida, longitud int sin firmar) {

ent
yo; for(int i=0;i<longitud;i++)
Salida[i] = EUSART_Read();
}

/**************************************************** ************
* Función: char EUSART_Write_Text (char *texto)
*

* Devoluciones: Nada
*

215
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

*
Descripción: Escribe texto el módulo EUSART
*
*
Uso: EUSART_Write_Text("Alguna cadena")
**************************************************** ***********/

void EUSART_Write_Text(char *texto)


{
ent yo;
for(i=0;texto[i]!='\0';i++)
EUSART_Escribir(texto[i]);
}

Ahora creamos el archivo principal que se comunica con el LCD, como


se muestra en el Listado 9-3.

Listado 9-3. Fuente principal

/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: I04_Serial_LCD
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*
*
*
Descripción del programa: este programa permite que PIC16F1717
comunicarse a través de la
* Módulo EUSART a LCD serie 16x2.
*
*

* Descripción del hardware: una pantalla LCD Parallax 16x2 está conectada al PIN
RB2 de la

216
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

* microcontrolador de la siguiente manera:


*
*

* Creado el 7 de noviembre de 2016 a las


19:05 */

/**************************************************** ************
*Incluye y define
********************************************** ****************/

#incluye "16F1717_Internal.h"
#incluye "EUSART.h"

/**************************************************** ************
* Función: void initMain()
*

* Devoluciones: Nada
*
*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************/

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

//////////////////////
// Configurar
PIN ////////////////////

TRISBbits.TRISB2 = 0;
ANSELBbits.ANSB2 = 0;

217
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

//////////////////////

// Configurar
EUSART /////////////////////
PPSLOCK = 0x55;
BLOQUEO PPS =
0xAA; PPSLOCKbits.PPSLOCKED = 0x00; // desbloquear PPS

RB2PPSbits.RB2PPS = 0x14 //RB2->EUSART:TX;


RXPPSbits.RXPPS = 0x0B; //RB3->EUSART:RX;

PPSLOCK = 0x55;
BLOQUEO PPS =
0xAA; PPSLOCKbits.PPSLOCKED = 0x01; // bloquear
PPS }

/**************************************************** ************
* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************/

vacío principal (vacío)


{ initMain ();

// Inicializar módulo EUSART con 19200 baudios


EUSART_Inicializar(19200);

mientras(1){

// Enviar comando

// Enciende la luz de fondo


EUSART_Escribir(17);

218
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

// Enviar texto
EUSART_Write_Text("Hola");

// Enviar cada 2 segundos


__retraso_ms(2000);
}

regreso;

Comunicación USART a PC
Cuando necesite comunicarse con una PC, puede usar un convertidor
de serie a USB. Hay algunos microcontroladores que tienen USB
integrado; sin embargo, la comunicación USB es muy compleja y
requiere que los usuarios escriban su propia pila o usen pilas (a veces
poco confiables) provistas por el fabricante. Al usar un puente UART a
USB, puede evitar muchos dolores de cabeza. El CP2104 es excelente y lo recomiendo much

Texto a voz
Ahora veremos la síntesis de voz utilizando un módulo de texto a voz (TTS).
Los módulos TTS convierten el texto en voz hablada. El módulo TTS que
usaremos es el módulo EMIC 2 TTS (consulte la Figura 9-2). Este módulo
es muy fácil de usar. Permite al usuario seleccionar muchas voces y
produce una voz que es muy fácil de entender. Una vez que haya terminado
de ejecutar el código de esta sección, descargue la hoja de datos del
módulo. Experimente con diferentes voces y juegue un poco con el módulo.
Esta es una buena práctica. Una vez que haya leído las hojas de datos de
los módulos y sensores, puede crear sus propias bibliotecas y código, sin
quedarse atascado si no puede encontrar una biblioteca en línea.

219
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

Figura 9-2. Módulo EMIC 2 TTS

El archivo de encabezado sigue siendo el mismo. El código principal se muestra en el Listado 9-4.

Listado 9-4. Código principal TTS

/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: 21_EUSART
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*
*
*
Descripción del programa: este programa permite que PIC16F1717
comunicarse a través de la
* Módulo EUSART a un módulo EMIC 2 TTS.
*
*

220
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

* Descripción del hardware: un módulo EMIC 2 TTS está conectado al


PIC16F1717
como * sigue:
*

* RB2-> SIN;
* RB3-> SUR;
*

* Los otros pines en el EMIC2 TTS están conectados según


* la hoja de datos.
*

* Creado el 25 de febrero de 2017 a las


21:55 */

/**************************************************** ************
*Incluye y define
********************************************** ****************/

#incluye "16F1717_Internal.h"
#incluye "EUSART.h"

/**************************************************** ************
* Función: void initMain()
*

Devoluciones: Nada
*
*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ***********/

221
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

// Configurar
PINS TRISBbits.TRISB3
= 1; ANSELBbits.ANSB3 = 0;

TRISBbits.TRISB2 = 0;
ANSELBbits.ANSB2 = 0;

//////////////////////
// Configurar
EUSART /////////////////////
PPSLOCK = 0x55;
BLOQUEO PPS =
0xAA; PPSLOCKbits.PPSLOCKED = 0x00; // desbloquear PPS

RB2PPSbits.RB2PPS = 0x14; //RB2->EUSART:TX;


RXPPSbits.RXPPS = 0x0B; //RB3->EUSART:RX;

PPSLOCK = 0x55;
BLOQUEO PPS =
0xAA; PPSLOCKbits.PPSLOCKED = 0x01; // bloquear
PPS }

/**************************************************** ************
* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ***********/

222
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

vacío principal (vacío)


{ initMain ();

lectura de charEmic;

// Inicializar módulo EUSART con 9600 baudios


EUSART_Inicializar(9600);

// dar tiempo al módulo para estabilizar


__delay_ms(3000);

// Enviar CR en caso de que el sistema esté activo

EUSART_Escribir(13);

mientras(1){

// Si el módulo TTS está listo if


(EUSART_Read() == 58){

// Di algo
EUSART_Escribir(83);
EUSART_Write_Text("Hola");
EUSART_Escribir(13);
__retraso_ms(500); }

regreso;

223
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

Uso de GPS (sistemas de posicionamiento global)


Ahora nos fijamos en el uso de GPS (Sistema de Posicionamiento Global). GPS es un
sistema que utiliza satélites para determinar la posición de un receptor GPS, que recibe

una señal de estos satélites. Simplemente no puedo cubrir el GPS en su totalidad en


este libro, ya que lo confundiría todo. Si quieres saber cómo funciona el GPS en detalle,
navega por Internet. Una vez que esté satisfecho, regrese y aprenda a usar el módulo. Una
buena característica del GPS es que no requiere una conexión activa a Internet o una red
celular para funcionar.

En este ejemplo, analizamos el uso del módulo GPS U-BLOX NEO-6M, ya que es muy
fácil de usar y, en el momento de escribir este artículo, está ampliamente disponible y tiene
un costo extremadamente bajo (consulte la Figura 9-3).

Figura 9-3. Módulo GPS U-BLOX NEO-6M

Comandos NMEA
Para usar el módulo GPS de manera efectiva, debemos comprender cómo funcionan
los datos NMEA transmitidos por el módulo GPS. NMEA significa Asociación
Nacional de Electrónica Marina y ese organismo produjo una especificación que
permite que el receptor GPS brinde los datos de tiempo, posición y velocidad que
el usuario puede analizar. El receptor GPS envía estos comandos como oraciones en
un formato particular.

224
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

Para el receptor GPS, todas estas oraciones comienzan con un


símbolo $ seguido de cinco letras. Las dos primeras letras siempre son
GP seguidas de otras tres letras, que nos dicen de qué trata la oración. Por
ejemplo, la oración que nos interesa es la GLL, que significa Latitud y
longitud geográfica. La sentencia tipo GLL tiene el siguiente formato:

$GPGLL,1123.01,N,1234.00,W,000111,A,*65

El $GPGLL nos dice el tipo de sentencia NMEA que es. el fragmento


1123.01,N nos indica una posición de latitud de 11 grados y 23,01
minutos norte. De manera similar, 1234.00,W indica una posición de
Longitud 12 grados y 34.00 minutos Oeste.
Para extraer la información sobre la posición del receptor, necesitamos
crear un búfer para almacenar la información a medida que llega. Luego,
Necesitamos eliminar cualquier dato no válido y usar la función strstr del
lenguaje C, que proporciona XC8, para determinar si la cadena que estamos
buscando está presente en el búfer.
Tengo un reto para usted. El código del Listado 9-5 se ha escrito para
mostrar las coordenadas en una pantalla LCD HD44780 (cubriremos esto
más adelante en el capítulo). Modifíquelo para imprimir en su LCD serial en
su lugar. (Si no desea hacer esto, es comprensible y puede pasar al Capítulo
8, donde se cubre la pantalla en su totalidad).

Listado 9-5. Código principal de GPS

/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: 21_EUSART
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*
*

225
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

*
Descripción del programa: este programa permite que PIC16F1717
comunicarse a través de la

* Módulo EUSART a un módulo GPS NEO-6M y visualización de


coordenadas de latitud * y longitud en una pantalla LCD.
*

* Descripción del hardware: un módulo GPS NEO-6M está conectado al


PIC16F1717
como * sigue:
*
* PPS -> NC
* RXD-> TX
*TXD->RX
* TIERRA -> TIERRA

* CCV -> CCV


*
*

* Creado el 18 de abril de 2017 a las 12:51 p.


m. */

/**************************************************** ************
*Incluye y define
********************************************** ****************/

#incluye "16F1717_Internal.h"
#incluye "EUSART.h"
#incluir "LCD.h"
#incluir <cadena.h>

// Variables
carbón volátil c;
carbón volátil d;

char* datos;

226
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

static char uartBuffer[300]; ent


yo;

terminador char*;
char conversionString[8];

doble latitud = 0,0;


doble lon = 0,0;

doble *longitud = &lon;


doble *latitud = &lat;

// Prototipo de función
void read_gps();

/**************************************************** ************
* Función: void initMain()
*

* Devoluciones: Nada
*
*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************/

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

// Configurar
PINS TRISBbits.TRISB3
= 1; ANSELBbits.ANSB3 = 0;

TRISBbits.TRISB2 = 0;
ANSELBbits.ANSB2 = 0;

227
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

TRISD = 0;
ANSELD = 0;
PUERTO = 0;

//////////////////////
// Configurar
EUSART /////////////////////
PPSLOCK = 0x55;
BLOQUEO PPS =
0xAA; PPSLOCKbits.PPSLOCKED = 0x00; // desbloquear PPS

RB2PPSbits.RB2PPS = 0x14; //RB2->EUSART:TX;


RXPPSbits.RXPPS = 0x0B; //RB3->EUSART:RX;

PPSLOCK = 0x55;
BLOQUEO PPS =
0xAA; PPSLOCKbits.PPSLOCKED = 0x01; // bloquear PPS

INTCONbits.GIE = 1;
INTCONbits.PEIE = 1;

// configurar UART 1 recibir interrupción


PIE1bits.RCIE = 1; }

/**************************************************** ************
* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************/

228
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

vacío principal (vacío)


{ initMain ();
Lcd_Inicio();
Lcd_Borrar();

// Inicializar módulo EUSART con 9600 baudios


EUSART_Inicializar(9600);

// dar tiempo al módulo para estabilizar


__delay_ms(100);

mientras(1){

Lcd_Set_Cursor(1,1);

leer_gps();

// Escribir Latitud

Lcd_Write_Float(*latitud);

Lcd_Set_Cursor(2,1);

// Escribir Longitud
Lcd_Write_Float(*longitud);

__retraso_ms(2000);
Lcd_Borrar(); }

regreso;

229
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

/**************************************************** ************
* Función: anular read_gps()
*
* Devoluciones: punteros a lat y lon
*
*
Descripción: Función para leer el módulo GPS
*
*
Uso: read_gps()
**************************************************** ***********/

anular leer_gps(){

// Leer caracteres de UART en el búfer


for(i=0; i<sizeof(uartBuffer)-1; i++) { d =
EUSART_Read_Char(c); uartBuffer[i] = d; }

// El último carácter es un terminador nulo


uartBuffer[tamaño(uartBuffer)-1] = '\0';

// Busque la aguja en el pajar para encontrar la cadena de


datos GPGLL = strstr(uartBuffer, "$GPGLL");

// si es nulo exit
if(data == NULL)
{ return; }

// Encuentra el
terminador terminador = strstr(datos,",");

230
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

// si es nulo exit
if(terminator == NULL)
{ return; }

// Si el primer byte del campo de latitud es ',', no hay información // así


que salga

if(datos[7] == ',')
{ retorno; }

////////////////////////////////////
// Buscar datos de búfer para valores
de latitud // y longitud ///////////////////////////////////

datos = terminador+1;

terminador = strstr(datos,",");

si (terminador == NULL)
{ retorno; }

memset(conversionString,0,sizeof(conversionString));
memcpy(conversionString, datos, 2); *latitud =
atof(conversionString);

datos +=
2; *terminador = '\0';
*latitud += (atof(datos)/60);

231
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

datos = terminador+1;
terminador = strstr(datos,","); si
(terminador == NULL) { retorno; }
if(*datos == 'S') { *latitud *= -1; }

datos = terminador+1;
terminador = strstr(datos,","); si
(terminador == NULL) { retorno; }

memset(conversionString,0,sizeof(conversionString));
memcpy(conversionString, datos, 3); *longitud =
atof(conversionString);

datos += 3;
*terminador = '\0';
*longitud += (atof(datos)/60);

datos = terminador+1;
terminador = strstr(datos,","); si
(terminador == NULL) { retorno; }

232
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

si(*datos == 'W')
{
*longitud *= -1;
}

Software USART
El PIC16F1717 solo tiene un módulo USART que los usuarios pueden
usar en sus aplicaciones. Ahora puede haber situaciones en las que
necesite usar más de un módulo USART para su aplicación. En este
caso, es posible que deba rediseñar su circuito y utilizar un chip que tenga más funciones.
Sin embargo, esto no es tan simple como parece, porque es posible que ya
esté familiarizado con el chip que está utilizando para su aplicación y es
posible que no desee asumir los costos asociados con el uso de un chip
más grande. En tales casos, puede ser útil usar una implementación de
software USART (también llamada "bit-banged").
El USART bit-banged que usamos en este ejemplo funciona de manera confiable hasta

aproximadamente 2400 baudios. Las velocidades de bits más altas pueden ser inestables y es
posible que no funcionen según lo previsto.

Módulo GSM
Veremos una aplicación del USART bit-banged utilizando un módulo
GSM. Usaremos el módulo SIM 800L (vea la Figura 9-4), que es muy
popular en el momento de escribir este artículo y es muy fácil de usar.

233
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

Figura 9-4. Módulo SIM800L

Comandos AT
En una sección anterior, analizamos los datos estructurados en formato NMEA, que es
el tipo de datos que suelen proporcionar los módulos GSM. En esta sección, analizamos
el uso de comandos AT (atención). Los comandos AT se usan comúnmente para
controlar módems. Estos son algunos comandos AT de uso común para controlar el
módulo SIM 800L:

• AT: Compruebe si el módulo funciona correctamente. Si se


es, volverá OK.

• AT+CREG?: Obtenga información sobre el registro de la red.


Si los módulos devuelven +CREG: 0,1, entonces todo es Mne.

• AT+IPR=9600: Cambia la tasa de baudios. Por ejemplo,


cambiar el 9600 a 2400 en el ejemplo establecería la tasa de
baudios en 2400.

Los otros comandos AT se usan para cosas como enviar y recibir


mensajes, llamadas, acceso a las funciones de GPS, entre otros. En este
ejemplo, nos centraremos únicamente en enviar mensajes de texto, por lo que los
comandos para enviar mensajes de texto se muestran en el código del Listado 9-6.
Nuevamente, otro desafío: modifique el código en el Listado 9-6 para ejecutarlo con la pantalla LCD en serie

234
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

en lugar del carácter LCD. Si no desea hacer esto, puede pasar a la sección
más adelante en este capítulo titulada “Carácter: la pantalla LCD Hitachi
HD44780” y usar el código de la pantalla LCD de caracteres en esa sección.

Listado 9-6. Código principal GSM

/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: I08_GSM
Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*
*
*
Descripción del programa: este programa permite que PIC16F1717
comunicarse con un
* Módulo GSM SIM800L y envío de un mensaje SMS.
*
*

* Descripción del hardware: un módulo GSM SIM800L se conecta de la


siguiente manera:

*5v -> 5V
*TIERRA -> TIERRA

*VDD -> NC
*SIM_TXD -> RX
* SIM_RXD -> TX
*TIERRA -> TIERRA
*
*

* Creado el 18 de abril de 2017 a las 13:11


*/

235
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

/**************************************************** ************
*Incluye y define
********************************************** ****************/

#incluye "16F1717_Internal.h"
#incluye "LCD.h"

// Configuración para
UART suave #define Baudrate
2400 //bps #define OneBitDelay (1000000/
Baudrate) #define DataBitCount 8 // sin paridad, sin
control de flujo #define UART_RX LATEbits.LATE0// UART
RX pin #define UART_TX LATEbits.LATE1 // Pin UART TX
#define UART_RX_DIR TRISE0// Registro de dirección de pin
UART RX #define UART_TX_DIR TRISE1 // Registro de dirección de pin UART TX

//Declaraciones de
funciones void
InitSoftUART(void); carácter sin
firmar UART_Receive(void); void
UART_Transmit(const char); void
SUART_Write_Text(char *texto);
vacío SUART_Write_Char(char a); void SUART_Read_Text(char *Salida, longitud int sin
/**************************************************** ************
* Función: void initMain()
*

* Devoluciones: Nada
*
*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************/

236
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

// Configurar pines
TRISD = 0x00;
ANSELD = 0x00;
PUERTO = 0x00;

TRISE = 0;
ANSELE = 0; }

/**************************************************** ************
* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************/

vacío principal (vacío)


{ initMain ();

Lcd_Inicio();
__retraso_ms(1000);

InitSoftUART(); // Inicializar UART suave


__delay_ms(1000);

mientras(1){

// Enviar comandos al módulo

SUART_Write_Text("AT+CMGF=1\r\n");
__retraso_ms(1000);

237
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

SUART_Write_Text("AT+CMGS=\"0009999\"\r\n"); // reemplaza el número


__delay_ms(1000);

// Mensaje a enviar
SUART_Write_Text("Prueba");
__retraso_ms(1000);

UART_Transmit((char)26);
__retraso_ms(1000);

// Notificar mensaje de usuario enviado


Lcd_Borrar();
Lcd_Set_Cursor(1,1);
__retraso_ms(100);

// Escribir cadena
Lcd_Write_String("Enviado");

__retraso_ms(2000);

regreso; }

/*
* Iniciar SW UART
*/
void InitSoftUART(void) // Inicializa los pines UART a los valores
adecuados
{
UART_TX = 1; // El pin TX está alto en estado inactivo

UART_RX_DIR = 1; // Aporte
UART_TX_DIR = 0; // Producción }

238
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

/*
* Recibir a través de SW UART
*/
char sin firmar UART_Receive(void) {

// Configuraciones de pines
// GP1 es pin UART RX

carácter sin firmar DataValue = 0;

//esperar el bit de inicio


while(UART_RX==1);

__delay_us(OneBitDelay);
__delay_us(OneBitDelay/2); // Toma el valor de la muestra a la mitad de la
duración del bit

for (char unsigned i = 0; i < DataBitCount; i++) { if (UART_RX


== 1) //si el bit recibido es alto {

ValorDatos += (1<<i); }

__delay_us(OneBitDelay); }

// Comprobar el bit de
parada si ( UART_RX == 1 ) // El bit de parada debe ser
alto { __delay_us(OneBitDelay/2); devolver valor de
datos; } else //¡ocurrió algún error!

239
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

{ __delay_us(OneBitDelay/2);
devolver 0x000; } }

/*
* Transmitir a través de SW UART

*/
void UART_Transmit(const char DataValue) {

/* Lógica básica

El pin TX suele ser alto. Un bit alto a bajo es el bit inicial y un bit bajo a alto
es el bit final. Sin bit de paridad. Sin control de flujo.
BitCount es el número de bits a transmitir. Los datos se transmiten LSB
primero.

*/

// Enviar bit de inicio


UART_TX =
0; __delay_us(OneBitDelay);

for (caracter sin signo i = 0; i <DataBitCount; i++) {

//Establece el pin de datos de acuerdo con el


valor de datos if(((DataValue>>i)&0x1) == 0x1 ) //si el bit es
alto {
UART_TX =
1; }

240
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

else //si el bit es bajo {

UART_TX =
0; }

__delay_us(OneBitDelay); }

//Enviar bit de parada


UART_TX = 1;
__delay_us(OneBitDelay); }

/*
* Escribir texto a través de SW UART

*/
void SUART_Write_Text(char *texto)
{ int i;

for(i=0;texto[i]!='\0';i++)
UART_Transmit(texto[i]); }

/*
* Leer texto a través de SW UART
*/
void SUART_Read_Text(char *Salida, longitud int sin signo) { int
i; for(int i=0;i<longitud;i++)

241
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

{
Salida[i] = UART_Receive();
}
}

/*
* Escribir Char a través de SW UART

*/
vacío SUART_Write_Char(char a)
{
UART_Transmitir (a - 0x128);
}

Uso de SPI (interfaz periférica en serie)


La interfaz periférica en serie (SPI) es otro tipo de protocolo de comunicación
en serie que se usa comúnmente en los sistemas integrados y está presente en
el microcontrolador PIC®. SPI es un protocolo muy importante y está
ampliamente implementado en una variedad de sensores. A diferencia de
USART, donde muy pocas aplicaciones requieren un reloj, en SPI un reloj está
presente en todas las aplicaciones porque SPI usa transferencia de datos síncrona.
El dispositivo en la comunicación SPI que genera el reloj se
conoce como maestro y el otro se conoce como esclavo. SPI siempre
tiene solo un dispositivo maestro, aunque puede haber muchos esclavos.
SPI tiene varias líneas: Serial Clock (SCK), Master Out Slave In (MOSI),
Master In Slave Out (MISO) y Slave Select (SS). Si solo hay un dispositivo
esclavo conectado al bus SPI, entonces esta línea puede dejarse baja ya que SPI está activo baj
Una de las principales desventajas de SPI es que utiliza muchas líneas de E/S.
Aunque SCK, MOSI y MISO siguen siendo los mismos
independientemente de la cantidad de dispositivos esclavos en el bus, se
debe usar una línea SS adicional para cada dispositivo esclavo que esté
conectado al bus. La ventaja de SPI es que puede transferir millones de bytes de datos por segundo

242
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

al interactuar con dispositivos como tarjetas SD, lo que requeriría una


transferencia de datos a velocidades muy altas.
Al aprender a usar el periférico SPI disponible en el PIC®
microcontrolador, utilizaremos un potenciómetro digital MCP4131 con el
microcontrolador PIC®.
El código para el SPI se generó utilizando el configurador de
código de Microchip. Hay muchos tutoriales sobre cómo usar el MCC,
así que te dejo que aprendas por tu cuenta. También te dejo que averigües
cómo conectar las líneas SPI. Sin embargo, aquí hay una pista: lea la hoja
de datos del MCP4131. Debe realizar algunas modificaciones en los nombres de los
funciones según el archivo de cabecera. Debe modificar los nombres para que coincidan
con los que se muestran en el archivo de encabezado.

El Listado 9-7 muestra el archivo de encabezado modificado de MCC para el SPI.

Listado 9-7. Encabezado SPI

/*
* Archivo: SPI.h
* Autor: Armstrong Subero
* FOTO: 16F1717 con X OSC @ 16MHz, 5v
*
Programa: archivo de encabezado para el módulo SPI
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
*
Versión del programa 1.0
*
*
Descripción del programa: este encabezado de programa proporciona funciones
prototipos para
* Módulo SPI en PIC16F1717
*
*
*

* Creado el 7 de noviembre de 2016 a las 17:45


*/

243
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

/**************************************************** ************
*Incluye y define
**************************************************** ************/

#incluye "16F1717_Internal.h"
#define DUMMY_DATA 0x0

vacío SPI_Initialize (vacío);


uint8_t SPI_Exchange8bit(uint8_t datos);
uint8_t SPI_Exchange8bitBuffer(uint8_t *entrada de datos, uint8_t bufLen,
uint8_t *salida de datos\
);
bool SPI_IsBufferFull(vacío);
bool SPI_HasWriteCollisionOccured(void);
vacío SPI_ClearWriteCollisionStatus (vacío);

Potenciómetro digital
El potenciómetro digital que usamos para demostrar el uso del bus SPI es el
MCP4131. El MCP4131 es un dispositivo de 7 bits que proporciona un total de
129 valores diferentes y se controla a través de SPI. En este ejemplo, enviamos
comandos al dispositivo y el dispositivo ajusta su resistencia. El cambio en la
resistencia es visible al conectar el pin POW del dispositivo a un LED a través de una resistencia de 1
La resistencia entonces variará en brillo.
El listado 9-8 proporciona el código principal.

Listado 9-8. Código principal

/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: 22_SPI
* Compilador: XC8 (v1.38, MPLAX X v3.40)

244
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

*
Versión del programa: 1.0
*
*
*
Descripción del programa: este programa permite que PIC16F1717
comunicarse a través de la

* Interfaz SPI
*
*

* Descripción del hardware: se conecta un LCD HD44780 a través de


PORTD y un potenciómetro digital MCP4131 * se conecta de la
siguiente manera:
*
* Vss --> Vss
* Vdd --> Vdd
* SS --> RD1
* SCK --> RC3
* SDI --> RC5
* POB --> TIERRA
* POW --> LED a través de una resistencia de 1k

* POA --> Vdd


*
*

* Creado el 10 de noviembre de 2016 a las


16:42 */

/**************************************************** ************
*Incluye y define
********************************************** ****************/

#incluye "16F1717_Internal.h"
#incluye "LCD.h"
#incluir "SPI.h"

245
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

vacío digiPot_write(int i);

/**************************************************** ************
* Función: void initMain()
*

* Devoluciones: Nada
*
*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************/

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

// Establecer PIN D1 como


salida TRISDbits.TRISD1 = 0;

// Apagar LED
LATDbits.LATD1 = 0;

// Configurar PUERTO
TRISD = 0;
ANSELD = 0;

// Inicializar LCD
Lcd_Inicio();
__retraso_ms(100);
Lcd_Borrar();

// Configurar PORTC para


SPI ANSELCbits.ANSC3 =
0; ANSELCbits.ANSC4 = 0;

246
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

ANSELCbits.ANSC5 = 0;

TRISCbits.TRISC3 = 0;
TRISCbits.TRISC4 = 1;
TRISCbits.TRISC5 = 0;

PPSLOCK = 0x55;
BLOQUEO PPS =
0xAA; PPSLOCKbits.PPSLOCKED = 0x00; // desbloquear PPS

SSPDATPPSbits.SSPDATPPS = 0x14; //RC4->MSSP:SDI;


RC3PPSbits.RC3PPS =0x10; //RC3->MSSP:SCK;
RC5PPSbits.RC5PPS =0x11; //RC5->MSSP:SDO;

PPSLOCK = 0x55;
BLOQUEO PPS =
0xAA; PPSLOCKbits.PPSLOCKED = 0x01; // bloquear PPS

// Inicializar SPI
SPI_Inicializar();

/**************************************************** ************
* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************/

vacío principal
(vacío) { initMain ();

// Variable Digipot int i;

247
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

Lcd_Set_Cursor(1,1);
__retraso_ms(5);
Lcd_Write_String("Listo para
SPI"); __retraso_ms(1000);
Lcd_Borrar();

mientras(1){

// Resolución de siete bits


para (i = 0; i <= 128; i++){
// Escribir valor
digiPot_write(i);
// Escribir en LCD
Lcd_Set_Cursor(1,1);
__retraso_ms(5);
Lcd_Write_Integer(i);
__retraso_ms(250);
Lcd_Borrar(); } }

regreso;

/**************************************************** ************
* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Escribe un valor particular en un potenciómetro digital
MCP4131
*
*
Uso: digiPot_write(x);
**************************************************** ************/

248
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

vacío digiPot_write(int i){


// Establecer SS bajo

LATDbits.LATD1 = 0;

// dirección del esclavo

SPI_Exchange8bit(0x00);

// Datos

SPI_Exchange8bit(yo);

// Establecer SS alto
LATDbits.LATD1 = 1;
}

Visualización de caracteres

Aunque el enfoque del siguiente capítulo son las pantallas, utilizamos una
pantalla LCD de caracteres simples para demostrar el protocolo I2C.

Personaje: Hitachi HD44780 LCD


La Hitachi HD44780 es conocida como la pantalla LCD de caracteres
estándar de la industria. La razón es simple: el HD44780 es muy fácil de usar. La
pantalla LCD se utiliza para mostrar caracteres a los usuarios. El tipo de pantalla
más utilizado es la variedad 2x16, que muestra hasta 16 caracteres en dos líneas.
La pantalla LCD es esencial para cualquier caja de herramientas integrada y constituye una excelente

pantalla para la creación de prototipos.

La pantalla LCD comúnmente tiene 14 pines; sin embargo, las pantallas LCD
que tienen luz de fondo tienen 16 pines. Recomiendo la versión con la luz de fondo.
Descargue la hoja de datos de su pantalla en particular para determinar qué versión
de pantalla tiene.
Veamos el código para usar la pantalla LCD HD44780.
Primero, el Listado 9-9 muestra el archivo de encabezado.

249
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

Listado 9-9. Archivo de encabezado HD44780

/*
* Archivo: LCD.h
* Autor: Armstrong Subero
* FOTO: 16F1717 con X OSC @ 16MHz, 5v
*
Programa: Archivo de
encabezado para * Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa
1.1 * *Comentarios adicionales agregados
*
*
Descripción del programa: este encabezado de programa proporciona rutinas
para controlar
*
un STD HITACHI HD44780 y LCD compatibles
*

* Descripción del hardware:


*
* RS ---> RD2
* L/E ---> TIERRA
* ES ---> RD3
* D4 ---> RD4
* D5 ---> RD5
* D6 ---> RD6
* D7 ---> RD7
*
*

* Creado el 7 de noviembre de 2016 a las 23:56


*/

250
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

/**************************************************** ************
*Incluye y define
********************************************** ****************/
// STD XC8 incluir
#incluir <xc.h>

#define RS RD2 //Selección de registro (carácter o instrucción)


#define EN RD3 //PIN de activación de reloj LCD, activado por flanco descendente

// Operación de 4
bits #define D4 RD4 //Bit 4
#define D5 RD5 //Bit 5
#define D6 RD6 //Bit 6
#define D7 RD7 //Bit 7

// prototipos de funciones
void Lcd_Port(char a);
vacío Lcd_Cmd(char a);
vacío Lcd_Clear(); void
Lcd_Set_Cursor(char a, char b); vacío
Lcd_Init(); vacío Lcd_Write_Char(char a);
void Lcd_Write_String(const char *a);
vacío Lcd_Shift_Right(); vacío
Lcd_Shift_Left(); vacío Lcd_Write_Integer(int
v); vacío Lcd_Write_Float (flotante f);

El siguiente es el archivo fuente, provisto en el Listado 9-10.

251
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

Listado 9-10. Archivo fuente HD44780

/*
* Archivo: LCD.c
* Autor: Armstrong Subero
* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: archivo de biblioteca para configurar PIC16F1717
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa:
1.1 * *Comentarios adicionales agregados
*
*
Descripción del programa: esta biblioteca le permite interactuar
HD44780 y *
LCD compatibles
*

* Creado el 7 de noviembre de 2016 a las 11:55


*/

#incluir "LCD.h"
#incluye "16F1717_Internal.h"

/**************************************************** ************
* Función: void Lcd_Port (char a)
*

* Devoluciones: Nada
*
*
Descripción: Rutinas de configuración de LCD
**************************************************** ************/

void Lcd_Port(char a)
{ if(a & 1)

D4 = 1;

252
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

demás

D4 = 0;

si (a & 2)
D5 = 1;
demás

D5 = 0;

si (a & 4)
D6 = 1;
demás

D6 = 0;

si (a y 8)
D7 = 1;
demás

D7 = 0; }

/**************************************************** ************
* Función: void Lcd_Cmd (char a)
*

* Devoluciones: Nada
*
*
Descripción: Establece el comando
LCD ******************************************** ****************/

vacío Lcd_Cmd(char a)
{
RS = 0; // => RS = 0
puerto_lcd(a);
ES = 1; // => E = 1
__delay_ms(1);
ES = 0; // => E = 0 }

253
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

/**************************************************** ************
* Función: anular Lcd_Clear()
*

* Devoluciones: Nada
*
*
Descripción: Borra la pantalla
LCD ******************************************** ****************/

vacío Lcd_Clear()
{
Lcd_Cmd(0);
Lcd_Cmd(1); }

/**************************************************** ************
* Función: void Lcd_Set_Cursor(char a, char b)
*

* Devoluciones: Nada
*
*
Descripción: Establece la posición del cursor LCD
**************************************************** ************/

void Lcd_Set_Cursor(char a, char b)


{ char temp,z,y; si(a == 1) { temp = 0x80
+ b - 1; z = temperatura>>4; y =
temperatura y 0x0F;

Lcd_Cmd(z);
Lcd_Cmd(y); }

254
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

de lo contrario si (a
== 2) { temp = 0xC0
+ b - 1; z = temperatura>>4;
y = temperatura y 0x0F;

Lcd_Cmd(z);
Lcd_Cmd(y); } }

/**************************************************** ************
* Función: anular Lcd_Init()
*

* Devoluciones: Nada
*
*
Descripción: Inicializa la pantalla LCD
**************************************************** ************/

vacío Lcd_Init() {

Puerto_Lcd(0x00);
__retraso_ms(10);
Lcd_Cmd(0x03);
__retraso_ms(3);
Lcd_Cmd(0x03);
__retraso_ms(10);

Lcd_Cmd(0x03); /////////////////////////////////////////////////// ///


Lcd_Cmd(0x02);
Lcd_Cmd(0x02);
Lcd_Cmd(0x08);
Lcd_Cmd(0x00);

255
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

Lcd_Cmd(0x0C);
Lcd_Cmd(0x00);
Lcd_Cmd(0x06); }

/**************************************************** ************
* Función: void Lcd_Write_Char (char a)
*

* Devoluciones: Nada
*
*
Descripción: Escribe un carácter en la pantalla LCD
**************************************************** ************/

void Lcd_Write_Char(char a)
{ char temp,y; temperatura =
a&0x0F; y = a&0xF0;

RS = 1; // => RS = 1
Puerto_Lcd(y>>4); //Transferencia de datos
ES = 1;
__delay_us(20);
ES = 0;
Lcd_Port(temp);
ES = 1;
__delay_us(20);
ES =
0; }

256
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

/**************************************************** ************
* Función: void Lcd_Write_String (const char *a)
*

* Devoluciones: Nada
*
*
Descripción: Escribe una cadena en la
pantalla LCD ****************************************** *******************/
void Lcd_Write_String(const char *a)
{ int i; para(i=0;a[i]!='\0';i++)

Lcd_Write_Char(a[i]); }

/**************************************************** ************
* Función: anular Lcd_Shift_Right()
*

* Devoluciones: Nada
*
*
Descripción: Cambia el texto en la pantalla LCD a la derecha
**************************************************** ************/

vacío Lcd_Shift_Right()
{
LCD_Cmd(0x01);
Lcd_Cmd(0x0C); }

257
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

/**************************************************** ************
* Función: anular Lcd_Shift_Left()
*

* Devoluciones: Nada
*
*
Descripción: desplaza el texto de la pantalla
LCD a la izquierda ****************************************** *******************/

vacío Lcd_Shift_Left() {

LCD_Cmd(0x01);
Lcd_Cmd(0x08); }

/**************************************************** ************
* Función: void Lcd_Write_Integer(int v)
*

* Devoluciones: Nada
*
*
Descripción: Convierte una cadena en un entero
**************************************************** ************/

void Lcd_Write_Integer(int v)
{ unsigned char buf[8];

Lcd_Write_String(itoa(buf, v, 10)); }

258
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

/**************************************************** ************
* Función: void Lcd_Write_Float(float f)
*

* Devoluciones: Nada
*
*
Descripción: Convierte una cadena en un flotante
**************************************************** ************/

void Lcd_Write_Float(float f)
{ char* buf11; estado int;

buf11 = ftoa(f, &estado);

Lcd_Write_String(buf11); }

Finalmente, el Listado 9-11 proporciona el código fuente que pasa por todos los
rutinas

Listado 9-11. HD44780 Principal

/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: 15_HD44780_LCD
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*
*

259
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

*
Descripción del programa: este programa permite que
PIC16F1717 interactúe con
* HD44780 y LCD compatibles
*

* Descripción del hardware: se conecta una pantalla LCD compatible con


HD44780 al PORTD del * microcontrolador de la siguiente manera:

*
* RS ---> RD2
* L/E ---> TIERRA
* ES ---> RD3
* D4---> RD4
* D5---> RD5
* D6---> RD6
* D7---> RD7
*
*

* Creado el 7 de noviembre de 2016 a las


11:05 */

/**************************************************** ************
*Incluye y define
********************************************** ****************/

#incluye "16F1717_Internal.h"
#incluye "LCD.h"

/**************************************************** ************
* Función: void initMain()
*

* Devoluciones: Nada
*

260
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

*
Descripción: Contiene inicializaciones para main
*
*
Uso: initMain()
**************************************************** ************/

void initPrincipal(){
// Ejecutar a 16 MHz

interno_16();

TRISD = 0x00;
ANSELD = 0x00;
PUERTO = 0x00; }

/**************************************************** ************
* Función: Principal
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************/

vacío principal
(vacío) { initMain ();
Lcd_Inicio();

en un;
intc;
flotador b;

mientras(1){
Lcd_Borrar();
Lcd_Set_Cursor(1,1);

261
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

// Escribir cadena
Lcd_Write_String("PIC16F1717");

// Desplazarlo a la
izquierda
para(a=0;a<15;a++)
{ __delay_ms(500);
Lcd_Shift_Left(); }

// Desplazarlo a la
derecha para
(a=0;a<15;a++)
{ __delay_ms(500);
Lcd_Shift_Derecha(); }

Lcd_Borrar();
Lcd_Set_Cursor(1,1);

// Escribir entero
para (c = 0; c < 100; c++){
Lcd_Write_Integer(c);
__retraso_ms(300);
Lcd_Borrar();
__retraso_ms(15);

// Escribir Flotante

para (b = 0.0; b <= 5; b+= 0.5)


{ Lcd_Write_Float(b); __retraso_ms(300);
Lcd_Borrar();

262
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

__retraso_ms(15);
}

__retraso_ms(1000);
}

regreso;
}

El Samsung KS0066U
El código del Listado 9-11 funciona en HD44780 y LCD compatibles,
incluido el Samsung KS0066U, y se probó en ambas pantallas.

Usando el I2C (Circuito Inter-Integrado)


Protocolo
Ahora veremos el protocolo final presentado en este capítulo, el protocolo
I2C (Inter-Integrated Circuit). Hay muchos tutoriales que profundizan en el
protocolo I2C y, por lo tanto, no intentaré dar una explicación detallada al
respecto. Hay algunas cosas que primero debe saber para usar este protocolo
de manera efectiva.
El protocolo I2C es ampliamente utilizado. En comparación con SPI, I2C
usa menos (solo dos) líneas, pero la comunicación ocurre a un ritmo más lento
y es un protocolo muy complejo. El ejemplo que vemos es leer y escribir una
EEPROM. Esta es una aplicación importante porque el PIC16F1717 no tiene una
EEPROM integrada.

I2C es único en comparación con los otros protocolos que hemos discutido
hasta ahora en que solo se usa una línea para el flujo de datos. En el bus I2C, el
dispositivo conocido como maestro se utiliza para comunicarse con otro dispositivo, conocido
como el esclavo. El maestro puede comunicarse con el esclavo porque cada
dispositivo en el esclavo tiene su propia dirección.

263
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

Las líneas utilizadas para la comunicación con el esclavo son las seriales.

línea de reloj (SCL) y línea de datos en serie (SDA). Para que I2C funcione,
las líneas deben estar conectadas a VCC mediante resistencias pull-up. Hay
cálculos que se pueden usar para determinar el valor de estas resistencias
calculando la capacidad de las líneas. En la práctica, sin embargo, he descubierto
que las resistencias de 4,7 K o 1 K hacen el trabajo de manera bastante adecuada.
Estas resistencias pull-up son necesarias porque los dispositivos I2C extraen la señal
línea baja pero no puede subirla, y las resistencias pull-up están ahí para
restaurar la línea de señal a alta.
La velocidad que utilizan la mayoría de los dispositivos I2C para comunicarse es de 100 kHz o

400 kHz. El protocolo transmite información a través de tramas. Hay dos tipos
de marcos disponibles: un marco de dirección, que informa al bus qué dispositivos
esclavos recibirán el mensaje, seguido de marcos de datos que contienen los datos
reales de 8 bits. Cada cuadro tiene un noveno bit, llamado bit de reconocimiento
(ACK) o no reconocimiento (NACK), que se utiliza para indicar si el dispositivo
esclavo lee la transmisión.

Cada comunicación I2C del maestro comienza con el maestro bajando la


línea SDA y dejando la línea SCL alta. Esto se conoce como la condición de inicio.
De manera similar, hay una condición de parada, donde hay una transición de
bajo a alto en SDA después de una transición de bajo a alto en SCL con SCL
siendo alto.

EEPROM
El ejemplo que usamos para I2C es conectar el microcontrolador con un dispositivo
EEPROM basado en I2C. El archivo de encabezado se muestra en el Listado 9-12.

Listado 9-12. Encabezado I2C

/*
* Archivo: I2C.h

* Autor: Armstrong Subero


* FOTO: 16F1717 con X OSC @ 16MHz, 5v

264
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

*
Programa: archivo de encabezado para configurar PIC16F1717 I2C
* Compilador: XC8 (v1.35, MPLAX X v3.10)
*
Versión del programa
1.2 * Archivo separado en encabezado y archivo
fuente C * Código no mcc usado
*
*
*
Descripción del programa: este encabezado de programa permitirá la
configuración de I2C
*

* Creado el 12 de septiembre de 2016 a las 19:00


*/

/**************************************************** ************
*Incluye y define
********************************************** ****************/

#incluye "16F1717_Internal.h"

vacío I2C_Init (vacío);


void Send_I2C_Data (byte de datos int sin
firmar); int sin firmar Read_I2C_Data(void); void
Send_I2C_ControlByte(unsigned int BlockAddress, unsigned int
RW_bit); vacío Send_I2C_StartBit (vacío); vacío Send_I2C_StopBit
(vacío); vacío Send_I2C_ACK (vacío); vacío Send_I2C_NAK (vacío);

265
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

El archivo fuente se muestra en el Listado 9-13.

Listado 9-13. Fuente I2C

/*
* Archivo: I2C.c
* Autor: Armstrong Subero
* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: archivo de biblioteca para configurar el módulo PIC16F1717 I2C
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa:
1.1 * *Comentarios adicionales agregados
*
*
Descripción del programa: esta biblioteca le permite controlar
PIC16F1717 I2C
*

* Creado el 12 de noviembre de 2016 a las 7:05 a.


m. */

#incluir "I2C.h"

vacío I2C_Init (vacío) {

//**************************************************** ************\
********

// Configure MSSP como modo maestro I2C, velocidad de reloj


de 100Khz //*********************************** ************************\
********

SSPCONbits.SSPM=0x08;// Modo maestro I2C, reloj = Fosc/(4 * (SSPADD+1))


SSPCONbits.SSPEN=1; // habilitar el puerto MSSP

266
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

// **************************************************** ***********\
************

// El valor del registro SPADD se usa para determinar la velocidad del


reloj para la comunicación // I2C.

// Ecuación para la frecuencia de reloj I2C: Fclock = Fosc/[(SSPADD +1)*4] //

// Para este ejemplo, queremos la frecuencia de reloj I2C estándar de


100Khz y nuestro
// Fosc interno es 16Mhz por lo que obtenemos: 100000 = 16000000/
[(SSPADD+1)*4] //
o resolviendo SSPADD = [(16000000/100000)-4]/4 // y
obtenemos SSPADD = 39

SSPADD = 39; // establece el divisor de reloj de


velocidad en baudios // ***************************************** *****************\
************

__retraso_ms(10); // deja que todo se asiente. }

//**************************************************** ************\
********

// Enviar un byte a VER //


******************************************** *******************\
********

void Send_I2C_Data (byte de datos int sin firmar)


{ PIR1bits.SSP1IF=0; // borra el bit de interrupción
del SSP SSPBUF = byte de datos; // enviar byte de
datos while(!PIR1bits.SSP1IF); // Espere a que el
indicador de interrupción suba, lo que indica que la transmisión está
completa }

267
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

//**************************************************** ************\
********

// Leer un byte de VER //


******************************************** *******************\
********

unsigned int Read_I2C_Data(void)


{ PIR1bits.SSP1IF=0; // borrar el bit
de interrupción del SSP SSPCON2bits.RCEN=1;//
configurar el bit de activación de recepción para iniciar una lectura de 8
bits de la EEPROM serial while(!PIR1bits.SSP1IF);// Esperar a que el
indicador de interrupción suba, indicando que la transmisión está
devolución completa (SSPBUF); // Los datos de la EEPROM ahora están
en el SSPBUF, devuelva ese valor

//**************************************************** ************\
********

// Enviar byte de control a SEE (esto incluye 4 bits de código de


dispositivo, bits de selección de bloque y el bit R/W) //
************************ ***************************************
****************\
********
// Notas:
// 1) El código del dispositivo para las EEPROM en serie se define
como '1010', que estamos usando en este ejemplo
// 2) RW_bit solo puede ser uno o cero
// 3) La dirección de bloque solo se usa para dispositivos SEE de más de
4K, sin embargo, en
// algunos otros dispositivos estos bits pueden convertirse en los bits
de dirección de hardware que

268
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

// le permite poner varios dispositivos del mismo tipo en el mismo bus.

// Lea la hoja de datos de su dispositivo EEPROM serial particular para


estar seguro.
//**************************************************** ************\
********

void Send_I2C_ControlByte (sin firmar int BlockAddress, sin firmar int


RW_bit)
{
PIR1bits.SSP1IF=0; // borrar el bit de interrupción del SSP

// Reúna el byte de control del código del dispositivo, bloquee los bits
de dirección y el bit R/W
// por lo que se ve así: CCCCBBBR
// donde 'CCCC' es el código de control del dispositivo
// 'BBB' es la dirección del bloque
// y 'R' es el bit de lectura/escritura

SSPBUF = (((0b1010 << 4) | (BlockAddress <<1)) + RW_bit); // envia


el byte de control

while(!PIR1bits.SSP1IF);// Espere a que el indicador de interrupción


aumente, lo que indica que la transmisión está completa
}

//**************************************************** ************\
********

// Enviar bit de inicio a VER


//**************************************************** ************\
********

269
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

void Send_I2C_StartBit(void)
{ PIR1bits.SSP1IF=0; // borra
el bit de interrupción del SSP
SSPCON2bits.SEN=1; // enviar bit de inicio while(!
PIR1bits.SSP1IF); // Espere a que el bit SSPIF vuelva a estar alto
antes de cargar el búfer de datos }

//**************************************************** ************\
********

// Enviar bit de parada a


VER //******************************************** *******************\
********

vacío Send_I2C_StopBit (vacío)


{ PIR1bits.SSP1IF=0; // borra el
bit de interrupción del SSP SSPCON2bits.PEN=1; //
enviar el bit de parada while(!PIR1bits.SSP1IF);//
Esperar a que el indicador de interrupción aumente indicando que la
transmisión está completa }

//**************************************************** ************\
********
// Enviar bit ACK a VER //
******************************************** *******************\
********

270
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

vacío Send_I2C_ACK (vacío)


{
PIR1bits.SSP1IF=0; // borrar el bit de interrupción del SSP
SSPCON2bits.ACKDT=0; // borre el bit de datos de reconocimiento: esto
significa que estamos enviando un reconocimiento o 'ACK'
SSPCON2bits.ACKEN=1; // establece el bit de habilitación de ACK
para iniciar la transmisión del bit ACK a la EEPROM serie
while(!PIR1bits.SSP1IF); // Espere a que el indicador de interrupción suba,
lo que indica que la transmisión está completa
}

//**************************************************** ************\
********

// Enviar bit NAK a SEE


//**************************************************** ************\
********

vacío Send_I2C_NAK (vacío)


{
PIR1bits.SSP1IF=0; // borrar el bit de interrupción del SSP
SSPCON2bits.ACKDT=1; // configure el bit de datos de reconocimiento;
esto significa que estamos enviando un No-Ack o 'NAK'
SSPCON2bits.ACKEN=1; // establece el bit de habilitación de ACK
para iniciar la transmisión del bit ACK a la EEPROM serie
while(!PIR1bits.SSP1IF); // Espere a que el indicador de interrupción suba,
lo que indica que la transmisión está completa
}

271
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

Ahora para el código principal, que se muestra en el Listado 9-14.

Listado 9-14. Archivo principal

/*
* Archivo: Principal.c

* Autor: Armstrong Subero


* FOTO: 16F1717 con OSC interno @ 16MHz, 5v
*
Programa: 24_I2C
* Compilador: XC8 (v1.38, MPLAX X v3.40)
*
Versión del programa: 1.0
*
*
*
Descripción del programa: este programa permite que PIC16F1717
comunicarse a través de la
* Interfaz I2C
*
*

* Descripción del hardware: un LCD HD44780 está conectado a través de


PORTD y un 24LC16B
* El chip EEPROM está conectado al bus I2C
*
*

* Creado el 10 de noviembre de 2016 a las


20:02 */

/**************************************************** ************
*Incluye y define
**************************************************** ************/

#incluye "16F1717_Internal.h"
#incluye "LCD.h"
#incluir "I2C.h"

272
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

/**************************************************** ************
*Incluye y define
**************************************************** ************/

int dirección_bloque = 0x00; // Establecer la dirección del bloque EEPROM


en el que escribiremos los datos

int palabra_dirección = 0x00; // Establecer la dirección de la palabra EEPROM que


vamos a escribir los datos a
int eeprom_data = 0x09; // Estos son los datos que vamos a escribir
int datos_entrantes;

/**************************************************** ************
* Función: vacío initmain (vacío)
*

* Devoluciones: Nada
*
*
Descripción: Inicializaciones para main
**************************************************** ************/

vacío initmain(vacío)
{ internal_16();

// Configurar pines para


I2C ANSELCbits.ANSC4
= 0; ANSELCbits.ANSC5 = 0;

TRISCbits.TRISC4 = 1;
TRISCbits.TRISC5 = 1;

PPSLOCK = 0x55;
BLOQUEO PPS =
0xAA; PPSLOCKbits.PPSLOCKED = 0x00; // desbloquear PPS

RC4PPSbits.RC4PPS =0x0011; //RC4->MSSP:SDA;


SSPDATPPSbits.SSPDATPPS =0x0014; //RC4->MSSP:SDA;

273
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

SSPCLKPPSbits.SSPCLKPPS =0x0015; //RC5->MSSP:SCL;


RC5PPSbits.RC5PPS =0x0010; //RC5->MSSP:SCL;

PPSLOCK = 0x55;
BLOQUEO PPS =
0xAA; PPSLOCKbits.PPSLOCKED = 0x01; // bloquear
PPS // Configuración para LCD TRISD = 0; ANSELD =
0;

//Configurar LCD

Lcd_Inicio();
__retraso_ms(1000);
Lcd_Borrar();

/**************************************************** ************
* Función: vacío principal (vacío)
*

* Devoluciones: Nada
*
*
Descripción: Punto de entrada del programa
**************************************************** ************/

vacío principal
(vacío) { initmain
();
I2C_Init();

Lcd_Set_Cursor(1,1);
Lcd_Write_String("Listo para I2C");
__retraso_ms(1000);
Lcd_Borrar();

274
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

mientras
(1)
{ ////////////////////////////
// Escribir EEPROM
///////////////////////////

Lcd_Set_Cursor(1,1);
Lcd_Write_String("Escribir");
__retraso_ms(1000);
Lcd_Borrar();

Enviar_I2C_StartBit(); // enviar bit de inicio


Send_I2C_ControlByte(block_address,0); // enviar byte de control con
bit R/W\
poner bajo

Send_I2C_Data(palabra_dirección); // enviar dirección de palabra


Enviar_I2C_Data(eeprom_data); // enviar byte de datos
Send_I2C_StopBit();//enviar bit de parada
__delay_ms(200);

/////////////////////////////
// Leer EEPROM
////////////////////////////

Lcd_Set_Cursor(1,1);
Lcd_Write_String("Leer");
__retraso_ms(1000);
Lcd_Borrar();

Enviar_I2C_StartBit(); // enviar bit de inicio


Send_I2C_ControlByte(block_address,0); // enviar byte de control
con bit R/W establecido bajo

Send_I2C_Data(palabra_dirección); // enviar dirección de palabra

275
Machine Translated by Google

CAPÍTULO 9 USART, SPI E I2C: PROTOCOLOS DE COMUNICACIÓN EN SERIE

Enviar_I2C_StartBit(); // enviar bit de inicio


Send_I2C_ControlByte(block_address,1); // enviar el byte de control con
el bit R/W establecido en alto
datos_entrantes = Read_I2C_Data(); // lee los datos que regresan de la
EEPROM
Enviar_I2C_NAK(); // envía NACK para decirle a la EEPROM que no queremos ninguna
más datos
Send_I2C_StopBit();

Lcd_Set_Cursor(1,1);

Lcd_Write_Integer(incoming_data);
__retraso_ms(1000);

Lcd_Borrar();
}
}

Conclusión
En este capítulo, analizamos USART, SPI e I2C, que son los
protocolos de comunicación fundamentales de los sistemas basados en microcontroladores.
También analizamos GPS, GSM, LCD y muchas otras cosas. Una vez que
comprenda estos protocolos de comunicación, puede conectar fácilmente
su microcontrolador a una gran cantidad de sensores. En este punto puedes
hacer mucho; sin embargo, siga leyendo porque los próximos capítulos
llevarán sus habilidades a otro nivel.

276

También podría gustarte