Está en la página 1de 135

Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

INSTITUTO TECNOLÓGICO DE QUERÉTARO

GUIA DEL COMPILADOR C DE CCS


PARA MICROCONTROLADORES
PIC DE MICROCHIP

Elaboró: Prof. Armando Mora Campos.


Fecha: Febrero 2017.
Versión: 3.2

Armando Mora Campos 1


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

INDICE
1. FORMATO GENERAL DE UN PROGRAMA ............................................................... 4

2. TIPOS DE DATOS (type-specifier) .................................................................................. 7

3. DEFINICION DE FUNCIONES ....................................................................................... 9

4. SENTENCIAS DE CONTROL Y ESTATUTOS (stmt) .................................................. 10

5. EXPRESIONES................................................................................................................. 11

6. FUNCIONES Y DIRECTIVAS PARA EL MANEJO DE PERIFERICOS Y


RECURSOS ...................................................................................................................... 13
6.1 Entradas/Salidas discretas............................................................................................ 13
6.2 Temporizadores/contadores ......................................................................................... 14
6.3 Convertidores A/D ....................................................................................................... 16
6.4 Programación de retardos ........................................................................................... 17
6.5 Comunicación serie asincrona RS-232 ........................................................................ 17
6.6 Comunicación serie sincrona i2c (SSP)....................................................................... 19
6.7 Comunicación serie sincrona SPI (E/S en dos hilos)................................................... 21
6.8 Puerto paralelo esclavo (PSP)..................................................................................... 21
6.9 Comparadores .............................................................................................................. 22
6.10 EEPROM de datos (interna) ...................................................................................... 22
6.11 Manipulación de bits ................................................................................................. 22
6.12 Funciones para el display LCD .................................................................................. 24
6.13 Control del procesador.............................................................................................. 25
6.14 Standard C ................................................................................................................ 26

7. MANEJO DE INTERRUPCIONES .................................................................................. 28

8. DIRECTIVAS MISCELANEAS ....................................................................................... 30


8.1 Insertando código ensamblador en un programa en C ......................................... 30
8.2 Definición de constantes tipo bit y byte...................................................................... 30
8.3 Directivas auxiliares .................................................................................................... 30

9. SISTEMA OPERATIVO EN TIEMPO REAL ................................................................. 32


9.1 Directivas del RTOS ................................................................................................... 32
9.2 Funciones del RTOS .................................................................................................... 35
9.3 RTOS e interrupciones ............................................................................................... 46

Armando Mora Campos 2


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

10. NOTAS Y RECOMENDACIONES PARA EL COMPILADOR PCW ........................... 50


10.1 Manejo de puertos paralelos ..................................................................................... 50
10.2 Uso de variables que definen un bit (short y short int) .............................................. 50
10.3 Lectura y escritura de registros internos ................................................................... 51
10.4 Definición de funciones: ¿inline o separate? ............................................................. 52
10.5 Optimización en el manejo de la memoria RAM ...................................................... 53
10.6 Restricciones en llamadas a funciones en interrupciones .......................................... 54
10.7 Localización de tablas en memoria ROM ................................................................. 55

11. DIAGRAMA PARA LOS EJERCICIOS DEL PIC16F887. ............................................. 56

12. ARCHIVO H DEL PIC16F887.. ....................................................................................... 57

13. EJEMPLOS SUPERLAZO ............................................................................................... 65

14. EJEMPLOS RTOS COOPERATIVO ............................................................................. 109

Armando Mora Campos 3


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

1. FORMATO GENERAL DE UN PROGRAMA


(SUPERLAZO).
a) Indicando comentarios.
/*Comentarios*/ o //Comentarios:
//Ejemplo de comentarios básicos: Nombre del programa, autor, fecha, procesador, resumen de
//operación y uso.

b) Include para especificar el dispositivo y las constantes de terminales y registros:


#include <16c71.h> //Nota: los archivos dispositivo.h ya incluyen la directiva #device,
#include <16c84.h> // la cual define el MCU PIC a utilizar.

c) Include para definir los fusibles de programación (ejemplo):


#fuses RC, NOWDT, PROTECT, PUT //Configuración por default.

d) Include´s para el manejo de algunas funciones del compilador:


#include stdio.h //Include para algunas funciones del pto. serie RS-232.
#include ctype.h //Include para funciones isxxx().
#include stdlib.h //Include para algunas funciones char de c estandar.
#include math.h //Include para funciones matemáticas de punto flotante.

e) Directivas use para el manejo de funciones y periféricos que se utilizaran (ejemplos):


#use delay(clock=10000000, restart_wdt) //Directiva para el manejo de retardos.
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) //Directiva para el manejo del pto. Serie.
#use fast_io(A) //Una de las directivas para el manejo y operacion de puertos.

f) Directivas auxiliares (ejemplos):


#id word //Directiva para especificar el identificador del chip.
#zero_ram //Directiva para inicializar a cero todos los registros internos.
#rom dir = {data0, data1,..} //Directiva para insertar datos en el archivo.hex.

g) Declarando constantes (datos y localidades de memoria):


#define BITS 8 //Constantes.
#define INTS_PER_SECOND 76
#define LAST_VOLUME 10
#byte status = 3 //Localidad de memoria.
#bit time_out = 3.4 //Bit de un registro.

h) Declarando variables globales (ejemplo):


int a,b,c,d;
typedef int byte;
bit e,f;
enum ADC_SOURCE {an0, an1, an2, an3, bandgap, srefh, srefl, itemp, refa,refb, an4, an5,
an6, an7};

Armando Mora Campos 4


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

i) Funciones (ejemplos).
En forma de archivos include:
#include <ds1621.c>
#include <salida.c>

Con la función completa en el programa (ejemplos):


void display_data(long int data) {
char volt_string[6];
convert_to_volts(data, volt_string);
printf(volt_string);
printf(" (%4lX)",data);
}

float READ_FLOAT_CAL(int n) {
int i;
float data;
for (i = 0; i < 4; i++)
*(&data + i) = READ_CALIBRATION(i + n);
return(data);
}

j) Rutinas de servicio a interrupcion (ejemplos).


#int_rtcc // This function is called every time
clock_isr() { // the RTCC (timer0) overflows (255->0).
if(--int_count==0) { // For this program this is apx 76 times per second.
++seconds;
int_count=INTS_PER_SECOND;
}
}

#int_ccp2
void isr() {
rise = CCP_1;
fall = CCP_2;
pulse_width = fall - rise; // CCP_1 is the time the pulse went high
} // CCP_2 is the time the pulse went low

k) Función principal (ejemplos).

void main() {
byte i,j,address,value;
do {
printf("\r\n\nEEPROM:\r\n"); // Display contents of entire EEPROM in hex.
for(i=0; i<=3; ++i) {
for(j=0; j<=15; ++j) {

Armando Mora Campos 5


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

printf( "%2x ", read_eeprom( i*16+j ) );


}
printf("\n\r");
}
printf("\r\nLocation to change: ");
address = gethex();
printf("\r\nNew value: ");
value = gethex();
write_eeprom( address, value );
} while (TRUE);
}

void main() {
byte buffer[8];
byte i;
printf("\r\nWaiting for a touch device...\r\n");
while (TRUE) {
while(!touch_present()) ;
delay_ms(200);
if(touch_present()) {
touch_write_byte(0x33);
for(i=0;i<8;++i)
buffer[i]=touch_read_byte();
printf("Family: %2X ID: ",buffer[0]);
for(i=6;i!=0;--i)
printf("%2X",buffer[i]);
printf("\r\n");
delay_ms(1000);
}
}
}

void main() {
printf("\r\nHigh time (sampled every second):\r\n");
setup_ccp1(CCP_CAPTURE_RE); // Configure CCP1 to capture rise
setup_ccp2(CCP_CAPTURE_FE); // Configure CCP2 to capture fall
setup_timer_1(T1_INTERNAL); // Start timer 1
enable_interrupts(INT_CCP2); // Setup interrupt on falling edge
enable_interrupts(GLOBAL);
while(TRUE) {
delay_ms(1000);
printf("\r%lu us ", pulse_width/5 );
}
}

Armando Mora Campos 6


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

2. TIPOS DE DATOS (type-specifier).


Formato general para tipo de datos simples:

[TYPEDEF] [type-qualifier] [type-specifier] [declarator] ;

Donde:

typedef Palabra para especificar nuevas definiciones de datos.


type-qualifier:
static Variable es globalmente activa e inicializada a 0.
auto Variable existe solo mientras el procedimiento es activo (default).
Type-specifier:
int Define un número de 8 bits sin signo (int8).
unsigned int Define un número de 8 bits sin signo (int8).
char Define un número de 8 bits sin signo (unsigned int8).
long Define un número de 16 bits sin signo (int16).
long int Define un número de 16 bits sin signo (int16).
long long Define un número de 32 bits sin signo (int32)
signed int Define un número de 8 bits con signo (signed int8).
signed long Define un número de 16 bits con signo (signed int16).
signed long long Define un número de 32 bits con signo (signed int32).
float Define un número en punto flotante de 32 bits con signo (float32).
short Define un número de 1 bit sin signo (int1).
short int Define un número de 1 bit sin signo (int1).

Nota: short es un tipo especial utilizado para generar un código muy eficiente para
operaciones sobre bits y E/S. No son permitidos arreglos de short y apuntadores a short

Otros tipos de datos:

const Si se utiliza antes del identificador,el identificador es tratado como una


constante La constante debe ser inicializada y no puede cambiar en tiempo de
ejecución. Apuntadores a constantes no son permitidas.

Enum Formato: enum [id] [ id [= cexpr ]] 

El id después de enum es creado como un tipo suficientemente grande para incluir la constante
mas grande de la lista. Los ids de la lista son creados cada uno como una constante. Por
default, el primer id es establecido a cero, incrementandose los demás de uno en uno. Si una
expresión =cexpr le sigue a un id, ese id tendrá el valor de la constante y las siguientes se
incrementaran a partir de este valor.

Armando Mora Campos 7


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

Struct and union Formato: struct [id] [ type-qualifier [[*] id :cexpr [cexpr ]]] 
union

La expresión :cexpr después de un id especifica el numero de bits a utilizar del identificador.


Este numero puede ser de 1 a 8. Multiple [] puede ser usado para arreglos multidimencionales.
El id despues de la estructura o union puede ser utilizado en otra estructura o union.

//Ejemplos:
int a,b,c,d;
typedef int byte;
typedef short bit;
bit e,f;
byte g[3][2];
char *h;
enum boolean false,true;
boolean j;
byte k = 5;
byte const WEEKS = 52;
byte const FACTORS[4] = 8, 16, 64, 128;
struct data_record 
byte a[2];
byte b : 2;
byte c : 3;
int d;
 d1, d2;

Armando Mora Campos 8


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

3. DEFINICION DE FUNCIONES.

Formato para la definición de funciones:

[qualifier] id ( [ [type-specifier id]) [stmt]

Los qualifier para una función son VOID o algún especificador de tipo de dato.

La definición de una función puede ser precedida por alguna de las siguientes directivas para
identificar una característica especial de la función:
#separate #inline #int_...

Ejemplos de funciones:

float READ_FLOAT_CAL(int n) {
int i;
float data;
for (i = 0; i < 4; i++)
*(&data + i) = READ_CALIBRATION(i + n);
return(data);
}

void display( char one, char two) {


display_segs(one);
output_high(PIN_A0);
wait();
output_low(PIN_A0);
display_segs(two);
output_high(PIN_A1);
wait();
output_low(PIN_A1);
}

Armando Mora Campos 9


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

4. SENTENCIAS DE CONTROL Y ESTATUTOS.


Este compilador permite las siguientes estructuras y estatutos en la construcción de programas:

if (expr) stmt else stmt


while (expr) stmt
do stmt while (expr);
for (expr1 ; expr2 ; expr3 ) stmt
switch (expr)
 case cexpr : stmt
case cexpr :stmt
. .
default :stmt 
return [expr] ;
goto label ;
label : stmt
break ;
continue ;
expr;
;
stmt 

Armando Mora Campos 10


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

5. EXPRESIONES.
Constantes:
123 Decimal.
O123 Octal.
0x123 Hexadecimal.
0b0110010 Binario.
‘x’ Caracter.
‘\O10’ Caracter octal.
‘\x’ Caracter especial ( x es uno de n,t,b,r,f,’,\d,v,?).
“abcdef” String (un null es agregado al final).

Identificadores:
abcde Hasta 32 caracteres iniciando con un no-numerico.
id[x] Subscriptor simple.
id[x][x] Subscriptor multiple.
id.id Referencia a unión o estructura.
Id->id Referencia a unión o estructura.

Operadores:
+ Adición.
+= Adición y asignación (x += y es lo mismo que x = x + y).
&= And sobre bits y asignación (x &= y es lo mismo que x = x & y).
& Dirección.
& And sobre bits.
^= Or exclusiva sobre bits y asignación ( x ^= y es lo mismo que x = x ^ y).
^ Or exclusiva sobre bits.
|= Or sobre bits y asignación (x |= y es lo mismo que x = x | y).
| Or sobre bits.
?: Expresión condicional.
-- Decremento.
/= División y asignación (x /= y es lo mismo que x = x/y).
/ División.
== Igualación.
> Mayor que.
>= Mayor o igual que.
++ Incremento
* Indirecto
!= No igual.
<<= Corrimiento a la izquierda y asignación (x <<= y es lo mismo que x = x << y).
< Menor que.
<< Corrimiento a la izquierda.
<= Menor o igual.
&& And lógico
! Not lógico.

Armando Mora Campos 11


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

|| Or lógico.
%= Modulo y asignación.
% Modulo.
*= Multiplicación y asignación (x *= y es lo mismo que x = x * y).
* Multiplicación.
~ Complemento a uno.
>>= Corrimiento a la derecha y asignación ( x >>= y es lo mismo que x = x >> y).
>> Corrimiento a la derecha.
-> Apuntador a estructura.
-= Resta y asignación (x -= y es lo mismo que x = x -y).
- Resta.

Precedencia de operadores, en orden descendente:


(expr)
!exp ~expr ++expr expr++ -expr expr-
(type)expr *expr &|value sizeof expr sizeof(type)
expr * expr expr / expr expr % expr
expr + expr expr - expr
expr << expr expr >> expr
expr < expr expr >= expr expr > expr expr >= expr
expr == expr expr != expr
expr & expr
expr ^ expr
expr && expr
expr || expr
|value ? expr : expr
|value = expr |value += expr |value -= expr
|value *= expr |value /= expr |value %= expr
|value >>= expr |value <<= expr |value &= expr
|value ^= expr |value |= expr
expr, expr

Armando Mora Campos 12


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

6. FUNCIONES Y DIRECTIVAS PARA EL


MANEJO DE PERIFERICOS Y RECURSOS.

6.1 Entradas/Salidas discretas.


#use standard_io(port) //Directivas que definen como el compilador generara el código
#use fast_io(port) //de las funciones para puertos de E/S. Los puertos son de A a G.
#use fixed_io(port_OUTPUTS= pin,pin,..)
//Al utilizar #use standart_io(), se generara código para configurar el pin como entrada
//o salida cada vez que sea utilizado. Con #use fast_io(), no se configurara la dirección
//del puerto en cada proceso de lectura o escritura (se debe configurar aparte).Usando
//la directiva #use fixed_io, se establece la dirección de los puertos (entrada o salida).
//Estas directivas toman efecto hasta que se encuentra otra directiva que las sustituye.
#use standard_io(A) //Ejemplos.
#use fast_io(C)
#use fixed_io(a_outputs=PIN_A2, PIN_A3)

#byte identificador = localidad de memoria //Directiva para asignar la dirección de un puerto.


#byte b_port = 6 //Ejemplo para indicar que b_port es la dir. 6.
b_port = POSITIONS[stepper_state;//Ejemplo de escritura a la dirección 6.

set_tris_a( 0x__); //Funciones para configuración de E/S. Cada bit en el paréntesis


set_tris_b( 0x__); //representa un pin. Un 1 indica pin de entrada y un 0 de salida. Deben
set_tris_c( 0x__); //ser usadas con la directiva FAST_IO, cuando los puertos de E/S son
set_tris_d( 0x__); //accesados como memoria, cuando se usa la directiva #byte y los
set_tris_e( 0x__); //registros se escriben directamente. Ejemplo:
set_tris_B( 0x0F );

setup_port_a(value); //Configuración del puerto A. Establece el puerto. A para operación


//analógica, digital o una combinación. Las alternativas de value son:
//NO_ANALOGS (todas digitales).
//ALL_ANALOGS (referencia vdd).
//ANALOG_RA3_REF (referencia ra3).
//RA0_RA1_ANALOG (ra2, ra3 digitales).
//Para el dispositivo PIC16C74:
//A_ANALOG.
//A_ANALOG_RA3_REF
//RA0_RA1_RA3_ANALOG
//RA0_RA1_ANALOG_RA3_REF
setup_port_a(ALL_ANALOG); //Ejemplo.

output_low(pin); //Salida cero en un pin. El método de E/S depende de la ultima directiva


//#USE *_IO.

Armando Mora Campos 13


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

output_low(PIN_A0); //Ejemplo: pin 0 del puerto A = 0.

output_high(pin); //Salida uno en un pin. El método de E/S depende de la ultima directiva


//#USE *_IO.
output_high(PIN_B6); //Ejemplo: pin 6 del puerto B = 1.

output_float(pin); //Estableciendo un pin como entrada. Equivale a un pin en alta


//impedancia, como si flotara.
if ( (data & 0x80) == 0 ) //Ejemplo.
output_low(PIN_A5);
else
output_float(PIN_A5);

output_bit(pin,value); //Salida 0 ó 1 (value) en un pin. El método de E/S depende de la ultima


//directiva #USE *_IO.
output_bit(PIN_B3,0); //Ejemplo: igual que outp_low(pin_B3);
output_bit( PIN_A2, input(PIN_B1) ); //Ejemplo: hacer pin A2 igual que pin B1.
output_bit( PIN_B0, shift_left(&data,1,input(PIN_B1)));//Ejemplo: salida en B0 del
//MSB de data y al mismo tiempo correr
//B1 en el LSB.

input(pin); //Lectura de un pin. El método de E/S depende de la ultima directiva USE*_IO.


//el tipo de dato que retorna es SHORT INT.
while( ! input(PIN_B1) ); //Ejemplo.

port_b_pullups(flag); //Resistencias de pull-up en entradas del puerto B. Si flag es TRUE,


//resistencias activadas. Si flag es FALSE, resistencias desactivadas.

6.2 Temporizadores/contadores.
setup_counters(rtcc_state,ps_state); //Configurando el temporizador 0 y el watchdog.
//El rtcc_state determina quien activa el RTCC:
//RTCC_INTERNAL, RTCC_EXT_L_TO_H
//RTCC_EXT_H_TO_L
//El ps_state define el pre-escalador:
//RTCC_DIV_2, RTCC_DIV_4, RTCC_DIV_8
//RTCC_DIV_16, RTCC_DIV_32, RTCC_DIV_64
//RTCC_DIV_128, RTCC_DIV_256, WDT_18MS
//WDT_36MS, WDT_72MS, WDT_144MS
//WDT_288MS, WDT_576MS, WDT_1152MS
//WDT_2304MS
setup_counters(RTCC_INTERNAL,WDT_2304MS); //Ejemplo.

setup_timer1(mode); //Configurando temporizador 1. Los modos posibles son:

Armando Mora Campos 14


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//T1_DISABLED.
//T1_INTERNAL.
//T1_EXTERNAL.
//T1_EXTERNAL_SYNC.
//T1_CLK_OUT.
//T1_DIV_BY_1.
//T1_DIV_BY_2.
//T1_DIV_BY_4.
//T1_DIV_BY_8.

setup_timer2 (A,B,C); //Configurando temporizador 2 . Los parámetros de


//configuración son:
//A = Pre-escalador del Timer (1, 4, 16).
//B = Resultado numérico de PR2+1 (PR2 es un registro de 8 bits
//del microcontrolador).
//C = Post-escalador del timer 2 (de 1 a 16).
setup_timer_2(T2_DIV_BY_16,127,2); // Ejemplo.

set_rtcc(value); //Funciones para establecer el registro del timer al valor indicado.


set_timer0(value); //rtcc y timer0 son los mismos. Timer1 es de 16 bits y los otros
set_timer1(value); //de 8 bits.
set_timer2(value);
if (get_rtcc() == 25 ) //Ejemplo de uso.
set_rtcc(0);

get_rtcc(); //Valor del contador.Funciones que retornan el valor del contador


get_timer0(); //indicado; rtcc y timer0 son lo mismo. Timer1 es de 16 bits;
get_timer1(); //los demás de 8 bits.
get_timer2();
while (get_rtcc() !=0); //Ejemplo.

setup_ccp1(mode); //Inicializando el contador CCP. Los contadores CCP pueden ser


setup_ccp2(mode); //accesados usando las variables CCP_1_LOW, CCP_1_HIGH,
//CCP_2_LOW y CCP_2_HIGH.
//Los valores de mode son:
/CCP_OFF, CCP_CAPTURE_FE, CCP_CAPTURE_RE
//CCP_CAPTURE_DIV_4 CCP_CAPTURE_DIV_16
//CCP_COMPARE_SET_ON_MATCH
//CCP_COMPARE_CLR_ON_MATCH
//CCP_COMPARE_INT, CCP_COMPARE_RESET_TIMER
//CCP_PWM
//CCP_PWM_PLUS_1 (solo en 8 bits duty)
//CCP_PWM_PLUS_2 (solo en 8 bits duty).
//CCP_PWM_PLUS_3 (solo en 8 bits duty).

Armando Mora Campos 15


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

set_pwm1_duty(value); //Establecimiento del ciclo de trabajo del PWM.


set_pwm2_duty(value); //Esta función escribe un valor de 10 bits al PWM. 0x200 será el
//50%. Un valor de 8 bits puede ser usado haciendo un B<<2 si
//los bits menos significativos no son necesarios.

6.3 Convertidores A/D.


setup_vref(mode); //Establecimiento del voltaje de referencia para los dispositivos 62X.
//Alternativas del modo:
//FALSE (off), VREF_LOW (vdd*value/24)
//VREF_HIGH (vdd*value/32 + vdd/4), VREF_A2
setup_vref(vref_high | 6); //Ejemplo. A vdd=5, el voltaje es 2.19 V.

setup_adc(mode); //Configurando el convertidor A/D. Los modos son los siguientes:


//ADC_OFF, ADC_CLOCK_DIV_2, ADC_CLOCK_DIV_8
//ADC_CLOCK_DIV_32, ADC_CLOCK_INTERNAL
//Para el chip 14000 esta función establece la corriente de carga.
setup_adc(ADC_CLOCK_INTERNAL); //Ejemplo.

set_adc_channel(channel); //Especificando el canal para la sig. conversión. El canal puede


//ser 0 a 3 para el pic 71, 0 a 7 para el pic 74 y 0 a 4 para el
//pic 72. Es necesario esperar un tiempo corto, después de
//cambiar el canal, para leer el resultado de conversión. Si el
//canal es el mismo, no es necesario cambiarlo en cada lectura.
set_adc_channel(2); //Ejemplo.

value = read_adc(); //Lectura del resultado de conversion.


setup_adc(ALL_ANALOG); //Ejemplo de uso.
set_adc_channel(3);
while(input(PIN_B0)) {
delay_ms(5000);
value = read_adc();
printf(“A/D value = %2\n\r”, value);
puthex(value);
printf(“\n\r”);
}

//Nota: Para el uso del convertidor, tambien considerar la función setup_port_a().

Armando Mora Campos 16


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

6.4 Programación de retardos.


#use delay( ) //Directiva para habilitar las funciones de retardo e indicarle al
//compilador la velocidad del procesador.
//Debe declararse previo al uso de las funciones delay_us( ) y
//delay_ms( ). Se tienen dos opciones (ejemplos siguientes):
#use delay(clock = 20000000) //Indicando solo la velocidad del reloj en hertz.
#use delay(clock = 32000, RESTART_WDT) //Indicando la velocidad del reloj y
//restableciendo el watchdog timer mientras ocurre el retardo.

delay_cycles(ciclos); //Función de retardo del numero especificado de ciclos.


//Equivale a instrucciones NOP.
delay_cycles(1); //Ejemplo. Equivale a una instrucción NOP.

delay_us(tiempo); //Función de retardo en microsegundos.


//Si tiempo es una constante, puede tomar valores de 0 a 65535.
//Para tiempo variable el rango es de 0 a 255
//Los retardos cortos seran INLINE; los largos y los variables
//como SEPARATE.
#use delay(clock=20000000) //Ejemplo de retardos constante y variable.
delay_us(us_to_wait);
delay_us(5000);

delay_ms(tiempo); //Función de retardo en milisegundos, similar al delay_us( ).


#use delay(clock=4000000) //Ejemplo.
delay_ms(2);
void delay_seconds(intn) {
for( ; n!=0; n--);
delay_ms(1000);
}

6.5 Comunicación serie asincrona RS-232.


#use rs232() //Directiva para habilitar las funciones del puerto RS232 y establecer la
//velocidad en bps y los pines a utilizar.
//Previo a su uso debe existir la directiva #use delay(), asi como una de
//las directivas para la configuración de los puertos paralelos
//(#use standard_io, #use fixed_io, o #use fast_io).
//La operacion RESTART_WDT es opcional y si se incluye, causara que
//al ejecutar la funcion getc() se limpie el WDT cuando se espera por un
//caracter. La polaridad de los pines del puerto serie puede ser invertida
//agregando INVERT al final de la lista. La paridad se especifica con
//PARITY = N, E o O. El numero de bits de datos se define como
//BITS=x, donde x es 5,6,7,8 o9.

Armando Mora Campos 17


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Cuando el dispositivo incluya un periferico SCI y se especifican los


//pines del mismo, entonces automáticamente se usa el SCI.
//Si la tasa en bps indicada no puede ser generada con un error máximo
//del 3% se marcara un error. Ejemplo:
#use rs232(baud=9600,xmit=PIN_A2,rcv=PIN_A3,BITS=8,PARITY=N)

getch(); //Funciones que esperan por un caracter que se reciba por el pin de
getc(); //recepción del puerto RS-232
getchar(); //Ejemplo:
printf(“Continue (Y,N) ? “);
do 
answer = getch();
while (answer != ‘Y’ && answer != ‘N’);

putchar(character); //Transmision de un caracter sobre el pin XMIT. Antes


putc(character); //de su llamada debe existir la directiva #use rs232.
if (checksum == 0) //ejemplo.
putchart(ACK);
else
putchart(NAK);

kbhit(); //Deteccion de recepcion serie. Funcion que regresa un TRUE si


//el bit de inicio de un caracter se ha recibido por el pin RCV.
//Antes de su llamada debe existir la directiva #use rs232.
keypress = ´ ´; //Ejemplo.
while ( keypress !=´Q´ ) {
if (kbhit() )
keypress = getc();
if ( !input(PIN_B2))
output_high(PIN_B3);
else
output_low(PIN_B3);
}

gets(char *string); //Lectura de cadenas.Lee caracteres, usando getc() en el string hasta que
//un RETURN (valor 13) es encontrado. El string es terminado con 0.

puts(string); //Transmision de cadenas. Transmite cada caracter de una cadena


//utilizando putc(). Despues de que se envia la cadena, se
transmiten //un RETURN (13) y un LINE-FEED (10). Ejemplo:
puts(“------------”);
puts(“| HOLA |”);
puts(“------------”);

Armando Mora Campos 18


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

printf(string,...); //Transmisión con formato. Envío de los caracteres de una


cprintf(function,string...); //cadena utilizando putc() al puerto RS-232 o una función
//especifica. El formato esta de acuerdo con la cadena. Cuando se
//usan variables, la cadena debe ser constante. El caracter % se utiliza para indicar que un
//valor variable va a ser formateado y enviado. El formato toma la forma genérica %wt donde
//w es opcional y puede ser de 1 a 9 especificando cuantos caracteres se enviaran. El
//parámetro t es el tipo y puede ser uno de los siguientes:
// c Character.
// u Unsigned int.
// x Hex int (salida en minusculas).
// X Hex int (salida en mayusculas).
// d Signed int.
// %e Float en formato exp.
// %F Float.
// lx Hex long int (minusculas).
// lX Hex long int (mayusculas).
// lu Unsigned decimal long.
// ld Signed decimal long.
// % Justamente un %.

//Ejemplos:
byte x,y,z;
printf( “Hi There” );
printf( “RTCC Value => %2x\n\r”, get_rtcc() );
printf( “%2u %X %4X\n\r”, x,y,z);
printf(LCD_PUTC,”n=%v”,n);

//Ejemplos de formato:
// Especificador Valor = 0x12 Valor = 0xfe
// %03u 018 254
// %u 18 254
// %2u 18 254
// %5u 18 254
// %d 18 -2
// %x 12 fe
// %X 12 FE
// %4X 0012 00FE

6.6 Comunicación serie sincrona i2c (SSP).


#use i2c() //Directiva para habilitar las funciones de comunicación i2c. Las funciones
//son generadas por software, a menos que los pin especificados sean los de un
//periférico interno SSP. El modo esclavo puede ser usado solo con un SSP
//interno. Opciones:

Armando Mora Campos 19


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//MASTER Establece el modo maestro.


//SLAVE Establece el modo esclavo.
//SCL = pin Especifica el pin SCL.
//SDA = pin Especifica el pin SDA.
//ADDRESS = nn Especifica la dirección en modo esclavo.
//FAST Usa la especificación fast de i2c.
//SLOW Usa la especificación slow de i2c.
//RESTART_WDT Restablece el WDT mientras espera en función i2c_read().
//FORCE_SW Genera las funciones i2c por software aun cuando se
//especifiquen los pines del periférico SSP.
//Ejemplos de uso:
#use i2c(master, sda=PIN_C4, scl=PIN_B1)
#use i2c(slave, sda=PIN_C4, scl=PIN_C3, address=0xa0)

i2c_start(); //Condición de inicio para I2C en modo maestro.Se necesita la directiva #use
//i2c antes de invocar esta función. Después de la condición start el reloj es bajo
//hasta que son llamadas las funciones i2c_read() o i2c_write().

i2c_stop(); //Condición de paro para I2C en modo maestro. Se necesita la directiva #use i2c
//antes de invocar esta función.

i2c_write(byte); //Escritura de un byte sobre la interfaz i2C. Se necesita la directiva #use 12c
//antes de invocar esta función. En modo maestro generara un reloj con el dato
//y en modo esclavo esperara por el reloj del maestro. No proporciona un
//tiempo fuera automático cuando no se usa el periférico SPP.
//Ejemplo:
i2c_start(); //Condición de inicio.
i2c_write(0x0a); //Dirección del dispositivo.
i2c_write(5); //Comando.
i2c_write(12); //Dato;
i2c_stop(); //Condición de paro.

data = i2c_read(); //Lectura de un byte sobre la interfaz i2c. Se necesita la directiva #use
//i2c antes de invocar esta función. En modo maestro, generara el reloj.
//En modo esclavo esperara por el reloj. Esta función espera por datos
//sin que se incluya un tiempo fuera automático. Si se incluye
//RESTART_WDT en la directiva #use i2c, entonces esta función
//limpiara el WDT mientras espera. Ejemplo:
i2c_start(); //Condición de inicio.
i2c_write(0xa1); //Dirección del dispositivo.
r = i2c_read(); //Lectura del primer byte.
r2 = i2c_read(); //Lectura del segundo byte.
i2c_stop(); //Condición de paro.

ready = i2c_poll(); //Verificación de recepción. Esta función es valida solamente cuando el

Armando Mora Campos 20


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//microcontrolador cuenta con el periférico SPP. Retorna TRUE si el


//hardware tiene un byte recibido en el buffer. En este caso, un llamada a
//i2c_read() retornara inmediatamente el byte que fue recibido. Ejemplo:
i2c_start(); //Condición de inicio.
i2c_write(0xc1); //Dirección del dispositivo.
Read count = 0;
while(count !=4 ) {
if (i2c_poll() )
r[count++ = i2c_read();
..mas instrucciones..
}
i2c_stop(); //Condicion de paro.

6.7 Comunicación serie sincrona SPI (E/S en dos hilos).


setup_spi(mode); //Inicialización del SPI. Los modos posibles son:
//SPI_MASTER
//SPI_SLAVE
//SPI_L_TO_H
//SPI_H_TO_L
//SPI_CLK_DIV_4
//SPI_CLK_DIV_16
//SPI_CLK_DIV_64
//SPI_CLK_T2
//SPI_SS_DISABLED
setup_spi(spi_master | spi_l_to_h | spi_clk_div_16); //Ejemplo.

spi_data_is_in(); //Verificación de recepción. Esta función retornara TRUE si el


//dato ha sido recibido sobre el SPI.

spi_write(value); //Función de escritura del SPI.


spi_write(data_out); //Ejemplo.

spi_read(); //Función de lectura del SPI.


if (spi_data_is_in()) //Ejemplo.
new_data = spi_read();

6.8 Puerto paralelo esclavo (PSP).


setup_psp(mode); //Inicialización del PSP. Alternativas de mode: PSP_ENABLE,
//PSP_DISABLE. Para establecer la dirección de los datos se puede
//utilizar la función set_tris_e(value). El dato puede leerse o escribirse
//usando la variable PSP_DATA.

Armando Mora Campos 21


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

psp_output_full(); //Condiciones del PSP. Funciones que checan la condición indicada y


psp_input_full(); //retornan TRUE o FALSE.
psp_overflow();
while(psp_output_full()); //Ejemplos.
psp_data = command;
while(!psp_input_full());
if(psp_overflow())
error = TRUE;
else
data = psp_data;

6.9 Comparadores.
setup_comparator(mode); //Establecimiento del modo del comparador.
//Alternativas del modo:
//A0_A3_A1_A2, A0_A2_A1_A2, NC_NC_A1_A2
//NC_NC_NC_NC, A0_VR_A2_VR, A3_VR_A2_VR
//A0_A2_A1_A2_OUT_ON_A3_A4, A3_A2_A1_A2
//Donde los cuatro grupos son C1-, C1+, C2- y C2+.
setup_comparator(A0_A3_A1_A2); //Ejemplo: establecimiento de dos comparadores
//independientes normales.

6.10 EEPROM de datos (interna).


value = read_eeprom(address); //Lectura de un byte de la EEPROM. Lee el byte con
//dirección address (0 a 63) de la EEPROM.
#define LAST_VOLUME 10 //Ejemplo.
volume = read_eeprom(LAST_VOLUME);

write_eeprom(address,value); //Escritura de un byte a la EEPROM. Escribe un byte a la


//EEPROM, a la dirección indicada (0 a 63). Esta función
//tarda algunos mseg. en ejecutarse.
#define LAST_VOLUME 10 //ejemplo.
volume++;
write_eeprom(LAST_VOLUME,volume);

6.11 Manipulación de bits.


shift_left(address,byte,value); //Corrimiento a la izq. de un bit en un arreglo o
estructura. //address debe ser el identificador de un arreglo o un

Armando Mora Campos 22


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//apuntador a una estructura (tal como &data). Bytes es el


//numero de bytes involucrados en la operación de
//corrimiento. Value es el valor del bit a insertar.
//Esta función retornara el bit que salió.
byte buffer [3; //Ejemplo.
for (I=0; I<=24; ++I) { //Lectura de 24 bits del pin A2, cada bit es leído en el
while (!input(PIN_A1)) ; //cambio de bajo a alto del pin A1.
shift_left(buffer,3,input(PIN_A2));
while (input(PIN_A1)) ;
}

shift_right(address,byte,value); //Corrimiento a la der de un bit en un arreglo o estructura.


//address debe ser el identificador de un arreglo o un
//apuntador a una estructura (tal como &data). Bytes es el
//numero de bytes involucrados en la operación de
//corrimiento. Value es el valor del bit a insertar.
//La función regresa el bit que salió en el corrimiento.
struct {byte time; //Ejemplo:
byte command: 4; //Lectura de 16 bits del pin A1, cada bit es leído en el
byte source : 4; } msg; //cambio de bajo a alto del pin A2.
for(I=0; I<=16;++I) {
while (!input(PIN_A2)) ;
shift_right(&msg,3,input(PIN_A1));
while (input(PIN_A2)) ;
}

rotate_left(address,bytes); //Rotación de un bit a la izq. por un arreglo o estructura.


//La dirección puede ser el identificador de un arreglo
//o un apuntador a un byte o estructura (tal como &data)
//Bytes es el numero de bytes involucrados en la rotación.
byte x; //Ejemplo.
x = 0x86;
rotate_left(&x,1); //x vale ahora 0x0d.

rotate_right(address,bytes); //Rotación de un bit a la der. por un arreglo o estructura.


//La dirección puede ser el identificador de un arreglo
//o un apuntador a un byte o estructura (tal como &data)
//Bytes es el numero de bytes involucrados en la rotación.
struct{ int cell_1 : 4; //Ejemplo.
int cell_2 : 4;
int cell_3 : 4;
int cell_4 : 4; } cells;
rotate_right(&cells,2); //cell 1-->2, 2-->3, 3-->4, y 4-->1.
rotate_right(&cells,2);
rotate_right(&cells,2);

Armando Mora Campos 23


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

rotate_right(&cells,2);

bit_set(var,bit); //Estableciendo un bit en una var. Asigna un 1 en el bit


//especificado (0-7 o 0-15) de la var indicada.
int x; //Ejemplo.
x = 5;
bit_set(x,3); //x es ahora 13.

bit_clear(var,bit); //Limpiando un bit en una var. Asigna un 0 en el bit


//especificado (0-7 o 0-15) de la var indicada.
int x; //Ejemplo de uso.
x = 5;
bit_clear(x,2); //x es ahora 1.

bit_test(var,bit); //Prueba de un bit en una var. Función que prueba el bit


//especificado (0-7 o 0-15) en la var dada. Es mas
//eficiente que la siguiente expresión equivalente:
//((var & (1<<bit)) != 0);
if (bit_test(x,3) || !bit_test(x,1)) { //Ejemplo de uso.
....................... //Si el bit 3 es 1 o el bit 1 es 0 entonces....
}

swap(byte); //Intercambio de nibbles. Equivalente a lo siguiente:


//byte = (byte << 4) | (byte >> 4);
x = 0x45; //Ejemplo de uso.
swap(x); //x es ahora 0x54.

6.12 Funciones para el display 92X LCD.


setup_lcd(mode, prescale, segments); //Función para inicializar el controlador de LCD
//923/924.
//Los modos son:
//LCD_DISABLED LCD_STATIC
//LCD_MUX12 LCD_MUX13
//LCD_MUX14
//y pueden ser calificados por:
//STOP_ON_SLEEP USE_TIMER_1
//La prescala puede ser de 1 a 15 del CLK.
//Los segmentos pueden ser:
//SEG0_4 SEG5_8 SEG9_11
//SEG12_15 SEG18_19 SEG25_26
//SEG27_28 SEG29_30 ALL_LCD_PINS

Armando Mora Campos 24


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

lcd_symbol(symbol, b7_addr, b6_addr, b5_addr, b4_addr, b3_addr,


b2_addr,b1_addr,b0_addr);
//Función que carga 8 bits en el área de segmentos de datos para el LCD con cada
//dirección de bit especificada. Si el bit 7 del símbolo es establecido, el segmento del
//bit 7 es establecido; de otra manera es limpiado. Esto es verdadero para todos los
//demás bits en símbolo. El b7_addr es una dirección de bit en la RAM LCD.
//Ejemplo:
byte CONST DIGIT_MAP[10] = {0x90,0xb7,0x19,0x36,0x54,0x50,0xb5,0x24};
#define DIGIT_1_CONFIG
COM0+2,COM0+4,COM0+5,COM2+4,COM2+1,COM1+4,COM1+5
for(i=1;i<=9;++i) {
lcd_symbol(DIGIT_MAP[i], DIGIT_1_CONFIG);
delay_ms(1000);
}

6.13 Control del procesador.


sleep(); //Función para dormir al procesador. Igual a la instrucción sleep.

restart_wdt(); //Función para restablecer el WDT. Igual a la instrucción clrwdt.


while (!done) //Ejemplo.
{
restart_wdt();
.
}

restart_cause(causa); //Función que retornara la causa del ultimo reset del procesador.
//El valor de retorno será uno de los siguientes:
//WDT_FROM_SLEEP, WDT_TIME_OUT, MCLR_FROM_
//SLEEP, NORMAL_POWER_UP.
switch (restart_cause( ) ) //Ejemplo.
{
case WDT_FROM_SLEEP: ;
case WDT_TIME_OUT: handle_error( );
}

value = read_bank(bank,offset); //Lectura de un byte de un banco de memoria. El banco


//puede ser de 1 a 3 para la familia 57. El offset de 0 a 15.
data = read_bank(1,5); //Ejemplo.

write_bank (bank, offset, value); //Escritura de un byte a un banco de memoria. El banco


//puede ser de 1 a 3 para la familia 57. El offset de 0 a 15.
write_bank(1,0,23); //Ejemplo.

Armando Mora Campos 25


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

6.14 Standard C.
int abs(signed int j); //Calcula el valor absoluto de un entero j. Si el resultado
long int abs(signed long int j); //no puede ser representado, el comportamiento es
//indefinido.

asin(float x); //Calcula el principal valor de arco seno de x. El valor de


//retorno esta en el rango [-pi/2, pi/2] radianes. Para
//argumentos fuera del rango [-1,1] el comportamiento es
//indefinido.

acos(float x); //Calcula el principal valor de arco coseno de x. El valor


//de retorno esta en el rango [0, pi] radianes. Para
//argumentos fuera del rango [-1,1] el comportamiento es
//indefinido.

atan(float x); //Calcula el principal valor de arco tangente de x. El valor


//de retorno esta en el rango [-pi/2, pi/2] radianes.

float ceil(float x); //Calcula elvalor integral mas pequeño no mas grande que
//x.

float exp(float x); //Calcula la función exponencial de x. Si la magnitud de x


//es muy grande, el resultado es indefinido.

float floor(float x); //Calcula el valor integral mas pequeño no mas grande
//que x.

//Macros del archivo CTYPE.H. Retornan TRUE si:


isalnum(char x) //x es 0..9, A´..`Z´, o a´..`z´
isalpha(char x) //x es A´..`Z´, o a´..`z´
isdigit(char x) //x es 0´..`9´
islower(char x) //x es a´..`z´
isupper(char x) //x es A´..`Z´
isspace(char x) //x es un espacio
isxdigit(char x) //x es 0´..`9´, A´..`F´, o a´..`f´

float log(float x); //Calcula el logaritmo natural de x. Si el argumento es


//menor o igual a cero o muy grande, el comportamiento
//es indefinido.

float log10(float x); //Calcula el logaritmo base-10 de x. Si el argumento es


//menor o igual a cero o muy grande, el comportamiento
//es indefinido.

Armando Mora Campos 26


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

memcpy(dest,source,n); //Copiando un bloque de datos. Esta función copia n bytes


//de la fuente a destino en RAM; dest y source deben ser
//apuntadores. Ejemplo:
memcpy(&structA,&structB, sizeof(structA));
memcpy(arrayA, arrayB,sizeof(arrayA));
memcpy(&structA, &databyte, 1);

memset(dest,value,n); //Estableciendo un bloque de bytes de memoria. Esta


//función establecerá n bytes de memoria a dest con
//value; dest debe ser un apuntador. Ejemplo:
memset(arrayA,0,sizeof(arrayA));
memset(%structA,0xff,sizeof(structA));

signed int atoi(char *ptr) //Convierte la porción inicial del string apuntado por ptr a
//una representación int. Acepta argumentos decimal y
//hexadecimal. Si el resultado no puede ser representado,
//el comportamiento es indefinido.

signed long int atol(char *ptr) //Convierte la porción inicial del string apuntado por ptr a
//una representación long int. Acepta argumentos decimal
//y hexadecimal. Si el resultado no puede ser representado
//el comportamiento es indefinido.

sqrt(float x) //Calcula la raíz cuadrada no negativa de x. Si el


//argumento es negativo, el comportamiento es indefinido

strcpy(dest,string); //Copia una cadena constante a RAM.


char string[10; //Ejemplo de uso.
........
strcpy(string,”Hi There”);

strxxx( ); //Funciones string estándar. Son 14 funciones definidas en el archivo


//string.h. Ninguna de las funciones operaran con una constante string
//como parámetro. Usar strcpy para copiar un string constante a RAM
//antes de usar estas funciones.

tolower(x) //Retornara a´..`z´ por cada A´..`Z´. Otros caracteres no cambian.

toupper(x) //Retornara A´..`Z´ por cada a´..`z´. Otros caracteres no cambian.

Armando Mora Campos 27


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

7. MANEJO DE INTERRUPCIONES.
enable_interrupts(level); //Habilitación/deshabilitación de interrupciones. Estas funciones
disable_interrupts(level); //habilitan/deshabilitan la interrupción indicada. La interrupción
//debe tener su correspondiente rutina de servicio.
//Niveles validos:
//GLOBAL INT_RTCC (o RTCC_ZERO)
//INT_RB(o RB_CHANGE) INT_EXT (o EXT_INT)
//INT_AD (o ADC_DONE) INT_EEPROM
//INT_TIMER1 INT_TIMER2
//INT_CCP1 INT_CCP2
//INT_SSP INT_PSP
//INT_RDA INT_TBE
//INT_COMP INT_ADOF
//INT_RC INT_I2C
//INT_BUTTON INT_LCD
//Ejemplos:
disable_interrupts(GLOBAL); //Deshabilitar todas las interrupciones.
enable_interrupts(ADC_DONE); //Habilitando interrupciones.
enable_interrupts(RB_CHANGE);
enable_interrupts(GLOBAL);

ext_int_edge(edge); //Función para definir el borde de la interrupcion externa.


//Para el borde de subida, edge = L_TO_H
//Para el borde de bajada, edge = H_TO_L

#int_ext //Directivas para indicar que la siguiente función es una rutina


#int_rtcc //de servicio a interrupción.
#int_rb //Las rutinas no deben tener parámetros y todas las variables
#int_ad //locales son automáticamente definidas STATIC. Estas rutinas
#int_eeprom //no deben llamar funciones SEPARATE ya que el estado de la
#int_timer1 //pila no puede ser conocido.
#int_timer2 //El compilador generara el código para saltar a la rutina cuando
#int_ccp1 //se detecta la interrupción y también generara código para salvar
#int_ccp2 //y restaurar el estado de la maquina.
#int_ssp //La bandera de interrupción será limpiada por el compilador
#int_psp //Previo a su uso, se deben habilitar las interrupciones con la
#int_tbe //funcion ENABLE_INTERRUPT.
#int_rda
#int_comp
#int_adof //Interrupción sobreflujo a/d 14000.
#int_12c //14000 i2c.
#int_button //14000 push button.
#int_lcd //92x LCD.
#int_ad //Ejemplo.

Armando Mora Campos 28


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

adc_handler() {
adc_active = FALSE;
}

#priority //Directiva para establecer la prioridad de las interrupciones.


//La de mayor prioridad es primero.
#priority rtcc,rb //Ejemplo.

#int_global //Directiva para que la siguiente función listada reemplace el


//manejador de interrupciones del compilador. Normalmente no
//es requerida y se debe utilizar con mucho cuidado.

Armando Mora Campos 29


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

8. DIRECTIVAS MISCELANEAS.

8.1 Insertando código ensamblador en un programa en C.


#asm //Sintaxis.
“codigo en ensamblador”
.
#endasm
//Ejemplo:
int find_parity (int data) 
int count;
#asm
movlw 8
movwf count
loop:
xorwf data,w
rrf data,f
decfsz count,f
goto loop
movwf _return_ //_return_ es una variable predefinida para asignar un
#endasm //valor de retorno a una función en ensamblador.

8.2 Definición de constantes tipo bit y byte.


#byte id = x //Directiva para crear un identificador “id” que puede ser usado como la
//dirección de un dato int (un byte). El “id” referenciara un objeto
//localizado en dir x.
#byte a_port = 5 //Ejemplo.

#bit id = x . y //Directiva para crear un identificador “id” que puede ser usado como la
//dirección de un dato tipo short int (un bit). El “id” referenciara una
//localidad de memoria x con el bit de offset y.
#bit time_out = 3.4 //Ejemplo.

8.3 Directivas auxiliares:


#case //Directiva para que el compilador sea sensible a mayúsculas y minúscu-
//las. Por default, es insensible.

__date__ //Directiva para tomar de la PC la fecha en el momento de compilación

Armando Mora Campos 30


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//con el formato “01-OCT-96”


#define string id //Directiva para reemplazar el “id” por el string.
#define BITS 8 //Ejemplo.

#device chip //Directiva para indicar al compilador el chip utilizado. Para ver una lista
//de los dispositivos soportados, correr en DOS el archivo PICCHIPS.
#device PIC16C84 //Ejemplo.

#fuses options //Directiva para establecer la configuracion de los fusibles.


//Opciones: LP, XT, HS, RC, WDT, NOWDT, PROTECT,
//NOPROTECT, PROTECT_50%, PROTECT_75%, PUT, NOPUT,
//BROWNOUT, NOBROUNOUT, PAR, SWAP.
#fuses RC, NOWDT, PROTECT, PUT //Ejemplo: Configuración por default.

#id word //Directiva para especificar el “id” que se programara en el chip.


#id 0x1234 //Ejemplos.
#id “serial.num”
#id CHECKSUM

#include <filename> //Directiva para utilizar el texto del archivo indicado.


#include <pic16c54.h> //Ejemplo.

#inline //Directiva para compilar el procedimiento inmediato siguiente INLINE


//Es equivalente al uso de macros. Si no se coloca (y tampoco se usa la
//directiva SEPARATE) el conpilador decide si lo hace o no INLINE.
#inline //Ejemplo.
swapbyte(int &a, int &b) 
int t;
t = a;
a = b;
b = t;

#pragma cmd //Directiva utilizada para que otras directivas mantengan compatibilidad
//entre diferentes compiladores C.
#pragma inline //Ejemplo.

#rom dir = {data0, data1,....} //Directiva para insertar datos en el archivo.hex.


#rom 0x2100 = {1,2,3,4,5,6,7,8} //Ejemplo de uso, insertando datos en la EEPROM
//del PIC17C84.
#separate //Directiva para compilar el procedimiento siguiente SEPARATE
//(similar al manejo de subrutinas). Asi se previene que el compilador
//no lo realice como un procedimiento INLINE.

#zero_ram //Directiva para inicializar a cero todos los registros internos.

Armando Mora Campos 31


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

9. SISTEMA OPERATIVO EN TIEMPO REAL.


Este compilador C incluye un RTOS cooperativo multitarea, que permite ejecutar tareas
programadas en intervalos especificos de tiempo sin necesidad de interrupciones. Su operación
está apoyada por la función rtos_run() la cual actua como un despachador de tareas.

Cuando una tarea se gestiona para ejecutarse, la función rtos_run() cede el control del
procesador a esa tarea. Y cuando esta tarea termina su ejecución o no necesita al procesador
por el momento, el control del procesador regresa al despachador, el cual pasa el control del
procesador a la siguiente tarea que esta programada para correr en el tiempo apropiado.

El RTOS también incluye la función rtos_yield(), que se utiliza en cada tarea para evitar su
ejecución de forma permanente, en perjuicio de las otras tareas que se quedarian sin operar.

9.1 Directivas del RTOS.


#use rtos(options)

Directiva utilizada para especificar al compilador el uso del RTOS así como sus atributos de
operación, como el temporizador a utilizar, el tiempo del ciclo menor y la generación de
estadísticas. Para la ejecución de todas las funciones del RTOS, se requieren la declaración
previa de esta directiva.

Opciones:

Las opciones son separadas por comas y pueden ser:

a) timer=x. Especificación del temporizador utilizado por el RTOS, donde x es de 0 a 4.


b) minor_cycle=time. Máximo tiempo que tarda en ejecutarse la tarea de mayor duración, en
s, ms, us o ns. La tasa de ejecución de cada tarea debe ser un múltiplo de este tiempo. Si no
se especifica, el compilador lo calcula automáticamente.
c) statistics. Opción para que el compilador haga un seguimiento de la información del tiempo
mínimo, máximo y total utilizado por cada tarea.

El parámetro minor_cycle equivale al concepto de clock tick de otros RTOS. Este puede ser
visto como el heartbeat del sistema. Su valor permite al RTOS retardar las tareas por un
numero entero de clock ticks y definir tiempos fuera en forma similar cuando las tareas estan
esperando que ocurran ciertos eventos. Mientras más rápido es el clock tick, mayor es la
sobrecarga impuesta al sistema.

Armando Mora Campos 32


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

#task(options)

Esta directiva le indica al compilador que la siguiente función es una tarea. Cada tarea se
especifica como una función que no tiene parámetros ni valor de retorno. Una tarea RTOS no
puede ser llamada directamente como se hace con una función normal.

Opciones:

a) rate=time. Especificación de que tan a menudo debe ser ejecutada la tarea indicada, en
unidades de s, ms, us y ns. El tiempo debe ser un múltiplo de la opción minor_cycle de la
directiva #use_rtos.
b) max=time. Pronostico del tiempo máximo de ejecución de la tarea, en s, ms, us o ns. Debe
ser igual o menor a la opción minor_cycle de la directiva #use_rtos. Esta opción no necesita
ser especificada.
c) queus=bytes. Especifica el número de bytes de memoria RAM que se asignan a esta tarea
para recibir los mensajes de entrada de otras tareas o funciones. Su valor por defecto es 0.

