Vous êtes sur la page 1sur 171

CURSO DE LENGUAJE C PARA

MICROCONTROLADORES PIC 16F887


COMO SE HACE UN
MICROPROCESADOR
CURSO DE LENGUAJE C PARA
MICROCONTROLADORES PIC

PIC16F887
QUE ES UN MICROCONTROLADOR?

CIRCUITO INTEGRADO QUE CONTINE EN SU


ICIRCUITO INTEGRADO QUE CONTINE EN SU
INTERIOR LAS SIGUIENTES UNIDADES BÄSICAS:
•CPU
•MEMORIA RAM Y ROM
•PUERTOS DE ENTRADA Y SALIDA
, no realiza tarea alguna, este debe ser programado
fábrica

para que realice desde un simple parpadeo de un hasta


un sofisticado control
• Un microcontrolador de fábrica, no realiza tarea alguna, este
debe ser programado para que realice desde un simple
parpadeo de un led hasta un sofisticado control de un
robot. Un microcontrolador es capaz de realizar la tarea de
muchos circuitos lógicos como compuertas AND, OR, NOT,
NAND, conversores A/D, D/A, temporizadores,
decodificadores, etc., simplificando todo el diseño a una
placa de reducido tamaño y pocos elementos.
EL MICROCONTROLADOR
PIC16F887.
• Los microcontroladores PIC (Peripheral interface Controller),
son fabricados por la empresa MICROCHIP Technology INC.
cuya central se encuentra en Chandler, Arizona, esta empresa
ocupa el primer lugar en venta de microcontroladores de 8
bits desde el año 2002. Su gran éxito se debe a la gran
variedad (más de 180 modelos), gran versatilidad, gran
velocidad, bajo costo, bajo consumo de potencia, y gran
disponibilidad de herramientas para su programación. Uno
de los microcontroladores más populares en la actualidad es
el PIC16F887 y sus variantes PIC16FXXX y PIC16FXXX, estos
modelos (serie A) soportan hasta 100.000 ciclos de escritura
en su memoria FLASH, y 1’000.000 ciclos en su memoria
Eeprom.
PIC16F887
 CPU RISC
 8-bits de datos
 14 bits de memoria de programa
 Arquitectura Harvard, donde la memoria de programa y la
memoria de datos se encuentran en buses diferentes,
permitiendo mayor velocidad de acceso.
Principales características:

• Arquitectura RISC
• Frecuencia de Operación 0-20 MHz
• Oscilador interno de precisión calibrado de fábrica +/- 1%
• Selección de frecuencia por Software con un rango de
8MHz a 31KHz
• Voltaje de alimentación de 2.0-5.5V
• 35 Pines de Entrada/Salida
-Alta corriente de salida (source/sink) para operar
directamente un LED
-Resistencias de pull-up programables individualmente
por software
Principales características (2)

• 8K de memoria ROM con tecnología FLASH


-El Chip puede ser reprogramado hasta 100.000 veces
• Programación Serie In-Circuit.
El Chip puede ser programado aun instalado en la tarjeta.
• 256 bytes de memoria EEPROM
-Los datos Pueden ser escritos en EEPROM más de 1.000.000 de veces
• 368 bytes memoria RAM
• convertidor: A/D
-14-canales
-resolución 10-bits
• 3 temporizadores/contadores independientes
• Temporizador Watch-dog
• modulo Mejorado de USART
-Soporta RS-485, RS-232 y LIN2.0
Pines del PIC16F887
Tabla Comparativa del
PIC16F887
Características (2)
 14 fuentes de interrupciones
 Memoria de pila (stack) de 8 niveles de profundidad
 Protecciones:
• Power-on Reset (POR)
• Power-up Timer (PWRT)
• Oscillator Start-up Timer (OST)
• Watchdog Timer (WDT) independiente del cristal.
Puertos de entrada y salida
 PORTA ( RA5, RA4, RA3, RA2, RA1, RA0 )

 PORTB ( RB7, RB6, RB5, RB4, RB3, RB2, RB1, RB0 )

 PORTC ( RC7, RC6, RC5, RC4, RC3, RC2, RC1, RC0 )

 PORTD ( RD7, RD6, RD5, RD4, RD3, RD2, RD1, RD0 )

 PORTE ( RE2, RE1, RE0 )


Características (periféricos)
 Timer 0: timer/counter de 8 bits con un pre-
escalador de 8 valores.
 Timer 1: 16-bit timer/counter con pre-escalador
 Timer 2: 8-bit timer/counter con registro de estado
de 8-bit, pre-escalador y post-escalador
 Dos módulos de Capture, Compare, PWM
• Capture es de 16-bit, max. resolución es 12.5 ns
• Compare es de 16-bit, max. resolución es 200 ns
• PWM max. resolución de 10-bit
Características (periféricos 2)
 Convertidor analógico a digital de 10-bit multi-canal
 Puerto serial síncrono (SSP) con SPI. (modo maestro) e I2C
(maestro/esclavo)
 Transmisor-Receptor síncrono-asíncrono universal (USART/SCI) con
9-bit
 Puerto paralelo esclavo (PSP) con 8-bits de ancho, con terminales de
control RD, WR y CS
Arquitectura interna
 Arquitectura HARVARD.

 Buses separados (datos e instrucciones).

 Memoria de programa : 14 bits.

 Memoria de datos: 8 bits.

 Recursos mapeados en memoria de datos.


Arquitectura interna
PUERTOS
Puerto # funciones Funciones

PORTA 3 Entradas digital


Salidas digital
Entradas analógicas

PORTB 2 Entradas digital


Salidas digital
Entradas analógicas

PORTC 3 Entradas digital


Salidas digital
Medios de comunicación

PORTD 3 Entradas digital


Salidas digital
Puerto paralelo esclavo

PORTE 4 Entradas digital


Salidas digital
Entradas analógicas
Control del puerto paralelo esclavo
FUNCIONES PORTA
Terminal Funciones

RA0 Ent. Digital Sal. Digital Ent. Analógica

RA1 Ent. Digital Sal. Digital Ent. Analógica

RA2 Ent. Digital Sal. Digital Ent. Analógica VREF -

RA3 Ent. Digital Sal. Digital Ent. Analógica VREF +

RA4 Ent. Digital Sal. Digital Ent. contador 1

RA5 Ent. Digital Sal. Digital Ent. Analógica


FUNCIONES DEL PORTB

FUNCION
FUNCIONES
DEL PORTB
RB0 Ent. Digital Sal digital Ent. Interrupción 0
RB1 Ent. Digital Sal Digital
RB2 Ent. Digital Sal Digital
RB3 Ent. Digital Sal Digital PGM(función LVP)
RB4 Ent. Digital Sal Digital
RB5 Ent. Digital Sal Digital
RB6 Ent. Digital Sal Digital PGC (función LUP)
RB7 Ent. Digital Sal Digital PGD( función LVP)
FUNCIONES DEL PORTC
TERMINAL FUNCION
RC0 Ent. Digital Sal. Digital Sal. Osc Terminal1

RC1 Ent. Digital Sal. Digital Ent. Contador1

RC2 Ent. Digital Sal. Digital Captura/CompPWM1

RC3 Ent. Digital Sal. Digital Captura/comp PWM2

RC4 Ent. Digital Sal. Digital Reloj Sincrono SPI Reloj


Síncrono I2C

RC5 Ent. Digital Sal. Digital

RC6 Ent. Digital Sal. Digital Ent. Transmisión USART

RC7 Ent. Digital Sal. Digital Recepción USART


FUNCIONES DEL PORTD
TERMINAL FUNCION

RD0 Ent. Digital Sal. Digital Bit0 Parlelo Esclavo

RD1 Ent. Digital Sal. Digital Bit1Parlelo Esclavo


RD2 Ent. Digital Sal. Digital Bit2 Paralelo
Esclavo
RD3 Ent. Digital Sal. Digital Bit3Parlelo Esclavo
RD4 Ent. Digital Sal. Digital Bit4 Parlelo Esclavo
RD5 Ent. Digital Sal. Digital Bit5 Parlelo Esclavo
RD6 Ent. Digital Sal. Digital Bit6 Parlelo Esclavo
RD7 Ent. Digital Sal. Digital Bit7Parlelo Esclavo
FUNCIONES PORTE

Terminal Funciones

RE0 Ent. Digital Sal. Digital Ent. Analógica Lectura PSP

RE1 Ent. Digital Sal. Digital Ent. Analógica Escritura PSP

RE2 Ent. Digital Sal. Digital Ent. Analógica Habilitación PSP


Conceptos básicos de lenguaje
C
El lenguaje C data del año 1972; fue creado por los laboratorios Bell
como resultado de la necesidad de reescribir los sistemas operativos
UNIX con el fin de optimizar el conocido código ensamblador. De igual
manera el lenguaje C fue la evolución de lenguajes previos llamados B, y
BCPL. El nuevo lenguaje C, rápidamente tomó fuerza por su
funcionalidad y facilidad e n la implementación en diversos sistemas
computacionales que requerían códigos de máquina.

La forma del lenguaje C, se fundamenta en un complejo estructural que


requiere un amplio estudio de las mismas, sin embargo para la
programación de los microcontroladores el estudiante requiere una
porción fundamental que le permita iniciar y crear los primeros
proyectos en MikroC PRO, para este fin el actual capítulo se centra en
conocer las nociones necesarias para iniciar el estudio de los
microcontroladores.
Declaración de variables en lenguaje C
Las variables básicas en este compilador específico son:
• bit
• char
• short
• int
• long
• float
• double

