Está en la página 1de 53

Microcontroladores

CCS Compiler
CCS Compiler
El CCS Compiler
es una herramienta útil para programar microcontroladores PIC, en la
cual están incluidas muchas librerías para el manejo de puertos,
protocolos de comunicación y entre otros.

Es un compilador de lenguaje de alto nivel que permite


realizar las mismas tareas en un menor tiempo de desarrollo y con mucha
mayor facilidad en la programación en comparación al lenguaje
ensamblador. Básicamente el compilador CCS maneja la misma estructura
de programación que el lenguaje de programación C.
CARACTERÍSTICAS DE COMPILADOR

Traduce el código C del archivo fuente (.c) a lenguaje de máquina para


programar microcontroladores PIC (.HEX).

Se incluye Drivers o librerías de código fuente para manejo de pantallas


LCD, teclados, sensores, protocolos de comunicación, memorias,
conversión analógico a digital, etc.

Se integra al módulo de desarrollo IDE del MPLAB (software de


desarrollo de Microchip) y otros simuladores y editores para la
depuración del código fuente.

Funciones para el manejo de interrupciones


Estructura de un programa
Para escribir un programa en C con el CCS C se deben tener en
cuenta una serie de elementos básicos de su estructura

DIRECTIVAS DE PREPROCESADO : controlan la conversión del


programa a código máquina por parte del compilador.

PROGRAMAS o FUNCIONES : conjunto de instrucciones. Puede


haber uno o varios; en cualquier caso siempre debe haber uno
definido como principal mediante la inclusión de la llamada
main() .

INSTRUCCIONES : indican como debe comportar el PIC en todo


momento.

COMENTARIOS : permiten describir lo que significa cada línea


del programa.
Directivas de preprocesado
#INCLUDE <NOMBRE_DEL_FICHERO>
Esta directiva hace que el compilador incluya en el
fichero fuente el texto que contiene el archivo indicado.
Ejemplo: #include <16F877.H>

# FUSE
Esta directiva define qué fusibles deben activarse en el
dispositivo cuando se programe. Esta directiva no afecta
a la compilación; sin embargo, esta información se pone
en el archivo de salida. Algunas de las opciones más
usadas son:
LP, XT, HS, RC (Tipo de oscilador)
WDT, NOWDT (Activación del Watch Dog Timer)
PROTECT, NOPROTECT (Protección del código)
PUT, NOPUT (Temporizador de arranque)
BROWNOUT, NOBROWNOUT (Detección de caídas
de tensión de la fuente de alimentación)
Ejemplo #fuse HS, WDT.
Directivas de preprocesado
#INT_XX
Estas directivas especifican que la función que le sigue
es una función de interrupción. Las funciones de
interrupción no pueden tener ningún parámetro. Como es
natural, no todas las directivas pueden usarse con todos
los dispositivos. Las directivas más comunes son las
siguientes:
#INT_EXT: Interrupción externa
#INT_TRCC: Desbordamiento del TIMER0 (RTCC)
#INT_RB: Cambio en los pines B4, B5, B6, B7
#INT_AD: Conversor A/D
#INT_TIMER1: Desbordamiento del TIMER1.
#INT_TIMER2: Desbordamiento del TIMER2
#INT_CP1: Modo captura de datos por
CCP1
#INT_CCP2: Modo captura por CCP2
Directivas de preprocesado
#USE DELAY (Clock = Frecuencia):
Esta directiva indica al compilador la frecuencia del
procesador, en ciclos por segundo, a la vez que habilita el
uso de las funciones DELAY_MS() y DELAY_US().
Ejemplo: #USE DELAY (CLOCK = 4000000)

#USE STANDARD_io (Puerto)


Esta directiva afecta al código que el compilador
generará para las instrucciones de entrada y salida. Este
método rápido de hacer I/O ocasiona que el compilador
realice I/O sin programar el registro de dirección. El
puerto puede ser A-G.
Ejemplo: #USE STANDARD_io(B)
Directivas de preprocesado

#USE RS232 (BAUD = baudios, XMIT = pin,


RCV= pin)

Esta directiva le dice al compilador la