Ejemplo:

#include <16F887.h>
#use delay(clock=4000000)

// This tells the compiler that the rtos functionality will be needed, that
// timer0 will be used as the timing device, and that the minor cycle (tick) for
// all tasks will be 10 milisecond

#use rtos(timer=0,minor_cycle=10ms)

#use fast_io(B)
#byte portB = 6
#bit RED = portB.5
#bit BLUE = portB.6
#bit YELLOW = portB.7

// Each function that is to be an operating system task must have the #task
// preprocessor directive located above it.
// In this case, the task will run every 30 ms, 40 ms and 50 ms, its maximum
// time to run must be less than or equal to the minor cycle, and there is no
// need for a queue at this point, so no memory will be reserved.

#task(rate=30ms,max=10ms)
void The_first_rtos_task ( );

#task(rate=40ms,max=8ms)
void The_second_rtos_task ( );

Armando Mora Campos 33


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

#task(rate=50ms,max=6ms)
void The_third_rtos_task ( );

void The_first_rtos_task ( ) {
int i;
for(i=0;i<3;i++){
RED=0;
delay_ms(3);
RED=1;
}
//rtos_yield( );
}

void The_second_rtos_task ( ) {
int i;
for(i=0;i<4;i++){
BLUE=1;
delay_ms(2);
BLUE=0;
}
//rtos_yield( );
}

void The_third_rtos_task ( ) {
int i;
for(i=0;i<5;i++){
YELLOW=1;
delay_ms(1);
YELLOW=0;
}
//rtos_yield( );
}

// Main is still the entry point for the program

void main ( ) {

portB = 0x00;
set_tris_B(0B00011111);

// rtos_run begins the loop which will call the task functions above at the schedualed time

rtos_run();
}

Armando Mora Campos 34


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

9.2 Funciones del RTOS.


rtos_run();

Funcion que inicia, habilita y controla la operación de todas las tareas del RTOS, para que
estas se ejecuten a la tasa asignada. Solo retorna cuando se llama a la función rtos_terminate().

rtos_terminate();

Esta función termina la ejecución de todas las tareas del RTOS y retorna la operación al
programa original en la siguiente línea después de la llamada a rtos_run(), de la cual opera
como su retorno.

Ejemplo:

#include <16F887.h>
#use delay(clock=4000000)
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
#use rtos(timer=0,minor_cycle=50ms)

#use fast_io(B)
#byte portB = 6

#bit RED = portB.5


#bit BLUE = portB.6
#bit YELLOW= portB.7

// A counter will be kept


int8 counter;

#task(rate=100ms,max=10ms)
void The_first_rtos_task ( )
{
RED = 1;
delay_ms(5);
RED = 0;

// If the counter has reached the desired value, the rtos will terminate
if(++counter==5)
rtos_terminate ( );
//rtos_yield ( );
}

#task(rate=100ms,max=25ms)

Armando Mora Campos 35


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

void The_second_rtos_task ( )
{
int8 i;
for(i=0;i<2;i++){
BLUE=1;
delay_ms(5);
BLUE=0;
delay_ms(5);
}
//rtos_yield ( );
}

#task(rate=100ms,max=35ms)
void The_third_rtos_task ( )
{
int8 i;
for(i=0;i<3;i++){
YELLOW=1;
delay_ms(5);
YELLOW=0;
delay_ms(5);
}
//rtos_yield ( );
}

void main ( )
{
// Main is the best place to initialize resources the rtos is dependent upon
portB = 0x00;
set_tris_B(0B00011111);
counter = 0;
rtos_run ( );
// Once the rtos_terminate function has been called, rtos_run will return
// program control back to main
printf("RTOS has been terminated\n\r");
}

rtos_enable(task);

Función que habilita la tarea indicada para su ejecución a la tasa especificada. Todas las tareas
son habilitadas por defecto en la llamada a la función rtos_run().

Armando Mora Campos 36


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

rtos_disable(task):

Esta función deshabilita la tarea indicada, lo que causa que no se ejecute hasta que sea
habilitada por rtos_enable().

Ejemplo:

#include <16F887.h>
#use delay(clock=4000000)
#use rtos(timer=0,minor_cycle=50ms)

#use fast_io(B)
#byte portB = 6
#bit RED = portB.5
#bit BLUE = portB.6
#bit YELLOW= portB.7

int8 counter;

// Now that task names will be passed as parameters, it is best to declare function
//prototypes so that there are no undefined identifier errors from the compiler

#task(rate=100ms,max=10ms)
void The_first_rtos_task ( );

#task(rate=200ms,max=40ms)
void The_second_rtos_task ( );

#task(rate=300ms,max=50ms)
void The_third_rtos_task ( );

void The_first_rtos_task ( ) {
RED = 1;
delay_ms(5);
RED = 0;
if(counter==3)
{
// To disable a task, simply pass the task name into the rtos_disable function
rtos_disable(The_third_rtos_task);
}
//rtos_yield ( );
}

void The_second_rtos_task ( ) {
int8 i;

Armando Mora Campos 37


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

for(i=0;i<2;i++){
BLUE=1;
delay_ms(5);
BLUE=0;
delay_ms(5);
}
if(++counter==10) {
counter=0;
// Enabling tasks is similar to disabling them
rtos_enable(The_third_rtos_task);
}
//rtos_yield ( );
}

void The_third_rtos_task ( ) {
int8 i;
for(i=0;i<3;i++){
YELLOW=1;
delay_ms(5);
YELLOW=0;
delay_ms(5);
}
//rtos_yield ( );
}

void main ( ) {
portB = 0x00;
set_tris_B(0B00011111);
counter = 0;
rtos_run ( );
}

rtos_msg_send(task, byte);

Función que envia un byte de datos a la tarea especificada. El dato es colocado en la cola de
recepción de mensajes de la tarea destino.

rtos_msg_poll();

Función que retorna el número de bytes que existen en la cola de mensajes de la tarea. Solo
puede ser usada dentro de una tarea.

Armando Mora Campos 38


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

rtos_msg_read();

Función que lee el primer byte recibido en la cola de mensajes de la tarea. Debe utilizarse en
conjunto con la función rtos_msg_poll() para que no se quede esperando por la llegada de un
mensaje. Solo puede ser usada dentro de una tarea.

Ejemplo:

#include <16F887.h>
#use delay(clock=4000000)
#use rtos(timer=0,minor_cycle=50ms)

#use fast_io(B)
#byte portB = 6
#bit RED = portB.5
#bit BLUE = portB.6

int8 count_red, count_blue;

// Each task will now be given a two byte queue


#task(rate=200ms,max=50ms,queue=2)
void The_first_rtos_task ( );

#task(rate=100ms,max=50ms,queue=2)
void The_second_rtos_task ( );

void The_first_rtos_task ( ) {
int8 i;
// The function rtos_msg_poll will return the number of messages in the
// current tasks queue.
// Always make sure to check that their is a message or else the read
// function will hang
if(rtos_msg_poll ( )>0){
// The function rtos_msg_read, reads the first value in the queue
count_red = rtos_msg_read ( );
// the function rtos_msg_send, sends the value given as the
// second parameter to the function given as the first
count_blue++;
rtos_msg_send(The_second_rtos_task,count_blue);
}
for(i=0;i<count_red;i++){
RED=1;
delay_ms(2);
RED=0;
delay_ms(2);

Armando Mora Campos 39


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

}
//rtos_yield ( );
}

void The_second_rtos_task ( ) {
int8 j;
if(rtos_msg_poll ( )>0){
count_blue = rtos_msg_read ( );
count_red++;
}
rtos_msg_send(The_first_rtos_task,count_red);
for(j=0;j<count_blue;j++){
BLUE=1;
delay_ms(2);
BLUE=0;
delay_ms(2);
}
//rtos_yield ( );
}

void main ( ) {
portB = 0x00;
set_tris_B(0B10011111);
count_red=0;
count_blue=0;
rtos_run();
}

rtos_signal(sem);

Función que incrementa un semáforo para indicar a las tareas que el recurso compartido que
estan esperando esta disponible para su uso. Puede ser usada solo dentro de una tarea.

rtos_wait();

Funcion para esperar por la disponibilidad del recurso asociado con el semáforo (cuando la
variable del semáforo es mayor a cero). Mientras espera, permite la ejecución de otras tareas.
Cuando dispone del recurso, decrementa la variable del semáforo para indicar que está
utilizando el recurso (y si la variable se decrementa a cero, indicar que por lo pronto el recurso
no está disponible) y la tarea que la llamó continua su ejecución. Solo puede ser usada dentro
de una tarea.

Armando Mora Campos 40


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

Ejemplo:

#include <16F887.h>
#use delay(clock=4000000)
#use rtos(timer=0,minor_cycle=20ms)

#use fast_io(B)
#byte portB = 6
#bit RED = portB.5

// A semaphore is simply a shared system resource


// in the case of this example, the semaphore will be the red LED
int8 sem;

#task(rate=100ms,max=20ms)
void The_first_rtos_task ( );

#task(rate=80ms,max=10ms)
void The_second_rtos_task ( );

void The_first_rtos_task ( ) {
int i;
// this will decrement the semaphore variable to zero which signals
// that no more user may use the resource
rtos_wait(sem);
for(i=0;i<5;i++){
RED = 0;
delay_ms(2);
RED = 1;
delay_ms(2);
RED = 0;
}
// this will increment the semaphore variable from zero which then signals
// that the resource is available for use
rtos_signal(sem);
//rtos_yield ( );
}

void The_second_rtos_task ( ) {
int i;
rtos_wait(sem);
for(i=0;i<3;i++){
RED = 1;
delay_ms(1);
RED = 0;

Armando Mora Campos 41


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

delay_ms(1);
RED = 1;
}
rtos_signal(sem);
//rtos_yield ( );
}

void main ( ) {

portB = 0x00;
set_tris_B(0B11011111);

// sem is initialized to the number of users allowed by the resource


// in the case of the LED and most other resources that limit is one
sem=1;
rtos_run();
}

rtos_yield();

Funcion que detiene la ejecución de la tarea que la llama para que el control del programa
retorne a la función rtos_run(). Al volverse a ejecutar la tarea, esta inicia en la línea de código
después de la llamada a rtos_yield(). “Todas las tareas deben incluir esta función cuando
terminan”(¿?). Puede ser usada solo dentro de una tarea.

Ejemplo:

#include <16F887.h>
#use delay(clock=4000000)
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
#use rtos(timer=1,minor_cycle=100ms)

#task(rate=1000ms,max=100ms,queue=2)
void The_first_rtos_task ( );

#task(rate=500ms,max=100ms,queue=2)
void The_second_rtos_task ( );

void The_first_rtos_task ( ) {
int count=0;
// rtos_yield allows the user to break out of a task at a given point
// and return to the same point when the task comes back into context
while(TRUE){
count++;

Armando Mora Campos 42


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

rtos_msg_send(The_second_rtos_task,count);
rtos_yield ( );
}
//rtos_yield ( );
}

void The_second_rtos_task ( ) {
if(rtos_msg_poll( ))
{
printf("count is :%i\n\r",rtos_msg_read ( ));
}
//rtos_yield ( );
}

void main ( ) {
rtos_run();
}

rtos_await(expre);

Función que espera que la expresión lógica evaluada sea verdadera antes de continuar con la
ejecución del resto del código de la tarea. Esta función permite la ejecución de otras tareas
mientras espera que la expresión sea verdadera. Solo puede ser usada dentro de una tarea.

Ejemplo:

#include <16F887.h>
#use delay(clock=4000000)
#use rtos(timer=0,minor_cycle=20us)

#use fast_io(B)
#byte portB = 6
#bit RED = portB.5
#bit GREEN = portB.4

int8 count;

#task(rate=60us)
void The_first_rtos_task ( );

#task(rate=100us)
void The_second_rtos_task ( );

void The_first_rtos_task ( ) {

Armando Mora Campos 43


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

// rtos_await simply waits for the given expression to be true


// if it is not true, it acts like an rtos_yield and passes the system
// to the next task
rtos_await(count==15);
GREEN = 0; delay_us(8); GREEN = 1;
count=0;
//rtos_yield();
}

void The_second_rtos_task ( ) {
RED=0; delay_us(10); RED=1;
count++;
//rtos_yield();
}

void main ( ) {
portB = 0;
set_tris_B(0b11001111);
count=0;
rtos_run();
}

rtos_overrun(task)

Función que retorna verdadero si la tarea indicada sobrepasa su tiempo de ejecución. Task es
un parámetro opcional, ya que si no es especificado, la función retornará verdadero cuando
cualquier tarea sobrepase su tiempo de ejecución permitido.

rtos_stats(task, stat);

Función que retorna las estadisticas de la tarea especificada. Las estadisticas de salida se
definen por los siguientes parámetros:

rtos_min_time - Tiempo minimo de uso del procesador para una ejecución de la tarea..
rtos_max_time - Tiempo máximo de uso del procesador para una ejecución de la tarea.
Rtos_total_time - Tiempo total de uso del procesador por la tarea indicada.ejecución

Retorna un número I32 que representa los s de la estadistica y tarea indicadas.

Ejemplo:

#include <16F887.h>
#use delay(clock=4000000)

Armando Mora Campos 44


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
#use rtos(timer=1,minor_cycle=100ms,statistics)

// This structure must be defined in order to retrieve the statistical


// information
struct rtos_stats {
int32 task_total_ticks; // number of ticks the task has used
int16 task_min_ticks; // the minimum number of ticks used
int16 task_max_ticks; // the maximum number of ticks used
int16 hns_per_tick; // us = (ticks*hns_per_tic)/10
};

#task(rate=1000ms,max=100ms)
void The_first_rtos_task ( );

#task(rate=1000ms,max=100ms)
void The_second_rtos_task ( );

void The_first_rtos_task ( ) {
struct rtos_stats stats;
rtos_stats(The_second_rtos_task,&stats);
printf ( "\n\r" );
printf ( "task_total_ticks : %Lius\n\r" ,
(int32)(stats.task_total_ticks)*stats.hns_per_tick );
printf ( "task_min_ticks : %Lius\n\r" ,
(int32)(stats.task_min_ticks)*stats.hns_per_tick );
printf ( "task_max_ticks : %Lius\n\r" ,
(int32)(stats.task_max_ticks)*stats.hns_per_tick );
printf ("\n\r");
//rtos_yield();
}

void The_second_rtos_task ( ) {
int i, count = 0;

while(TRUE) {
if(rtos_overrun(the_second_rtos_task)) {
printf("The Second Task has Overrun\n\r\n\r");
count=0;
}
else
count++;

for(i=0;i<count;i++)
delay_ms(50);

Armando Mora Campos 45


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//rtos_yield();
}
}

void main ( ) {
rtos_run ( );
}

9.3 RTOS e interrupciones.


Este sistema operativo RTOS permite el manejo normal de interrupciones. Solo es necesario
habilitarlas en la función principal antes de la llamada a la función rtos_run() e incluir la rutina
de servicio a la interrupción correspondiente. Como ejemplo, en la función principal del
siguiente programa y antes de la llamada a la función rtos_run() se habilita la interrupción de
disponibilidad de datos en el receptor RS-232 (int_rda), junto con la habilitación global de
interrupciones (global) y dentro del programa se incluye la ISR correspondiente.

Ejemplo:

Este programa demuestra como crear una línea de comandos básica utilizando interrupciones
del puerto serie, sin tener que parar la operación del RTOS. Este puede ser considerado un
semi-kernel para el RTOS.

Un kernel es la parte de un sistema multitareas responsable de la administración de las tareas


(y por tanto de la administración del tiempo del CPU) y de la comunicación entre tareas. El
servicio fundamental que proporciona el kernel es la conmutación de contexto (conmutación
de tareas).

Cuando un kernel multitarea decide correr una tarea diferente, primero salva el contexto de la
tarea actual (registros del CPU) en su área de almacenamiento de contexto (pila de la tarea
actual). Después restaura el contexto de la nueva tarea de su área de almacenamiento e inicia la
ejecución de su código.

El uso de un kernel de tiempo real generalmente simplifica el diseño de sistemas al permitir


que la aplicación sea dividida en múltiples tareas que el kernel administra. Un kernel permite
un mejor uso del CPU, al proporcionar servicios como administración de semaforos, buzones,
colas y retardos de tiempo.

#include <16F887.h>
#use delay(clock=4000000)
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
#use rtos(timer=1,minor_cycle=100ms)

Armando Mora Campos 46


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

#use fast_io(B)
#byte portB = 6
#bit GREEN = portB.4
#bit RED = portB.5

#include <string.h>

// this character array will be used to take input from the prompt
char input [ 30 ];
// this will hold the current position in the array
int index;
// this will signal to the kernel that input is ready to be processed
int1 input_ready;
// different commands
char en1 [ ] = "enable1";
char en2 [ ] = "enable2";
char dis1 [ ] = "disable1";
char dis2 [ ] = "disable2";

#task(rate=1000ms,max=100ms)
void The_first_rtos_task ( );

#task(rate=1000ms,max=100ms)
void The_second_rtos_task ( );

#task(rate=500ms,max=100ms)
void The_kernal ( );

// serial interrupt
#int_rda
void serial_interrupt ( )
{
if(index<29) {
input [ index ] = getc ( ); // get the value in the serial recieve reg
putc ( input [ index ] ); // display it on the screen
if(input[index]==0x0d){ // if the input was enter
putc('\n');
input [ index ] = '\0'; // add the null character
input_ready=TRUE; // set the input read variable to true
index=0; // and reset the index
}
else if (input[index]==0x08){
if ( index > 1 ) {
putc(' ');
putc(0x08);

Armando Mora Campos 47


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

index-=2;
}
}
index++;
}
else {
putc ( '\n' );
putc ( '\r' );
input [ index ] = '\0';
index = 0;
input_ready = TRUE;
}
}

void The_first_rtos_task ( ) {
RED=0; delay_ms(50); RED=1;
}

void The_second_rtos_task ( ) {
GREEN=0; delay_ms(20); GREEN=1;
}

void The_kernal ( ) {
while ( TRUE ) {
printf ( "INPUT:> " );
while(!input_ready)
rtos_yield ( );

printf ( "%S\n\r%S\n\r", input , en1 );

if ( !strcmp( input , en1 ) )


rtos_enable ( The_first_rtos_task );
else if ( !strcmp( input , en2 ) )
rtos_enable ( The_second_rtos_task );
else if ( !strcmp( input , dis1 ) )
rtos_disable ( The_first_rtos_task );
else if ( !strcmp ( input , dis2 ) )
rtos_disable ( The_second_rtos_task );
else
printf ( "Error: unknown command\n\r" );

input_ready=FALSE;
index=0;
}
}

Armando Mora Campos 48


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

void main ( ) {

portB = 0x00;
set_tris_B(0B11001111);

// initialize input variables


index=0;
input_ready=FALSE;
// initialize interrupts
enable_interrupts(int_rda);
enable_interrupts(global);
rtos_run();
}

Armando Mora Campos 49


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

10. NOTAS Y RECOMENDACIONES PARA EL


COMPILADOR PCM.

10.1 Manejo de puertos paralelos.


Para el manejo de un pin único de un puerto paralelo, se utilizan las funciones input(pin),
output_low(pin), output_high(pin), output_float(pin) y output_bit(pin, value).

Para la operación de todo el puerto, se tiene el siguiente ejemplo:

#byte portb = 0x06;


#define all_out 0x00
#define all_in 0xff

void main() {
int i;
#use fast_io(A)
set_tris_b(all_out);
portb = 0x00; //Puerto B como salida.
for(i = 0; i <= 127; ++i)
portb = i;
set_tris_b(all_in); //Puerto B como entrada.
i = portb;
}

10.2 Uso de variables que definen un bit (short y short int).


Evitar usar variables tipo bit en operaciones aritméticas en combinación con variables tipo
byte, como en el siguiente ejemplo:

int x,y;
short int bx, by;
x = 5;
y = 10;
bx = 0;
by = 1;
x = (x+by)-bx*by+(y-by);

Estas expresiones pueden ser escritas más eficientemente usando sentencias de control IF para
probar las variables tipo bit, por ejemplo:

Armando Mora Campos 50


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