Las variables bit permiten almacenar un valor lógico es decir verdadero o falso, 0 ó 1.

Las variables char se utilizan para almacenar caracteres codificados con el código ASCII, son útiles para
guardar letras o textos.

Una variable short almacena un número entero de 8 bits corto puede valer de: -127 a 127.

Las variables tipo int guardan números enteros de 16 bits, está variable permite guardar números de: -32767
a 32767.

La variable tipo long almacena números enteros largos de 32 bits, su rango puede ser de:
-2147483647 a 2147483647.

Las variables tipo float y double permiten guardar números con punto decimal.
En la siguiente tabla se pueden apreciar las características de las
variables Tipo de variable Tamaño en Bytes Valores que soporta
bit 1 0ó1
char 1 -127 a 127
short 1 -127 a 127
int 2 - 32767 a 32767
long 4 - 2147483647 a 2147483647
float 4 -1.5x10^45 a 3.4x10^38
double 4 -1.5x10^45 a 3.4x10^38
unsigned char 1 0 a 255
unsigned short 1 0 a 255
unsigned int 2 0 a 65535
unsigned long 4 0 a 4294967295
• La declaración de variables se realiza indicando el tipo de variable seguido de un nombre
que el desarrollador asigna arbitrariamente a la variable. En el punto de la declaración de
una variable es posible dar un valor inicial a cada una de las variables sin embargo
este último no es estrictamente necesario. Por último la declaración debe culminar con el
carácter punto y coma (;).
• En los siguientes ejemplos se puede apreciar como se hacen las declaraciones:

• bit VARIABLE1_BIT; //Declaración de una variable tipo bit.


• char CARACTER; //Declaración de una variable tipo char.
• char CARACTER2='J'; //Declaración de una variable tipo char inicializada con el
• //valor ASCII del carácter J.
• int ENTERO=1234; //Declaración de una variable tipo entera inicializada con
• //el valor 1234.
• float DECIMAL=-12.45; //Declaración de una variable con punto decimal
• //inicializada con el valor -12,45.
• double DECIMAL2=56.68; //Declaración de una variable con punto decimal
• //inicializada con el valor 56,68.
• long ENTERO2=-954261; //Demacración de una variable de tipo entero largo
• //inicializada con el valor -954261.
• Los siguientes ejemplos muestras como declarar variables sin signo:

• unsigned char CARACTER; //Declaración de una variable tipo char


sin signo.
• unsigned int ENTERO; //Declaración de una variable tipo entera
sin signo.
• unsigned long ENTERO2; //Demacración de una variable de tipo
entero largo sin signo.

• Las variables también pueden ser declaradas en un formato que


asocia varias variables a un mismo nombre, este formato se conoce
como una cadena de variables, o un vector e incluso puede ser una
matriz de variables, en conclusión este tipo de declaraciones pueden
ser de una o más dimensiones.
• El siguiente ejemplo muestra un vector de caracteres, o también conocido como
una cadena de caracteres:

• char Texto[20]; //Cadena de caracteres con 20 posiciones de memoria.



• De igual manera las cadenas de caracteres o de variables pueden ser declaradas
con un valor inicial, este tipo de declaración se puede ver en el siguiente
ejemplo:

• char Texto[20] = “Nuevo Texto”; //Declaración de una cadena de caracteres


• //inicializada con el texto: Nuevo Texto.
• int Enteros[5]={5,4,3,2,1}; //Declaración de una cadena de enteros con
• //valores iniciales.
• float Decimales[3]={0.8,1.5,5.8}; //Declaración de una cadena de números con
• //punto decimal inicializadas.
• La declaración de las variables debe respetar algunas reglas básicas
que evitan errores y contradicciones en la compilación del código,
para este fin tenga presente las siguientes recomendaciones:

• · Las variables no deben tener nombres repetidos.
• · Las variables no deben empezar por un número.
• · Una variable no puede utilizar caracteres especiales como: / * „ ; {
}-\! · % &.

• A continuación se muestran ejemplos de declaraciones de variables
que no se pueden hacer:

• bit 1_VARIABLE-; char -CARÁCTER!; int 3ENTERO*;
• De igual manera es posible crear estructuras de información como un nuevo tipo
de variable creada por el desarrollador. Estás estructuras se pueden realizar con
las variables ya predefinidas y pueden ser declaraciones de variables o de
arreglos de variables. Este tipo de estructuras se declarar, por medio de la
directriz: typedef struct, y la forma de declarar una variable creada por el
desarrollador es la siguiente:

• typedef struct
• {
• char Nombre[10];
• int Edad;
• }Usuario;

• La siguiente es la forma de usar una variable personalizada por el desarrollador:

• Usuario U; U.Edad = 25; U.Nombre[0]=‟J‟; U.Nombre[1]=‟u‟; U.Nombre[2]=‟a‟;

Formatos numéricos usados en el lenguaje C
Los aplicativos en lenguaje C usan números en diferentes bases numéricas, a pesar
de que para el trabajo de bajo nivel del microcontrolador todos sus números están
procesados en base 2 es decir en números binarios. El ser humano no está
acostumbrado a pensar y procesar operaciones en está base numérica. Desde las
primeras etapas de la formación académica las escuelas y colegios enseñan a pensar
y procesar todos los cálculos en base 10, es decir con números decimales. Es por
esto que los compiladores en lenguaje C trabajan los números decimales facilitando
los diseños para el desarrollador. Además del sistema decimal el compilador en
lenguaje C puede trabajar otras bases tales como el binario, y hexadecimal haciendo
más simple realizar cálculos y tareas que en decimal serían más complejas. Los
sistemas numéricos en base 2, 10, y 16, son los implementados en este compilador
en lenguaje C. La escritura de números decimales, es la forma de mayor simplicidad
ya que se escriben en lenguaje C de la misma manera convencional que se aprende
desde los primeros cursos de matemáticas. Los números binarios se escriben con el
encabezado 0b seguidos del número en binario, un ejemplo de está escritura es:
0b10100001 que es equivalente al número decimal 161. Los números en base 16 o
hexadecimales se denotan con el encabezado 0x precedidos de un número en
hexadecimal, la expresión 0x2A, es un ejemplo de un número hexadecimal en
lenguaje C, y equivale a 42 en decimal. Los números binarios solo pueden tener dos
dígitos que son el 0 y el 1. Los números hexadecimales pueden tener 16 dígitos que
son; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E y F.
Operadores en lenguaje C
El lenguaje C permite hacer operaciones aritméticas o matemáticas básicas entre números
contenidos en variables o constantes. Las operaciones aritméticas disponibles son las siguientes:

• · Suma
• · Resta
• · Multiplicación
• · División
• · Modulo

La suma aritmética entre dos o más números, se puede hacer como se ve en el siguiente ejemplo:
int A; int B; int C;
C = A+B; //Está expresión guarda la suma de A y B en la variable C.
C = A+B+C; //Está expresión guarda la suma de A, B y C en la variable C.

La resta aritmética entre dos o más números, se puede hacer como se ve en el siguiente ejemplo:
int A; int B; int C;
C = A-B; //Está expresión guarda la diferencia entre A y B en la variable C.
C = A-B-C; //Está expresión guarda la diferencia entre A, B y C en la variable C.
La operación matemática de multiplicación se puede realizar entre dos o más
números, la operación se relaciona con el carácter asterisco (*), está expresión se
puede apreciar con mayor claridad en los siguientes ejemplos:
int A; int B; int C;
C = A*B; //Está expresión guarda la multiplicación entre A y B en la variable C.
C = A*B*C; //Está expresión guarda la multiplicación entre A, B y C en la variable C.

La división aritmética en lenguaje C se especifica por medio de la barra inclinada (/),


en el siguiente ejemplo se puede observar su implementación:
int A; int B; int C;
C = A/B; //Está expresión guarda la división A entre B en la variable C.

La operación módulo calcula el módulo de una división aritmética es decir calcula el


residuo de una división, el cálculo del módulo se denota con el carácter de
porcentaje, (%), la aplicación de está operación se puede ver en el siguiente ejemplo:
int A; int B; int C;
C = A%B; //Está expresión guarda el residuo de la división de A entre B en la variable
C.
Las operaciones aritméticas pueden ser usadas en forma combinada, es
decir que se pueden mezclar varias operaciones en una misma
expresión, para ver esto con mayor claridad observe los siguientes
ejemplos:
int A; int B; int C;

C = (A+B)/C; //Está expresión es equivalente a C = (A+B)÷C.


C = (A/B)*C; // Está expresión es equivalente a C = (A÷B) X C.

Otros operadores matemáticos abreviados pueden ser utilizados