velocidad en bits por segundo y los pines
utilizados para la comunicación serie. Esta
directiva tiene efecto hasta que se encuentra
otra directiva RS232. La directiva #USE DELAY
debe aparecer antes de utilizar #USE RS232.
Esta directiva habilita el uso de funciones tales
como GETCH, PUTCHAR y PRINTF.
Funciones
FUNCIONES DISCRETAS DE I/0

Input(pin)
Devuelve el estado '0' o '1' de la patilla indicada en pin. El método de acceso de I/O depende de la última
directiva #USE *_IO utilizada. El valor de retorno es un entero corto.

Ejemplo : if (Input(Pin_B0)==1)

Output (Pin, Value)


Esta función saca el bit dado en value(0 o 1) por la patilla de I/O especificada en pin. El modo de establecer la dirección
del registro, está determinada por la última directiva #USE *_IO.
Ejemplo : output_bit( PIN_B0, 0);

Output _high(pin)
Pone a 'uno' el pin indicado. El método de acceso de I/O depende de la última directiva #USE *_IO utilizada.
Ejemplo : Output_high(PIN_C0)

Output_low(pin)
Pone a 'cero' el pin indicado. El método de acceso de I/O depende de la última directiva #USE *_IO.
Ejemplo : Output_low(PIN_D0)
Funciones
FUNCIONES DISCRETAS DE I/0

Port_b_pullups(flag)
Esta función activa/desactiva las resistencias pullups en las entradas del puerto B. Flag puede ser TRUE (activa)
o FALSE (desactiva).

Ejemplo: Port_b_pullups(false)

Set_ tris_puerto(Valor)
Estas funciones permiten escribir directamente los registros tri-estado para la configuración de los puertos (configurar
pines de entrada y salida)

Esto debe usarse con FAST_IO(), cuando se accede a los puertos de I/O como si fueran memoria, igual que cuando se
utiliza una directiva #BYTE. Cada bit de value representa una patilla. Un '1' indica que la patilla es de entrada y un '0'
que es de salida.

Ejemplo : Set_tris_A(0xff); puerto A como entrada


FUNCIONES DE RETARDO
Delay_cicles(Valor)
Esta función realiza retardos según el número de ciclos de instrucción especificado en count; los valores
posibles van desde 1 a 255. Un ciclo de instrucción es igual a cuatro periodos de reloj.

Ejemplo : Delay_cicles(100); Cuenta 100 ciclos

Delay_ms(Valor)
Esta función realiza retardos del valor especificado en tiempo. Dicho valor de tiempo es en milisegundos y
el rango es 0-65535.
Para obtener retardos más largos así como retardos 'variables' es preciso hacer llamadas a una función
Separada.

Delay_us(Valor)
Esta función realiza retardos del valor especificado en tiempo. Dicho valor es en microsegundos y el rango va
desde 0 a 65535. Es necesario utilizar la directiva #use delay antes de la llamada a esta función para que el
compilador sepa la frecuencia de reloj.
FUNCIONES PARA LA MANIPULACIÓN DE BITS
Bit_clear (Var, Bit)
Esta función simplemente borra (pone a '0') el dígito especificado en bit(0-7 ó 0-15) del byte o palabra aportado en var. El
bit menos significativo es el 0.

Ejemplo : int x = 10;


Bit_clear(x,0) ;

Bit_set(Var, bit)
Esta función pone a '1' el dígito especificado en bit(0-7 o 0-15) del byte o palabra aportado en var.

Rotate_left(Dirección, bytes)
Esta función rota a la izquierda un bit de un array o de una estructura. Nótese que la rotación implica que el
bit MSB pasa a ser el bit LSB. Dirección puede ser un identificador de un array o la dirección a un byte o a
una estructura, por ejemplo, &dato. bytes es el número de bytes implicados en la rotación.
Ejemplo : X = 0*50
Rotate_left(&X, 1) ; 0*A0

Rotate_right (Dirección, bytes)