if (by || (bx && bz) || !bw)


bz = 0;

Recordar el uso de ! y no de ˜, de && y no de &, de || y no de | con bits. Tambien tomar en


cuenta que la función input(...) y algunas otras regresan un bit. Por ejemplo:

if ( !input(PIN_B0) ) y no if ( input(PIN_B0) == 0)

Ambas expresiones funcionaran, pero la primera se realizara con operaciones de un bit y la


segunda primero convertirá a byte para hacer la comparación con cero.

10.3 Lectura y escritura de registros internos.


Un registro de hardware puede ser mapeado en una variable C para realizar lecturas o
escrituras directas. Para manejar el registro completo observar el siguiente ejemplo:

#byte timer0 = 0x01


.
.
timer0 = 128 //Hacer timer0 igual a 128.
While (timer0 != 200); //Esperar que timer0 alcance el valor 200.

Los bits de un registro también pueden ser mapeados:

#bit t0if = 0x0b.1


.
.
while (!t0if); //Esperar por la interrupción del timer.

Los registros pueden ser direccionados indirectamente:

printf (“enter address:”);


a = gethex();
printf (“\r\n value is %x\r\n”, *a);

El compilador tiene un gran conjunto de funciones correspondientes a las funciones de C. En


lo posible, lo mejor es usar las funciones internas en vez de escribir directamente a registros.
La dirección de los registros cambia entre diferentes microcontroladores y algunas operaciones
con registros necesitan un algoritmo especifico para cambiar su valor. El compilador también
toma en cuenta los errores conocidos del chip en el desarrollo de funciones internas. Por
ejemplo, es mejor hacer set_tris_A(0) que *0x85 = 0.

Armando Mora Campos 51


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

10.4 Definición de funciones: ¿inline o separate?


El error OUT OF ROM puede ocurrir cuando ya no se tiene suficiente espacio de memoria
para las funciones del programa.

Normalmente el compilador define de manera automática si la función será “inline” o


“separate”. Las funciones INLINE son establecidas como macros, por lo que no utilizan la pila
pero el texto de la función se repite en cada llamada (provocando un alto consumo de
memoria) y las funciones SEPARATE se desarrollan como subrutinas, utilizando un nivel de
la pila, pero el texto no se repite en cada llamada, con un consumo mínimo de memoria.

Si el problema de falta de memoria es por el uso de demasiadas funciones “inline”, se debe


usar la directiva #SEPARATE para forzar la función a que sea separate. Considerar el
siguiente ejemplo, en donde se muestra la estructura en arbol del ultimo programa compilado
en PCM (para llamar este arbol teclear Alt T):

└─TEST.C
└─MAIN ?/614 Ram = 5
├─DELAY_MS 0/19 Ram = 1
├─READ_DATA (Inline) Ram = 5
├─PROCESS_DATA (Inline) Ram = 11
├─OUTPUT_DATA (Inline) Ram = 6
└─PUT_HEX (Inline) Ram = 2
├─PUT_HEX1 0/18 Ram = 2
│ ├─PUTCHAR_9600_52_49 0/30 Ram = 2
│ └─PUTCHAR_9600_52_49 0/30 Ram = 2
└─PUT_HEX1 0/18 Ram = 2
├─PUTCHAR_9600_52_49 0/30 Ram = 2
└─PUTCHAR_9600_52_49 0/30 Ram = 2

Este ejemplo muestra un programa principal con varias funciones INLINE. El consumo de
memoria es de 614 localidades, excesivo para dispositivos con 512 localidades en ROM. El
ensamblador coloca un ? en el numero de segmento de main() ya que este no puede ser
ubicado (la notación es numero_pagina/numero_localidades).

La solución en este ejemplo es hacer que la función PROCESS_DATA sea separate y no


inline, colocando la directiva #separate antes de la declaración de esta función, aunque esto se
puede aplicar a cualquier función que se llame en main(). El resultado es el siguiente:

Armando Mora Campos 52


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

└─TEST.C
└─MAIN 1/406 Ram = 5
├─DELAY_MS 0/19 Ram = 1
├─READ_DATA (Inline) Ram = 5
├─PROCESS_DATA 0/212 Ram = 11
├─OUTPUT_DATA (Inline) Ram = 6
└─PUT_HEX (Inline) Ram = 2
├─PUT_HEX1 0/18 Ram = 2
│ ├─PUTCHAR_9600_52_49 0/30 Ram = 2
│ └─PUTCHAR_9600_52_49 0/30 Ram = 2
└─PUT_HEX1 0/18 Ram = 2
├─PUTCHAR_9600_52_49 0/30 Ram = 2
└─PUTCHAR_9600_52_49 0/30 Ram = 2

10.5 Optimización en el manejo de la memoria RAM.


El compilador trata por todos los medios de optimizar el uso de la RAM. El usuario tambien
puede contribuir a este objetivo, declarando variables locales en funciones que no se activan a
un mismo tiempo y con esto reutilizar las localidades de RAM. A diferencia de las variables
locales, las globales utilizan permanentemente localidades de RAM, por lo que no es posible
su optimización.

La RAM también se utiliza para la evaluación de expresiones cuando estas son complejas, por
lo que una función reserva localidades de memoria para su ejecución, las cuales pueden ser re-
usadas por expresiones dentro de la misma función.

El numero total de localidades de RAM que necesita una función es igual a la suma de los
parametros, las variables locales y el numero de localidades auxiliares que necesita la
expresión mas compleja en la función. La RAM requerida por una función se muestra en el
arbol (Alt T) de la misma, después de la identificación RAM = . La RAM se sigue usando
cuando la función llama a otras funciones, por lo que nueva RAM se debe disponer para esas
otras funciones. Cuando se llega al RETURN de la función, la RAM se libera, para su reuso en
la función actualmente activa.

Las llamadas secuenciales a pequeñas funciones con variables locales es mas eficiente que el
uso de grandes funciones que tienen gran cantidad de variables locales y que siempre estan
activas.

Utilizar lo mas posible el tipo de dato SHORT INT (1 bit) para banderas y otras variables
booleanas. El compilador puede ubicar 8 de estas variables en un solo byte.

También se puede considerar el uso de memoria externa para almacenar datos no muy
utilizados (dispositivos EEPROM y SRAM de 8 bits seriales pueden proporcionar una alta
capacidad de almacenamiento). El compilador incluye ejemplos para el manejo de estos

Armando Mora Campos 53


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

dispositivos; se debe tomar en cuenta los tiempos de acceso y el tipo de almacenamiento


deseado (temporal o semipermanente).

10. 6 Restricciones en llamadas a funciones en interrupciones.


Cuando se utilizan interrupciones, se debe asegurar que se tendrá el suficiente espacio en la
pila. El compilador verifica el numero de localidades de pila utilizados por la función main() y
no permite un sobregiro de la pila.

Las interrupciones y las funciones tipo SEPARATE utilizan una localidad de pila cada una.
Asegurar que el numero máximo de localidades de pila utilizados en un momento dado sea
menor a 9.

El compilador no permite llamadas recursivas a funciones porque el conjunto de instrucciones


RISC no proporciona un medio eficiente para el manejo de la pila como en el lenguaje C
tradicional. Todas las localidades de RAM necesarias para una función son ubicadas en una
dirección específica en tiempo de compilación, de tal forma que la RAM sea reutilizada entre
funciones no activas al mismo tiempo. Esto prohibe la recursión. Por ejemplo la función
main() puede llamar a una función A() y A() puede llamar a B(), pero B() no puede llamar a
main() ni a A() ni a B().

Una interrupción puede llegar en cualquier momento y poseer una situación especial.
Considerar la función de llamada a interrupción ISR() que llama a la función A() en el
momento que también main() está trabajando con A(); esto provoca recursión.

Para prevenir problemas como el anterior, el compilador “protegerá” la llamada de la función


A() desde main() deshabilitando todas las interrupciones antes de llamar a A() y habilitandolas
nuevamente después de retornar de A().

Finalmente, para el manejo de interrupciones, tomar en cuenta las siguientes consideraciones:

a) En el ejemplo anterior, las interrupciones se deshabilitaran en todo el tiempo de ejecución


de A(). Esto incrementa el tiempo que transcurre antes de atender las interrupciones, y será
función de la duración de la función A().

b) Si la función A() cambia las interrupciones utilizando enable/disable_interrupts, este efecto


se perderá al retornar de A(), ya que todo el registro intcon es respaldado antes de entrar en
A() y restaurado al salir. Aun mas, si el bit global GIE es habilitado en A(), el programa
puede ejecutarse incorrectamente.

c) Un programa no debe depender de la deshabilitación de interrupciones del ejemplo anterior.


Posiblemente el compilador no deshabilitara las interrupciones si la función A() no utiliza
variables locales o si no se realizan llamadas a función.

Armando Mora Campos 54


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

d) Las interrupciones pueden ser deshabilitadas como se describió anteriormente debido a


funciones internas del compilador, así como en llamadas a expresiones. Por ejemplo, la
multiplicación invocada por un simple * puede tener este efecto.

10.7 Localización de tablas en memoria ROM.


El compilador tiene soporte para colocar cualquier estructura de datos en la ROM del
dispositivo como elementos constantes de solo lectura.

Ya que las rutas de ROM y RAM estan separadasen los PIC, se tienen algunas restricciones
para el acceso a los datos. Por ejemplo, para colocar un arreglo de bytes de 10 elementos en
ROM:

byte const table = 9, 8, 7, 6, 5, 4, 3, 2, 1, 0;

y para acceder a la tabla:

x = table [i];

x = table [5];

pero no

ptr = 2 table[i]

En este caso, no se puede construir un apuntador a tabla.

Construcciones similares utilizando CONST pueden ser utilizadas con cualquier tipo de dato
incluyendo estructuras, longs y floats.

Armando Mora Campos 55


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

11.DIAGRAMA PARA LOS EJERCICIOS DEL


PIC16F887.
TERMINALES DE TERMINALES DE
SERVICIO: APLICACIÓN:
PIC16F887
+V
11, 32 VDD RA0/AN0/ULPWU/C12IN0- 2 PUERTO A
RA1/AN1/C12IN1- 3 DIR 0x05
2 × 0.1 uF RA2/AN2/VREF-/CVREF//C2IN+ 4 E/S DIGITALES
12, 31 VSS RA3/AN3/VREF+/C1IN+ 5 ENT ANALOGICAS
RA4/T0CKI/C1OUT 6 E/S COMPARADORES
RA5/AN4//SS/C2OUT 7 VOLTAJES REFERENCIA
CLK TIMER 0
13 RA7/OSC1/CLKIN SEL ESCLAVO SPI
ENT WAKE-UP ULP
4 MHz RB0/AN12/INT 33 PUERTO B
14 RA6/OSC2/CLKO RB1/AN10/C12IN3- 34 DIR 0x06
2 Mohm RB2/AN8 35 E/S DIGITALES
2 × 22 pF (opc.)
RB3/AN9/PGM/C12IN2- 36 ENT ANALOGICAS
RB4/AN11 37 INT EXTERNA
RB5/AN13//T1G 38 INT EN CAMBIO
RB6/ICSPCLK 39 ENT COMPARADORES
+V RB7/ICSPDAT 40 PINES PROGRAMACION
ENT TIMER 1 GATE
10 Kohm
1 RE3/MCLR/VPP
0.1 uF RC0/T1OSO/T1CKI 15 PUERTO C
(opcional) RC1/T1OSI/CCP2 16 DIR 0x07
RC2/P1A/CCP1 17 E/S DIGITALES
RC3/SCK/SCL 18 TIMER 1
RC4/SDI/SDA 23 CAPTURA/COMP/PWM 1 Y 2
RC5/SDO 24 EUSART
RC6/TX/CK 25 SPI
RC7/RX/DT 26 I2C
SAL PWM

RD0 19 PUERTO D
RD1 20 DIR 0x08
RD2 21 E/S DIGITALES
RD3 22 SAL PWM
RD4 27
RD5/P1B 28
RD6/P1C 29
RD7/P1D 30

RE0/AN5 8 PUERTO E
RE1/AN6 9 DIR 0x09
RE2/AN7 10 E/S DIGITALES
ENT ANALOGICAS

Armando Mora Campos 56


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

12. ARCHIVO H DEL PIC16F887.


//////// Standard Header file for the PIC16F887 device ////////////////
#device PIC16F887
#nolist
//////// Program memory: 8192x14 Data RAM: 367 Stack: 8
//////// I/O: 36 Analog Pins: 14
//////// Data EEPROM: 256
//////// C Scratch area: 77 ID Location: 2000
//////// Fuses: LP,XT,HS,EC_IO,INTRC_IO,INTRC,RC_IO,RC,NOWDT,WDT,PUT,NOPUT
//////// Fuses: NOMCLR,MCLR,PROTECT,NOPROTECT,CPD,NOCPD,NOBROWNOUT
//////// Fuses: BROWNOUT_SW,BROWNOUT_NOSL,BROWNOUT,NOIESO,IESO,NOFCMEN,FCMEN
//////// Fuses: NOLVP,LVP,DEBUG,NODEBUG,BORV21,BORV40,WRT_50%,WRT,WRT_BOOT
//////// Fuses: NOWRT
////////
////////////////////////////////////////////////////////////////// I/O
// Discrete I/O Functions: SET_TRIS_x(), OUTPUT_x(), INPUT_x(),
// PORT_x_PULLUPS(), INPUT(),
// OUTPUT_LOW(), OUTPUT_HIGH(),
// OUTPUT_FLOAT(), OUTPUT_BIT()
// Constants used to identify pins in the above are:

#define PIN_A0 40
#define PIN_A1 41
#define PIN_A2 42
#define PIN_A3 43
#define PIN_A4 44
#define PIN_A5 45
#define PIN_A6 46
#define PIN_A7 47

#define PIN_B0 48
#define PIN_B1 49
#define PIN_B2 50
#define PIN_B3 51
#define PIN_B4 52
#define PIN_B5 53
#define PIN_B6 54
#define PIN_B7 55

#define PIN_C0 56
#define PIN_C1 57
#define PIN_C2 58
#define PIN_C3 59
#define PIN_C4 60
#define PIN_C5 61
#define PIN_C6 62
#define PIN_C7 63

#define PIN_D0 64
#define PIN_D1 65
#define PIN_D2 66
#define PIN_D3 67
#define PIN_D4 68

Armando Mora Campos 57


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

#define PIN_D5 69
#define PIN_D6 70
#define PIN_D7 71

#define PIN_E0 72
#define PIN_E1 73
#define PIN_E2 74
#define PIN_E3 75

////////////////////////////////////////////////////////////////// Useful defines


#define FALSE 0
#define TRUE 1

#define BYTE int8


#define BOOLEAN int1

#define getc getch


#define fgetc getch
#define getchar getch
#define putc putchar
#define fputc putchar
#define fgets gets
#define fputs puts

////////////////////////////////////////////////////////////////// Control
// Control Functions: RESET_CPU(), SLEEP(), RESTART_CAUSE()
// Constants returned from RESTART_CAUSE() are:
#define WDT_FROM_SLEEP 3
#define WDT_TIMEOUT 11
#define MCLR_FROM_SLEEP 19
#define MCLR_FROM_RUN 27
#define NORMAL_POWER_UP 25
#define BROWNOUT_RESTART 26

////////////////////////////////////////////////////////////////// Timer 0
// Timer 0 (AKA RTCC)Functions: SETUP_COUNTERS() or SETUP_TIMER_0(),
// SET_TIMER0() or SET_RTCC(),
// GET_TIMER0() or GET_RTCC()
// Constants used for SETUP_TIMER_0() are:
#define T0_INTERNAL 0
#define T0_EXT_L_TO_H 32
#define T0_EXT_H_TO_L 48

#define T0_DIV_1 8
#define T0_DIV_2 0
#define T0_DIV_4 1
#define T0_DIV_8 2
#define T0_DIV_16 3
#define T0_DIV_32 4
#define T0_DIV_64 5
#define T0_DIV_128 6
#define T0_DIV_256 7

Armando Mora Campos 58


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

#define T0_8_BIT 0

#define RTCC_INTERNAL 0 // The following are provided for compatibility


#define RTCC_EXT_L_TO_H 32 // with older compiler versions
#define RTCC_EXT_H_TO_L 48
#define RTCC_DIV_1 8
#define RTCC_DIV_2 0
#define RTCC_DIV_4 1
#define RTCC_DIV_8 2
#define RTCC_DIV_16 3
#define RTCC_DIV_32 4
#define RTCC_DIV_64 5
#define RTCC_DIV_128 6
#define RTCC_DIV_256 7
#define RTCC_8_BIT 0

// Constants used for SETUP_COUNTERS() are the above


// constants for the 1st param and the following for
// the 2nd param:

////////////////////////////////////////////////////////////////// WDT
// Watch Dog Timer Functions: SETUP_WDT() or SETUP_COUNTERS() (see above)
// RESTART_WDT()
// WDT base is 18ms
//

#define WDT_18MS 8
#define WDT_36MS 9
#define WDT_72MS 10
#define WDT_144MS 11
#define WDT_288MS 12
#define WDT_576MS 13
#define WDT_1152MS 14
#define WDT_2304MS 15

// One of the following may be OR'ed in with the above:

#define WDT_ON 0x4100


#define WDT_OFF 0
#define WDT_DIV_16 0x100
#define WDT_DIV_8 0x300
#define WDT_DIV_4 0x500
#define WDT_DIV_2 0x700
#define WDT_TIMES_1 0x900 // Default
#define WDT_TIMES_2 0xB00
#define WDT_TIMES_4 0xD00
#define WDT_TIMES_8 0xF00
#define WDT_TIMES_16 0x1100
#define WDT_TIMES_32 0x1300
#define WDT_TIMES_64 0x1500
#define WDT_TIMES_128 0x1700

////////////////////////////////////////////////////////////////// Timer 1
// Timer 1 Functions: SETUP_TIMER_1, GET_TIMER1, SET_TIMER1
// Constants used for SETUP_TIMER_1() are:

Armando Mora Campos 59


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

// (or (via |) together constants from each group)


#define T1_DISABLED 0
#define T1_INTERNAL 5
#define T1_EXTERNAL 7
#define T1_EXTERNAL_SYNC 3

#define T1_CLK_OUT 8

#define T1_DIV_BY_1 0
#define T1_DIV_BY_2 0x10
#define T1_DIV_BY_4 0x20
#define T1_DIV_BY_8 0x30

#define T1_GATE 0x40


#define T1_GATE_INVERTED 0xC0

////////////////////////////////////////////////////////////////// Timer 2
// Timer 2 Functions: SETUP_TIMER_2, GET_TIMER2, SET_TIMER2
// Constants used for SETUP_TIMER_2() are:
#define T2_DISABLED 0
#define T2_DIV_BY_1 4
#define T2_DIV_BY_4 5
#define T2_DIV_BY_16 6

////////////////////////////////////////////////////////////////// CCP
// CCP Functions: SETUP_CCPx, SET_PWMx_DUTY
// CCP Variables: CCP_x, CCP_x_LOW, CCP_x_HIGH
// Constants used for SETUP_CCPx() are:
#define CCP_OFF 0
#define CCP_CAPTURE_FE 4
#define CCP_CAPTURE_RE 5
#define CCP_CAPTURE_DIV_4 6
#define CCP_CAPTURE_DIV_16 7
#define CCP_COMPARE_SET_ON_MATCH 8
#define CCP_COMPARE_CLR_ON_MATCH 9
#define CCP_COMPARE_INT 0xA
#define CCP_COMPARE_RESET_TIMER 0xB
#define CCP_PWM 0xC
#define CCP_PWM_PLUS_1 0x1c
#define CCP_PWM_PLUS_2 0x2c
#define CCP_PWM_PLUS_3 0x3c
#word CCP_1 = getenv("SFR:CCPR1L")
#byte CCP_1_LOW = getenv("SFR:CCPR1L")
#byte CCP_1_HIGH = getenv("SFR:CCPR1H")
// The following should be used with the ECCP unit only (or these in)
#define CCP_PWM_H_H 0x0c
#define CCP_PWM_H_L 0x0d
#define CCP_PWM_L_H 0x0e
#define CCP_PWM_L_L 0x0f

#define CCP_PWM_FULL_BRIDGE 0x40


#define CCP_PWM_FULL_BRIDGE_REV 0xC0
#define CCP_PWM_HALF_BRIDGE 0x80

#define CCP_SHUTDOWN_ON_COMP1 0x100000

Armando Mora Campos 60


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

#define CCP_SHUTDOWN_ON_COMP2 0x200000


#define CCP_SHUTDOWN_ON_COMP 0x300000
#define CCP_SHUTDOWN_ON_INT0 0x400000
#define CCP_SHUTDOWN_ON_COMP1_INT0 0x500000
#define CCP_SHUTDOWN_ON_COMP2_INT0 0x600000
#define CCP_SHUTDOWN_ON_COMP_INT0 0x700000

#define CCP_SHUTDOWN_AC_L 0x000000


#define CCP_SHUTDOWN_AC_H 0x040000
#define CCP_SHUTDOWN_AC_F 0x080000

#define CCP_SHUTDOWN_BD_L 0x000000


#define CCP_SHUTDOWN_BD_H 0x010000
#define CCP_SHUTDOWN_BD_F 0x020000

#define CCP_SHUTDOWN_RESTART 0x80000000

#define CCP_PULSE_STEERING_A 0x01000000


#define CCP_PULSE_STEERING_B 0x02000000
#define CCP_PULSE_STEERING_C 0x04000000
#define CCP_PULSE_STEERING_D 0x08000000
#define CCP_PULSE_STEERING_SYNC 0x10000000

#word CCP_2 = getenv("SFR:CCPR2L")


#byte CCP_2_LOW = getenv("SFR:CCPR2L")
#byte CCP_2_HIGH = getenv("SFR:CCPR2H")
////////////////////////////////////////////////////////////////// SPI
// SPI Functions: SETUP_SPI, SPI_WRITE, SPI_READ, SPI_DATA_IN
// Constants used in SETUP_SPI() are:
#define SPI_MASTER 0x20
#define SPI_SLAVE 0x24
#define SPI_SCK_IDLE_HIGH 0x10
#define SPI_SCK_IDLE_LOW 0x00
#define SPI_CLK_DIV_4 0x00
#define SPI_CLK_DIV_16 0x01
#define SPI_CLK_DIV_64 0x02
#define SPI_CLK_T2 0x03
#define SPI_SS_DISABLED 0x01

#define SPI_XMIT_L_TO_H 0x4000


#define SPI_XMIT_H_TO_L 0x0000

#define SPI_SAMPLE_AT_MIDDLE 0x0000


#define SPI_SAMPLE_AT_END 0x8000

//The following are provided for compatibility


#define SPI_L_TO_H SPI_SCK_IDLE_LOW
#define SPI_H_TO_L SPI_SCK_IDLE_HIGH

////////////////////////////////////////////////////////////////// UART
// Constants used in setup_uart() are:
// FALSE - Turn UART off
// TRUE - Turn UART on
#define UART_ADDRESS 2
#define UART_DATA 4

Armando Mora Campos 61


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

#define UART_AUTODETECT 8
#define UART_AUTODETECT_NOWAIT 9
#define UART_WAKEUP_ON_RDA 10
#define UART_SEND_BREAK 13
////////////////////////////////////////////////////////////////// COMP
// Comparator Variables: C1OUT, C2OUT
// Constants used in setup_comparator() are:
//

#define NC_NC_NC_NC 0x00


#define NC_NC 0x00

//Pick one constant for COMP1


#define CP1_A0_A3 0x00090080
#define CP1_A1_A3 0x000A0081
#define CP1_B3_A3 0x00880082
#define CP1_B1_A3 0x00280083
#define CP1_A0_VREF 0x00010084
#define CP1_A1_VREF 0x00020085
#define CP1_B3_VREF 0x00800086
#define CP1_B1_VREF 0x00200087
//Optionally OR with one or both of the following
#define CP1_OUT_ON_A4 0x00000020
#define CP1_INVERT 0x00000010
#define CP1_ABSOLUTE_VREF 0x20000000

//OR with one constant for COMP2


#define CP2_A0_A2 0x00058000
#define CP2_A1_A2 0x00068100
#define CP2_B3_A2 0x00848200
#define CP2_B1_A2 0x00248300
#define CP2_A0_VREF 0x00018400
#define CP2_A1_VREF 0x00028500
#define CP2_B3_VREF 0x00808600
#define CP2_B1_VREF 0x00208700
//Optionally OR with one or both of the following
#define CP2_OUT_ON_A5 0x00002000
#define CP2_INVERT 0x00001000
#define CP2_ABSOLUTE_VREF 0x10000000

