Está en la página 1de 6

PROGRAMACIÓN 

MCU´s EN LENGUAJE C  
(CCS  C COMPILER) 
Parte  3 
 
Por:  Miguel Angel Montilla G. 
 
 
 
EEPROM DE DATOS: 
 
ESCRITURA:  LECTURA: 
   
    WRITE_EEPROM(DIRECCIÓN, VALOR)      VALOR= READ_EEPROM(DIRECCIÓN) 
 
 
Si  se  desea  que  al  ensamblar  el  programa,  el  MCU  disponga  de  valores  iniciales  en  su  memoria 
EEPROM, se usa la directiva #ROM, indicando la dirección en la que se desea disponer de un dato, 
teniendo en cuenta que la primer posición de EEPROM se direcciona 0x2100. 
 
Ej:  
  #ROM INT8 0x2100={0X10}    // 10h en dirección 00 
  #ROM INT8 0x2101={127}    // 127d en dirección 01 
  #ROM INT8 0x2102={“A”}     // ‘A’ ASCII en dirección 02 
 
 
 
COMUNICACIÓN SERIAL POR USART (Universal Synchronous Asynchronous Receiver Transmitter): 
 
A nivel lógico, USART es compatible con RS‐232. 
 
Pasos para realizar comunicación serial: 
 
• Se definen los parámetros de comunicación (Identificador, Tasa de Baudios, Pin de Transmisión, 
Pin de Recepción, Paridad, Timeout). 
 
Ej:  2400 bps, Tx: RC6,  Rx: RC7, Sin Paridad, sin Timeout: 
    #use rs232(baud=2400, xmit=PIN_C6, rcv=PIN_C7)     
 
• Para transmitir un dato se usa la instrucción Putc(Dato), para transmitir una cadena de texto se 
usa Printf(“Texto”). 
 
• Para  recibir  un  dato,  primero  se  averigua  si  hay  un  dato  disponible  mediante  la  instrucción 
Kbhit(), que toma el valor true en ese caso. Luego, mediante Getc() o Gets() se lee un dato o una 
cadena de texto respectivamente. 
 
 
 
 
EJEMPLO: 
 
Realizar un programa para un 16F877A que transmita por puerto serie cada 20ms el contenido de la 
variable  ‘DatoTx’.  Adicionalmente,  el  programa  debe  verificar  de  forma  continua  si  se  recibe  un 
dato por puerto serie y en caso de que así sea, éste debe almacenarse en la variable ‘DatoRx’. 
 
 
 
///////////////////////////////////////////////////////////////////////////////////////// 
//                    // 
//    EJEMPLO DE TRANSMISIÓN Y RECEPCIÓN SERIAL      // 
//                    // 
///////////////////////////////////////////////////////////////////////////////////////// 
 
#include <16F877A.h>   
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT 
#use delay(clock=4000000) 
 
#use rs232(baud=2400, xmit=PIN_C6, rcv=PIN_C7)    // Se definen los parámetros de comunicación 
 
int8 DatoTx, DatoRx; 
 