Esta función rota a la derecha un bit de un array o de una estructura. Nótese que esta rotación implica que el
bit LSB pasa a ser el bit MSB. address puede ser un identificador de un array o la dirección a un byte o a una
estructura, por ejemplo, &dato. bytes es el número de bytes implicados en la rotación.
El CCS acepta el los siguientes tipos de variables
CONSTANTES
Las constantes se pueden especificar en octal, decimal, hexadecimal
o en binario
VARIABLES
La variables se utilizan para nombrar posiciones de memoria RAM.
Se deben de declarar obligatoriamente antes de utilizarlas, para
ello se debe indicar el nombre y el tipo de dato que se utilizará.
Se definen de la siguiente manera.

tipo nombre_variable = valor inicial


Ejemplo:

float voltaje=0;
int8 suma=0;
int contador=10;
VARIABLES globales y locales
Las variables de finidas en un programa pueden ser de tipo LOCAL o GLOBAL . Las variables locales sólo
se utilizan en la función donde se encuentran declaradas; las variables globales se pueden utilizar en
todas las funciones del programa. Ambas deben declararse antes de ser utilizadas y las globales deben
declararse antes de cualquier función y fuera de ellas. Las variable globales son puestas a cero cuando
se inicia la función principal main().
VARIABLES globales y locales
Las variables pueden ser de fi nidas con:

AUTO : (usada por defecto, no hace falta que se indique) donde la variable existe mientras la función
esta activa. Estas variables no se inicializan a cero. Su valor se pierde cuando se sale de la función.

STATIC : Una variable local se activa como global, se inicializa a cero y mantiene su valor al entrar y salir
de la función.

EXTERN : Permite el uso de variables en compilaciones múltiples.


Operadores de asignación
Operadores aritméticos
Operadores
relacionales Operadores Operadores
lógicos de bit
Funciones
Las funciones son bloques de sentencias; todas las sentencias se deben enmarcar dentro de las funciones. Al
igual que las variables, las funciones deben de fi nirse antes de utilizarse. Una función puede ser invocada
desde una sentencia de otra función. Una función puede devolver un valor a la sentencia que la ha llamado.
El tipo de dato se indica en la de fi nición de la función; en el caso de no indicarse nada se entiende que es un
int8 y en el caso de no devolver un valor se debe especifi car el valor VOID . La función, además de devolver
un valor, puede recibir parámetros o argumentos.

La estructura de una función es:


Manejo de puertos
Los microcontroladores PIC tienen
terminales de entrada/salida divididos en
puertos, que se encuentran nombrados
alfabéticamente A, B, C, D, etc. Cada
puerto puede tener hasta 8 terminales
que, de forma básica, se comportan
como una entrada/ salida digital. Según
las características del PIC , cada puerto
puede tener, además, asignado un
bloque funcional: convertidor AD ,
USART , I2C , etc. Por ejemplo la familia
PIC16F87X, pueden llegar hasta 5
puertos en el PIC16F877 donde se
pueden encontrar bloques de TIMERS ,
CCP , MSSP , USART , PSP y
convertidores AD.
Manejo de puertos

Considerando a los puertos como entradas/salidas digitales, los puertos se caracterizan


por ser independientes, es decir, se puede programar cada terminal del puerto para que
se comporte como una entrada o una salida digital la habilitación como entrada o salida
se realiza a través del registro TRISx (TRISA: 85h, TRISB: 86h, TRISC: 87h, TRISD: 88h o
TRISE: 89h en el BANCO 1 de la memoria RAM ).

Un valor 0 (cero) en estos registros indica que el terminal correspondiente del puerto es
de salida, mientras que un valor 1(uno) indica que será de entrada.
Manejo de puertos en C compiler

En lenguaje C se pueden gestionar los puertos de dos formas:

• Se declaran los registros TRISX y PORTX definiendo su posición en la memoria


RAM como variables de C.