//Optionally OR with one or both of the following


#define CP2_T1_SYNC 0x01000000
#define CP2_T1_GATE 0x02000000

#bit C1OUT = 0x107.6


#bit C2OUT = 0x108.6

////////////////////////////////////////////////////////////////// VREF
// Constants used in setup_vref() are:
//
#define VREF_LOW 0xa0
#define VREF_HIGH 0x80
// Or (with |) the above with a number 0-15

Armando Mora Campos 62


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

////////////////////////////////////////////////////////////////// INTERNAL RC
// Constants used in setup_oscillator() are:
#define OSC_31KHZ 1
#define OSC_125KHZ 0x11
#define OSC_250KHZ 0x21
#define OSC_500KHZ 0x31
#define OSC_1MHZ 0x41
#define OSC_2MHZ 0x51
#define OSC_4MHZ 0x61
#define OSC_8MHZ 0x71
#define OSC_INTRC 1
#define OSC_NORMAL 0
// Result may be (ignore all other bits)
#define OSC_STATE_STABLE 4
#define OSC_31KHZ_STABLE 2

////////////////////////////////////////////////////////////////// ADC
// ADC Functions: SETUP_ADC(), SETUP_ADC_PORTS() (aka SETUP_PORT_A),
// SET_ADC_CHANNEL(), READ_ADC()
// Constants used for SETUP_ADC() are:
#define ADC_OFF 0 // ADC Off
#define ADC_CLOCK_DIV_2 0x100
#define ADC_CLOCK_DIV_8 0x40
#define ADC_CLOCK_DIV_32 0x80
#define ADC_CLOCK_INTERNAL 0xc0 // Internal 2-6us

// Constants used in SETUP_ADC_PORTS() are:


// First argument:
// OR together desired pins
#define sAN0 1 //| A0
#define sAN1 2 //| A1
#define sAN2 4 //| A2
#define sAN3 8 //| A3
#define sAN4 16 //| A5
#define sAN5 32 //| E0
#define sAN6 64 //| E1
#define sAN7 128 //| E2
#define sAN8 0x10000 //| B2
#define sAN9 0x20000 //| B3
#define sAN10 0x40000 //| B1
#define sAN11 0x80000 //| B4
#define sAN12 0x100000 //| B0
#define sAN13 0x200000 //| B5
#define NO_ANALOGS 0 // None
#define ALL_ANALOG 0x1F00FF // A0 A1 A2 A3 A5 E0 E1 E2 B0 B1 B2 B3 B4 B5

// Optional Second argument:


#define VSS_VDD 0x0000 //| Range 0-Vdd
#define VSS_VREF 0x1000 //| Range 0-Vref
#define VREF_VREF 0x3000 //| Range Vref-Vref
#define VREF_VDD 0x2000 //| Range Vref-Vdd

Armando Mora Campos 63


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

// Constants used in READ_ADC() are:


#define ADC_START_AND_READ 7 // This is the default if nothing is specified
#define ADC_START_ONLY 1
#define ADC_READ_ONLY 6

////////////////////////////////////////////////////////////////// INT
// Interrupt Functions: ENABLE_INTERRUPTS(), DISABLE_INTERRUPTS(),
// CLEAR_INTERRUPT(), INTERRUPT_ACTIVE(),
// EXT_INT_EDGE()
//
// Constants used in EXT_INT_EDGE() are:
#define L_TO_H 0x40
#define H_TO_L 0
// Constants used in ENABLE/DISABLE_INTERRUPTS() are:
#define GLOBAL 0x0BC0
#define PERIPH 0x0B40
#define INT_RTCC 0x000B20
#define INT_RB 0x01FF0B08
#define INT_EXT_L2H 0x50000B10
#define INT_EXT_H2L 0x60000B10
#define INT_EXT 0x000B10
#define INT_AD 0x008C40
#define INT_TBE 0x008C10
#define INT_RDA 0x008C20
#define INT_TIMER1 0x008C01
#define INT_TIMER2 0x008C02
#define INT_CCP1 0x008C04
#define INT_CCP2 0x008D01
#define INT_SSP 0x008C08
#define INT_BUSCOL 0x008D08
#define INT_EEPROM 0x008D10
#define INT_TIMER0 0x000B20
#define INT_OSC_FAIL 0x008D80
#define INT_COMP 0x008D20
#define INT_COMP2 0x008D40
#define INT_ULPWU 0x008D04
#define INT_RB0 0x0010B08
#define INT_RB1 0x0020B08
#define INT_RB2 0x0040B08
#define INT_RB3 0x0080B08
#define INT_RB4 0x0100B08
#define INT_RB5 0x0200B08
#define INT_RB6 0x0400B08
#define INT_RB7 0x0800B08

#list

Armando Mora Campos 64


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

13.EJEMPLOS SUPERLAZO.
//Ejemplo 1. PUERTOS PARALELOS.
//Generar una señal cuadrada con un ciclo de trabajo del 50%, periodo de 10 ms y que se
//presente en todos los pines del puerto B.

//Directivas.
#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales.(pag. 57).

#fuses XT,NOWDT,NOPROTECT,PUT //Fusibles de configuración de hardware (pag. 31).

#use delay(clock=4000000)//Base de tiempo para retardos (pag. 17).

#use fast_io(B) //Directiva para el manejo normal del puerto (pag. 13).

#byte portb = 0x06 //Apuntando con una constante a la direccion del puerto B (pag. 30).

//Función de inicialización.
void inicializar( ) {

portb = 0x00; //Valor inicial del puerto B.

set_tris_b(0b00000000);//Configurando todos los pines del puerto B como salida (pag. 13).

} //Fin inicializar.

//Programa principal.
void main( ) { //Inicio programa principal.

inicializar( ); //Llamada a la funcion de inicializar.

while(TRUE) { //Inicio bucle infinito while (pag. 10).

portb = 0xff; //Salidas 1's en todo el puerto B.

delay_ms(5); //Retardo de 5 ms (pag. 17).

portb = 0x00; //Salidas 0's en todo el puerto B.

delay_ms(5); //Retardo de 5 ms (pag. 17).

} //Fin while.

} //Fin programa principal.

Armando Mora Campos 65


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 2. PUERTOS PARALELOS.


//Generar una señal cuadrada con un ciclo de trabajo del 30%, periodo de 350 us y que se
//presente en todos los pines de todos los puerto (A,B,C,D,E).

//Directivas.
#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales (pag. 57).

#fuses XT,NOWDT,NOPROTECT,PUT //Fusibles de configuración de hardware (pag. 31).

#use delay(clock=4000000) //Base de tiempo para retardos (pag. 17).

#use fast_io(A) //Directivas para el manejo normal de puertos (pag. 13).


#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)

#byte porta = 0x05 //Apuntando con una constante a la dirección de cada puerto (pag. 30).
#byte portb = 0x06
#byte portc = 0x07
#byte portd = 0x08
#byte porte = 0x09

//Función de inicialización.
void inicializar( ) {

setup_port_a(NO_ANALOGS); //Config. del puerto A (Todas digitales, pag. 13)


porta = 0x00; //Valor inicial puerto A.
set_tris_a(0b00000000); //Configurando pines como salida (pag. 13).

portb = 0x00; //Valor inicial puerto B.


set_tris_b(0b00000000); //Configurando pines como salida.

portc = 0x00; //Valor inicial puerto C.


set_tris_c(0b00000000); //Configurando pines como salida.

portd = 0x00; //Valor inicial puerto D.


set_tris_d(0b00000000); //Configurando pines como salida.

porte = 0x00; //Valor inicial puerto E.


set_tris_e(0x00); //Configurando pines como salida.

} //Fin inicializar.

Armando Mora Campos 66


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Programa principal.
void main( ) { //Inicio programa principal.

inicializar( ); //Llamada a la función de inicializar.

do { //Inicio bucle infinito do-while (pag. 10).

porta = 0xff; //Salidas 1's en todos los puertos.


portb = 0xff;
portc = 0xff;
portd = 0xff;
porte = 0xff;

delay_us(95); //Retardo de 95 us (pag. 17).

porta = 0x00; //Salidas 0's en todos los puertos.


portb = 0x00;
portc = 0x00;
portd = 0x00;
porte = 0x00;

delay_us(255);//Retardo de 255 us (pag. 17).

} while(1); //Fin do-while.


} //Fin programa principal.

Armando Mora Campos 67


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 3. PUERTOS PARALELOS.


//Generar una señal cuadrada con un periodo de 500 ciclos de maquina, ciclo de trabajo del
//10% y que se presente en los pines PA0, PB1, PC2, PD3, PE0. La señal en PC2 debe estar
//invertida con respecto a las otras. Las líneas no utilizadas, configurarlas como entradas.

//Directivas.
#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales (pag. 57).

#fuses XT,NOWDT,NOPROTECT,PUT //Fusibles de configuración de hardware (pag. 31).

#use delay(clock=4000000) //Base de tiempo para retardos (pag. 17).

#use fast_io(A) //Directivas para el manejo normal de puertos (pag. 13).


#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)

#bit PA0 = 0x05.0 //Apuntando con una constante a un bit de un puerto (pag. 30).
#bit PB1 = 0x06.1
#bit PC2 = 0x07.2
#bit PD3 = 0x08.3
#bit PE0 = 0x09.0

//Función de inicialización.
void inicializar( ) {

setup_port_a(NO_ANALOGS); //Configuración del puerto A (Todas digitales, pag. 13)


PA0 = 0; //Valor inicial pin A0.
set_tris_a(0b00111110); //Configurando pines. (pag. 13).

PB1 = 0; //Valor inicial pin B1.


set_tris_b(0b11111101); //Configurando pines.

PC2 = 0; //Valor inicial pin C2.


set_tris_c(0b11111011); //Configurando pines como salida.

PD3 = 0; //Valor inicial pin D3.


set_tris_d(0b11110111); //Configurando pines.
PE0 = 0; //Valor inicial pin E0.
set_tris_e(0b00000110); //Configurando pines.

} //Fin inicializacion.

Armando Mora Campos 68


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Programa principal.
void main( ) { //Inicio programa principal.

inicializar( ); //Llamada a la función de inicializar.

for(;;) { //Bucle infinito for (pag. 10).

PA0 = 1; //Salidas 1's en los bits indicados.


PB1 = 1;
PC2 = 0;
PD3 = 1;
PE0 = 1;

delay_cycles(50); //Retardo de 50 ciclos (pag. 17).

PA0 = 0; //Salidas 0's en los bits indicados.


PB1 = 0;
PC2 = 1;
PD3 = 0;
PE0 = 0;

delay_cycles(450); //Retardo de 450 ciclos (pag. 17).

}; //Fin for.
} //Fin programa principal.

Armando Mora Campos 69


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 4. PUERTOS PARALELOS.


//Generar una señal cuadrada con un ciclo de trabajo del 50%, periodo de 2 s, que se presente
//en todos los pines del puerto B y que sea activada o desactivada por el pin 0 del puerto A
//(PA0).

//Directivas.
#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales.(pag. 57).
#fuses XT,NOWDT,NOPROTECT,PUT //Fusibles de configuración de hardware (pag. 31).
#use delay(clock=4000000) //Base de tiempo para retardos (pag. 17).
#use fast_io(A) //Directiva para el manejo normal de puertos (pag. 13).
#use fast_io(B)
#byte portb = 0x06 //Apuntando con una constante a la direccion del puerto B (pag. 30).
#bit PA0 = 0x05.0 //Apuntando con una constante al pin 0 del puerto A (pag. 30).

//Funcion de inicializacion.
void inicializar( ) {
setup_port_a(NO_ANALOGS); //Configuración del puerto A (Todas digitales, pag. 13).
set_tris_a(0b00111111); //Configurando los 6 pines del puerto A como entradas (pag. 13).
portb = 0x00; //Valor inicial del puerto B.
set_tris_b(0b00000000); //Configurando los pines del puerto B como salidas (pag. 13).
} //Fin inicializar.

//Programa principal.
void main( ) { //Inicio programa principal.
inicializar( ); //Llamada a la funcion de inicializar.

while(TRUE) { //Inicio bucle infinito while (pag. 10).

if(PA0 = = 1) { //Toma de decision en funcion de PA0 (pag. 10).


portb = 0xff; //Salidas 1's en todo el puerto B.
delay_ms(1000); //Retardo de 1 s (pag. 17).
portb = 0x00; //Salidas 0's en todo el puerto B.
delay_ms(1000); //Retardo de 1 s (pag. 17).
} //Fin if.

else {
portb = 0x00;
} //Fin else.
} //Fin while.
} //Fin main.

Armando Mora Campos 70


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 5. PUERTOS PARALELOS.


//Realizar la misma funcion del ejemplo 4, agregando la proteccion del Watch-Dog.

//Directivas.
#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales (pag. 57).
#fuses XT,WDT,NOPROTECT,PUT //Fusibles de configuracion de hardware (pag. 31).

#use delay(clock=4000000,RESTART_WDT)//Base de tiempo para retardos con limpieza del


//WatchDog mientras ocurre el retardo (pag. 17).
#use fast_io(A) //Directiva para el manejo normal de puertos (pag. 13).
#use fast_io(B)

#byte portb = 0x06 //Apuntando con una constante a la dir. del puerto B (pag. 30).
#bit PA0 = 0x05.0 //Apuntando con una constante al pin 0 del puerto A (pag. 30).

//Funcion de inicializacion.
void inicializar( ) {
setup_wdt(WDT_36MS); //Base de tiempo del watchdog (pag. 59).
setup_port_a(NO_ANALOGS); //Configuracion digital del puerto A (pag. 13).
set_tris_a(0b00111111); //Puerto A como entrada (pag. 13).
portb = 0x00; //Valor inicial del puerto B.
set_tris_b(0b00000000); //Configurando todos el puerto B como salida (pag. 13).
}

//Programa principal.
void main( ) { //Inicio programa principal.

inicializar( ); //Llamada a la funcion de inicializar.


while(TRUE) { //Inicio bucle infinito while (pag. 10).
if(PA0 == 1) { //Toma de decision en funcion de PA0
portb = 0xff; //Salidas 1's en todo el puerto B.
delay_ms(1000);//Retardo de 1000 ms (pag. 17).
portb = 0x00; //Salidas 0's en todo el puerto B.
delay_ms(1000);//Retardo de 1000 ms (pag. 17).
} //Fin if.

else {
portb = 0x00;
} //Fin else.

restart_wdt(); //Restableciendo el Watch Dog.


} //Fin while.
} //Fin main.

Armando Mora Campos 71


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 6. PUERTOS PARALELOS.


//Un motor de pasos de cuatro terminales de control gira en un sentido al aplicarle la siguiente
//secuencia hexadecimal: 1,5,4,6,2,A,8,9. Hacer un programa que haga girar el motor a una
//velocidad constante, con un tiempo entre pasos de 10 ms. Considerar un pin de arranque-
//paro del motor y la proteccion del Watch-Dog.

//Solucion: se utilizara la parte baja del puerto B para activar el motor y el pin 0 del puerto E
//como control ON/OFF del motor.

//Directivas del compilador.


#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales (pag. 57).

#fuses XT,WDT,NOPROTECT,PUT //Fusibles de configuracion de hardware (pag. 31).

#use delay(clock=4000000,RESTART_WDT) //Base de tiempo para retardos con


//restablecimiento del WDT mientras ocurre el
//retardo (pag. 17).

#use fast_io(B) //Directiva para el manejo normal de puertos (pag. 13).


#use fast_io(E)

#byte portb = 0x06 //Apuntando con una constante a la direccion del puerto B (pag. 30).

#bit PE0 = 0x09.0 //Apuntando con una constante al pin 0 del puerto E (pag. 30).

byte const pasos[8] = {0x01,0x05,0x04,0x06,0x02,0x0a,0x08,0x09}; //Arreglo constante de


//bytes.
//Funcion de inicializacion.
void inicializar( ) {
setup_wdt(WDT_36MS); //Base de tiempo del watchdog (pag. 59).
setup_ADC_ports(NO_ANALOGS);// Puertos A y E como digitales (pag. 13).
set_tris_e(0b00000111); //Configurando el puerto E como entradas.

portb = 0x00; //Valor inicial del puerto B.


set_tris_b(0b11110000); //Configurando parte baja del puerto B como salida (pag. 13).

} //Fin inicializar.

//Programa principal.
void main( ) { //Inicio programa principal.
int i; //Variable del for, 8 bits sin signo.

inicializar( ); //Llamada a la funcion de inicializar.

while(TRUE) { //Inicio bucle infinito while (pag. 10).

Armando Mora Campos 72


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

if(PE0 == 1) { //Sentencia if (pag. 10).


for(i=0;i<=7;i++) { //Bucle for (pag. 10).
portb = pasos[i]; //Escritura al puerto B del valor del arreglo pasos.
delay_ms(10); //Retardo de 10 ms (pag. 17).
} //Fin for.
} //Terminador if
else portb = 0x00; //Si PE0 = 0, mandar ceros al motor.
restart_wdt(); //Limpiar timer Watch-Dog (pag. 25).

} //Fin while.
} //Fin main.

Armando Mora Campos 73


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 7. PUERTOS PARALELOS.


//Incluir en el ejemplo 6 una entrada para el control de la direccion de giro del motor a pasos.

//Solucion: se utilizara la parte baja del puerto B para activar el motor, del puerto E el pin 0
//como control ON/OFF del motor y el pin 1 como control de direccion de giro.

//Directivas del compilador.


#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales (pag. 57).

#fuses XT,WDT,NOPROTECT,PUT //Fusibles de configuracion de hardware (pag. 31).

#use delay(clock=4000000,RESTART_WDT) //Base de tiempo para retardos con


//restablecimiento del WDT mientras ocurre el
//retardo (pag. 17).

#use fast_io(B) //Directiva para el manejo normal de puertos (pag. 13).


#use fast_io(E)

#byte portb = 0x06 //Apuntando con una constante a la direccion del puerto B (pag. 30).

#bit PE0 = 0x09.0 //Apuntando con una constante al pin 0 del puerto E (pag. 30).

#bit PE1 = 0x09.1 //Apuntando con una constante al pin 1 del puerto E (pag. 30).

byte const pasos[8] = {0x01,0x05,0x04,0x06,0x02,0x0a,0x08,0x09}; //Arreglo constante de


//bytes.
//Funcion de inicializacion.
void inicializar( ) {
setup_wdt(WDT_36MS); //Base de tiempo del watchdog (pag. 59).
setup_adc_ports(NO_ANALOGS); // Puertos A y E como digitales (pag. 13).
set_tris_e(0b00000111); //Configurando el puerto E como entradas.

portb = 0x00; //Valor inicial del puerto B.


set_tris_b(0b11110000); //Configurando la parte baja del puerto B como
//salida (pag. 13).
} //Fin inicializar.

//Programa principal.
void main( ) { //Inicio programa principal.
int i; //Variable de 8 bits sin signo para el for.
inicializar( ); //Llamada a la funcion de inicializar.

while(TRUE) { //Inicio bucle infinito while (pag. 10).

Armando Mora Campos 74


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

if(PE0 == 1) { //Sentencia if (pag. 10).


for(i=0;i<=7;i++) { //Bucle for (pag. 10).
if(PE1 == 1) portb = pasos[i]; //Un sentido de giro.
else portb = pasos[7-i]; //El otro sentido de giro.
delay_ms(10); //Retardo de 10 ms (pag. 17).
} //Fin for.
}

else portb = 0x00;

restart_wdt(); //Limpiar timer Watch-Dog (pag. 25).

} //Fin while.
} //Fin main.

Armando Mora Campos 75


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 8. PUERTOS PARALELOS.


//Incluir en el ejemplo 7 el control de la velocidad de giro del motor de pasos utilizando un
//puerto de 8 bits para tener 256 valores diferentes de velocidad.

//Solucion: se utilizara la parte baja del puerto B para activar el motor, el puerto C como
//entrada de velocidad y del puerto E el pin 0 como control ON/OFF del motor y el pin 1 como
//control de direccion de giro.

#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales (pag. 57).

#fuses XT,WDT,NOPROTECT,PUT //Fusibles de configuracion de hardware (pag. 31).

#use delay(clock=4000000,RESTART_WDT) //Base de tiempo para retardos con


//restablecimiento del WDT mientras ocurre el
//retardo (pag. 17).
#use fast_io(B) //Directiva para el manejo normal de puertos (pag. 13).
#use fast_io(C)
#use fast_io(E)

#byte portb = 0x06 //Apuntando con una constante a la direccion del puerto B (pag. 30).

#byte portc = 0x07 //Apuntando con una constante a la direccion del puerto C (pag. 30).

#bit PE0 = 0x09.0 //Apuntando con una constante al pin 0 del puerto E (pag. 30).

#bit PE1 = 0x09.1 //Apuntando con una constante al pin 1 del puerto E (pag. 30).

byte const pasos[8] = {0x01,0x05,0x04,0x06,0x02,0x0a,0x08,0x09}; //Arreglo constante de