cuando se requiere de conteos o cambios de una variable de forma
constante, por ejemplo es posible incrementar o decrementar una
variable en términos de un número, de igual manera es posible hacer
está operación con la multiplicación y la división. Para entender de
forma más clara este concepto observe los siguientes ejemplos:
int A=100;
int B=10;
A++; //Este operador incrementa en una unidad el valor de A. A--;
//Este operador decrementa en una unidad el valor de A. A+=4; //Este
operador incrementa en 4 el valor de A.
A-=5; //Este operador decrementa en 5 el valor de A. A/=4; //Este
operador divide el valor de A en 4. A*=3; //Este operador multiplica el
valor de A por 3.
A+=B;//Este operador incrementa el valor de A en el valor de B
unidades. A*=B; //Este operador multiplica el valor de A por B veces.
Otras operaciones matemáticas de mayor complejidad se pueden
realizar en lenguaje C, por medio de funciones predefinidas en la
librería math, está temática será tratada posteriormente cuando se
estudie el uso y declaración de funciones.
OPREADORES LOGICOS
Los operadores lógicos permiten realizar acciones u operaciones que
respetan la lógica digital planteada por el matemático inglés George
Boole, en el siglo XIX. Boole planteó las operaciones OR, AND, NOT,
XOR, NOR, NAND, XNOR, Estás operaciones son ampliamente
estudiadas en los cursos de sistemas digitales combinacionales y
secuenciales.
Las operaciones lógicas se realizan en lenguaje C entre dos variables o
constantes, estás se hacen bit a bit, del mismo peso en una variable o
número. Para ver y entender los ejemplos recuerde primero las tablas
de verdad de las operaciones lógicas que se muestran a continuación
Como Operan las funciones lógicas
Las operaciones lógicas en lenguaje C, se realizan con caracteres específicos, que
denotan cada una de ellas, en el siguiente ejemplo pueden verse las aplicaciones de
los operadores lógicos:
Operación lógica NOT, negación, se denota con el carácter virgulilla (~);
unsigned short VALOR1=0b01010000; //Variable inicializada en binario con el
número 80.
unsigned short RESULTADO;
RESULTADO = ~VALOR1; //La variable RESULTADO guarda el complemento de
//VALOR1, 175.

Operación lógica OR, o inclusiva, está se denota con el carácter barra vertical (|);
unsigned short VALOR1=0b01010000; //Variable inicializada en binario con el
número 80. unsigned short VALOR2=0b01011111; //Variable inicializada en binario
con el número 95. unsigned short RESULTADO;
RESULTADO = VALOR1|VALOR2; //El valor de la operación lógica o, es
guardado en
//RESULTADO, 95.
Operación lógica XOR, o exclusiva, está se denota con el carácter acento
circunflejo (^); unsigned short VALOR1=0b01010000; //Variable
inicializada en binario con el número 80. unsigned short
VALOR2=0b01011111; //Variable inicializada en binario con el número
95. unsigned short RESULTADO;
RESULTADO = VALOR1^VALOR2; //El valor de la operación lógica
AND
//es guardado en RESULTADO, 15.

Operación lógica AND, y, está se denota con el carácter ampersand (&);


unsigned short VALOR1=0b01010000; //Variable inicializada en binario
con el número 80. unsigned short VALOR2=0b01011111; //Variable
inicializada en binario con el número 95. unsigned short RESULTADO;
RESULTADO = VALOR1&VALOR2; //El valor de la operación lógica o
//exclusiva, es guardado en RESULTADO, 80.
La implementación de las operaciones lógicas NAND, NOR, XNOR, son similares a
AND, OR, y XOR, a agregando el carácter de negación virgulilla, observe los siguieres
ejemplos:
unsigned short VALOR1=0b01010000; //Variable inicializada en binario con el
número 80. unsigned short VALOR2=0b01011111; //Variable inicializada en binario
con el número 95. unsigned short RESULTADO;
RESULTADO = ~(VALOR1|VALOR2); //El valor de la operación lógica o negada
// exclusiva, es guardado en RESULTADO.
RESULTADO = ~(VALOR1&VALOR2); //El valor de la operación lógica y negada,
// es guardado en RESULTADO.
RESULTADO = ~(VALOR1^VALOR2); //El valor de la operación lógica o negada
// exclusiva negada, es guardado en RESULTADO.
El desplazamiento de bits dentro de una variable es útil para realizar procesos y
tareas que impliquen la manipulación de datos a nivel de los bits. El corrimiento a la
derecha en una variable o valor constante, en lenguaje C se realiza por medio del
doble carácter mayor que, (>>), de la misma manera el corrimiento a la izquierda se
ejecuta con el doble carácter menor que, (<<). La operación de corrimiento hace
perder los valores de los bits que salen, e ingresa ceros en
los nuevos bits. En los siguientes ejemplos se puede
observar la implementación de estos operadores:
short Dato=0xFF; //Declaración de variables.
short Resultado;
Resultado = Dato>>4; //Está operación guarda en la variable
Resultado el corrimiento de 4 bits
//a la derecha de la variable Dato, valor final de Resultado es
0x0F.
Resultado = Dato<<4; //Está operación guarda en la variable
Resultado el corrimiento de 4 bits
//a la izquierda de la variable Dato, valor final de Resultado es
0xF0.
Funciones en lenguaje C

Una función es una fracción de código que realiza una tarea específica cada vez que
está es invocada por el flujo del programa principal. Las funciones cuentan con dos
características fundamentales, uno o más parámetros de entrada, y un parámetro de
salida. Cualquiera de estás dos características puede ser una variable o un arreglo de
ellas, de igual manera estos parámetros de entrada y salida pueden ser vacíos.

La estructura de las funciones se puede apreciar en los siguientes ejemplos:

void Funcion ( void ) //Función con parámetros de entrada y salida vacíos.


{ // Apertura de la función con corchete.
//Porción de código donde se ejecutan la rutina de la función.
} //Cierre de la función con corchete.

void Funcion ( int A ) //Función con un parámetro de entrada y salida vacía.


{ // Apertura de la función con corchete.
//Porción de código donde se ejecutan la rutina de la función.
} //Cierre de la función con corchete.
int Funcion ( void ) //Función con parámetro de entrada vacío y salida entera.
{ // Apertura de la función con corchete.
//Porción de código donde se ejecutan la rutina de la función.
} //Cierre de la función con corchete.

int Funcion ( int A ) //Función con un parámetro de entrada y salida enteras.


{ // Apertura de la función con corchete.
//Porción de código donde se ejecutan la rutina de la función.
} //Cierre de la función con corchete.

Los nombres que se designan a las funciones cumplen con las mismas reglas para nombrar las variables. El siguiente
ejemplo muestra una función que es capaz de calcular el producto de dos números con punto decimal:

float Producto ( float A, flota B ) //Función para calcular el producto de A y B.


{ // Apertura de la función con corchete.
float RESULTADO;
RESULTADO = A*B; //Producto de A y B.
return RESULTADO; //La función retorna el resultado guardado en RESULTADO.
} //Cierre de la función con corchete.

Una función puede recurrir a otra función para realizar funciones más complejas, para demostrar está situación se
puede ver el siguiente ejemplo, que realiza el cálculo del área de una circunferencia en función de su radio:
El área de la circunferencia se calcula por medio de la ecuación A=πr², donde el valor
de π es
aproximadamente 3,1416.

float Valor_PI ( void ) //Función que retorna el valor de π.


{ // Apertura de la función con corchete.
float PI=3.1416;
return PI;
} //Cierre de la función con corchete.

En el caso en que una función requiera variables internas está declaración se debe
hacer al principio de la misma, antes de realizar cualquier otra acción o instrucción.