//  PROGRAMA PRINCIPAL 
void main() { 
  while (true){ 
    delay_ms(20); 
    putc(DatoTx);      // Transmisión de DatoTx 
    if(kbhit()){      // Preguntamos si hay disponible dato en bufer de recepción. 
      DatoRx= getc();    // Si así es, lo leemos y guardamos en DatoRx. 
    } 
  } 

 
 
 
 
 
 
 
INTERRUPCIONES 
 
Los  diferentes  recursos  y  periféricos  en  cualquier  MCU,  se  pueden  manejar  normalmente  por 
interrupción. En este caso, se ordena al procesador iniciar el trabajo con un módulo dado y, cuando 
éste termine saltará a ejecutar una rutina preestablecida. 
 
Para el caso de los MCU’s de la serie 16F87X, la arquitectura de interrupciones está dada por: 
 
 

 
 
 
Cuando un módulo termina su labor, se encarga de levantar la bandera de interrupción ‘XXIF’, sin 
embargo,  esto  no  garantiza  que  se  ejecute  una  rutina  de  atención  a  interrupción.  Para  que  se 
genere  la  interrupción,  es  necesario  que  la  bandera  de  habilitación  de  interrupción  del  módulo 
(XXIE)  esté  activa  y,  que  la  bandera  de  habilitación  global  (GIE)  esté  activa  y  para  los  periféricos 
además, ‘PEIE’ debe estar activa. 
 
 
 
 
La  manera  más  general  de  trabajar  en  el  compilador  cualquier  recurso  o  periférico,  corresponde 
con el siguiente esquema: 
 
SETUP_MODULO(Parámetros)   :  Permite configurar un módulo del MCU.  
Los nombres de estos parámetros están disponibles en 
el archivo .h de cada procesador. 
 
SET_MODULO(valor)     :  Ajusta valor específico del módulo. 
CLEAR_INTERRUPT(MODULO)  :  Borra flag de interrupción del módulo (XXIF). 
ENABLE_INTERRUPTS(MODULO)  :  Habilita Interrupción del módulo (XXIE). 
DESABLE_INTERRUPTS(MODULO)  :  Deshabilita Interrupción del módulo (XXIE). 
ENABLE_INTERRUPTS(GLOBAL)  :  Habilita Interrupciones globales (GIE, PEIE). 
 
 
 
RUTINA ATENCIÓN A INTERRUPCIÓN (ISR): 
 
#INT_MODULO 
void NombreDeseado(){ 
  Sentencias; 

 
En algunos casos se requiere una directiva de tipo: 
  #USE MODULO(Parámetros) 
 
 
 
 
 
MÓDULOS TEMPORIZADORES/CONTADORES: 
 
Es  común  en  los  MCU´s  encontrar  módulos  que  se  encargan  de  llevar  de  forma  autónoma  un 
conteo de ciclos máquina o, de pulsos que entran por ciertos pines específicos. A estos módulos se 
les denomina Timers.  
 
Para el caso de la familia 16F87XA, se cuenta con tres Timers (Timer0 o RTCC, Timer1 y Timer2). 
 
Una descripción resumida de los tres Timers se presenta en la tabla siguiente: 
 
TIMER0  TIMER1  TIMER2 
• Temp/contador de 8 bits. 
• Flanco externo  Temporizador/contador de 16 
Temporizador de 8 bits 
seleccionable en modo  bits. 
contador. 
Pin de entrada de pulsos:  RA4  Pin de entrada de pulsos:  RC0  Periodo programable (0 a 255) 
Modos de trabajo:  Modos Básicos de trabajo:  Post‐escalador (post‐divisor) 
RTCC_INTERNAL  T1_DISABLED  de la frecuencia de reloj 
RTCC_EXT_L_TO_H  T1_INTERNAL  programable: 
RTCC_EXT_H_TO_L  T1_EXTERNAL   Cualquier número entre 0 y 16 
Prescalador (predivisor) de la  Prescalador (predivisor) de la  Prescalador (predivisor) de la 
frecuencia de reloj  frecuencia de reloj  frecuencia de reloj 
programable:  programable:  programable: 
RTCC_DIV_2,         RTCC_DIV_4,  T1_DIV_BY_1   T2_DISABLED 
RTCC_DIV_8,         RTCC_DIV_16,  T1_DIV_BY_2    T2_DIV_BY_1 
RTCC_DIV_32,       RTCC_DIV_64,  T1_DIV_BY_4    T2_DIV_BY_4 
RTCC_DIV_128,     RTCC_DIV_256  T1_DIV_BY_8  T2_DIV_BY_16
Funcionamiento General: 
Funcionamiento General:  Funcionamiento General:  El valor del Timer se 
El valor del Timer se  El valor del Timer se  incrementa cada ‘predivisor’ 
incrementa cada ‘predivisor’  incrementa cada ‘predivisor’  pulsos externos o CM. El 
pulsos externos o CM.   pulsos externos o CM.  conteo se reinicia cada 
´periodo+1’ incrementos. 
Genera interrupción si el valor  Genera interrupción al pasar  Genera interrupción cada 
del Timer pasa de 0xFF a 0x00  de 0xFFFF a 0x0000   ‘postdivisor’ conteos.  
Nombre Interrupción:  Nombre Interrupción:  Nombre Interrupción: 
INT_TIMER0  INT_TIMER1 INT_TIMER2 
Número de Pulsos o Ciclos  Número de Pulsos o Ciclos 
Si el valor inicial del Timer es 0: 
Máquina necesarios para  Máquina necesarios para 
 
generar interrupción:  generar interrupción: 
N= (Periodo+1)*Prediv*PosDiv 
  N= (256‐ValIniTimer)*Prediv  N= (65536‐ValIniTimer)*Prediv
 
 
Ejercicios: 
 
1. (a) Cuál es el mayor número de pulsos externos o ciclos máquina que podría contabilizarse de 
forma directa con cada Timer. (b) Con cristal de 4Mhz, a cuánto tiempo equivalen los resultados 
anteriores. 
 
2. Si se desea implementar una temporización de 50ms y se dispone de un cristal de 4MHz, cuáles 
serían los valores de configuración para cada Timer (Prediv, Valor Inicial, Postdiv, Periodo). 
 
 
 
Pasos para realizar una temporización con Timer: 
 
1. Realizar los cálculos de los valores de configuración, como se hizo en el ejercicio pasado. 
2. Configurar el módulo: 
setup_timer_0(Modo|Predivisor)  ‐    setup_timer_1(Modo|Predivisor) 
setup_timer_2(Predivisor,Periodo,PosDivisor) 
 
3. Inicializar el valor del Timer: 
    set_timer0(ValorInicialTimer)       ‐  set_timer1(ValorInicialTimer) 
    set_timer2(0) 
 
4. Borrar la bandera de interrupción del módulo: 
clear_interrupt(INT_TIMERx) 
 
5. Si se desea, se habilita interrupción: 
enable_interrupts(INT_TIMER0)             enable_interrupts(GLOBAL) 
 
6. En caso de trabajar por interrupción, en la rutina de atención a interrupción se hace el segmento de 
programa que se desea ejecutar cuando el módulo termina la temporización. Adicionalmente, aquí 
es necesario volver a asignar el valor inicial del Timer, en caso de que éste sea diferente de cero. 
 
7. En cualquier momento se puede obtener el valor de un Timer, mediante la instrucción get_timerX().  
Ej.  Val= get_timer1() 
 
 

EJEMPLO: 
Atender el timer0 por interrupción, cada 1 ms en un PIC 16F877A con XT= 4MHz. 
 
//  Encabezado 
... 
// Otras funciones 
... 
#INT_TIMER0 
void INTERRUPCION_1ms(){    // Atención a interrupción cada 1 ms 
     SET_TIMER0(6); 
     // Atención a interrupción 
 } 
void main(){ 
  ... 
  // Sentencias; 
  ... 
  setup_timer_0(RTCC_INTERNAL | RTCC_DIV_4);   
     SET_TIMER0(6); 
     clear_interrupt(INT_TIMER0);   
     enable_interrupts(INT_TIMER0); 
     enable_interrupts(GLOBAL);   
 
  while(true){ 
    Sentencias; 
  } 

También podría gustarte