//bytes.
//Funcion de inicializacion.
void inicializar( ) {
setup_wdt(WDT_36MS); //Base de tiempo del watchdog (pag. 59).
setup_adc_ports(NO_ANALOGS); // Puertos A y E como digitales (pag. 13).
set_tris_e(0b00000111); //Configurando el puerto E como entradas.

portb = 0x00; //Valor inicial del puerto B.


set_tris_b(0b11110000); //Configurando la parte baja del puerto B como
//salida (pag. 13).
set_tris_c(0b11111111); //Configurando puerto C como entradas.

//Programa principal.

void main( ) { //Inicio programa principal.

Armando Mora Campos 76


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

int i; //Variable 8 bits sin signo para el for.


inicializar( ); //Llamada a la funcion de inicializar.

while(TRUE) { //Inicio bucle infinito while (pag. 10).

if(PE0 == 1) { //Sentencia if (pag. 10).


for(i=0;i<=7;i++) { //Bucle for (pag. 10).
if(PE1 == 1) portb = pasos[i]; //Un sentido de giro.
else portb = pasos[7-i]; //El otro sentido de giro.
delay_ms(portc); //Retardo en ms en funcion del
//valor del puerto C (pag. 17).
} //Fin for.
}
else portb = 0x00;

restart_wdt(); //Limpiar timer Watch-Dog (pag. 25).

} //Fin while.
} //Fin main.

Armando Mora Campos 77


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 9. CONVERSION ANALOGICA/DIGITAL.


//Adquirir continuamente una señal analogica de 0 a +5 V conectada en la entrada AN0.
//Exhibir el resultado de conversion A/D en binario por el puerto B. Utilizar el voltaje Vdd
//como referencia.

#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales. (pag. 57).


#device ADC = 10 //ADC = 8;
#fuses XT,NOWDT,NOPROTECT,PUT //Fusibles de configuracion de hardware (pag. 31).

#use fast_io(A) //Directiva para el manejo normal de puertos (pag. 13).


#use fast_io(B)

#byte portb = 0x06 //Apuntando con una constante a la direccion de puerto (pag. 30).

//Funcion de inicializacion.

void inicializar( ) {

setup_adc_ports(A_ANALOG); //Puerto A analogico, Vdd como voltaje de referencia.

set_tris_a(0b11111111); //Configurando puerto A como entrada (pag. 13).

portb = 0x00; //Valor inicial del puerto B.


set_tris_b(0b00000000); //Configurando puerto B como salida (pag. 13).

setup_adc(ADC_CLOCK_INTERNAL); //Configurando el convertidor ADC con


//reloj interno (pag. 16).
set_adc_channel(0); //Indicando el canal a convertir (pag. 16).

//Programa principal.

void main( ) { //Inicio programa principal.


inicializar( ); //Llamada a la funcion de inicializar.
while(TRUE) { //Inicio bucle infinito while (pag. 10).
portb = read_adc(); //Conversion y escritura a puerto (pag. 16).
} //Fin while.
} //Fin main.

Armando Mora Campos 78


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 10. CONVERSION ANALOGICA/DIGITAL.


//Realizar la misma operacion del ejemplo 9, pero ahora considerando el control de tiempo de
//muestreo, de 0 a 255 ms, en funcion del valor del puerto C. Incluir la proteccion del watch
//Dog.

#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales (pag. 57).

#fuses XT,WDT,NOPROTECT,PUT //Fusibles de configuracion de hardware (pag. 31).

#use delay(clock=4000000,RESTART_WDT) //Base de tiempo para retardos con


//restablecimiento del WDT mientras ocurre el
//retardo (pag. 17).
#use fast_io(A) //Directivas para el manejo normal de puertos (pag. 13).
#use fast_io(B)
#use fast_io(C)

#byte portb = 0x06 //Apuntando con una constante a la direccion de puertos (pag. 30).
#byte portc = 0x07

//Funcion de inicializacion.

void inicializar( ) {
setup_wdt(WDT_36MS); //Base de tiempo del watchdog (pag. 59).
setup_adc_ports(A_ANALOG);//Puerto A analogico, Vdd como voltaje de referencia.
set_tris_a(0b11111111); //Configurando puerto A como entradas (pag. 13).

portb = 0x00; //Valor inicial del puerto B.


set_tris_b(0b00000000); //Configurando el puerto B como salida (pag. 13).

set_tris_c(0b11111111); //Configurando puerto C como entrada (pag. 13).

setup_adc(ADC_CLOCK_INTERNAL);//Configurando el convertidor ADC con reloj


//interno (pag. 16).
set_adc_channel(0); //Indicando el canal a convertir (pag. 16).

//Programa principal.

void main( ) { //Inicio programa principal.

inicializar( ); //Llamada a la funcion de inicializar.


while(TRUE) { //Inicio bucle infinito while (pag. 10).

Armando Mora Campos 79


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

portb = read_adc(); //Conversion y escritura a puerto (pag. 16).


delay_ms(portc); //Tiempo entre muestras (pag. 17).
restart_wdt(); //Limpieza del Watch Dog.

} //Fin while.
} //Fin main.

Armando Mora Campos 80


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 11. CONVERSION ANALOGICA/DIGITAL.


//Hacer un programa que exhiba en un puerto de 8 bits el resultado de conversion A/D, en
//binario, de una las señales presentes en los 8 canales de entrada analogica del PIC16F887.
//Utilizar tres lineas para seleccionar el canal a desplegar.

//Solucion: Se utiliza el puerto B para desplegar los 8 bits de la conversion A/D y las lineas
//PC0 a PC2 como seleccion del canal.

#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales (pag. 57).

#fuses XT,NOWDT,NOPROTECT,PUT //Fusibles de configuracion de hardware (pag. 31).

#use fast_io(A) //Directiva para el manejo normal de puertos (pag. 13).


#use fast_io(B)
#use fast_io(C)
#use fast_io(E)

#byte portb = 0x06 //Apuntando con una constante a la direccion de puertos (pag. 30).
#byte portc = 0x07

//Funcion de inicializacion.

void inicializar( ) {

setup_adc_ports(ALL_ANALOG); //Puerto A y E analogicos , Vdd como voltaje de


//referencia (pag. 13).
set_tris_a(0b11111111); //Configurando puerto A como entrada (pag. 13).

portb = 0x00; //Valor inicial del puerto B.

set_tris_b(0b00000000); //Configurando el puerto B como salida (pag. 13).

set_tris_c(0b11111111); //Configuracion puerto C como entrada (pag. 13).

set_tris_e(0b00000111); //Configurando puerto E como entrada (pag. 13).

setup_adc(ADC_CLOCK_INTERNAL);//Configurando el convertidor ADC con reloj


//interno (pag. 16).
}

//Programa principal.

void main( ) { //Inicio programa principal.

Armando Mora Campos 81


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

int canal; //Variable de 8 bits sin signo para seleccion canal (pag. 7).

inicializar( ); //Llamada a la funcion de inicializar.

while(TRUE) { //Inicio bucle infinito while (pag. 10).

canal = portc & 0b00000111; //Enmascarando primeros 3 bits pto. C (pag. 11).

set_adc_channel(canal); //Seleccion canal A/D (pag. 16).

delay_cycles(5); //Retardo para estabilizacion MUX A/D (pag. 17).

portb = read_adc(); //Escribiendo al puerto B resultado de conversion (pag. 16).

} //Fin while.

} //Fin main.

Armando Mora Campos 82


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 12. CONVERSION ANALOGICA/DIGITAL.


//Modificar el programa del ejemplo 11 para que la exhibicion del resultado de conversion sea
//en hexadecimal, en dos display de C.C., 7 segmentos.

//Texto del ejemplo 11:


//Hacer un programa que exhiba en un puerto de 8 bits el resultado de conversion A/D, en
//binario, de una las señales presentes en los 8 canales de entrada analogica del PIC16F887.
//Utilizar tres lineas para seleccionar el canal a desplegar.

//Solucion del ejemplo 11:


//Se utiliza el puerto B para desplegar los 8 bits de la conversion A/D y las lineas PC0 a PC2
//como seleccion del canal.

//Solucion del ejemplo 12:


//Se incluira un decodificador de hexadecimal a 7 segmentos C.C. en base a una tabla en ROM
//(arreglo constante de bytes de 16 elementos). El manejo del digito menos significativo se
//realizara con el puerto B y el mas significativo con el puerto D.

//La conexion de cada segmento (C.C.) al puerto correspondiente se realiza de la forma


//siguiente:

//a - Pin 6 e - Pin 2


//b - Pin 5 f - Pin 1
//c - Pin 4 g - Pin 0
//d - Pin 3

//Directivas.

#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales (pag. 57).

#fuses XT,NOWDT,NOPROTECT,PUT //Fusibles de configuracion de hardware (pag. 31).

#use fast_io(A) //Directiva para el manejo normal de puertos (pag. 13).


#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)

#byte portb = 0x06 //Apuntando con una constante a la direccion de puertos (pag. 30).
#byte portc = 0x07
#byte portd = 0x08

//Tabla en ROM para el decodificador hex-7 segmentos.


byte const decodif[16] = {0x7e, 0x30, 0x6d, 0x79, 0x33, 0x5b, 0x5f, 0x70, 0x7f,
0x7b, 0x77, 0x1f, 0x0d, 0x3d, 0x4f, 0x47};

Armando Mora Campos 83


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Funcion de inicializacion.

void inicializar( ) {

setup_port_a(ALL_ANALOG); //Puerto A y E analogicos, Vdd como voltaje de


//referencia (pag. 13). (igual a
//setup_adc_ports(ALL_ANALOG) )
set_tris_a(0b11111111); //Configurando puerto A como entrada (pag. 13).

portb = 0x00; //Valor inicial puerto B.


set_tris_b(0b00000000); //Configurando puerto B como salida (pag. 13).

set_tris_c(0b11111111); //Configurando puerto C como entrada (pag. 13).

portd = 0x00; //Valor inicial puerto D.


set_tris_d(0b00000000); //Configurando puerto D como salida (pag. 13).

set_tris_e(0b00000111); //Configurando puerto E como entrada (pag. 13).

setup_adc(ADC_CLOCK_INTERNAL);//Configurando el convertidor ADC con reloj


//interno (pag. 16).
}

//Programa principal.

void main( ) { //Inicio programa principal.


int canal, resultado, display_lo, display_hi; //Variables de 8 bits sin signo (pag. 7).
//resultado : resultado de conversion A/D.
//display_lo : valor hex a exhibir digito lo.
//display_hi : valor hex a exhibir digito hi.
inicializar( ); //Llamada a la funcion de inicializar.

while(TRUE) { //Inicio bucle infinito while (pag. 10).

canal = portc & 0b00000111; //Enmascarando primeros tres bits puerto C (pag.
//11).
set_adc_channel(canal); //Seleccion canal A/D (pag. 16).
delay_cycles(5); //Retardo para estabilizacion MUX (pag. 17).
resultado = read_adc(); //Realizando la conversion A/D (pag. 16).

display_lo = resultado & 0x0f; //Enmascarando parte baja resultado.

portb = decodif[display_lo]; //Decodificando y escribiendo a puerto.

Armando Mora Campos 84


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

display_hi = swap(resultado); //Conmutando nibbles (pag. 24).

display_hi = display_hi & 0x0f; //Enmascarando parte baja

portd = decodif[display_hi]; //Decodificando y escribiendo a puerto.

} //Fin while.

} //Fin main.

Armando Mora Campos 85


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 13. CONVERSION ANALOGICA/DIGITAL.


//Generar una señal cuadrada con un ciclo de trabajo del 50%, periodo de 10 ms y que se
//presente en todos los pines del puerto B.

//Al mismo tiempo y MANEJANDO INTERRUPCIONES, adquirir continuamente una señal


//analogica de 0 a +5 V conectada en la entrada AN0. Exhibir el resultado de conversion A/D
//en binario por el puerto C. Utilizar un voltaje externo como referencia del convertidor.

#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales (pag. 57).

#fuses XT,NOWDT,NOPROTECT,PUT //Fusibles de configuracion de hardware (pag. 31).

#use delay(clock=4000000) //Base de tiempo para retardos.

#use fast_io(A) //Directiva para el manejo normal del puerto (pag. 13).
#use fast_io(B)
#use fast_io(C)

#byte portb = 0x06 //Apuntando con una constante a la direccion de puerto (pag. 30).
#byte portc = 0x07

#byte adres = 0x1e //Registro de resultado de conversion A/D.

#bit GO_DONE = 0x1f.2 //Bit de inicio de conversion (registro ADCON0).

//Funcion de inicializacion.

void inicializar( ) {

setup_adc_ports(RA0_RA1_ANALOG_RA3_REF);//PA0, PA1 analogicos, PA3


//entrada de referencia (pag. 13).
set_tris_a(0b00111111); //Configurando puerto A como entradas (pag. 13).

portb = 0x00; //Valor inicial del puerto B.


set_tris_b(0b00000000); //Configurando puerto B como salida (pag. 13).

portc = 0x00; //Valor inicial puerto C.


set_tris_c(0b00000000); //Configurando puerto C como salida (pag. 13).

setup_adc(ADC_CLOCK_INTERNAL);//Configurando el convertidor ADC con reloj


//interno (pag. 16).
set_adc_channel(0); //Indicando el canal a convertir (pag. 16).

enable_interrupts(INT_ADC); //Habilitando interrupcion por conversion A/D.

Armando Mora Campos 86


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

enable_interrupts(GLOBAL);

} //Fin inicializar.

//Rutina de servicio a la interrupcion del convertidor.

//Directiva para indicar que la sig. Funcion es una rutina de


#int_ad //servicio a interrupcion
convertidor( ) { //Inicio de rutina.

portc = adres; //Escritura al puerto C del resultado de conversion.


GO_DONE = 1; //Iniciando siguiente conversion A/D.

} //Fin rutina de interrupcion convertidor.

//Programa principal.

void main( ) { //Inicio programa principal.

inicializar( ); //Llamada a la funcion de inicializar.

GO_DONE = 1; //Iniciando primera conversion A/D.

while(TRUE) { //Inicio bucle infinito while (pag. 10).

portb = 0xff; //Salidas 1's en todo el puerto B.

delay_ms(5); //Retardo de 5 ms (pag. 17).

portb = 0x00; //Salidas 0's en todo el puerto B.

delay_ms(5); //Retardo de 5 ms (pag. 17).

} //Fin while.
} //Fin programa principal.

Armando Mora Campos 87


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 14. CONVERSION DIGITAL/ANALOGICA (FORMATO PWM).


//Obtener dos salidas analogicas, con formato PWM, cuyo valor este en funcion de dos
//entradas analogicas de 0 a +5v, resolución de 10 bits (0 a 1023).

//SOLUCION: Se utilizan los modulos CCP1 y CCP2, ya integrados en el PIC16F887, los


//cuales pueden operar en uno de los siguientes tres modos: captura de 16 bits, comparacion de
//16 bits y PWM de 8 o 10 bits.

//Para Modulacion de Ancho de Pulso, el PWM1 tiene como salida el pin 17 (RC2/CCP1)
//y el PWM2 el pin 16 (RC1/T1OSI/CCP2).

//Para el control del PWM1 se usa la entrada analogica 0 y para el PWM2 la entrada analogica
//1 (ambas de 10 bits de resolución).

//Con un cristal de 4 Mhz, como lo marca la directiva #use delay(clock=4000000), la


//frecuencia PWM es 3.906 Khz.

#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales (pag. 57).

#fuses XT,NOWDT,NOPROTECT,PUT //Fusibles de configuracion de hardware (pag. 31).

#use delay(clock=4000000) //Base de tiempo para retardos (pag. 17).

#use fast_io(A) //Directiva para el manejo normal de puertos (pag. 13).


#use fast_io(C)
#byte portc = 0x07 //Apuntando con una constante a la direccion de puerto (pag. 30).

void inicializar( ) {

setup_adc_ports(A_ANALOG); //Puerto A analogico, voltaje de referencia Vdd.


//(pag. 13).
set_tris_a(0b00111111); //Configurando puerto A como entradas (pag. 13).

portc = 0x00; //Valor inicial puerto C.

set_tris_c(0b11111001);
//Configurando pines 1 y 2 del puerto C como salida (pag.
//13).
setup_adc(ADC_CLOCK_INTERNAL);//Configurando el convertidor ADC con reloj
//interno (pag. 16).
setup_ccp1(CCP_PWM); //Configurando los modulos CCP 1 y CCP2 en modo
setup_ccp2(CCP_PWM); //PWM (pag. 15).

//Configurando el periodo de las senales PWM:

Armando Mora Campos 88


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Periodo ciclo PWM = (periodo_T2)(prescalador)/(f/4)

//lo cual se define con la funcion setup_timer_2(prescalador,periodo_T2,1).


//El prescalador solo permite la division entre 1,4 y 16 y el periodo debe tomar un valor
//de 0 a 255. El valor del PWM esta en el rango de 0 a periodo (para PWM de 8 bits).

setup_timer_2(T2_DIV_BY_1,255,1); //Configurando temporizador 2 (pag. 15).

//NOTA: Lo anterior configura el temporizador 2 para una frecuencia PWM de 3.906 Khz con
//un cristal del CPU de 4 Mhz. Si se desea una frecuencia PWM de 0.976 Khz, configurar el
//timer 2 como setup_timer_2(T2_DIV_BY_4,255,1), cristal del CPU de 4 Mhz. Para ambos
//casos, si se declara un cristal de 8 Mhz, la frecuencia PWM se duplica.

} //Fin inicializar.

void main() { //Inicio main.


long valor; //Variable de 16 bits sin signo.
inicializar();
while(TRUE) { //Bucle continuo (pag. 10).
set_adc_channel(0); //Indicando el canal 0 de adquisicion A/D (pag. 16).
delay_cycles(10); //Retardo para estabilizar el multiplexor (pag. 17).
valor = read_adc(); //Leyendo el resultado de conversion (pag. 17).
set_pwm1_duty(valor);//Escribiendo a la salida PWM1 (pag 16).

set_adc_channel(1); //Indicando el canal 1 de adquisicion A/D (pag. 16).


delay_cycles(10); //Retardo para estabilizar el multiplexor (pag. 17).
valor = read_adc(); //Leyendo el resultado de conversion (pag. 17).
set_pwm2_duty(valor);//Escribiendo a la salida PWM2 (pag 16).
delay_ms(200); //Retardo para esperar estabilizacion de salidas PWM.
} //Fin while.
} //Fin main.

//NOTA: La variable local en main “valor”, se define de 16 bits sin signo (long), por lo que los
//PWM reciben los 10 bits del convertidor A/D. Si “valor” se declara de 8 bits sin signo (int),
//los PWM toman una resolucion de 8 bits, ignorando los dos bits menos significativos. El
//valor que toman los PWM esta en el rango de 0 a period.

Armando Mora Campos 89


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//EJEMPLO 15. COMUNICACION SERIE RS-232 MICROCONTROLADOR-PC.


// (PROGRAMA DEL MICROCONTROLADOR).
//Realizar un programa donde la PC transmita via puerto serie RS-232 un valor de 8 bits sin
//signo al microcontrolador, el cual lo retransmitira a la PC (como un eco) y lo exhibira como
//salida por el puerto paralelo B..

#include<16F887.h> //Especificando dispositivo a utilizar y constantes generales (pag. 57).

#fuses XT,NOWDT,NOPROTECT,PUT //Fusibles de configuracion de hardware (pag. 31).

#use delay (clock=4000000) //Base de tiempo para retardos y para la comunicacion serie
//asincrona.

#use rs232 (baud=9600,XMIT=PIN_C6,RCV=PIN_C7,BITS=8,PARITY=N) //Directiva para


//el manejo del puerto serial RS-232 (pag. 17) en donde se indica:
//Velocidad : 9600 bits por segundo (bps).
//Pin de transmision: PIN_C6.
//Pin de recepcion: PIN_C7.
//Numero bits de datos: 9
//Tipo de paridad: Sin paridad.

#use fast_io(B) //Directiva para el manejo normal de puertos (pag. 13).


#use fast_io(C)

#byte portb = 0x06 //Apuntando con una constante a la direccion de puerto (pag. 30).
#byte portc = 0x07

void inicializar( ) {

portb = 0x00; //Valor inicial puerto B.


set_tris_b(0x00); //Configurando puerto B como salida.

portc = 0x00; //Valor inicial puerto C.


set_tris_c(0b10111111); //Configuracion PC6 como salida, PC7 como entrada.

} //Fin inicializar.

void main(){ //Inicio funcion principal.

int valor; //Declarando la variable valor como 8 bits sin signo.

inicializar( ); //Llamada a rutina de inicializacion.

Armando Mora Campos 90


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

while(true){ //Inicio ciclo continuo (pag. 10).

if( kbhit() ){ //Funcion que regresa TRUE si se ha recibido un dato por


//el puerto serie RS-232 (pag. 18).
valor = getch(); //Lectura del valor recibido desde la PC (pag. 18).
putchar(valor); //Retransmision a la PC del valor recibido (pag. 18)
portb = valor; //Escritura del dato recibido al puerto B.

} //Fin if.
} //Fin while.
} //Fin main.

Armando Mora Campos 91


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//EJEMPLO 15. COMUNICACIÓN SERIE RS-232 MICROCONTROLADOR-PC


// (PROGRAMA DE LA PC).
//Realizar un programa donde la PC transmita via puerto serie RS-232 un valor de 8 bits sin
//signo al microcontrolador, el cual lo retransmitira a la PC (como un eco) y lo exhibira como
//salida por el puerto paralelo B).

//Directivas de C.

#include <stdio.h>
#include <conio.h>
#include <dos.h>

//Declararando como constantes las direcciones de los registros del puerto serie COM1 de la
//PC.

#define TXR 0x3F8


#define RXR 0x3F8
#define DLL 0x3F8
#define DLH 0x3F9
#define IER 0x3F9
#define IIR 0x3FA
#define LCR 0x3FB
#define MCR 0x3FC
#define LSR 0x3FD
#define MSR 0x3FE

//Funcion de inicializacion del puerto serie (9600 bps, 8 bits de datos, 1 bit de paro, no
//paridad).

void inicializar() {
outp(LCR,0x80);
outp(DLL,0x0C);
outp(DLH,0x00);
outp(LCR,0x03);
}

//Funcion principal.

void main() {

unsigned char valor, dato; //Declarando variables como 8 bits sin signo.

inicializar(); //Llamada a funcion de inicializar.

while(1) { //Ciclo continuo con while.

Armando Mora Campos 92


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

if (kbhit()) { //Si oprimen una tecla, realizar proceso de transmision.

printf("Escribe valor a transmitir : "); //Solicitando valor a transmitir.


scanf("%d",&valor);
while (inp(LSR)&0x20==0); //Esperando que TXR se desocupe.
outp(TXR,valor); //Transmitiendo valor via RS-232.

} //Fin if.

if (inp(LSR) & 0x01) { //Verificando si se ha recibido un dato.

dato = inp(RXR); //Lectura del eco recibido.


printf("\neco=%d",dato); //Exhibicion del dato recibido (eco).

} //Fin if.
} //Fin while.
} //Fin main.

Armando Mora Campos 93


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//EJEMPLO 16. CONTROLADOR PID DIGITAL.


//Realizar un controlador PID digital, forma de posicion.

//Solucion:

//Se utilizara el algoritmo de control PID tipo posicion que maneja el libro "Sistemas de
//Control en Tiempo Discreto", de K. Ogata (capitulo 3, Funcion de transferencia de pulsos de
//un controlador PID digital, en forma de posicion).

//Funcion de transferencia de pulsos, forma de posicion:

//Gd(z) = Kp + Ki/(1-z-1) + Kd(1-z-1)

//donde:
// Kp = K - KT/2Ti = Ganancia proporcional (controlador digital).
// Ki = KT/Ti = Ganancia integral.
// Kd = KTd/T = Ganancia derivativa.

// Ti = Tiempo integral (o tiempo de restablecimiento, segundos).


// Td = Tiempo derivativo (o tasa de tiempo, segundos).
// K = Ganancia proporcional (controlador analogico).
// T = Periodo de muestreo (segundos).

//Los parametros anteriores, junto con otras señales, seran capturados utilizando los canales de
//entrada analogica de los puertos A y E en el siguiente orden:

//Ti Canal A/D 0 (Tiempo integral, segundos, PA0).


//Td Canal A/D 1 (Tiempo derivativo, segundos, PA1).
//K Canal A/D 2 (Constante proporcional, segundos, PA2).
//SP Canal A/D 3 (Set Point, PA3).
//RETRO Canal A/D 4 (Retroalimentacion, PA5).
//T Canal A/D 5 (Periodo de muestreo, segundos, PE0).

//Para la salida de control del PID, se utilizara la operacion PWM del modulo CCP1 (pin PC2).
//Esta salida nos indica la magnitud en 8 bits de la accion de control. El signo de la accion de
//control se muestra en el pin PC0 (0 positivo, 1 negativo).

//Directivas.

#include <16F887.H> //Especificando dispositivo a utilizar y constantes generales (pag. 57).

#fuses XT,NOWDT,NOPROTECT,PUT //Fusibles de configuracion de hardware (pag. 31).

#use delay(clock = 4000000) //Base de tiempo para retardos (pag. 17).

Armando Mora Campos 94


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

#use fast_io(A) //Directiva para el manejo normal de puertos (pag. 13).


#use fast_io(C)
#use fast_io(E)

#byte portc = 0x07 //Declarando la direccion del puerto C.

#bit PC0 = 0x07.0 //Apuntando como una constante a bits de puertos (pag. 30).
#bit PC2 = 0x07.2

//Variables globales:

int Ti, Td, K, SP, RETRO, T;//Variables de 8 bits sin signo (descritas anteriormente).
float m0,m1,e0,e1,e2; //Variables en punto flotante de 32 bits (pag. 7).
int magnitud; //Variable de 8 bits sin signo.
short signo; //Variable tipo bit.

//Donde:
//m0 = m(k) Accion de control en tiempo kT (actual).
//m1 = m(k-1) Accion de control en tiempo (k-1)T (anterior)
//e0 = m(k) Error en tiempo kT (actual).
//e1 = e(k-1) Error en (k-1)T (anterior)
//e2 = e(k-2) Error en (k-2)T.
//magnitud = Magnitud accion de control, limitada a valores de 0 a 255.
//signo = Signo de la accion de control PID (signo = 0, accion positiva, signo = 1, negativa).

//Funcion de inicializacion.

void inicializar() {

//Inicializando la operacion analogica de los puertos A y E.


setup_port_a(ALL_ANALOG); //Especificando operacion analogica de puertos A
//y E, Vref = Vdd. (pag. 13).
set_tris_a(0b00111111); //Configurando puerto A como entrada (pag. 13).
set_tris_e(0b00000111); //Configurando puerto E como entrada (pag. 13).
setup_adc(ADC_CLOCK_INTERNAL);//Habilitando el convertidor A/D con reloj
//interno (pag. 16).

//Inicializando el modo PWM del modulo CCP1.


portc = 0; //Valor inicial del puerto C.
set_tris_c(0b11111010); //Configurando PC0 y PC2 como salidas (pag. 13).
setup_ccp1(CCP_PWM); //Configurando el modulo CCP1 en modo PWM (pag.
//15).
setup_timer_2(T2_DIV_BY_4, 167, 0);//Definiendo el periodo del PWM con la
//configuracion del temporizador 2 (para es te caso

Armando Mora Campos 95


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//periodo pwm = (167)(4)/(4000000/4) = 668 us (pag.


//15). Ver tambien ejemplo 14.
set_pwm1_duty(0); //Valor inicial salida PWM.

m1 = 0; //Valor inicial parametros PID.


e1 = 0;
e2 = 0;
} //Fin inicializar.

//Funcion de adquisicion de datos.

void adquisicion_datos() {

set_adc_channel(0); //Adquisicion canal 0, Ti.


delay_cycles(3);
Ti = read_adc();

set_adc_channel(1); //Adquisicion canal 1, Td.


delay_cycles(3);
Td = read_adc();

set_adc_channel(2); //Adquisicion canal 2, K.


delay_cycles(3);
K = read_adc();

set_adc_channel(3); //Adquisicion canal 3, SP.


delay_cycles(3);
SP = read_adc();

set_adc_channel(4); //Adquisicion canal 4, RETRO.


delay_cycles(3);
RETRO = read_adc();

set_adc_channel(5); //Adquisicion canal 5, T, en milisegundos.


delay_cycles(3);
T = read_adc();

} //Fin adquisicion.

//Funcion del controlador PID digital, forma de posicion .

void control_PID() {

float Ts, Kp, Ki, Kd, salida_PID; //Variables locales en punto flotante de 32 bits.
Ts = T/1000; //Convirtiendo el periodo T de milisegundos a segundos.

Armando Mora Campos 96


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

Kp = K - (K*Ts/2*Ti); //Calculo de los parametros Kp, Ki y Kd segun algoritmo.


Ki = K*Ts/Ti;
Kd = K*Td/Ts;
m0 = m1+(Kp+Ki+Kd)*e0-(Kp+2*Kd)*e1+Kd*e2;//Calculo de la accion de control m(kT).

if( m0<0 ) { //Detectando el signo de la accion de control.


signo = 1; //m0 negativo, signo = 1, m0 positivo, signo = 0.
salida_PID = -m0; //Calculando valor absoluto de m0.
}
else {
signo = 0;
salida_PID = m0;
}

if(salida_PID>255) salida_PID = 255; //Limitando la magnitud de la accion de control a 255.

magnitud = (int)salida_PID; //Cambiando de tipo de dato float a 8 bits sin signo.


//para especificar la magnitud de salida del PID.
e2 = e1; //Actualizando e(k-2).

e1 = e0; //Actualizando e(k-1).

if(signo == 1) m1 = -salida_PID; //Actualizando m(k-1).

else m1 = salida_PID;

} //fin control PID.

//Funcion principal.

void main() { //Inicio programa principal.

inicializar(); //Llamada a funcion inicializar.

while(TRUE) { //Inicio ciclo continuo.

adquisicion_datos(); //Llamada a funcion de adquisicion de datos.

e0 = SP - RETRO; //Calculo del error actual.

control_PID(); //Llamada al controlador PID.

set_pwm1_duty(magnitud);//Actuacion del PWM en funcion de la magnitud


//de la accion de control calculada.
PC0 = signo; //Salida del signo de la accion de control.

Armando Mora Campos 97


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

delay_ms(T); //Retardo segun periodo de muestreo.

} //Fin while.

} //Fin main.

Armando Mora Campos 98


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 17. DRIVER MOTOR DE PASOS.


//Realizar un programa para operar un motor de pasos, que defina una funcion para el control
//del motor que incluya entrada de velocidad (0 a 255), direccion de giro (0 para un sentido, 1
//para el otro) y numero de pasos a moverse (de 0 a 255 pasos).

//Solucion: Se realiza la funcion de control del motor y para propositos de prueba, se utilizan
//las siguientes lineas del microcontrolador para introducir los parametros de entrada del driver
//del motor de pasos:

//Entrada para el valor de velocidad: AN0 (0 a +5v, pin PA0).


//Entrada del numero de pasos a moverse: AN1 (0 a +5v, pin PA1).
//Entrada para el cambio de sentido de giro: PA2 (1 o 0).
//Salidas al motor: PB0 a PB3.

//Tambien se define, para propositos de prueba, un retardo de 1 seg. entre movimiento y


//movimiento.

//Directivas.

#include <16F887.H> //Especificando dispositivo a utilizar y constantes generales (pag. 57).

#fuses XT,NOWDT,NOPROTECT,PUT //Fusibles de configuracion de hardware (pag. 31).

#use delay(clock = 4000000) //Base de tiempo para retardos (pag. 17).

#use fast_io(A) //Directiva para el manejo normal de puertos (pag. 13).


#use fast_io(B)

#byte portb = 0x06 //Declarando el puerto B.


#bit PA2 = 0x05.2 //Declarando el bit PA2.

byte const secuencia[8] = { 0b00000001, //Tabla de bytes en ROM (pag. 37).


0b00000101,
0b00000100,
0b00000110,
0b00000010,
0b00001010,
0b00001000,
0b00001001 };

//Funcion de inicializacion.

void inicializar() {

setup_port_a(RA0_RA1_RA3_ANALOG); //Estableciendo pines PA0, PA1 y PA3

Armando Mora Campos 99


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//analogicos, los demas digitales, Vref = Vdd (pag. 13).


set_tris_a(0b00111111); //Configurando el puerto A como entrada.
setup_adc(ADC_CLOCK_INTERNAL); //Habilitando el convertidor A/D con reloj
//interno (pag. 16).
portb = 0; //Valor inicial del puerto B.
set_tris_b(0xf0); //Configurando puerto B, parte baja como salidas (pag. 13).
} //Fin inicializar.

//Funcion para el control del motor de pasos.

//Esta funcion no altera la informacion que se maneja en los pines PB4 a PB7 (solo actua en la
//parte baja del puerto B).

void driver_MP(int vel, short dir, int cantidad_pasos) {

static signed paso_actual = 0; //Variable local tipo static (variable local que retiene su
//valor entre llamadas de funcion).
int i; //Variable de 8 bits sin signo para el for.

for(i=0; i<cantidad_pasos; i++) { //Control numero de pasos del movimiento.

portb = (portb & 0xf0) | secuencia[paso_actual]; //Cambiando informacion


//parte baja PB, según tabla.
if(dir) { //Control sentido de giro.
++paso_actual;
if(paso_actual > (sizeof(secuencia)-1)) paso_actual = 0;//El operador
//sizeof devuelve el tamaño del
//arreglo "secuencia"
}
else {
--paso_actual;
if(paso_actual < 0) paso_actual = (sizeof(secuencia)-1);
}

delay_ms(vel); //Retardo entre pasos para control de velocidad.

} //Fin for.
} //Fin driver_MP

//Funcion principal.

void main() {

int velocidad, num_pasos; //Variables locales de 8 bits sin signo.


inicializar(); //Llamada a funcion de inicializar.

Armando Mora Campos 100


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

while(TRUE) { //Ciclo continuo.

set_adc_channel(0); //Estableciendo el canal AN0.


delay_cycles(3); //Retardo para estabilizar el multiplexor.
velocidad = read_adc(); //Lectura del valor de velocidad.

set_adc_channel(1); //Estableciendo el canal AN1.


delay_cycles(3); //Retardo para estabilizar el multiplexor.
num_pasos = read_adc();//Lectura del valor de numero de pasos.

if(PA2) driver_MP(velocidad,1,num_pasos); //Movimiento en un sentido.

else driver_MP(velocidad,0,num_pasos); //Movimiento en el otro sentido.

delay_ms(1000); //Retardo entre ciclos de movimiento.

} //Fin while.
} //Fin main.

Armando Mora Campos 101


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 18. EXHIBICION EN PANTALLA LCD ALFANUMERICA SERIAL.

//Realizar un programa para exhibir en una pantalla alfanumerica LCD serial el resultado de la
//linealizacion de un sensor, cuya señal analogica de 0 a +5 volts se adquiere en la entrada
//AN0. La linealizacion se hace utilizando la ecuacion de segundo grado

// y = 0.0002345 x2 - 0.4519543 x + 100

//siendo "x" la entrada analogica no linealizada (canal AN0, 8 bits) y "y" la señal linealizada a
//exhibir. Con esta ecuacion, la salida toma valores de 0 a 100 %.

//INTRODUCCION AL EXHIBIDOR ALFANUMERICO LCD.

//El exhibidor utilizado es del tipo LCD alfanumerico con controlador integrado de 2 lineas
//por 16 caracteres, con interface serial a un puerto serie RS-232, recibiendo datos a 2400 o
//9600 bps. Esta unidad tiene dos modos de operacion, texto e instrucciones y por default esta
//en modo texto. Para operación en modo de instrucciones es necesario transmitir previamente
//el prefijo 254 en codigo ASCII. Una vez ejecutada la accion indicada (254 + instruccion), la
//pantalla regresa al modo texto, en el cual exhibe la informacion ASCII que recibe.

//El exhibidor LCD se conecta al puerto serie del microcontrolador, solo en la terminal Tx
//(PC6), Esta conexion es utilizando el circuito MAX232 para acoplar las señales TTL y RS-
//232.

//La lista siguiente muestra las instrucciones del exhibidor. Consisten en un codigo que se
//transfiere al exhibidor via puerto serie a una velocidad de 9600 bps. Para que tome en cuenta
//cada instruccion , el exhibidor debe recibir previamente un valor 254.

// INSTRUCCION CODIGO

//Borrar pantalla 1
//Mover todas las lineas una posicion a la izquierda 24
//Mover todas las lineas una posicion a la derecha 28
//Mover el cursor arriba e izquierda (posicion de HOME) 2
//Mover el cursor un caracter a la izquierda 16
//Mover el cursor un caracter a la derecha 20
//Hacer visible el cursor como "underline" 14
//Hacer visible el cursor como "block" 13
//Hacer invisible el cursor 12
//Hacer invisible la LCD, sin borrar el contenido 8
//Hacer visible la LCD 12
//Mover el cursor a una cierta posicion 128+posicion

//ADQUISICION DE DATOS A/D.

Armando Mora Campos 102


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Para reducir el ruido de alta frecuencia en la entrada analogica AN0, durante su adquisicion
//se realiza un proceso de promediacion de 10 valores (ver funcion de adquisicion).

//DIRECTIVAS.

#include <16F887.H> //Especificando dispositivo a utilizar y constantes generales (pag. 57).


#fuses XT,NOWDT,NOPROTECT,PUT //Fusibles de configuracion de hardware (pag. 31).
#use delay(clock = 4000000) //Base de tiempo para retardos (pag. 17).
#use rs232(baud=9600,xmit=PIN_C6) //Declaracion puerto serie RS-232.
#use fast_io(A) //Directiva para el manejo normal de puertos (pag. 13).
#use fast_io(C)
#bit PC6 = 0x07.6 //Declarando el bit PC6.

//DECLARACION DE CONSTANTES (coeficientes de la ecuacion cuadratica).

#define A 0.0002345 //Coeficiente de x2.


#define B 0.4519543 //Coeficiente x.
#define C 100 //Termino independiente.

//DECLARACION DE MACROS PARA EL EXHIBIDOR.

//Con la directiva #define, se pueden declarar macros, los cuales son un conjunto de
//instrucciones que tienen un nombre especifico. Para ejecutar las instrucciones que agrupa un
//macro, basta con escribir el nombre del macro en la posicion deseada del programa, sin
//necesidad de terminar con punto y coma. Al encontrar el nombre del macro, el compilador lo
//sustituye por las instrucciones que lo componen. Los macros siguientes son derivados
//directamente de las instrucciones del exhibidor LCD, incluyendo el dato 254 previo a cada
//instruccion.

#define instrucción { putchar(254); }


#define limpia { putchar(254); putchar(1); putchar(254); putchar(2); }
#define mueve _der { putchar(254); putchar(28); }
#define mueve_izq { putchar(254); putchar(24); }
#define cursor_home { putchar(254); putchar(2); }
#define cursor_izq { putchar(254); putchar(16); }
#define cursor_der { putchar(254); putchar(20); }
#define cursor_underline { putchar(254); putchar(14); }
#define cursor_block { putchar(254); putchar(13); }
#define borra_cursor { putchar(254); putchar(12); }
#define display_invis { putchar(254); putchar(8); }
#define ver_display { putchar(254); putchar(12); }
#define mueve_cursor{ putchar(254); putchar(192); }

//VARIABLES GLOBALES.

Armando Mora Campos 103


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

float salida, entrada; //Variables tipo float para la ecuacion cuadratica.

//FUNCION DE INICIALIZACION..

void inicializar() { //Inicio inicializar.


setup_port_a(RA0_RA1_RA3_ANALOG); //Estableciendo pines PA0, PA1 y
PA3
//analogicos, los demas digitales, Vref =
//Vdd (pag. 13).
set_tris_a(0b00111111); //Configurando el puerto A como entrada.
PC6 = 0; //Valor inicial del pin PC6.
set_tris_c(0b11011111); //Configurando pin PC6 como salida (pag. 13).
setup_adc(ADC_CLOCK_INTERNAL); //Habilitando el convertidor A/D con reloj
//interno (pag. 16).
set_adc_channel(0); //Estableciendo el canal 0 en el convertidor A/D.
} //Fin inicializar.

//FUNCION DE DESPLIEGUE DE BIENVENIDA.

void Bienvenida() { //Inicio bienvenida.


limpia //Llamada a macro limpia.
printf(" BIENVENIDO "); //Transmision serie de una cadena de caracteres.
mueve_cursor //Lamada a macro mueve_cursor.
printf(" ITQ "); //Transmision serie de una cadena de caracteres.
delay_ms(3000); //Retardo inicial de bienvenida.
}

//FUNCION DE LA ECUACION CUADRATICA..

//Esta ecuacion se define utilizando los coeficientes A, B y C declarados previamente,


//manejando las variables salida y entrada tipo float globales.

void ecuacion() {
salida = (A * entrada * entrada) – (B * entrada) + C;
}

//ADQUISICION CON PROMEDIACION.

//En esta funcion se realizan 10 conversiones, se van sumando los resultados y el total se
//divide entre 10, para asi obtener el promedio de 10 conversiones. Se tiene un retardo entre
//conversiones de 1 ms.

void adquisicion() {
int j; //Variable de 8 bits sin signo para el for.

Armando Mora Campos 104


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

long suma; //Variable de 16 bits sin signo para la suma.


suma = 0; //Inicializacion de la suma.
for(j=0;j<10;++j)  //Suma de 10 conversiones.
suma += read_adc();
delay_ms(1); //Tiempo entre conversiones.

entrada = (float)suma/10; //Promediacion convirtiendo suma a tipo float.
}

//FUNCION DE EXHIBICION DE RESULTADO.

void exhibicion() {
limpia //Llamada a macro limpia.
printf(" VALOR = %3.4f ",salida); //Transmision serie de un numero float
} //de hasta 3 digitos enteros y 4 decimales.

//FUNCION PRINCIPAL.

void main() {

inicializar(); //Llamada a funcion de inicializar.

bienvenida(); //Exhibicion de bienvenida.

while(TRUE) { //Ciclo continuo.

adquisicion(); //Adquisicion y promediacion de informacion en AN0.


ecuacion(); //Procesamiento de la ecuacion cuadratica.
exhibicion(); //Exhibicion del resultado en pantalla LCD.
delay_ms(500); //Retardo entre exhibiciones de 1/2 segundo.
} //Fin while.

} //Fin main.

Armando Mora Campos 105


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

Ejemplo 19. DRIVER CONVERTIDOR A/D.


Realizar un controlador (driver) del convertidor A/D, que tenga las siguientes características:

a) Conversión de 10 bits.
b) Referencia de voltaje interno.
c) Promediación de la conversión, con 4 muestras (periodo de muestreo de 1 ms).
d Que el convertidor A/D se duerma durante la conversión.
e Programación del driver como función que reciba como argumento el canal de adquisición y
entregue el resultado de conversión.