Utilizando las directivas específicas del compilador ( #USE FAST_IO , #USE


FIXED_IO , #USE STANDARD_IO ).
Manejo de puertos en C compiler

A través de la RAM Se de finen los registros PORTx y TRISx como bytes y se sitúan
en la posición correspondiente de la memoria RAM .

La directiva utilizada de C es #BYTE :


#BYTE variable=constante;
#BYTE TRISA = 0x85 // Variable TRISA en 85h.
#BYTE PORTA = 0x05 // Variable PORTA en 05h.
#BYTE TRISB = 0x86 // Variable TRISB en 86h.
#BYTE PORTB = 0x06 // Variable PORTB en 06h
#BYTE TRISC = 0x87 // Variable TRISC en 87h
#BYTE PORTC = 0x07 // Variable PORTC en 07h.
Manejo de puertos en C compiler

Una vez definidas estas variables se pueden configurar y controlar los puertos a
través de los comandos de asignación.
TRISA = 0xFF; // 8 terminales de entrada
TRISB = 0x00; // 8 terminales de salida
TRISC = 0x0F; // 4 terminales de mayor peso de salida, 4 terminales de
// menor peso de entrada

Escritura en los puertos:


PORTC = 0x0A; // salida del datos 00001010 por el puerto C

Lectura de puertos:
valor = PORTA; // Asigna el dato del puerto A a la variable valor.
Manejo de puertos en C compiler
Manejo de sentencias:
TRISD=0x0F;
if (PORTD & 0x0F) PORTD |= 0xA0; // comprueba los 4 terminales de
// menor peso del puerto D y si son
// 1111 saca por los 4 terminales de
// mayor peso el dato 1010.

Existen unas funciones de C que permiten trabajar bit a bit con los registros o
variables definidas previamente.
Estas funciones son las siguientes:
bit_clear (var,bit); // Pone a 0 el bit especí fi co (0 a 7) de la variable.
bit_set (var , bit); // Pone a 1 el bit especí fi co (0 a 7) de la variable.
bit_test (var , bit); // Muestra el bit especí fi co (0 a 7) de la variable.
swap (var); // Intercambia los 4 bits de mayor peso por los 4);
// menor peso de la variable los 4 de bit_set (PORTC ,
Manejo de puertos
El compilador nos ofrece funciones predefinidas que nos ayudan a trabajar con los puertos

Ejemplos:

output_B(0b11001100); //saca un uno lógico por el pin(b7,b6,b4,b3)


valor = input_A(); //lee el valor del puerto A y lo almacena en valor
Algunas funciones asociadas

Ejemplos:

output_toggle(pin_b6); //complementa el valor del pin b6


input(pin_c3); //lee el valor del pin c3
output_low(pin_b0); //Pone el pin b0 a un cero logico
Estructuras o declaraciones de control

Las declaraciones son usadas para controlar el proceso


de ejecución del programa.

Las que admite CCS son:

 If-Else
 While
 Do-While
 For
 Switch-Case
 Return
 Break, Continue y Goto
IF-ELSE
Con la ayuda del comando IF-ELSE se pueden tomar decisiones

Primero se evalúa la EXPRESIÓN y si es cierta ( TRUE o 1)


ejecuta la SENTENCIA_1 , en el caso contrario ( FALSE o 0)
ejecuta la SENTENCIA_2 .

Pueden anidarse los IF-ELSE dando lugar a los ELSE-IF ; esto


permite tomar decisiones múltiples. if (expresión_1)
sentencia_1; [else if (expresión_2) sentencia_2;] [else
sentencia_3;]

En este caso las EXPRESIONES se evalúan en orden, si


alguna de ellas es cierta la SENTENCIA asociada a ella se
ejecutará y se termina la función. En caso contrario se ejecuta
la SENTENCIA del ELSE .

En ambos casos si existen varias sentencias para ejecutar se


deben utiliza las llaves
Ejemplos
For Se usa para repetir sentencias su estructura es :
for (inicialización ; condición de fi nalización
; incremento ) {

sentencias;

}
En las expresiones del FOR la inicialización es una variable a la cual se le asigna un
valor inicial con el que controlar el bucle.
La condición de finalización sirve para evaluar ANTES de ejecutar las sentencias si
es cierta o no, en el caso de ser cierta se ejecutan las sentencias y en caso contrario
se sale del FOR .

Por último, la expresión de incremento o decremento modifica la variable de control


DESPUÉS de ejecutar el bucle.

NOTA Se pueden anidar bucles FOR utilizando distintas variables de control.


Ejemplo For
Switch

Switch es un caso particular de una decisión múltiple


switch (expresión)
{
case constante 1:
sentencias;
break;
case constante 2:
sentencias;
break;
...
[default: sentencias;]

Evalúa la expresión y en orden a la CONSTANTE adecuada realiza las sentencias asociadas. Si ninguno
de los CASE corresponde a la CONSTANTE se ejecuta DEFAULT (este comando es opcional).

El comando BREAK provoca la salida de SWITCH , de lo contrario se ejecuta el siguiente CASE . NOTA
No pueden existir dos CASE con la misma CONSTANTE
Ejemplo de Switch en diagrama de bloque
While y Do-While
Se utiliza para repetir sentencias.

La expresión se evalúa y la sentencia se ejecuta mientras


while (expresión) la expresión es verdadera, cuando es falsa se sale del
{ WHILE .
sentencias;
}

Do
DO-WHILE se diferencia del WHILE y del FOR en la
{ condición de finalización, la cual se evalúa al final del
sentencias; bucle, por lo que las sentencias se ejecutan al menos una
} while (expresión); vez.

Se debe tener cuidado al usar las estructuras de manera que


no se tenga un BUCLE SIN FIN
Ejemplos de While y Do-While
Return, Break y Goto

Return: se emplea para devolver datos en las funciones.


Break: permite salir de un bucle, se utiliza para While , For , Do y
Switch .
Goto: provoca un salto incondicional.
Comentarios
Los comentarios en el programa facilitan la compresión de las distintas expresiones tanto
para el programador como para quién tiene que interpretar dicho programa.

No afectan a la compilación por lo que pueden ser tan extensos como el programador quiera.
Se pueden colocar en cualquier parte del programa y con dos formatos:

• Utilizando // . Al colocar estos signos se comienza el comentario y finaliza en el final de la


línea. Por ejemplo:
//Comentario que terminará al final de esta línea

• Utilizando /* y */ . Se debe utilizar al inicio y al final de comentario, pero no pueden repetirse


dentro del mismo comentario. Por ejemplo:

/* Este comentario no finaliza al final de esta línea,


finaliza cuando
se cierre el comentario */
Entorno de trabajo CCS Compiler
Barra de comandos

Pestaña del Barra de sub comandos


programa

Barra de Zona de código


ventanas
auxiliares
Ejemplo de programa
Ejemplo 1: Se con figuran los terminales RB1 como salida y el RB0 como
entrada (con resistencia de pull-up ). La salida debe tener el mismo valor que la
entrada. Se utiliza un interruptor en la entrada y un led en la salida

Componentes
proteus ISIS:
PIC16F876, RES,
LED-BLUE y SW-
SPST-MOM.
Ejemplo de programa
#include <16F876.h>
#fuses XT,NOWDT
#use delay( clock = 4000000 ) // Reloj de 4 MHz
#BYTE TRISB = 0x86 // TRISB en 86h.
#BYTE PORTB = 0x06 // PORTB en 06h
#BYTE OPTION_REG = 0x81 // OPTION_REG en 81h.
void main()
{
bit_clear(OPTION_REG,7); // Habilitación Pull-up
bit_set(TRISB,0); // B0 como entrada
bit_clear(TRISB,1); // B1 como salida
bit_clear(PORTB,1); // Apaga el LED
while (1)
{
if (bit_test(portb,0) == 1 ) // Si RB0 es 1, apaga el LED
bit_clear(portb,1);
else
bit_set(portb,1); // Si RB0 = 0, enciende el LED
}
}
Display
Display ¿COMO LO CONECTAMOS AL PIC?
Para poder trabajar directamente con el PIC sin hacer uso de un 7447 o 7448 (conversor de BCD a 7
segmentos), para poder visualizar los números del 0 al 9 en un display cátodo común
LCD
El LCD(Liquid Crystal Dysplay) o pantalla de cristal líquido es un dispositivo empleado para la visualización de
contenidos, mediante carácteres, símbolos o pequeños dibujos dependiendo del modelo.
Por ejemplo un LCD de 16x2, esto quiere decir que dispone de 2 filas de 16 caracteres cada una.
Los píxeles de cada símbolo o carácter, varían en función de cada modelo.
¿Cómo se conecta?
Pines de alimentación:

Vss: Gnd
Vdd: +5 voltios
Vee: corresponde al pin de contraste,( se puede regular con un potenciómetro de 10K)

Pines de control:

RS: Corresponde al pin de selección de registro de control de datos (0) o registro de datos(1). Es decir el pin RS funciona
paralelamente a los pines del bus de datos. Cuando RS es 0 el dato presente en el bus pertenece a un registro de
control/instrucción. y cuando RS es 1 el dato presente en el bus de datos pertenece a un registro de datos o un carácter.
RW: Corresponde al pin de Escritura(0) o de Lectura(1). Permite escribir un dato en la pantalla o leer un dato desde la
pantalla.
E: Corresponde al pin Enable o de habilitación. Si E(0) esto quiere decir que el LCD no esta activado para recibir datos,
pero si E(1) se encuentra activo y se puede escribir o leer desde el LCD.

Pines de Bus de datos:


El Bus de datos bidireccional comprende desde los pines D0 a D7. Para realizar la comunicación con el LCD podemos
hacerlo utilizando los 8 bits del bus de datos(D0 a D7) o empleando los 4 bits mas significativos del bus de datos(D4 a
D7)
¿Cómo se conecta?
Conexión en Proteus
Librería LCD en C
Para poder visualizar los caracteres o símbolos en el LCD es necesario que en el programa de código fuente a emplear,
incluyamos la librería.

En este caso se emplea la librería "lcd.c".

La librería viene configurada de esta manera Pero se puede configurar de otra manera, según el puerto deseado

#define LCD_ENABLE_PIN PIN_D0


#define LCD_ENABLE_PIN PIN_E0
#define LCD_RS_PIN PIN_D1
#define LCD_RS_PIN PIN_E1
#define LCD_RW_PIN PIN_D2
#define LCD_RW_PIN PIN_E2
#define LCD_DATA4 PIN_D4
#define LCD_DATA4 PIN_D4
#define LCD_DATA5 PIN_D5
#define LCD_DATA5 PIN_D5
#define LCD_DATA6 PIN_D6
#define LCD_DATA6 PIN_D6
#define LCD_DATA7 PIN_D7
#define LCD_DATA7 PIN_D7
Funciones a utilizar en la LCD

•lcd_init(): Inicializa el lcd


•lcd_gotoxy(x,y): Establece la posición de escritura en el lcd.
•lcd_putc(char s): nos muestra un dato en la siguiente posición del lcd.
\f se limpia el lcd

\n el cursor se posiciona al inicio de la segunda línea

• \b el cursor retrocede una posición


lcd_getc(x,y): lee el carácter de la posición (x,y)
•printf(lcd_putc, cadena, variable)
Ejemplo de programa
#include <16f877a.h>
#fuses hs,nowdt
#use delay(clock=20M)

#define lcd_rs_pin pin_b0


#define lcd_rw_pin pin_b1
#define lcd_enable_pin pin_b2
#define lcd_data4 pin_b4
#define lcd_data5 pin_b5
#define lcd_data6 pin_b6
#define lcd_data7 pin_b7
#include <lcd.c>

void main()
{
lcd_init();
while(true)
{
lcd_gotoxy(1,1);
printf(lcd_putc," HOLA MUNDO ");
delay_ms(1000);
lcd_gotoxy(1,1);
printf(lcd_putc," BIENVENIDOS ");
delay_ms(1000);
lcd_gotoxy(1,1);
printf(lcd_putc,“L. de D. de S. logicos");
delay_ms(1000);
}
}
Practica LCD
Realizar programa en lenguaje c que realice la suma de dos números y muestre el resultado en un
panel LCD de 16x2. Los dos números son de 4 bits

En la primera fila del panel se escribirá la expresión “Suma de: “ y el valor de los sumandos
separados por el signo +. En la segunda fila se escribirá el valor de la suma.

También podría gustarte