float Area_Circunferencia ( float Radio ) //Función para calcular el área del circulo.
{ // Apertura de la función con corchete.
float Area;
La sentencia condicional if e if
else
La estructura de la sentencia if evalúa una condición lógica y ejecuta
una porción de código si y solo si el resultado de la evaluación es
verdadera. Observe la estructura del la sentencia if en el siguiente
ejemplo:

short Valor;
if( Valor>100 ) //Este if evalúa si la variable Valor es mayor que 100.
{
// Porción de código que se ejecuta si el if es verdadero.
}

La estructura if else es igual que la sentencia if, su única diferencia es


que en el dado caso de que la evaluación de la condición sea falsa se
ejecuta la porción de código asociada al else. Para entender está
situación observe el siguiente ejemplo:
short Valor;
if( Valor>100 ) //Este if evalúa si la variable Valor es mayor que
100.
{
}
else
{
}

// Porción de código que se ejecuta si la condición del if es


verdadero.
// Porción de código que se ejecuta si la condición del if es falsa.
Las sentencias if e if else se pueden anidar para crear estructuras más
completas y complejas, está característica se puede ver con claridad en
el siguiente ejemplo:
short Valor1; //Declaración de variables.
short Valor2;
if( Valor1>30 ) //Sentencia if.
{
// Código que se ejecuta cuando el primer if tiene una condición
verdadera.
if( (Valor2==4)&&(Valor1<50) ) //Segunda sentencia if anidad.
{
//Código que se ejecuta cuando el segando if tiene una condición
verdadera.
}
}
Tipos de datos
Tipo bytes Rango
(unsigned) char 1 0 .. 255
signed char 1 - 128 .. 127
(signed) short (int) 1 - 128 .. 127
unsigned short (int) 1 0 .. 255
(signed) int 2 -32768 .. 32767
unsigned (int) 2 0 .. 65535
(signed) long (int) 4 -2147483648 ..2147483647
unsigned long (int) 4 0 .. 4294967295
La sentencia switch case
La sentencia switch case, funciona de manera similar a la sentencia if,
difiere en que no se evalúa una condición si no el valor de una variable,
y ejecuta una porción de código para cada valor posible de la variable.
Los valores contemplados en los casos o case posibles de la variable los
escoge el desarrollador arbitrariamente en función de su criterio y
necesidad. Los casos o valores que no son de interés para el
desarrollador se ejecutan en un fragmento de código por defecto, por
medio de la directriz default. Cada uno de los fragmentos de código
editados deben terminar con la directriz break para romper el flujo de
la estructura switch case, está acción es necesaria dado que si dos casos
están seguidos los fragmentos de código seguidos se ejecutarán hasta
encontrar la directriz break o hasta finalizar la estructura switch case.
Para comprender de forma clara el funcionamiento de la sentencia
switch case observe el siguiente ejemplo:
short Valor;
switch( Valor ) //Evaluación de la variable Valor.
{
case 0: //Fragmento de código correspondiente al valor 0 de la variable Valor.
break; //Ruptura del caso 0.
case 1: //Fragmento de código correspondiente al valor 1 de la variable Valor.
break; //Ruptura del caso 1.
case 10: //Fragmento de código correspondiente al valor 10 de la variable Valor.
break; //Ruptura del caso 10.
case 20: //Fragmento de código correspondiente al valor 20 de la variable Valor.
break; //Ruptura del caso 20.
case 50: //Fragmento de código correspondiente al valor 50 de la variable Valor.
break; //Ruptura del caso 50.
default: //Código correspondiente para cualquier otro valor por defecto.
break; //Ruptura del default.
}
El ciclo iterativo while y do
while
El ciclo iterativo while repite o ejecuta un fragmento de programa siempre y cuando la
condición contenida en el while sea verdadera. Para conocer la forma de declarar este tipo de
ciclo observe el siguiente ejemplo:

short CONT=0; //Declaración de variable entera que cuenta hasta 100. while( CONT<100 )
//Declaración del ciclo while.
{
CONT++; //Incremento de la variable CONT.
}

La implementación de un ciclo do while, es similar al ciclo while, con la diferencia puntual de


que en este ciclo el fragmento de código se ejecuta y después evalúa la condición del while. En
conclusión el código se ejecuta por lo menos una vez antes de evaluar la condición. En el
siguiente ejemplo se puede ver la forma de usar este tipo de ciclo:

short CONT=0; //Declaración de variable entera que cuenta hasta 100.


do //Declaración del ciclo do while.
{
CONT++; //Incremento de la variable CONT.
} while( CONT<100 );
El ciclo iterativo for

El ciclo iterativo for es una estructura parecida al ciclo while, la


diferencia es una estructura más compleja en los paréntesis de la
condición. La condición cuenta con tres parámetros, el primero es
un espacio de código para dar valores iniciales a una o más
variables, el segundo campo permite crear una condición lógica
que hace repetir el fragmento de código del for cuando está es
verdadera, el último espacio realiza cambio sobre una o más
variables, tal como: incrementos, decrementos, etc. Las variables
que se cambian en el último campo son generalmente las mismas
que se inician en el primer campo, pero está no es una regla.
Observe la estructura del for en el siguiente modelo:
for( _INICIO_ ; _CONDICION_; _CAMBIO_ )
{
}
Para conocer el funcionamiento del ciclo for observe el siguiente ejemplo:
short A; //Declaración de variables.
short B;
for( A=0, B=100; (A<100)||(B>20); A++, B-- ) //Estructura del ciclo for.
{
//Fragmento de código que se ejecuta cuando la condición del for es verdadera.
}
Uso anidado de ciclos iterativos
Muchas de las aplicaciones incrementan su funcionalidad y
optimizan el tamaño del código de máquina final al usar los
ciclos iterativos de forma anidada. La anidación de ciclos
consiste en ejecutar un ciclo dentro de otro. Un ciclo puede
contener uno o más ciclos anidados. Para comprender este
concepto de mejor manera observe el siguiente ejemplo:
short COL; //Declaración de variables.
short FIL;
short MATRIZ[10][10]; //Declamación de un vector bidimensional.
for( COL=0; COL<10; COL++ ) //Declaración de ciclo for.
{
//Fragmento del primer ciclo.
for( FIL=0; FIL<10; FIL++ ) //Declaración de ciclo for anidado.
{
//Fragmento del ciclo anidado. MATRIZ[COL][FIL] = COL*FIL;
}
}
El ejemplo anterior, guarda valores en una matriz de 10 por 10, recorriendo
una a una las posiciones de la misma.
La sentencia switch case
La sentencia switch case, funciona de manera similar a la sentencia if,
difiere en que no se evalúa una condición si no el valor de una
variable, y ejecuta una porción de código para cada valor posible de la
variable. Los valores contemplados en los casos o case posibles de la
variable los escoge el desarrollador arbitrariamente en función de su
criterio y necesidad. Los casos o valores que no son de interés para el
desarrollador se ejecutan en un fragmento de código por defecto, por
medio de la directriz default. Cada uno de los fragmentos de código
editados deben terminar con la directriz break para romper el flujo de
la estructura switch case, está acción es necesaria dado que si dos
casos están seguidos los fragmentos de código seguidos se ejecutarán
hasta encontrar la directriz break o hasta finalizar la estructura switch
case. Para comprender de forma clara el funcionamiento de la
sentencia switch case observe el siguiente ejemplo:
short Valor;
switch( Valor ) //Evaluación de la variable Valor.
{
case 0: //Fragmento de código correspondiente al valor 0 de la variable Valor.
break; //Ruptura del caso 0.
case 1: //Fragmento de código correspondiente al valor 1 de la variable Valor.
break; //Ruptura del caso 1.
case 10: //Fragmento de código correspondiente al valor 10 de la variable Valor.
break; //Ruptura del caso 10.
case 20: //Fragmento de código correspondiente al valor 20 de la variable Valor.
break; //Ruptura del caso 20.
case 50: //Fragmento de código correspondiente al valor 50 de la variable Valor.
break; //Ruptura del caso 50.
default: //Código correspondiente para cualquier otro valor por defecto.
break; //Ruptura del default.
}
El ciclo iterativo while y do while
El ciclo iterativo while repite o ejecuta un fragmento de programa siempre y cuando la
condición contenida en el while sea verdadera. Para conocer la forma de declarar este tipo de
ciclo observe el siguiente ejemplo:

short CONT=0; //Declaración de variable entera que cuenta hasta 100. while( CONT<100 )
//Declaración del ciclo while.
{
CONT++; //Incremento de la variable CONT.
}

La implementación de un ciclo do while, es similar al ciclo while, con la diferencia puntual de


que en este ciclo el fragmento de código se ejecuta y después evalúa la condición del while. En
conclusión el código se ejecuta por lo menos una vez antes de evaluar la condición. En el
siguiente ejemplo se puede ver la forma de usar este tipo de ciclo:

short CONT=0; //Declaración de variable entera que cuenta hasta 100.


do //Declaración del ciclo do while.
{
Tipos de datos 2
Tipo bytes Rango

float 4 ±1.17549435082 x 10-38 .. ±6.80564774407 x 1038

Double 4 ±1.17549435082 x 10-38 .. ±6.80564774407 x 1038

long double 4 ±1.17549435082 x 10-38 .. ±6.80564774407 x 1038


Asignación de datos
 Decimal
• int i = 10; /* decimal 10 */
• int j = -10; /* decimal -10 */
• int p = 0; /* decimal 0 */

 Hexadecimal
• short x = 0x37; /* decimal 55 */
• short y = 0x7F; /* decimal 127 */
• int z = 0x125; /* decimal 293 */
Asignación de datos
 Octal
• int m = 023; /* 19 */
• short n = 016; /* 14 */

 Binario
• char dato = 0b00001111;
• short dat = 0b10101010;
• unsigned char sig = 0b11001100;

 ASCII
• char dat = ‘a’;
• char m = ‘5’;
Registros asociados
Entrada/salida Configuración
 PORTA TRISA

 PORTB TRISB

 PORTC TRISC

 PORTD TRISD

 PORTE TRISE
Entrada o salida
 SALIDA DE DATOS : 0

 ENTRADA DE DATOS: 1

 La asignación es individual correspondiente a cada terminal del


puerto.
Acceso individual de bits 1
 mikroC te permite acceso individual en variables de 8 bits
(char and unsigned short). Simplemente usando el selector (.)
seguido de uno de los identificadores F0, F1, … , F7. Siendo F7
el bit mas significativo.

 Ejemplo:
PORTC.F0 = 1;
PORTD.F5 = 0;
PORTB.F7 = 1;

Los identificadores F0–F7 no se reconocen en minúsculas.


NOTA: Entre dos accesos a bits se debe tener un retardo mínimo de 2
microsegundos.
Entrada o salida
 Si deseamos configurar el puerto C con la
siguiente asignación:
RC0 entrada
RC1 entrada
RC2 entrada
RC3 entrada
RC4 salida
RC5 salida
RC6 salida
RC7 salida

 Posibles instrucciones a utilizar


TRISC = 0b00001111;
TRISC = 0x0F;
TRISC = 15;
Entrada o salida
 Si deseamos configurar el puerto D con la
siguiente asignación:
RD0 entrada
RD1 salida
RD2 entrada
RD3 salida
RD4 entrada
RD5 salida
RD6 entrada
RD7 salida

 Debemos utilizar cualquiera de las siguientes instrucciones


TRISD = 0b01010101;
TRISD = 0x55;
TRISD = 85;
Entrada o salida
 Si deseamos configurar el puerto A con la siguiente asignación:
RA0 salida
RA1 salida
RA2 salida
RA3 salida
RA4 entrada
RA5 entrada
RA6 entrada

 Posibles instrucciones a utilizar


ANSEL = 0;
ANSELH=0;/* instrucción indispensable para usar el puerto A y el puerto
E como entrada o salida de datos digitales */
TRISA = 0b01110000;
TRISA = 0x70;
TRISA = 112;
ANSEL Y ANSEL H

Programación del registro ANSEL.

Este registro define cuales de las 8 primeras entradas se


configurarán como entradas analógicas.

ANSEL = 0B00000011;

Configura AN0 y AN1 como entradas analógicas.

Programación del registro ANSELH.

Este registro define cuales de las 4 ultimas entradas se


configurarán como entradas analógicas, no se están usando como
entradas analógicas por lo tanto se inicializa con 0.

ANSELH = 0;
Delay_ms (retardo por software)
 Descripción: Crea un retardo por software dado el tiempo en
milisegundos (constante). El rango de constantes aplicables a la función
depende de la frecuencia del oscilador. Es una función interna; El código es
generado en el lugar donde se hace la llamada, así que la llamada de esta
función no cuenta dentro del limite de llamadas anidadas.

 void Delay_ms(const time_in_ms)

 Ejemplo:
Generar un retardo de 1 segundo

Delay_ms(1000); /* Pausa de un segundo */


Estructura de un programa en C
( ciclo while )
// Definición de variables globales

// Definición de funciones

void main(void)
{
// Definición de variables locales

// Configuración de registros (recursos y puertos)

// ciclo infinito
while ( 1 )
{

// Programa de usuario

}
}
Estructura de un programa en C
( ciclo for )
// Definición de variables globales

// Definición de funciones

void main(void)
{
// Definición de variables locales

// Configuración de registros (recursos y puertos)

// ciclo infinito
for ( ; ; )
{

// Programa de usuario

}
}
Estructura de un programa en C
( ciclo do - while )
// Definición de variables globales

// Definición de funciones

void main(void)
{
// Definición de variables locales

// Configuración de registros (recursos y puertos)

// ciclo infinito
do
{

// Programa de usuario

} while ( 1 ) ;
}
1.- Encendido de LED
 Crear un programa que encienda y apague un led, ubicado en la
terminal RC7 del puerto C. El tiempo de encendido es de 1000
milisegundo y el de apagado de 300 milisegundos.
Encendido de LED (algoritmo)
• Configurar el bit 7 del puerto C como salida de
datos
• Encendido del led
• Retardo por software de 1000 milisegundos.
• Apagado del led
• Retardo por software de 300 milisegundos
• Repetir el paso 2
Encendido de LED (diagrama de flujo)
Led

Configura bit del


puerto como salida Apaga bit

Enciende bit Retardo de 300 ms

Retardo de 1000ms
Encendido de LED (esquemático)
Encendido de LED (programa)
Void main (void)
{
ANSEL= 0;//
ANSELH = 0;
TRISE = 0;
PORTE = 1;
PORTC= 0;

TRISC.F7 = 0;
while( 1 )
{
PORTC.F7 = 1;
Delay_ms( 500 );
PORTC.F7 = 0;
Delay_ms( 300 );
}
}
Encendido de LED (programa 2)
Void main (void)
{
ANSEL= 0;
ANSELH = 0;
TRISE = 0;
PORTE = 1;
PORTC= 0;

TRISC = 0;
while( 1 )
{
PORTC = 0x80;
Delay_ms( 500 );
PORTC = 0;
Delay_ms( 300 );
}
}
Ejercicios propuestos 1
• El alumno encenderá y apagara en forma alternada
dos led’s ubicados en los bit’s 2 y 3 del puerto B.
Los retardos serán de 500 milisegundos (ambos).
Usando asignación directa a bits.

• El alumno encenderá y apagara un led ubicado en


el bit 5 del puerto C. Los retardos serán de 100
milisegundos y 2 segundos, respectivamente.
Usando asignación de byte.
2.- Luces secuenciales
 Programa que envíe la siguiente secuencia de datos
al puerto de salida C.

Secuencia :
• 00000001
• 00000010
• 00000100
• 00001000
• 00010000
• 00100000
• 01000000
• 10000000
Luces secuenciales (algoritmo)
• Configuración de puerto como salida de datos.
• Envío de primer dato al puerto de salida
• Envío de segundo dato al puerto de salida
• Envío de tercer dato al puerto de salida
.
.
.
9. Envío de ultimo dato al puerto de salida
10. Regresar a 2
Luces secuenciales (diagrama de flujo)
Luces

Configura puerto
como salida Envía 00000100 Envía 00100000

Envía 00000001 Envía 00001000 Envía 01000000

Envía 00000010 Envía 00010000 Envía 10000000


Luces secuenciales (esquemático)
Luces secuenciales (programa)
Void main (void)
{
ANSEL= 0;
ANSELH = 0;
TRISE = 0;
PORTE = 1;
PORTC= 0;
TRISC = 0;
WHILE (1)
{
PORTC = 0B00000001;
delay_ms(500);
PORTC = 0B00000010;
delay_ms(500);
PORTC = 0B00000100;
delay_ms(500);
PORTC = 0B00001000;
delay_ms(500);
PORTC = 0B00010000;
delay_ms(500);
PORTC = 0B00100000;
delay_ms(500);
PORTC = 0B01000000;
delay_ms(500);
PORTC = 0B10000000;
delay_ms(500);
}
}
Ejercicios propuestos 2
• El alumno enviara una secuencia de datos distinta por el
puerto B, utilizando retardos por software de distintas
duraciones, con incrementos de 100 milisegundos entre si.

• El alumno enviara la secuencia de datos por el puerto A,


utilizando retardos por software con duración de 800
milisegundos.
100001
010010
001100
010010
100001
Arreglos (definiciones)
#define MAX 50
int vector_one[10]; /* arreglo de 10 enteros */
float vector_two[MAX]; /* arreglo 50 flotantes */
float vector_three[MAX - 20]; /* arreglo 30 flotantes */
char numero[5];
short dato[8];
long temperatura[15];
unsigned peso[7];
unsigned short d[3];
Arreglos (Inicializando)
/* Arreglo el cúal contiene el número de días de cada mes */

int days[12] = {31,28,31,30,31,30,31,31,30,31,30,31};

/* La declaraciones es identica a la anterior */

int *days = {31,28,31,30,31,30,31,31,30,31,30,31};

/* Las dos declaraciones son identicas */

const char msg1[ ] = {'T', 'e', 's', 't', '\0'};


const char msg2[ ] = "Test";
Condicionante if
if (expresión) conjunto 1 [else conjunto 2]

 Cuando la expresión evaluada es verdadera, Las


instrucciones del conjunto 1 son ejecutadas. Si la
expresión es falso, las instrucciones del conjunto 2 es
ejecutada. La expresión debe ser evaluada a un valor
entero. Los paréntesis que encierra la expresión son
obligatorios.
 La palabra especial “else conjunto 2” es opcional.
Símbolos de condición
Operador Operación
== igual
!= no igual
> mayor que
< menor que
>= mayor que o igual a
<= menor que o igual a
3.- Luces con arreglo (algoritmo)
• Configuración de puerto como salida.
• Inicializa apuntador.
• Envío de dato apuntado.
• Incrementa apuntador.
• Si apuntador es mayor que o igual a 8 inicia el apuntador.
• Regresa a 3.
Luces con arreglo (diagrama de flujo)
Luces

Configura puerto Incrementa


como salida apuntador

Limpia apuntador si
apuntador ≥ 8 Limpia
apuntador

Envía dato
no
apuntado
Luces con arreglo (programa)
short dato [ 8 ] = {1, 2, 4, 8, 16, 32, 64, 128};
short apunta;

void main(void)
{
ANSEL= 0;
ANSELH = 0;
TRISE = 0;
PORTE = 1;
PORTC= 0;
TRISC = 0;

apunta = 0; // Limpia apuntador


while(1) // Ciclo infinito
{
PORTC = dato [ apunta ]; // Envía dato
Delay_ms(1000);
apunta ++; // Incrementa apuntador
if ( apunta >= 8 ) // Si apuntador ≥ 8
apunta = 0; // Limpia apuntador
}
}
Ejercicios propuestos 3
• El alumno enviara una secuencia por el puerto B usando los
valores almacenado en un arreglo.
00000011
00000110
00001100
00011000
00110000
01100000
11000000
Operadores a nivel de bits
Operador operacion

AND; compara pares de bits y regresa 1 si ambos son 1’s, de otra manera
regresa 0.
&

OR (inclusive); compara pares de bits y regresa 1 si uno o ambos son 1’s, de otra
manera regresa 0.
|

OR (exclusiva); compara pares de bits y regresa 1 si los bits son


complementarios, de otra manera regresa 0.
^

Complemento (unitario); invierte cada bit

<< Corrimiento hacia la izquierda; mueve los bits hacia la izquierda, descartando el
bit mas a la izquierda y asignando ceros al bit a la derecha.

>> Corrimiento hacia la derecha; mueve los bits hacia la derecha, descartando el bit
mas a la derecha y asignando ceros al bit a la izquierda.
Ejemplos operadores lógicos
0x1234 & 0x5678 /* Igual 0x1230 */

porque...
0x1234 : 0001 0010 0011 0100
0x5678: 0101 0110 0111 1000
-----------------------------------
&: 0001 0010 0011 0000 esto es, 0x1230

/* De forma similar: */

0x1234 | 0x5678; /* Igual 0x567C */


0x1234 ^ 0x5678; /* Igual 0x444C */
~ 0x1234; /* Igual 0xEDCB */
Ejemplos a nivel de bits
000001 << 5; /* Igual 000032 */
0x3801 << 4; /* Igual 0x8010, sobreflujo! */

0x02F6 >> 4; /* Igual 0x002F */


0xFF56 >> 4; /* Igual 0x0FF5 */

Corrimiento a la derecha division entre 2n.


Corrimiento a la izquierda producto por 2n.
4.- Luces con desplazamiento (algoritmo)
• Configuración de puerto como salida.
• Inicializa variable.
• Envía valor de la variable al puerto.
• Modifica la variable.
• Si variable es cero, Inicializa la variable.
• Regresa a 3.
Luces con desplazamiento (diagrama de flujo)

Luces

Configura puerto Modifica


como salida variable

Inicializa variable si
variable = 0 Inicializa
variable

Envía variable
no
al puerto
Luces con desplazamiento (programa 1)
void main ( void )
{unsigned short dato;
ANSEL= 0;
ANSELH = 0;
TRISE = 0;
PORTE = 1;
PORTC= 0;
TRISC = 0;
dato = 0b00000001;
while ( 1 )
{
PORTC = dato;
Delay_ms ( 300 );
dato = dato << 1;
if ( dato == 0 )
dato = 0x01;
}
}
Operaciones aritméticas
Operador Operación

+ Suma

- Resta

* Multiplicación

/ División

% Resto, regresa el residuo de la división entera (no puede ser usado con
variables flotantes

++ Como prefijo Incrementa en uno el valor de la variable antes de evaluar la


expresión. Como Postfijo suma en uno la variable después de ser evaluado la
expresión.

-- Como prefijo decrementa en uno el valor de la variable antes de evaluar la


expresión. Como Postfijo resta en uno la variable después de ser evaluado la
expresión.
Luces con desplazamiento (programa 2)
void main ( void )
{unsigned short dato;
ANSEL= 0;
ANSELH = 0;
TRISE = 0;
PORTE = 1;
PORTC= 0;
TRISC = 0;
dato = 0b00000001;
while ( 1 )
{
PORTC = dato;
Delay_ms ( 300 );
dato = dato *2;
if ( dato == 0 )
dato = 0x01;
}
}
Ejercicios propuestos 4
• El alumno realizara un programa que envíe al
puerto C los siguientes valores utilizando para
generarlas, las instrucciones de desplazamiento y/o
aritméticas.

1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45

• Lo mismo que el ejercicio anterior con la siguiente


secuencia:

3, 6, 12, 24, 48, 92, 172, 1, 3, 6, 9, 12, 15, 18, 21, 24


Acceso a bits individual
 mikroC te permite acceso individual en variables de 8 bits
(char and unsigned short). Simplemente usando el selector (.)
seguido de uno de los identificadores F0, F1, … , F7, siendo F7
el bit mas significativo.

 Ejemplo:
// Si RB0 es uno, colocar en uno la terminal RC0:
if ( PORTB.F0 )
PORTC.F0 = 1;

Los Identificadores F0–F7 no se reconocen en minúsculas.


5.- Secuencias condicionadas ( problema )
 Realizar un programa que envíe secuencias distintas al puerto C,
dependiendo del valor de la terminal RD0. Si RD0 es igual a cero se
envía la serie de dos bits desplazados hacia la izquierda, mientras
que si RD0 es igual a 1 entonces se envía la serie de tres bits
desplazados hacia la derecha.
Secuencias condicionadas (algoritmo)
• Configuración de puertos
• Inicia contador
• Si RD0 es igual a 0 entonces envía
secuencia_izquierda
• De lo contrario envía secuencia_derecha
• Incrementa contador
• Si contador es igual a 8 entonces contador igual a 0
• Regresa a 3
Secuencias condicionadas (diagrama de flujo)
Luces
Envía
Configura puertos
RC salida, RD entrada secuencia_izquierda

Incrementa
Limpia contador contador

si
si Contador = 10 Limpia
RD0 = 0 contador

Envía no
no Secuencia_derecha
Secuencias condicionadas (programa)
short izquierda[10] = { 0, 1, 3, 6, 12, 24, 48, 96, 192, 128 };
short derecha[10] = { 128, 192, 226, 102, 56, 28, 14, 7, 3, 1 };
Short contador = 0;
void main ( void )
{
TRISD.F0 = 1;
ANSEL= 0;
ANSELH = 0;
TRISE = 0;
PORTE = 1;
TRISC = 0;

for ( ; ; )
{
Delay_ms ( 500 );

if ( PORTD.F0 == 0 )
PORTC = izquierda [ contador];
else
PORTC = derecha [ contador];

contador ++ ;

If ( contador == 10 )
contador = 0;
}
}
Ejercicios propuestos 5
• El alumno desarrollara un programa que envíe una secuencia de
números BCD a un display de 7 segmentos ubicados en el puerto
D. Si la terminal RA1 ubicada en el puerto A, es igual a 0, la
numeración debe ser incremental; en caso contrario debe
decrementarse.
Ejercicios propuestos 5 (esquemático)
6.- Display de 7 segmentos
 Realizar un programa en donde se implemente un contador de 00-
99 desplegando en un par de display’s de 7 segmentos. El programa
debe realizar la visualización utilizando el multiplexaje de los datos,
utilizando el puerto B como bus de datos y las terminales RC0 y RC1
como terminales de habilitación de display.
Display de 7 segmentos (algoritmo)
• Configurar los puertos, inicialización de variables (unidades = ‘0’
decenas = ‘0’)
• Envío de decenas
• Habilitación de decenas
• Envío de unidades
• Habilitación de unidades
• Incremento de unidades
• Si unidades mayor de ‘9’ entonces 9
• Sigue 2
• Unidades = ‘0’
• Incrementa decenas
• Si decenas mayor de ‘9’ entonces 12
• Sigue 2
• Decenas=‘0’
• Sigue 2
Display de 7 segmentos (diagrama de flujo)
Display

Limpia unidades
Incrementa decenas
Configura puertos
Inicia variables
si
Envía decena Decenas>’9’
Envía unidad
Incrementa unidad no

si Limpia decenas
Unidades>’9’

no
Display de 7 segmentos (programa)
short numero[ ] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F };
short unidades , decenas = 0;
void main() {
TRISC = 0;
ANSEL= 0;
TRISA.F4 = 0;
TRISA.F5 = 0;
while ( 1 )
{
PORTC = numero [ decenas ]; // Envía decenas
PORTA.F4 = 1; // Habilita el display de decenas
Delay_ms( 100 );
PORTA.F4 = 0;
PORTC = numero [ unidades ]; // Envía unidades
PORTA.F5 = 1; // Habilita el display de unidades
delay_ms( 100 );
PORTA.F5 = 0;
unidades++; // Incrementa unidades
if ( unidades > 9 )
{
unidades = 0; // Reinicia unidades
decenas++; // Incrementa decenas
if ( decenas > 9 )
{
decenas = 0; // Reinicie decenas
}
}
}
}
Display de 7 segmentos ( esquemático )
Ejercicio propuesto 6 (d7seg)
 El alumno modificara el programa elaborado de tal forma que se
cambie el incremento por decremento, al usar un interruptor. Si el
interruptor esta apagado el conteo será incremental, en caso
contrario, el conteo será decremental. El interruptor estará ubicado
en la terminal RD0 del puerto D.
Ejercicio propuesto 6 (esquemático)
Contador 7 segmentos usando interrupciones
unsigned short unidades,decenas, digit_no;
unsigned int cnt ; // Definir la variable cnt
short numero[ ] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F };
void interrupt() {
cnt++; // Con una interrupción la cnt se incrementa en 1
if (digit_no == 0) {
PORTA.F4 = 0; // Apagar ambos visualizadores
PORTA.F5 = 0;
PORTC = numero [ unidades ]; // Envía unidades
PORTA.F5 = 1; // Habilita el display de unidades
digit_no = 1;
}
else{
PORTA.F4 = 0; // Apagar ambos visualizadores
PORTA.F5 = 0;
PORTC = numero [decenas]; // Colocar máscara para visualizar decenas en el
PORTA.F4 = 1; // Habilita el display de unidades
digit_no = 0;
}
TMR0 = 96; // El valor inicial se devuelve en el temporizador TMR0
INTCON = 0x20; // Bit T0IE se pone a 1, el bit T0IF se pone a 0
}
Contador 7 segmentos usando interrupciones
void main (void) {
unsigned short dato , led;
ANSEL= 0;
TRISA.F3 = 0;
TRISA.F4 = 0;
TRISA.F5 = 0;
TRISC = 0;
unidades, decenas, digit_no = 0;
OPTION_REG = 0x84; // Pre-escalador se le asigna al temporizador TMR0
TMR0 = 96; // Temporizador T0 cuenta de 96 a 255
INTCON = 0xA0; // Habilitada interrupción TMR0
while(1) { //Ciclo inifinito
delay_ms(500);
unidades ++;
if (unidades > 9) {
unidades = 0;
decenas ++ ;
if ( decenas > 9 ) {
decenas = 0;
}
}
}
}
Display de cristal liquido
Comandos predefinidos

Comando
Función

_LCD_FIRST_ROW Mueve el cursor a la 1a. fila.

_LCD_SECOND_ROW Mueve el cursor a la 2a. fila.

_LCD_THIRD_ROW Mueve el cursor a la 3a. fila.

_LCD_FOURTH_ROW Mueve el cursor a la 4a. fila.

_LCD_CLEAR Limpia el display.

_LCD_RETURN_HOME Regresa el cursor a la posición 1,1. Los datos de la RAM no son afectados.

_LCD_CURSOR_OFF Apaga el cursor.

_LCD_UNDERLINE_ON Coloca el caracter subrayado.

_LCD_BLINK_CURSOR_ON Parpadeo del cursor.

_LCD_MOVE_CURSOR_LEFT Mueve el cursor hacia la izquierda sin cambiar la RAM

_LCD_MOVE_CURSOR_RIGHT Mueve el cursor hacia la derecha sin cambiar el contenido de la RAM


• _LCD_TURN_ON
• Enciende el display
• _LCD_TURN_OFF
• Apaga el display
• _LCD_SHIFT_LEFT
• Mueve el display hacia la izquierda sin cambiar el contenido
de la RAM
• _LCD_SHIFT_RIGHT
• Mueve el display hacia la derecha sin cambiar el contenido
de la RAM
LCD (funciones bus 4 bits)

 Lcd_Init
 Lcd_Out
 Lcd_Out_Cp
 Lcd_Chr
 Lcd_Chr_Cp
 Lcd_Cmd
Lcd_Out
 Descripción: Imprime mensaje en el LCD en la fila y
columna especificada (row y col).

 void Lcd_Out( unsigned short row,


unsigned short col,
char *text );

 Ejemplo:
-Imprime “Hello!” en el LCD en la línea 1, columna 3
Lcd_Out(1, 3, "Hello!");
Lcd_Out_Cp
 Descripción: Imprime mensaje en el LCD en la
posición actual del cursor.

 void Lcd_Out_Cp(char *text);

 Ejemplo:
- Imprime “Here!” en la posición actual del cursor
Lcd_Out_Cp("Here!");
Lcd_Chr
 Descripción: Imprime un caracter en el LCD en la fila
y columna especificada (row y col).

 void Lcd_Chr( unsigned short row,


unsigned short col,
char character );

Ejemplo:
- Imprime la letra ‘i’ en el LCD en la línea 2,y columna 3
Lcd_Chr(2, 3, 'i');
Lcd_Chr_Cp
 Descripción: Imprime un caracter en el LCD en la
posición actual del cursor.

 void Lcd_Chr_Cp(char character);

 Ejemplo:
- Imprime la letra ‘e’ en la posición actual del cursor
Lcd_Chr_Cp('e');
Lcd_Cmd
 Descripción: Envía un comando al LCD. Se puede pasar a la
función una de las constantes predefinidas. Los comandos son
los mismos para ambos modos de manejo del LCD (bus 8 o 4
bits).

 void Lcd_Cmd(unsigned short command);

 Ejemplo:
- Apaga el cursor, no aparece en el LCD
Lcd_Cmd(_LCD_CURSOR_OFF);
8.- LCD 4 BITS
 Diseñar el programa que inicialice un LCD, usando un bus de datos
de 4 bits, y a continuación mande un mensaje cualquiera de
bienvenida. El mensaje debe desplazarse hacia la derecha en forma
continua.
LCD 4 BITS (algoritmo)
• Inicialice los puertos de datos y control.
• Envía mensaje a desplegar.
• Envía comando de desplazamiento hacia la derecha.
• Repite el paso 3.
LCD 4 BITS (diagrama de flujo)
LCD 8 bits

Inicializa puertos de
datos y control

Envía mensaje

Envía comando de
Corrimiento a la der.
LCD 4 BITS (programa 1)

sbit LCD_RS at RD2_bit;


sbit LCD_EN at RD3_bit;
sbit LCD_D4 at RD4_bit;
sbit LCD_D5 at RD5_bit;
sbit LCD_D6 at RD6_bit;
sbit LCD_D7 at RD7_bit;
sbit LCD_RS_Direction at TRISD2_bit;
sbit LCD_EN_Direction at TRISD3_bit;
sbit LCD_D4_Direction at TRISD4_bit;
sbit LCD_D5_Direction at TRISD5_bit;
sbit LCD_D6_Direction at TRISD6_bit;
sbit LCD_D7_Direction at TRISD7_bit;
// Fin de conexiones del modulo LCD
char txt1[] = "mikroElektronika";
char txt2[] = "EasyPIC6";
char txt3[] = "Lcd4bit";
char txt4[] = "example";
char i; // Loop variable
void Move_Delay() { // Function used for text moving
Delay_ms(500); // You can change the moving speed here
}
LCD 4 BITS (programa 1)

void main(){
ANSEL = 0; // Configura los pins AN como e/s digital
ANSELH = 0;
C1ON_bit = 0; // Desabilita comparadores
C2ON_bit = 0;
Lcd_Init(); // Initializa el LCD
Lcd_Cmd(_LCD_CLEAR); // Borra el display
Lcd_Cmd(_LCD_CURSOR_OFF); // Apaga el Cursor
Lcd_Out(1,6,txt3); // Escribe text in first row
Lcd_Out(2,6,txt4); // Write text in second row
Delay_ms(2000);
Lcd_Cmd(_LCD_CLEAR); // Clear display
Lcd_Out(1,1,txt1); // Write text in first row
Lcd_Out(2,5,txt2); // Write text in second row
Delay_ms(2000);
for(i=0; i<4; i++) { // Move text to the right 4 times
Lcd_Cmd(_LCD_SHIFT_RIGHT);
Move_Delay();
}
LCD 4 BITS (programa 1)

while(1) { // Ciclo infinito


for(i=0; i<8; i++) { // Mueve text a la izquierda 7 veces
Lcd_Cmd(_LCD_SHIFT_LEFT);
Move_Delay();
}
for(i=0; i<8; i++) { // Mueve el text a la derecha 7 veces
Lcd_Cmd(_LCD_SHIFT_RIGHT);
Move_Delay();
}
}
}
LCD 4 BITS (programa 2)
char mensaje[11]={‘B’, ‘u’, ‘s’, ‘ ’, ‘4’, ‘ ’, ‘b’, ‘i’, ‘t’, ‘s’, ‘\0’};

void main(void)
{ TRISD = 0;

Lcd_Config(&PORTD,0,2,1,7,6,5,4);

Lcd_Out(1, 6, mensaje);

while(1)
{
Lcd_Cmd(LCD_SHIFT_RIGHT);
Delay_ms(200);
}
}
LCD 4 BITS (esquemático Init)
Conversión de tipo de datos
Tipo de dato a cadena
 ByteToStr

 ShortToStr

 WordToStr

 IntToStr

 LongToStr

 FloatToStr
ByteToStr
Descripcion: Crea una cadena de salida de un pequeño numero sin
signo (valor numérico menos a 0x100). La cadena esta ajustada a un
ancho de 3 caracteres; Las posiciones a la izquierda que no se usan
en la conversión se rellenan con espacios.

void ByteToStr(unsigned short number, char *output);

Ejemplo:
unsigned short t = 24;
char txt[4]; //se declara arreglo con 4 lugares

ByteToStr(t, txt); // txt es " 24" (un espacio en blanco)


ShortToStr
Descripción: Crea una cadena de salida de un numero pequeño con
signo (valor numérico menor a 0x100). La cadena esta ajustada a
un ancho de 4 caracteres; Las posiciones a la izquierda que no se
usan en la conversión se rellenan con espacios.

void ShortToStr(short number, char *output);

Ejemplo:
short t = -4;
char txt[5]; // Se inicializa un apuntador de 5 espacios

ShortToStr(t, txt); // txt es " -4" (dos espacio en blanco)


WordToStr
Descripción: Crea una cadena de salida de un numero sin signo
(Valor numérico de una variable unsigned). La cadena esta
ajustada a un ancho de 5 caracteres; Las posiciones a la
izquierda que no se usan en la conversión se rellenan con
espacios.

void WordToStr(unsigned number, char *output);

Ejemplo:
unsigned int t = 437;
char txt=[6]; // Se declara arreglo con 6 lugares

WordToStr(t, txt); // txt es “ 437" (dos espacios vacios)


IntToStr
Descripción: Crea una cadena de salida de un numero con signo (Valor
numérico de una variable int). La cadena esta ajustada a un ancho
de 6 caracteres; Las posiciones a la izquierda que no se usan en la
conversión se rellenan con espacios.

void IntToStr(int number, char *output);

Ejemplo:
int j = -4220;
char txt[7]; // Se declara arreglo con 7 lugares

IntToStr(j, txt); // txt es " -4220" (un espacio en blanco)


LongToStr
Descripción: Crea una cadena de salida de un numero largo con signo
(Valor numérico de una variable long). La cadena esta ajustada a un
ancho de 11 caracteres; Las posiciones a la izquierda que no se usan
en la conversión se rellenan con espacios.

void LongToStr(long number, char *output);

Ejemplo:
long jj = -3700000;
char txt[12]; // Se declara arreglo con 12 espacios

LongToStr(jj, txt); // txt es “ -3700000" (3 espacios en blanco)


FloatToStr
Descripción: Crea una cadena de salida de un numero de punto
flotante. La cadena contiene un formato normalizado de un numero
(mantisa entre 0 y 1) con signo en la primera posición. La mantisa
esta ajustada a un formato de 6 dígitos, 0.ddddd; Hay siempre 5
dígitos a continuación del punto decimal.

void FloatToStr(float number, char *output);

Ejemplo:
float ff = -374.2;
char txt[14]; // Se declara arreglo con 14 espacios

FloatToStr(ff, txt); // txt es "-0.37420e3"


9.- Contador 0-9 (problema)
 Se quiere un programa que visualice un conteo de 0 a 9 en un LCD.
Contador 0-9 (algoritmo)
• Configura el LCD
• Inicializa el contador
• Convierte a ASCII el valor del contador
• Envía valor en ASCII al LCD
• Incrementa el contador
• Regresa a 3
Contador 0-9 (diagrama de flujo)
teclado

Inicializa puertos
(LCD)
Convierte contador
a ASCII
Inicializa contador

Envía a LCD
ASCII

Incrementa
contador
Contador 0-9 (programa)
sbit LCD_RS at RD2_bit;
sbit LCD_EN at RD3_bit;
sbit LCD_D4 at RD4_bit;
sbit LCD_D5 at RD5_bit;
sbit LCD_D6 at RD6_bit;
sbit LCD_D7 at RD7_bit;
sbit LCD_RS_Direction at TRISD2_bit;
sbit LCD_EN_Direction at TRISD3_bit;
sbit LCD_D4_Direction at TRISD4_bit;
sbit LCD_D5_Direction at TRISD5_bit;
sbit LCD_D6_Direction at TRISD6_bit;
sbit LCD_D7_Direction at TRISD7_bit;

void main(void){
char cadena[ 4] ;
unsigned short contador = 0;
Lcd_init();
Lcd_Out(1,1,”Contador 0-255”);

while(1)
{
ByteToStr ( contador , cadena );
Lcd_Out ( 2 , 8 , cadena );
contador ++;
Delay_ms(500);
}
}
Contador 0-9 (esquemático)
Contador 0-9 (funcionamiento)
Contador 0-9 : Contador 0-9 : Contador 0-9 :
0 1 2

Contador 0-9 : Contador 0-9 : Contador 0-9 :


3 4 5

Contador 0-9 :
6
. . . Contador 0-9 :
9
Ejercicio propuesto 8
• Programa que utilice un LCD, configurado para usar
un bus de 8 bits. En el LCD deben aparecer en
forma secuencial, los números de la secuencia 1 – 2
– 4 – 8 – 16 – 32 – 64 – 128 – 256 – 512 – 1024 – 2048 –
4096 – 8192 – 16384 - 32768. Los numero deben ser
generados por operaciones aritméticas. El
desplegado debe hacerse de la forma mostrada en
las siguientes figuras. Se utiliza la segunda fila,
presentando hasta 3 numeros consecutivos, un
numero a la izquierda, uno mas al centro y otro a la
derecha.
Ejercicio propuesto 8

Serie de numeros Serie de numeros Serie de numeros


1 1 2

Serie de numeros Serie de numeros Serie de numeros


1 2 4 8 8 16

Serie de numeros
8 16 32
. . . Serie de numeros
8192 16384 32768
Ejercicio propuesto 9
• El alumno diseñara un programa en donde se muestre en un LCD
los números desde 00 hasta el 99. Con un intervalo de tiempo
entre cambio igual a 500 milisegundos.
Ejercicio propuesto 9
Contador 00-99 cada 500 mseg Contador 00-99 cada 500 mseg Contador 00-99 cada 500 mseg
00 01 02

Contador 00-99 cada 500 mseg Contador 00-99 cada 500 mseg Contador 00-99 cada 500 mseg
03 04 05

Contador 00-99 cada 500 mseg


06
. . . Contador 00-99 cada 500 mseg
99
Teclado matricial (esquemático)
Teclado matricial (funciones)

 Keypad_Init
 Keypad_Read
 Keypad_Released
Keypad_Init
 Descripción: Inicializa el puerto para trabajar con el teclado.
Las terminales del teclado deben estar conectadas de la
siguiente forma:
port.F0 columna 1
port.F1 columna 2
port.F2 columna 3
port.F3 columna 4
port.F4 fila 1
port.F5 fila 2
port.F6 fila 3
port.F7 fila 4

 void Keypad_Init(unsigned *port);


Keypad_Init 2
Ejemplo:
Keypad_Init(&PORTB);
Keypad_Read
 Descripción: Verifica si alguna tecla fue presionada. La función regresa 1
a 12, dependiendo la tecla presionada, o 0 si no existe tecla presionada.
1 1
2 2
… …
9 9
* 10
0 11
# 12

 unsigned short Keypad_Read(void);

 Ejemplo:
kp = Keypad_Read();
Keypad_Released
 Descripción: La llamada a la función Keypad_Released es una función
blocking call: La función espera hasta que cualquier tecla sea presionada y
liberada. Cuando se libera, la función regresa de 1 a 12, dependiendo de la
tecla presionada.

 unsigned short Keypad_Released(void);

 Ejemplo:
Keypad_Released();
10.- Teclado matricial (problema)
 Se desea un programa con el cual se muestre en un LCD (bus 8 bits
en puerto B y puerto C como control) la tecla presionada en un
teclado matricial (puerto D).
Teclado matricial (algoritmo)
• Configuración de puertos (teclado y lcd).
• Lectura de teclado
• Conversión a ASCII
• Envío al LCD
• Regresar a 2
Teclado matricial (diagramas de flujo)
teclado

Inicializa puertos
(LCD y teclado)

Lee teclado

Convierte a ASCII

Envía a LCD
Teclado matricial (esquemático)
Teclado matricial (programa)
// Conexiones del Modulo LCD
sbit LCD_RS at RD2_bit;
sbit LCD_EN at RD3_bit;
sbit LCD_D4 at RD4_bit;
sbit LCD_D5 at RD5_bit;
sbit LCD_D6 at RD6_bit;
sbit LCD_D7 at RD7_bit;
sbit LCD_RS_Direction at TRISD2_bit;
sbit LCD_EN_Direction at TRISD3_bit;
sbit LCD_D4_Direction at TRISD4_bit;
sbit LCD_D5_Direction at TRISD5_bit;
sbit LCD_D6_Direction at TRISD6_bit;
sbit LCD_D7_Direction at TRISD7_bit;
// Fin de conexiones del modulo LCD
// definicion de conexiones del teclado
char keypadPort at PORTB;
// esta conectado al puerto B
char kp, contador=0;
void main(){
ANSEL = 0; // Deshabilita entradas analogicas 0-7
ANSELH = 0; // Deshabilita entradas analógicas 8-11
Keypad_Init(); //Inicializa el teclado.
Lcd_Init(); //Inicializa el LCD.
Lcd_Cmd(_LCD_CLEAR); //Borra el display.
Lcd_Cmd(_LCD_CURSOR_OFF); //Apaga el cursor.
Teclado matricial (programa)

Lcd_Out(1,1,"Prueba del techado");


Lcd_Out(2,1,"Matricial");
Delay_ms(1000);
Lcd_Cmd(_LCD_CLEAR); //Borra el display.
while (1){
kp=0;
do //Espera por una tecla.
kp=Keypad_Key_Click(); //Lee el número de la tecla y lo guarda en kp.
while (!kp);
switch (kp){
case 1: kp = 49; break; //49 es el código ASCII del número 1.
case 2: kp = 50; break; //50 es el código ASCII del número 2.
case 3: kp = 51; break; //51 es el código ASCII del número 3.
case 4: kp = 65; break; // A
case 5: kp = 52; break; // 4
case 6: kp = 53; break; // 5
case 7: kp = 54; break; // 6
case 8: kp = 66; break; // B
case 9: kp = 55; break; // 7
case 10: kp = 56; break; // 8
case 11: kp = 57; break; // 9
case 12: kp = 67; break; // C
case 13: kp = 42; break; // *
case 14: kp = 48; break; // 0
case 15: kp = 35; break; // #
case 16: kp = 68; break; // D
}
Teclado matricial (programa)

Lcd_Chr_CP(kp); //Presenta el carácter en el LCD.


contador++; //Cuenta el número de pulsaciones.
if (contador==16){ //Si se han efectuado 16 pulsaciones.
contador=0;
Delay_1sec(); //Espera 1 s.
Lcd_Cmd(_LCD_CLEAR); //Borra la pantalla y retorna el cursor al
} //origen.
}
}
Ejercicio propuesto 9
• El alumno realizara un programa que tome 3 números desde un
teclado matricial, los guarde en un arreglo, los convierta a un
numero que se guarde en una variable tipo entera. Con este
numero el alumno deberá proporcionar el producto por 2 y
división entre 2 resultantes. Visualizando los resultados en un
LCD.
Ejercicio propuesto 9
Cual es el numero de 3 cifras: Cual es el numero de 3 cifras:
025

Cual es el numero de 3 cifras: Cual es el numero de 3 cifras:


025 025
El producto por 2 es: 050 El producto por 2 es: 050
La división entre 2 es: 012