Utilizar el driver en un programa que reciba el número de canal por un puerto paralelo y que
entregue el resultado de conversión por el mismo medio.

//Solución: se realiza la función de adquisición utilizando el reloj interno (requisito para


//dormir al microcontrolador en el proceso de conversión), durmiendo el microprocesador
//durante la conversión y despertandolo mediante la interrupción de fin de conversión. El
//programa de prueba del driver tiene las siguientes entradas y salidas:

//Entrada del canal de conversión: bits 2:0 del puerto C.


//Salida parte baja de la conversión. bits 7:0 del puerto B.
//Salida parte alta de la conversión: bits 1:0 del puerto D.

//Directivas.

#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales (pag. 57).


#device ADC = 10 // Indicando resultado de conversión en 10 bits.
#fuses XT,NOWDT,NOPROTECT,PUT //Fusibles de configuracion de hardware (pag. 31).
#use delay(clock = 4000000) //Base de tiempo para retardos (pag. 17).

#use fast_io(A) //Directivas para el manejo normal de puertos (pag. 13).


#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)

#byte portb = 0x06 //Declarando el puerto B.


#byte portc = 0x07 //Declarando el puerto C.
#byte portd = 0x08 //Declarando el puerto D.

//Funcion de inicializacion.

void inicializar(void) {

setup_adc_ports(ALL_ANALOG); //Estableciendo pines analogicos, Vref=Vdd

Armando Mora Campos 106


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//(pag. 13).
set_tris_a(0b11111111); //Configurando el puerto A como entrada.
portb = 0x00; //Valor inicial puerto B.
set_tris_b(0b00000000); //Configurando el puerto B como salida.
set_tris_c(0b11111111); //Configurando el puerto C como entrada.
portd = 0x00; //Valor inicial puerto D.
set_tris_d(0b00000000); //Configurando el puerto D como salida.
set_tris_e(0b00000111); //Configurando el puerto E como entrada.
setup_adc(ADC_CLOCK_INTERNAL); //Habilitando el convertidor A/D con reloj
//interno (pag. 16).
enable_interrupts(GLOBAL); //Habilitación global de interrupciones.
} //Fin inicializar.

//Controlador del convertidor A/D.

long adquisicion(int canal) {


int i; //Variable del for.
long suma = 0; //Variable para acumulación de conversiones.
set_ADC_channel(canal); //Configurando canal de adquisición.
delay_us(20); //Tiempo de adquisición.
enable_interrupts(INT_AD); //Habilitación interrupción por fin de conversión
for(i=0; i<4; i++) { //Adquisición de 4 muestras.
read_adc(ADC_START_ONLY); //Inicio de conversión.
sleep(); //Durmiendo al microcontrolador.
suma += read_adc(ADC_READ_ONLY);//Lectura en fin de conversión por interrupción.
delay_ms(1); //Periodo de muestreo.
}
disable_interrupts(INT_AD); //Deshabilitando interrupciones fin conversión.
suma = suma >> 2; //División entre 4 por corrimiento a la derecha.
return suma; //Retorno de función.
} //Fin adquisición.

//Rutina de servicio a la interrupción por fin de conversión del ADC.


//ISR solo para despertar al microcontrolador, sin ninguna operación.

#INT_AD
void int_convertidor(void) {
delay_cycles(1);
}

//Programa principal.

void main ( ) {
int channel; //Variable canal de adquisición.
long resultado; //Variable resultado de conversión en 10 bits.

Armando Mora Campos 107


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

inicializar(); //Inicialización dispositivo.


while(TRUE) { //Superlazo.
channel = portc & 0b00000111; //Definición del canal de adquisición.
resultado = adquisicion(channel);//Llamada a función de adquisición y lectura de resultado.
portb = resultado; //Escritura de la parte baja del resultado en puerto B.
portd = resultado >> 8; //Corrimiento y escritura de parte alta del resultado en PD
} //Fin while.
} //Fin main.

Armando Mora Campos 108


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

14.EJEMPLOS RTOS COOPERATIVO.


//Ejemplo 1-RTOS. PUERTOS PARALELOS.
//Generar una señal cuadrada con un ciclo de trabajo del 50%, periodo de 10 ms y que se
//presente en todos los pines del puerto B. Realizarlo en base al RTOS cooperativo del
//compilador C PCW de CCS.

//DIRECTIVAS.

#include <16F887.h> //Dispositivo y constantes generales.(pag. 57).


#fuses XT,NOWDT,NOPROTECT,PUT //Fusibles de configuración (pag. 31).
#use delay(clock=4000000) //Base de tiempo para retardos (pag. 17).
#use rtos(timer=0,minor_cycle=5ms) //Declaración del manejo del Kernel.
#use fast_io(B) //Manejo normal del puerto (pag. 13).
#byte portb = 0x06 //Direccion del puerto B (pag. 30).

//PROTOTIPOS DE TAREAS Y FUNCIONES.

//Tarea de conmutación del puerto B.


#task(rate=5ms,max=1ms)
void conmutacion_PB();

//Inicialización.
void inicializar();

//PROGRAMA PRINCIPAL.

void main(void) { //Inicio programa principal.


inicializar(); //Llamada a la funcion de inicialización.
rtos_run(); //Ejecución del kernel.
} //Fin programa principal.

//TAREAS Y FUNCIONES.

//Tarea de conmutación del puerto B.


void conmutacion_PB() {
portb = ~portb; //Complemento del puerto B.
} //Fin función de tarea.

//Función de inicialización.
void inicializar() {
portb = 0x00; //Valor inicial del puerto B.
set_tris_b(0x00); //Pines del puerto B como salida (pag. 13).
} //Fin inicializar.

Armando Mora Campos 109


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 2-RTOS. PUERTOS PARALELOS. Primera versión (uso de retardos).


//Generar una señal cuadrada con un ciclo de trabajo del 30%, periodo de 350 us y que se
//presente en todos los pines de todos los puerto (A,B,C,D,E). Utilizar el kernel del
//compilador PCW de CCS.
//Nota: Este programa utiliza la función delay_us() para realizar el ciclo de trabajo solicitado.
// Aun cuando es valido, se debe evitar el uso de retardos, ya que en su ejecución el
// microprocesador no efectua un trabajo util. Para la realización de retardos, preferir
// contar ticks, utilizando las funciónes rtos_await() o rtos_yield().

//DIRECTIVAS.

#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales (pag. 57).


#fuses XT,NOWDT,NOPROTECT,PUT //Fusibles de configuración de hardware (pag. 31).

#use delay(clock=4000000) //Base de tiempo para retardos (pag. 17).


#use rtos(timer=0,minor_cycle=350us) //Declaración del uso del Kernel.

#use fast_io(A) //Directivas para el manejo normal de puertos (pag. 13).


#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)

#byte porta = 0x05 //Apuntando con una constante a la dirección de cada puerto (pag. 30).
#byte portb = 0x06
#byte portc = 0x07
#byte portd = 0x08
#byte porte = 0x09

//PROTOTIPOS DE TAREAS Y FUNCIONES.

#task(rate=350us,max=350us)
void control_puertos();

void inicializar();

//PROGRAMA PRINCIPAL.

void main() { //Inicio programa principal.


inicializar(); //Llamada a la función de inicializar.
rtos_run(); //Ejecución multitarea.
} //Fin main.

//TAREAS Y FUNCIONES.

Armando Mora Campos 110


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Tarea de control de puertos.


void control_puertos() {
porta = 0xff; //Salidas 1's en todos los puertos.
portb = 0xff;
portc = 0xff;
portd = 0xff;
porte = 0xff;
delay_us(105); //Retardo 30% ciclo de trabajo

porta = 0x00; //Salidas 0's en todos los puertos.


portb = 0x00;
portc = 0x00;
portd = 0x00;
porte = 0x00;
delay_us(245); //Retardo 70% ciclo de trabajo.
} //Fin tarea.

//Función de inicialización.
void inicializar() {
setup_port_a(NO_ANALOGS); //Config. del puerto A (Todas digitales, pag. 13)
porta = 0x00; //Valor inicial puerto A.
set_tris_a(0x00); //Configurando pines como salida (pag. 13).

portb = 0x00; //Valor inicial puerto B.


set_tris_b(0x00); //Configurando pines como salida.

portc = 0x00; //Valor inicial puerto C.


set_tris_c(0x00); //Configurando pines como salida.

portd = 0x00; //Valor inicial puerto D.


set_tris_d(0x00); //Configurando pines como salida.

porte = 0x00; //Valor inicial puerto E.


set_tris_e(0x00); //Configurando pines como salida.
} //Fin inicializar.

Armando Mora Campos 111


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 2-RTOS. PUERTOS PARALELOS. Segunda versión (uso rtos_yield()).


//Generar una señal cuadrada con un ciclo de trabajo del 30%, periodo de 350 us y que se
//presente en todos los pines de todos los puerto (A,B,C,D,E). Utilizar el kernel del
//compilador PCW de CCS.
//Nota: para lograr el mayor acercamiento a los tiempos solicitados, sin utilizar la función de
// retardo, se utiliza un cristal de 20 MHz.

//DIRECTIVAS.

#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales (pag. 57).


#fuses XT,NOWDT,NOPROTECT,PUT //Fusibles de configuración de hardware (pag. 31).

#use delay(clock=20000000) //Base de tiempo para retardos (pag. 17).


#use rtos(timer=0,minor_cycle=35us) //Declaración del uso del Kernel.

#use fast_io(A) //Directivas para el manejo normal de puertos (pag. 13).


#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)

#byte porta = 0x05 //Apuntando con una constante a la dirección de cada puerto (pag. 30).
#byte portb = 0x06
#byte portc = 0x07
#byte portd = 0x08
#byte porte = 0x09

//PROTOTIPOS DE TAREAS Y FUNCIONES.

#task(rate=35us,max=10us)
void control_puertos();

void inicializar();

//PROGRAMA PRINCIPAL.

