Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Apuntes PIC C 2017 PDF
Apuntes PIC C 2017 PDF
INDICE
1. FORMATO GENERAL DE UN PROGRAMA ............................................................... 4
5. EXPRESIONES................................................................................................................. 11
i) Funciones (ejemplos).
En forma de archivos include:
#include <ds1621.c>
#include <salida.c>
float READ_FLOAT_CAL(int n) {
int i;
float data;
for (i = 0; i < 4; i++)
*(&data + i) = READ_CALIBRATION(i + n);
return(data);
}
#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
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) {
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 );
}
}
Donde:
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
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.
Struct and union Formato: struct [id] [ type-qualifier [[*] id :cexpr [cexpr ]]]
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;
3. DEFINICION DE FUNCIONES.
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);
}
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.
|| 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.
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.
//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.
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’);
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.
//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
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.
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.
rotate_right(&cells,2);
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( );
}
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.
float ceil(float x); //Calcula elvalor integral mas pequeño no mas grande que
//x.
float floor(float x); //Calcula el valor integral mas pequeño no mas grande
//que x.
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.
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);
adc_handler() {
adc_active = FALSE;
}
8. DIRECTIVAS MISCELANEAS.
#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.
#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.
#pragma cmd //Directiva utilizada para que otras directivas mantengan compatibilidad
//entre diferentes compiladores C.
#pragma inline //Ejemplo.
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.
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:
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.
#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 ( );
#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( );
}
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();
}
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
#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)
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().
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;
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.
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
#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);
}
//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.
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
#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;
delay_ms(1);
RED = 1;
}
rtos_signal(sem);
//rtos_yield ( );
}
void main ( ) {
portB = 0x00;
set_tris_B(0B11011111);
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++;
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 ( ) {
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
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,statistics)
#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);
//rtos_yield();
}
}
void main ( ) {
rtos_run ( );
}
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.
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.
#include <16F887.h>
#use delay(clock=4000000)
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
#use rtos(timer=1,minor_cycle=100ms)
#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);
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 ( );
input_ready=FALSE;
index=0;
}
}
void main ( ) {
portB = 0x00;
set_tris_B(0B11001111);
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;
}
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:
if ( !input(PIN_B0) ) y no if ( input(PIN_B0) == 0)
└─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).
└─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
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
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.
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.
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:
x = table [i];
x = table [5];
pero no
ptr = 2 table[i]
Construcciones similares utilizando CONST pueden ser utilizadas con cualquier tipo de dato
incluyendo estructuras, longs y floats.
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
#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
#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
////////////////////////////////////////////////////////////////// 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
#define T0_8_BIT 0
////////////////////////////////////////////////////////////////// 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
////////////////////////////////////////////////////////////////// Timer 1
// Timer 1 Functions: SETUP_TIMER_1, GET_TIMER1, SET_TIMER1
// Constants used for SETUP_TIMER_1() are:
#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
////////////////////////////////////////////////////////////////// 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
////////////////////////////////////////////////////////////////// UART
// Constants used in setup_uart() are:
// FALSE - Turn UART off
// TRUE - Turn UART on
#define UART_ADDRESS 2
#define UART_DATA 4
#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:
//
////////////////////////////////////////////////////////////////// VREF
// Constants used in setup_vref() are:
//
#define VREF_LOW 0xa0
#define VREF_HIGH 0x80
// Or (with |) the above with a number 0-15
////////////////////////////////////////////////////////////////// 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
////////////////////////////////////////////////////////////////// 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
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).
#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( ) {
set_tris_b(0b00000000);//Configurando todos los pines del puerto B como salida (pag. 13).
} //Fin inicializar.
//Programa principal.
void main( ) { //Inicio programa principal.
} //Fin while.
//Directivas.
#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales (pag. 57).
#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( ) {
} //Fin inicializar.
//Programa principal.
void main( ) { //Inicio programa principal.
//Directivas.
#include <16F887.h> //Especificando dispositivo a utilizar y constantes generales (pag. 57).
#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( ) {
} //Fin inicializacion.
//Programa principal.
void main( ) { //Inicio programa principal.
}; //Fin for.
} //Fin programa principal.
//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.
else {
portb = 0x00;
} //Fin else.
} //Fin while.
} //Fin main.
//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).
#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.
else {
portb = 0x00;
} //Fin else.
//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.
#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).
} //Fin inicializar.
//Programa principal.
void main( ) { //Inicio programa principal.
int i; //Variable del for, 8 bits sin signo.
} //Fin while.
} //Fin main.
//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.
#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).
//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.
} //Fin while.
} //Fin main.
//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.
#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).
//Programa principal.
} //Fin while.
} //Fin main.
#byte portb = 0x06 //Apuntando con una constante a la direccion de puerto (pag. 30).
//Funcion de inicializacion.
void inicializar( ) {
//Programa principal.
#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).
//Programa principal.
} //Fin while.
} //Fin main.
//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.
#byte portb = 0x06 //Apuntando con una constante a la direccion de puertos (pag. 30).
#byte portc = 0x07
//Funcion de inicializacion.
void inicializar( ) {
//Programa principal.
int canal; //Variable de 8 bits sin signo para seleccion canal (pag. 7).
canal = portc & 0b00000111; //Enmascarando primeros 3 bits pto. C (pag. 11).
} //Fin while.
} //Fin main.
//Directivas.
#byte portb = 0x06 //Apuntando con una constante a la direccion de puertos (pag. 30).
#byte portc = 0x07
#byte portd = 0x08
//Funcion de inicializacion.
void inicializar( ) {
//Programa principal.
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).
} //Fin while.
} //Fin main.
#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
//Funcion de inicializacion.
void inicializar( ) {
enable_interrupts(GLOBAL);
} //Fin inicializar.
//Programa principal.
} //Fin while.
} //Fin programa principal.
//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).
void inicializar( ) {
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).
//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.
//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.
#use delay (clock=4000000) //Base de tiempo para retardos y para la comunicacion serie
//asincrona.
#byte portb = 0x06 //Apuntando con una constante a la direccion de puerto (pag. 30).
#byte portc = 0x07
void inicializar( ) {
} //Fin inicializar.
} //Fin if.
} //Fin while.
} //Fin main.
//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.
//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.
} //Fin if.
} //Fin if.
} //Fin while.
} //Fin main.
//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).
//donde:
// Kp = K - KT/2Ti = Ganancia proporcional (controlador digital).
// Ki = KT/Ti = Ganancia integral.
// Kd = KTd/T = Ganancia derivativa.
//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:
//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.
#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() {
void adquisicion_datos() {
} //Fin adquisicion.
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.
else m1 = salida_PID;
//Funcion principal.
} //Fin while.
} //Fin main.
//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:
//Directivas.
//Funcion de inicializacion.
void inicializar() {
//Esta funcion no altera la informacion que se maneja en los pines PB4 a PB7 (solo actua en la
//parte baja del puerto B).
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.
} //Fin for.
} //Fin driver_MP
//Funcion principal.
void main() {
} //Fin while.
} //Fin main.
//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
//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 %.
//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
//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.
//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.
//VARIABLES GLOBALES.
//FUNCION DE INICIALIZACION..
void ecuacion() {
salida = (A * entrada * entrada) – (B * entrada) + C;
}
//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.
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() {
} //Fin main.
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.
//Directivas.
//Funcion de inicializacion.
void inicializar(void) {
//(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.
#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.
//DIRECTIVAS.
//Inicialización.
void inicializar();
//PROGRAMA PRINCIPAL.
//TAREAS Y FUNCIONES.
//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.
//DIRECTIVAS.
#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
#task(rate=350us,max=350us)
void control_puertos();
void inicializar();
//PROGRAMA PRINCIPAL.
//TAREAS Y FUNCIONES.
//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).
//DIRECTIVAS.
#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
#task(rate=35us,max=10us)
void control_puertos();
void inicializar();
//PROGRAMA PRINCIPAL.
//TAREAS Y FUNCIONES.
//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).
//DIRECTIVAS.
#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
#task(rate=35us,max=10us)
void control_puertos();
void inicializar();
//PROGRAMA PRINCIPAL.
//TAREAS Y FUNCIONES.
//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).
//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)
//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();
void senal_cuadrada(){
portB = ~portB;
//Funciones.
void inicializar() {
setup_adc_ports(NO_ANALOGS);
set_tris_A(0b00111111);
portB = 0x00;
set_tris_B(0x00);
}
//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)
//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;
}
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);
}
//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)
//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();
}
}
//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);
}
//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
//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.
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);
}
//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
//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);
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);
}
//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
//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);
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);
}
//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>
//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();
}
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();
}
//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>
//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.
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();
}
//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.
#fuses XT,NOWDT,NOPROTECT
#use delay(clock=4000000)
//Controladores de periféricos.
#include <LCD.c>
#include <KBD.c>
#use fast_io(A)
#use fast_io(C)
#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);
}
delay_ms(1);
}
disable_interrupts(INT_AD);
return suma >> 2;
}
//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();
}
//Función principal.
void main(){
inicializar();