void main() { //Inicio programa principal.


inicializar(); //Llamada a la función de inicializar.
rtos_run(); //Ejecución multitarea.
} //Fin main.

//TAREAS Y FUNCIONES.

//Tarea de control de puertos.


void control_puertos() {

Armando Mora Campos 112


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

porta = 0xff; //Salidas 1's en todos los puertos.


portb = 0xff;
portc = 0xff;
portd = 0xff;
porte = 0xff;

rtos_yield(); //Esperar 3 ticks antes de continuar:


rtos_yield(); //3 * 35 us = 105 us = 30% del periodo de 350 us.
rtos_yield();

porta = 0x00; //Salidas 0's en todos los puertos.


portb = 0x00;
portc = 0x00;
portd = 0x00;
porte = 0x00;

rtos_yield(); //Esperar 7 ticks antes de continuar (6 ticks con rtos_yield


rtos_yield(); //y un tick al volver a conmutar los puertos):
rtos_yield(); //7 * 35 us = 245 us = 70% del periodo de 350 us.
rtos_yield();
rtos_yield();
rtos_yield();
} //Fin tarea.

//Función de inicialización.
void inicializar() {
setup_port_a(NO_ANALOGS); //Config. del puerto A (Todas digitales, pag. 13)
porta = 0x00; //Valor inicial puerto A.
set_tris_a(0x00); //Configurando pines como salida (pag. 13).

portb = 0x00; //Valor inicial puerto B.


set_tris_b(0x00); //Configurando pines como salida.

portc = 0x00; //Valor inicial puerto C.


set_tris_c(0x00); //Configurando pines como salida.

portd = 0x00; //Valor inicial puerto D.


set_tris_d(0x00); //Configurando pines como salida.

porte = 0x00; //Valor inicial puerto E.


set_tris_e(0x00); //Configurando pines como salida.
} //Fin inicializar.

Armando Mora Campos 113


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 2-RTOS. PUERTOS PARALELOS. Tercera versión (uso rtos_await()).


//Generar una señal cuadrada con un ciclo de trabajo del 30%, periodo de 350 us y que se
//presente en todos los pines de todos los puerto (A,B,C,D,E). Utilizar el kernel del
//compilador PCW de CCS.
//Nota: para lograr el mayor acercamiento a los tiempos solicitados, se utiliza un
// cristal de 20 MHz.

//DIRECTIVAS.

#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales (pag. 57).


#fuses XT,NOWDT,NOPROTECT,PUT //Fusibles de configuración de hardware (pag. 31).

#use delay(clock=20000000) //Base de tiempo para retardos (pag. 17).


#use rtos(timer=0,minor_cycle=35us) //Declaración del uso del Kernel.

#use fast_io(A) //Directivas para el manejo normal de puertos (pag. 13).


#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)

#byte porta = 0x05 //Apuntando con una constante a la dirección de cada puerto (pag. 30).
#byte portb = 0x06
#byte portc = 0x07
#byte portd = 0x08
#byte porte = 0x09

//PROTOTIPOS DE TAREAS Y FUNCIONES.

#task(rate=35us,max=10us)
void control_puertos();

void inicializar();

//PROGRAMA PRINCIPAL.

void main() { //Inicio programa principal.


inicializar(); //Llamada a la función de inicializar.
rtos_run(); //Ejecución multitarea.
} //Fin main.

//TAREAS Y FUNCIONES.

//Tarea de control de puertos.


void control_puertos() {

Armando Mora Campos 114


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

static int8 contador_ticks; //Variable local, contador de ticks.

contador_ticks = 0; //Inicialización contador.


porta = 0xff; //Salidas 1's en todos los puertos.
portb = 0xff;
portc = 0xff;
portd = 0xff;
porte = 0xff;
rtos_await(++contador_ticks > 3); //Condicion para esperar la duración de 3 ticks.
//Mientras, otras tareas se pueden ejecutar.
porta = 0x00; //Salidas 0's en todos los puertos.
portb = 0x00;
portc = 0x00;
portd = 0x00;
porte = 0x00;
rtos_await(++contador_ticks > 9); //Condicion para esperar la duración de 6 ticks.
//Mientras, otras tareas se pueden ejecutar.
} //Fin tarea.

//Función de inicialización.
void inicializar() {
setup_port_a(NO_ANALOGS); //Config. del puerto A (Todas digitales, pag. 13)
porta = 0x00; //Valor inicial puerto A.
set_tris_a(0x00); //Configurando pines como salida (pag. 13).

portb = 0x00; //Valor inicial puerto B.


set_tris_b(0x00); //Configurando pines como salida.

portc = 0x00; //Valor inicial puerto C.


set_tris_c(0x00); //Configurando pines como salida.

portd = 0x00; //Valor inicial puerto D.


set_tris_d(0x00); //Configurando pines como salida.

porte = 0x00; //Valor inicial puerto E.


set_tris_e(0x00); //Configurando pines como salida.
} //Fin inicializar.

Armando Mora Campos 115


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 4-RTOS. Puertos Paralelos. Primera versión (uso rtos_terminate()).


//Generar una señal cuadrada con un ciclo de trabajo del 50%, periodo de 2 s, que se presente
//en todos los pines del puerto B y que sea activada o desactivada por el pin 0 del puerto A
//(PA0).

//Solución:
//Se define una tarea para generar la señal cuadrada y otra tarea para adquirir la entrada de
//control.

//Directivas.
#include <16F887.h>
#fuses XT,NOWDT,NOPROTECT,PUT
#use delay(clock=4000000)
#use rtos(timer=1,minor_cycle=100ms)

#use fast_io(A)
#use fast_io(B)

#byte portA = 0x05


#byte portB = 0x06

#bit PA0 = portA.0

//Prototipos de tareas.
#task(rate=100ms,max=1ms)
void boton_entrada();

#task(rate=1s,max=1ms)
void senal_cuadrada();

//Prototipo de función.
void inicializar();

//Función principal.
void main(){
inicializar();
while(true) {
if (PA0) rtos_run();
portB = 0x00;
}
}

//Tareas.
void boton_entrada() {
if(!PA0) rtos_terminate();

Armando Mora Campos 116


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

void senal_cuadrada(){

portB = ~portB;

//Funciones.
void inicializar() {
setup_adc_ports(NO_ANALOGS);
set_tris_A(0b00111111);
portB = 0x00;
set_tris_B(0x00);
}

Armando Mora Campos 117


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 4-RTOS. Puertos Paralelos. Segunda versión (uso rtos_enable()/rtos_disable()).


//Generar una señal cuadrada con un ciclo de trabajo del 50%, periodo de 2 s, que se presente
//en todos los pines del puerto B y que sea activada o desactivada por el pin 0 del puerto A
//(PA0).

//Solución:
//Se define una tarea para generar la señal cuadrada y otra tarea para adquirir la entrada de
//control.

//Directivas.
#include <16F887.h>
#fuses XT,NOWDT,NOPROTECT,PUT
#use delay(clock=4000000)
#use rtos(timer=1,minor_cycle=100ms)

#use fast_io(A)
#use fast_io(B)

#byte portA = 0x05


#byte portB = 0x06

#bit PA0 = portA.0

//Prototipos de tareas.
#task(rate=100ms,max=1ms)
void boton_entrada();

#task(rate=1s,max=1ms)
void senal_cuadrada();

//Prototipo de función.
void inicializar();

//Función principal.
void main(){
inicializar();
rtos_run();
}

//Tareas.
void boton_entrada() {
if(!PA0) {
rtos_disable(senal_cuadrada);
portB = 0;
}

Armando Mora Campos 118


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

else rtos_enable(senal_cuadrada);
}

void senal_cuadrada(){
portB = ~portB;
}

//Funciones.
void inicializar() {
setup_adc_ports(NO_ANALOGS);
set_tris_A(0b00111111);
portB = 0x00;
set_tris_B(0x00);
}

Armando Mora Campos 119


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 5-RTOS. Puertos Paralelos.


//Realizar la misma función del ejemplo 4-RTOS, agregando la protección del Watch-Dog.

//Solución:
//Se define una tarea para generar la señal cuadrada y otra tarea para adquirir la entrada de
//control. En la directiva de fusibles se habilita el WDT, y en la función de inicialización
//se configura el mismo para un tiempo fuera de 144 ms. En la tarea de adquisición de la

//entrada de control se incluye la instrucción de limpieza del WDT, para ejecutarse cada 100
//ms (tasa de la tarea) cuando opera el RTOS. Tambien se limpia el WDT en las funciones de
//inicialización y principal.

//Directivas.
#include <16F887.h>
#fuses XT,WDT,NOPROTECT,PUT
#use delay(clock=4000000,RESTART_WDT)
#use rtos(timer=1,minor_cycle=100ms)

#use fast_io(A)
#use fast_io(B)

#byte portA = 0x05


#byte portB = 0x06

#bit PA0 = portA.0

//Prototipos de tareas.
#task(rate=100ms,max=1ms)
void boton_entrada();

#task(rate=1s,max=1ms)
void senal_cuadrada();

//Prototipo de función.
void inicializar();

//Función principal.
void main(){
inicializar();
while(true) {
if (PA0) rtos_run();
portB = 0x00;
restart_wdt();
}
}

Armando Mora Campos 120


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Tareas.
void boton_entrada() {
restart_wdt();
if(!PA0) rtos_terminate();
}

void senal_cuadrada(){
portB = ~portB;
}

//Funciones.
void inicializar() {
restart_wdt();
setup_wdt(WDT_144MS);
setup_adc_ports(NO_ANALOGS);
set_tris_A(0b00111111);
portB = 0x00;
set_tris_B(0x00);
}

Armando Mora Campos 121


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 6-RTOS. PUERTOS PARALELOS.


//Un motor de pasos de cuatro terminales de control gira en un sentido al aplicarle la siguiente
//secuencia hexadecimal: 1,5,4,6,2,A,8,9.
//Hacer un programa que haga girar el motor a una velocidad constante, con un tiempo entre
//pasos de 10 ms. Considerar un pin de arranque-paro del motor y la proteccion del Watch
//Dog.

//Solucion: se utiliza la parte baja del puerto B para activar el motor y el pin 0 del puerto E
//como control ON/OFF del motor. Se programan dos tareas. La primera controla la secuencia
del
//motor y la segunda la lectura del pin de encendido/apagado. Se utilizan las funciones de
//habilitación y deshabilitación del RTOS.

//Directivas.
#include <16F887.h>
#fuses XT,WDT,NOPROTECT,PUT
#use delay(clock=4000000,RESTART_WDT)
#use rtos(timer=1,minor_cycle=10ms)

#use fast_io(B)
#use fast_io(E)
#byte portB = 0x06
#byte portE = 0x09
#bit PE0 = portE.0

//Variables y constantes globales.


byte const pasos[8] = {0x01,0x05,0x04,0x06,0x02,0x0a,0x08,0x09};

//Prototipos de tareas.
#task(rate=100ms,max=1ms)
void boton_entrada();

#task(rate=10ms,max=1ms)
void control_motor();

//Prototipo de función.
void inicializar();

//Función principal.
void main(){
inicializar();
rtos_run();
}

//Tareas.

Armando Mora Campos 122


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

void boton_entrada() {
restart_wdt();
if(PE0) rtos_enable(control_motor);
else {
rtos_disable(control_motor);
portB = 0x00;
}
}

void control_motor(){
static int i;
portB = pasos[i++];
if (i > 7) i = 0;
}

//Funciones.
void inicializar() {
restart_wdt();
setup_wdt(WDT_144MS);
portB = 0x00;
set_tris_B(0x00);
setup_adc_ports(NO_ANALOGS);
portE = 0x00;
set_tris_E(0b00001111);
}

Armando Mora Campos 123


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 7-RTOS. PUERTOS PARALELOS.


//Incluir en el ejemplo 6-RTOS una entrada para el control de la direccion de giro del motor a
//pasos.

//Solucion: se utilizara la parte baja del puerto B para activar el motor, del puerto E el pin 0
//como control ON/OFF del motor y el pin 1 como control de direccion de giro.

//Directivas.
#include <16F887.h>
#fuses XT,WDT,NOPROTECT,PUT
#use delay(clock=4000000,RESTART_WDT)
#use rtos(timer=1,minor_cycle=10ms)

#use fast_io(B)
#use fast_io(E)
#byte portB = 0x06
#byte portE = 0x09
#bit PE0 = portE.0
#bit PE1 = portE.1

//Variables y constantes globales.


byte const pasos[8] = {0x01,0x05,0x04,0x06,0x02,0x0a,0x08,0x09};

//Prototipos de tareas.
#task(rate=100ms,max=1ms)
void boton_entrada();

#task(rate=10ms,max=1ms,queue=2)
void control_motor();

//Prototipo de función.
void inicializar();

//Función principal.
void main(){
inicializar();
rtos_run();
}

//Tareas.
void boton_entrada() {
restart_wdt();
if(PE0) {
rtos_enable(control_motor);
if(PE1) rtos_msg_send(control_motor, 0x00);

Armando Mora Campos 124


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

else rtos_msg_send(control_motor, 0x01);


}
else {
rtos_disable(control_motor);
portB = 0x00;
}
}

void control_motor(){
static int i, dir;
if(rtos_msg_poll() > 0) dir = rtos_msg_read();
if (dir == 0x00) {
portB = pasos[i++];
if (i > 7) i = 0;
}
else {
portB = pasos[--i];
if (i == 0) i = 8;
}
}

//Funciones.
void inicializar() {
restart_wdt();
setup_wdt(WDT_144MS);
portB = 0x00;
set_tris_B(0x00);
setup_adc_ports(NO_ANALOGS);
portE = 0x00;
set_tris_E(0b00001111);
}

Armando Mora Campos 125


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 8-RTOS. PUERTOS PARALELOS.


//Incluir en el ejemplo 7-RTOS el control de la velocidad de giro del motor de pasos utilizando
//un puerto de 8 bits para tener 256 valores diferentes de velocidad.

//Solucion: se utiliza la parte baja del puerto B para activar el motor, el puerto C como entrada
//de velocidad y del puerto E el pin 0 como control ON/OFF del motor y el pin 1 como control
//de direccion de giro.

//Directivas.
#include <16F887.h>
#fuses XT,WDT,NOPROTECT,PUT
#use delay(clock=4000000,RESTART_WDT)
#use rtos(timer=1,minor_cycle=10ms)

#use fast_io(B)
#use fast_io(C)
#use fast_io(E)
#byte portB = 0x06
#byte portC = 0x07
#byte portE = 0x09
#bit PE0 = porte.0
#bit PE1 = porte.1

//Variables y constantes globales.


byte const pasos[8] = {0x01,0x05,0x04,0x06,0x02,0x0a,0x08,0x09};
int vel;

//Prototipos de tareas.
#task(rate=100ms,max=1ms)
void boton_entrada();

#task(rate=10ms,max=1ms,queue=2)
void control_motor();

//Prototipo de función.
void inicializar();

//Función principal.
void main(){
inicializar();
rtos_run();
}

//Tareas.
void boton_entrada() {

Armando Mora Campos 126


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

restart_wdt();
if(PE0) {
rtos_enable(control_motor);
if(PE1) rtos_msg_send(control_motor, 0x00);
else rtos_msg_send(control_motor, 0x01);
vel = portC;
}
else {
rtos_disable(control_motor);
portB = 0x00;
}
}

void control_motor(){
static int i, dir, contador;
rtos_await(vel == contador++);
contador = 0;
if(rtos_msg_poll() > 0) dir = rtos_msg_read();
if (dir == 0x00) {
portB = pasos[i++];
if (i > 7) i = 0;
}
else {
portB = pasos[--i];
if (i == 0) i = 8;
}
}

//Función.
void inicializar() {
restart_wdt();
setup_wdt(WDT_144MS);
portB = 0x00;
set_tris_B(0x00);
set_tris_C(0xFF);
setup_adc_ports(NO_ANALOGS);
portE = 0x00;
set_tris_E(0b00001111);
}

Armando Mora Campos 127


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 9-RTOS. CONVERSION ANALOGICA/DIGITAL.


//Adquirir una señal analogica de 0 a +5 V conectada en la entrada AN0 y realizar su
//conversión A/D en 10 bits. Exhibir el resultado en un display LCD alfanumérico. Utilizar el
//voltaje Vdd como referencia.

//Solucion.
//Se programan dos tareas, la del ADC y la del exhibidor, que comparten información por
//medio de la variable global "resultado".
//Para la exhibición, se utiliza un display LCD alfanumérico 2x16, conectado al puerto D del
//microcontrolador, utilizando el controlador de software LCD.c que incluye el compilador
//PCW.

//Directivas.
#include <16F887.h>
#device ADC=10
#fuses XT,WDT,NOPROTECT,PUT
#use delay(clock=4000000,RESTART_WDT)
#use rtos(timer=1,minor_cycle=100ms)
#include <LCD.c>

//Variables y constantes globales.


long resultado;

//Prototipos de tareas.
#task(rate=100ms,max=5ms)
void ADC();

#task(rate=300ms,max=5ms)
void LCD();

//Prototipo de función.
void inicializar();

//Función principal.
void main(){
inicializar();
rtos_run();
}

//Tareas.
void ADC() {
resultado = read_adc();
restart_wdt();
}

Armando Mora Campos 128


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

void LCD(){
lcd_gotoxy(1,1);
printf(LCD_PUTC,"resultado = %4lu", resultado);
}

//Funciones.
void inicializar() {
restart_wdt();
setup_wdt(WDT_144MS);
setup_adc_ports(AN0);
set_tris_a(0b00000001);
setup_adc(ADC_CLOCK_INTERNAL);
set_adc_channel(0);
delay_us(50); //Retardo de adquisición.
lcd_init();
}

Armando Mora Campos 129


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 11-RTOS. CONVERSION ANALOGICA/DIGITAL.


//Realizar un programa que exhiba en un display LCD alfanumérico el resultado de
//conversión de una de las señales presentes en los 8 canales de entrada analógica
//del PIC16F887. Utilizar el teclado para seleccionar el canal a desplegar.

//Solucion.
//Se programan tres tareas, para el ADC, exhibidor y teclado. La información del
//resultado de conversión se comparte utilizando la variable global "resultado".
//La información del canal a convertir se intercambia mediante mensajes.
//Para la exhibición, se utiliza un display LCD alfanumérico 2x16, conectado al puerto
//D del microcontrolador, utilizando el controlador de software LCD.c que incluye el
//compilador PICC. El teclado se conecta al puerto B y se utiliza el controlador KBD.c.

//Directivas.
#include <16F887.h>
#device ADC=10
#fuses XT,WDT,NOPROTECT,PUT
#use delay(clock=4000000,RESTART_WDT)
#use rtos(timer=1,minor_cycle=10ms)
#include <LCD.c>
#include <KBD.c>

//Variables y constantes globales.


long resultado;

//Prototipos de tareas.
#task(rate=100ms,max=5ms,queue=2)
void ADC();

#task(rate=300ms,max=5ms,queue=2)
void LCD();

#task(rate=10ms,max=5ms)
void Teclado();

//Prototipo de función.
void inicializar();

//Función principal.
void main(){
inicializar();
rtos_run();
}

//Tareas.

Armando Mora Campos 130


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

void ADC() {
static int channel;
if(rtos_msg_poll()) channel = rtos_msg_read();
set_adc_channel(channel);
delay_us(25);
resultado = read_adc();
rtos_msg_send(LCD,channel);
restart_wdt();
}

void LCD(){
static int canal_adc;
if(rtos_msg_poll()) canal_adc = rtos_msg_read();
lcd_gotoxy(1,1);
printf(LCD_PUTC,"Resultado = %4lu", resultado);
lcd_gotoxy(1,2);
printf(LCD_PUTC,"Canal = %u", canal_adc);
restart_wdt();
}

void Teclado(){
int canal;
char k;
k = kbd_getc();
if(k!='\0' && k!='*' && k!='8'&& k!='9' && k!='#'){
canal = (int)k - 48;
rtos_msg_send(ADC,canal);
}
restart_wdt();
}

//Funciones.
void inicializar() {
restart_wdt();
setup_wdt(WDT_144MS);
setup_adc_ports(AN0);
set_tris_a(0b00000001);
set_adc_channel(0);
setup_adc(ADC_CLOCK_INTERNAL);
port_b_pullups(TRUE);
lcd_init();
kbd_init();
}

Armando Mora Campos 131


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Ejemplo 18-RTOS. Conversión A/D, teclado y exhibidor LCD.


//Utilizando el RTOS cooperativo, realizar un programa que adquiera uno de los 8 canales del
//convertidor A/D (conversión en 10 bits, voltaje de referencia Vdd) y lo exhiba en forma de
//voltaje de 0 a + 5V en un exhibidor LCD alfanumérico. Modificar el canal de adquisición por
//medio de un teclado 4x3.

//Solución:
// Se definen 3 tareas: ADC, LCD y teclado. Para el teclado y exhibidor se utilizan los
//controladores que incluye el compilador PCWH de CCS. Para el convertidor A/D, se utiliza
//el controlador realizado en el ejemplo 19 de superlazo.
//Las conexiones del teclado y exhibidor son:
//Teclado (conectar resistencias de pull-up en los renglones):
//RD1 renglon 0.
//RD2 renglon 1.
//RD3 renglon 2.
//RD4 renglon 4.
//RD5 columna 0.
//RD6 columna 1.
//RD7 columna 2.

//Exhibidor LCD 16x2:


//RB0 E.
//RB1 RS.
//RB2 R/W.
//RB4 D4.
//RB5 D5.
//RB6 D6.
//RB7 D7.

//Dispositivo PIC16F887 con conversión A/D de 10 bits.


#include <16F887.h>
#DEVICE ADC=10

#fuses XT,NOWDT,NOPROTECT
#use delay(clock=4000000)

//Activación de la funcionalidad del RTOS, usando timer 0 y tick = 2 ms.


#use rtos(timer=0,minor_cycle=2ms)

//Controladores de periféricos.
#include <LCD.c>
#include <KBD.c>

#use fast_io(A)
#use fast_io(C)

Armando Mora Campos 132


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

#use fast_io(E)

//Variables globales.
long resultado; //Resultado de conversion A/D.

//Prototipos de tareas.
#task(rate=100ms,queue=2)
void ADC();
#task(rate=50ms,queue=2)
void LCD();
#task(rate=2ms)
void teclado();

//Prototipo de ISR.
#INT_AD
void ISR_convertidor();

//Prototipos de funciones.
void inicializar();
long adquisicion(int canal);

//Función de inicialización.
void inicializar() {
setup_adc_ports(ALL_ANALOG);
set_tris_a(0b11111111);
set_tris_c(0b00000111);
set_tris_e(0b00000111);
lcd_init();
kbd_init();
setup_adc(ADC_CLOCK_INTERNAL);
set_adc_channel(0);
enable_interrupts(GLOBAL);
}

//Controlador del convertidor A/D.


long adquisicion(int canal) {
int i;
long suma = 0;
set_ADC_channel(canal);
delay_us(20);
enable_interrupts(INT_AD);
for(i=0; i<4; i++) {
read_adc(ADC_START_ONLY);
sleep();
suma += read_adc(ADC_READ_ONLY);

Armando Mora Campos 133


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

delay_ms(1);
}
disable_interrupts(INT_AD);
return suma >> 2;
}

//Tarea conversion ADC.


void ADC() {
static int channel = 0;
if(rtos_msg_poll() > 0) channel = rtos_msg_read();
resultado = adquisicion(channel);
rtos_yield();
}

//Tarea exhibidor.
void LCD() {
int canal;
float volts;
if(rtos_msg_poll() > 0) canal = rtos_msg_read();
lcd_gotoxy(1,1);
printf(LCD_PUTC,"canal: %d\n",canal);
volts=(((float)resultado*5)/1024);
lcd_gotoxy(1,2);
printf(LCD_PUTC,"volts: %3.4f",volts);
rtos_yield();
}

//Tarea teclado.
//En el controlador del teclado, definir KBD_DEBOUNCE_FACTOR 3.
void teclado() {
int channel;
char k;
k = kbd_getc();
if (k!='\0' && k!='*' && k!='8' && k!= '9' && k!='#') {
channel = (int) k - 48;
rtos_msg_send(ADC,channel);
rtos_msg_send(LCD, channel);
}
rtos_yield();
}

//ISR para despertar el microcontrolador en fin de conversión A/D.


void ISR_convertidor(){
delay_cycles(1);
}

Armando Mora Campos 134


Guia del Compilador C para Microchip Instituto Tecnológico de Querétaro

//Función principal.
void main(){
inicializar();

//Ejecución del RTOS.


rtos_run();
}

Armando Mora Campos 135

También podría gustarte