PicManía by RedRaven
 

Búsqueda personalizada

 

TEORÍA Y PRAXIS DE
 LAS COMUNICACIONES TTL

 
 

Hablando con el PIC hasta por los codos usando su USART.

Desde la mas simple emisión o recepción de un sólo carácter por el PIC, con o sin el uso de interrupciones, hasta el tratamiento de búferes lineales o cíclicos, comandos de control simples o complejos, unidireccionales o interactivos, y que incluyen parámetros de todo tipo, color y sabor.

 

 
 A modo de Índice:
 
 
Introducción Qué vamos a hacer.
 
El mas simple "echo" Menos no se puede.
 
Un  "echo" interrupto  (mediante la interrupción por recepción serie) Solo cuando llega algo.
 
Comandos de un solo carácter ¡Esto ya hace cosas!
 
Recibiendo sobre un Buffer. 1ª Parte Complicando, que es gerundio
 
 

 


 

  Introducción
 
 

   Una y otra vez vemos consultas, consultas y consultas sobre este tema ...

   Desde la mas simple emisión o recepción de un sólo carácter por el PIC, con o sin el uso de interrupciones, hasta el tratamiento de búferes lineales o cíclicos, comandos de control simples o complejos, unidireccionales o interactivos, y que incluyen parámetros de todo tipo, color y sabor. Y planteado para comunicar PIC's con PC's, PIC's con PIC's ó PIC's con casi cualquier otro tipo de dispositivo, usando niveles TTL, RS232, RS485 ...

   Sobre este tema hay innumerables artículos abiertos en Internet con absolutamente todo lo necesario para realizar casi cualquier cosa que podamos imaginar, usando un buscador y teniendo la paciencia necesaria para leer y rebuscar entre los resultados este artículo sería totalmente innecesario.

 

 Exclusiones

 
 

   Lo que no voy a tratar son los hardware's necesarios para comunicar distintos dispositivos según los distintos protocolos y/o niveles. Desde el punto de vista de un PIC es totalmente indiferente si se comunica con un PC o con otro PIC y es absolutamente igual si lo hace en RS232 con el uno que en TTL con el otro.

 

 Propósito
 
 

   Escribo este artículo en un intento por clarificar conceptos, organizarlos y mostrarlos de la forma mas clara y sencilla posible, unificarlos y crear una jerarquía de menos a más según sea lo que necesitemos creciendo en complejidad.

   Pero sin quedarme sólo en la teoría sino que además deseo proponer ejemplos prácticos listos para usar, profusamente comentados línea a línea para que sea posible "leer" el programa, seguir su ejecución, mediante los comentarios añadidos. Con todos los ejemplos escritos, compilados y probados sobre un PIC para certificar su correcto funcionamiento.

   En este artículo voy a desarrollar, en lenguaje C variante CCS, las técnicas y conceptos necesarios para emitir y recibir con un PIC de las series 16F y 18F (por la gran similitud que hay entre ellas, tanta que solo va a ser necesario cambiar el #include del modelo de PIC concreto y los #defines de los pines reales conectados a la USART). Vamos a presentar desde el mas simple echo hasta un completo tratamiento de comandos con parámetros de distinto tipo.

 

 Metodología
 
 

   Voy a ir escribiendo sub-artículos cerrados y completos. Cada uno con sus respectivos Objetivos, Implementación en C y su Programa Fuente completo funcionando.

   Y como he descrito anteriormente avanzando en complejidad e intentando que estos "saltos" de lo sencillo a lo complejo se vayan haciendo paulatinamente, paso a paso, y así poder describir esos avances de forma que sean acumulables para los amigos que empiezan y no se vean en la obligación de "tragar" mas de lo que son capaces de comprender.

 

 Condiciones del Test
 
 

   Todos los programas los voy a escribir en CCS C, versión 3.242, y van a ser probados sobre un PIC 18F4550 con un cristal de 20 Mhz con el PLL activado para generar un ciclo de reloj de 48 Mhz, conectado a un PC mediante una interface hardware RS232 construida alrededor de un MAX232, transmitiendo y recibiendo a 115200 baudios, 8 bits, 1 bit de Stop y sin Paridad (none) . Por ello los fuses que aparecerán en los ejemplos y la definición CCS del canal Serie va a ser:

 
     
  /////////////////////////////////////////////
// Definiciones de configuración
/////////////////////////////////////////////

#include <18f4550.h>

/////////////////////////////////////////////
// Fuses y ajuste de Clock
/////////////////////////////////////////////

#fuses HSPLL, NOMCLR, PUT, BROWNOUT, BORV43, NOWDT, NOPROTECT, NOLVP
#fuses NODEBUG, USBDIV, PLL5, CPUDIV1, VREGEN, CCP2B3
#use delay(clock=48000000)

/////////////////////////////////////////////
// Canal de Comunicación : usart
/////////////////////////////////////////////

#define TTL_TX PIN_C6
#define TTL_RX PIN_C7

#use rs232(baud=115200, xmit=TTL_TX, rcv=TTL_RX)
 
 
     
 

   Esta parte va a ser común a todos los ejemplos y es la única, salvo que expresamente se diga lo contrario, que es necesario adaptar a cada uno de los distintos modelos y condiciones de vuestro PIC en particular. Si esta cabecera corresponde con vuestro PIC todos los ejemplos que tratemos deben funcionar correctamente desde el principio.

Así si nuestro PIC es un 16F876A, con un cristal de 4 Mhz y transmitiendo y recibiendo a 9600 baudios la cabecera debería ser:

 
     
  ////////////////////////////////////////////////
// Definiciones de configuración
////////////////////////////////////////////////

#include <16f876a.h>

////////////////////////////////////////////////
// Fuses y ajuste de Clock
////////////////////////////////////////////////

#fuses XT,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT
#use delay(clock=4000000)

////////////////////////////////////////////////
// Canal de Comunicación : usart
////////////////////////////////////////////////

#define TTL_TX PIN_C6
#define TTL_RX PIN_C7

#use rs232(baud=9600, xmit=TTL_TX, rcv=TTL_RX)
 
 
     
 

   Como veis las modificaciones son mínimas. El resto lo dejamos para cada uno de los artículos que tratemos. Espero que os guste y os sirva.

 

 

 

 
  El mas simple "echo"
 
 
Objetivos
 

   Lo mas simple que se puede hacer con un PIC en esto de las comunicaciones es recibir un carácter y devolverlo a modo de eco. Sin manos, sin pies y casi sin bicicleta, esperamos a recibir algo e inmediatamente lo reenviamos a su destino.

 
Implementación en C
 

   Para implementarlo en C lo que vamos a hacer es montar nuestro sempiterno bucle infinito del While(true) y dentro de él vamos a utilizar las funciones built-in de C llamadas kbhit() que devuelve true cuando hay algo pendiente de recibir (comprueba si está en alto el bit 5 RCIF del registro PIR1), getc() que obtiene, "lee", el byte recibido (descarga RCREG) y putc() que emite un byte por la USART (escribe TXREG).

   Podemos describir lo que vamos a hacer de la forma: Espera mientras te avisen que hay algo pendiente de recibir, que cuando llegue lo lees y lo vuelves a enviar, y así hasta el infinito y mas allá. 

 
Programa Fuente
 

   Recuerda que la cabecera es la misma para todos los programas y la tienes descrita en nuestra Introducción  de esta serie.

 
     
  void main() {

  char rec;

  printf("TyP_Serie_TTL\r\n"); // Al inicio escribe para ver que emite correctamente
  do{ // Bucle ...
    if(kbhit()){ // Si hay algo pendiente de recibir ....
      rec=getc(); // recibe el caracter ...
      putc(rec); // ... y lo escribes ...
    } // ... después continúa ...
  }while(TRUE); // ... hasta el infinito.
}
 
 
 

Descargar typ_serie_ttl_01_eco_main.c

 
 
   Al inicio he incluido una línea de la forma  printf("TyP_Serie_TTL\r\n"); para ver que emite correctamente nada mas darle alimentación al PIC.
 
 
Realmente la variable rec de tipo char que hemos escrito no es necesaria ya que las líneas :
 
      rec=getc(); // recibe el caracter ...
      putc(rec); // ... y lo escribes ...
 
las podemos escribir en una sola de la forma:
 
      getc(putc(rec)); // escribe lo que recibas ...
 
 

 

  Un  "echo" interrupto  (mediante la interrupción por recepción serie)
 
 
Objetivos
 

   No tan simple como nuestro anterior ejemplo pero casi. Esta vez vamos a hacer que el eco se produzca de igual forma que anteriormente pero haciendo uso de la interrupción por recepción serie, INT_RDA, que se nos va a disparar cuando nuestro PIC reciba un carácter por dicho canal.

 
Implementación en C
 

   Para implementarlo en C lo que vamos a hacer es simplemente mover la recepción y reenvío del carácter desde el bucle infinito en el main(), que es donde lo teníamos antes, a una rutina especial que solo se ejecutará cada vez que se reciba un carácter por la USART. Recordad que la función escrita a continuación de la directiva #int_rda será la que se ejecute cuando se dispare dicha interrupción. De ahí que le haya llamado rda_handler o manejador de la interrupción RDA.

   Podemos describir lo que vamos a hacer de la forma: Haz lo que te de la gana en el main() porque cuando te avisen de que hay algo pendiente de recibir saldrás de allí y en la rutina de la interrupción lo lees y lo vuelves a enviar, devolviéndote adonde estabas en cuanto termines. 

 
Programa Fuente
 

   Recuerda que la cabecera es la misma para todos los programas y la tienes descrita en nuestra Introducción  de esta serie.

 
     
  ////////////////////////////////////////////////
// INTERRUPCIONES : RDA Recepción USART
///////////////////////////////////////////////
#int_rda
  void rda_handler(void){
  putc(getc()); // recibe el caracter y lo reenvía...
}
///////////////////////////////////////////////
// MAIN
///////////////////////////////////////////////
void main() {

  printf("TyP_Serie_TTL\r\n"); // Al inicio escribe para ver que emite correctamente
  printf("Method : Interrupt\r\n");

  enable_interrupts(int_rda); // Habilitamos la interrupción por recepción serie
  enable_interrupts(global); // Habilitamos las interrupciones

  do{ // Bucle ...

    // Aqui no tenemos nada que hacer ...
    // pero podemos hacer lo que queramos.


  }while(TRUE); // ... hasta el infinito.
}
   
 
 

Descargar typ_serie_ttl_02_eco_interrupcion.c

 
 
   Como podéis ver los resultados son idénticos al ejemplo anterior, pero con la inmensa diferencia de que en el bucle infinito del main() podemos escribir cualquier otro código que haga cualquier otra cosa con la seguridad de que al recibir un carácter lo tendremos disponible..
 
 

 

 
Comandos de un solo carácter
 
 
Objetivos
 

   Entramos ya en terrenos con una utilidad directa. En este tercer ejemplo tenemos la intención de recibir comandos desde fuera del PIC y ejecutar distintas funciones según sea lo recibido. Pero además vamos a tener un pequeño "feed-back" para poder saber qué es lo que está recibiendo el PIC, de forma que el PIC nos devuelva el comando recibido y los resultados de la función que se ejecuta, o algo que nos indique que el comando es erróneo.

 
Implementación en C
 

   Lo que vamos a hacer es declarar una variable de tipo char en la RAM a la que llamaremos Command, que inicializaremos a cero 0x00 en el main() y sobre la que recogeremos lo que recibamos por el canal serie con la interrupción #INT_RDA, tal como vimos en el ejemplo anterior.
 

   En el main(), dentro del bucle infinito While(true), comprobaremos en cada vuelta si el contenido de Command es distinto de de 0x00 (recordad que lo inicializamos con este valor) ya que entonces significaría que si hemos recibido algo.
 

   Entonces lo primero que haremos será monitorizar esta recepción mediante un printf y después usando un switch ejecutaremos la función seleccionada. En caso de no ser uno de los que hemos contemplado en el switch devolveremos una señal en tal sentido.
 

   En cualquier caso volveremos a inicializar a 0x00 la variable Command para no volver a ejecutar la misma función hasta no recibir de nuevo el comando correspondiente.

 
Programa Fuente
 

   Recuerda que la cabecera es la misma para todos los programas y la tienes descrita en nuestra Introducción  de esta serie.

 
     
  ////////////////////////////////////////////
// RAM
////////////////////////////////////////////

char Command;

////////////////////////////////////////////
// INTERRUPCIONES : RDA Recepción USART
////////////////////////////////////////////

#int_rda
  void rda_handler(void){

  Command=getc(); // recibe el comando ...

}

// Ejecutar según comando recibido /////////

void first_function(void){

  printf(" > Exec first_function()\r\n");
}

void second_function(void){

  printf(" > Exec second_function()\r\n");
}

////////////////////////////////////////////

void main() {

  printf("TyP_Serie_TTL\r\n"); // Al inicio escribe para ver que emite correctamente
  printf("Method : Interrupt\r\n");
  printf("Commands mono-character\r\n");

  enable_interrupts(int_rda); // Habilitamos la interrupción por recepción serie
  enable_interrupts(global); // Habilitamos las interrupciones

  Command=0x00; // Inicializamos Command para asegurar que vale 0x00

  do{ // inicio del Bucle infinito

    if(Command!=0x00){ // Si hemos recibido un comando ...
      printf(" < %c\r\n",Command); // Lo mostramos para saber que ha recibido ...
      switch(Command){
        case '1': // y si éste es el caracter ASCII '1' entonces ...
          first_function(); // llamamos a la primera funcion.
          break;
        case '2': // pero si éste es el caracter ASCII '2' entonces ...
          second_function(); // llamamos a la segunda funcion.
          break;
        default:
          printf(" < ?\r\n");// si no es ninguno de los anteriores protestamos ...
          break;
      }
      Command=0x00; // y volvemos a inicializar Command para que no
      // se vuelva a ejecutar hasta volver a recibirlo.
    }

  }while(TRUE); // final del Bucle infinito
}

// Fin del programa ////////////////////////////////////////////
 
 

Descargar recursos\typ_serie_ttl_03_comando_simple.c

 
 

   Un detalle importante a tener en cuenta con este modo de tratar los comandos recibidos: Aunque la USART no pierda ningún carácter que pueda enviársele solo se ejecutarán aquellos que sean recibidos fuera de la ejecución de una de las funciones asociadas a ellos, y esto es debido a que tras la ejecución de cualquiera de ellas ponemos a 0x00 la variable Command, por eso cualquier cosa recibida durante la ejecución no se tendrá en cuenta.

 
 

 

 
 
Recibiendo sobre un Buffer. 1ª Parte
 
 
Objetivos
 

   Las más de las veces todo lo que hemos visto hasta ahora de Comandos de Un Solo Carácter se nos queda corto, ya sea porque necesitamos comandos mas largos, usando palabras en lugar de solo una letra, ya sea porque necesitamos argumentos, o sea datos añadidos a nuestro comandos que deben ser procesados a la llegada de éstos. Todo esto no es posible montarlo procesando uno a uno los caracteres que le vamos enviando al PIC.
 

   Hay que hacerlo recibiendo y acumulando en la memoria del PIC todo aquello que necesitamos y enviando como último carácter uno especial que dispare su procesado. Esto es lo que se conoce como "recibir sobre un buffer" y es lo que vamos a estudiar aquí y ahora: Recibir caracteres sobre un buffer, uno a uno, y procesarlo cuando se reciba uno en concreto, yo siempre uso 0x0D [Retorno de Carro] o sea al pulsar la tecla [Enter].

 
Implementación en C
 

   El primer recurso que necesitamos es el Buffer. En C nuestro buffer va a ser una matriz (un arreglo) de caracteres, también conocido como string, o sea n caracteres consecutivos en la memoria del PIC, de forma que el primer carácter que recibamos lo guardemos en la primera posición del buffer, la 0, el segundo en la siguiente, la 1, y así sucesivamente hasta que le enviemos el carácter especial de procesado o que se nos acabe el buffer porque hayamos alcanzado su final.
 

   Muy importante es la longitud máxima que vamos a darle a nuestro buffer, o sea el máximo número de caracteres que va a tener, tanto para reservar la memoria RAM correspondiente como para detectar si hemos alcanzado el final del mismo y no podemos seguir recibiendo sobre él so pena de sobrescribir otras zonas de la memoria del PIC. Así que vamos a definir una constante con esta Longitud Máxima del buffer que utilizaremos después para estos dos cometidos: Declarar el buffer en la RAM y controlar la recepción máxima de caracteres sobre él.
 

   Además necesitamos un recurso añadido que nos diga a qué posición debe guardarse el siguiente carácter que se reciba. Esto lo vamos a hacer declarando en RAM una variable de tipo entero que inicialmente pondremos a 0 de forma que al recibir el primer carácter lo guardemos en esa posición e incrementamos nuestro índice, así al llegar el siguiente lo guardaremos en 1 y volveremos a incrementar el índice. ¿Hasta cuando? pues hasta recibir el carácter especial de final o llegar al final físico declarado con la constante anterior.

 
   Esta declaración y definición de nuestro buffer en CCS C se hace de la siguiente forma:
 
     
  ///////////////////////////////////////
// Constantes
///////////////////////////////////////

int const lenbuff=32; // Longitud máxima del buffer

///////////////////////////////////////
// RAM
///////////////////////////////////////

int xbuff=0x00; // Índice: siguiente char en cbuff
char cbuff[lenbuff]; // Buffer de recepción
   
 
 

 

 
 

   Con lenbuff definimos la máxima longitud del buffer que lo usamos al declarar el propio buffer en cbuff[lenbuff] y utilizaremos xbuff como índice del mismo, poniéndolo a cero para comenzar e incrementando su valor cada vez que guardemos un carácter en el buffer.
 

   Tenemos entonces ya lo fundamental, que es el "receptáculo" donde guardar lo recibido y los recursos para ello. Tenemos ahora que recibirlo y guardarlo efectivamente.
 

   Para ello vamos a utilizar la Interrupción por Recepción Serie que vimos en Comandos de un solo carácter pero que en aquel caso era un simple command=getc() y en el que nos ocupa va a ser un mucho mas complejo add_2_cbuff() que es una función donde vamos ha hacer todo lo necesario para recoger el carácter recibido y dejar el buffer preparado para el siguiente carácter por recibir.
 

   La interrupción RDA y el añadir lo recibido al Buffer podría quedar de esta forma:
 
     
  ///////////////////////////////////////
// INTERRUPCIONES : RDA Recepción USART
///////////////////////////////////////

#int_rda
void serial_isr() { // Interrupción recepción serie USART

  char rcvchar=0x00; // último carácter recibido

  if(kbhit()){ // Si hay algo pendiente de recibir ...
    rcvchar=getc(); // lo descargo y ...
    add_2_cbuff(rcvchar); // lo añado al buffer
  }
}

void add_2_cbuff(char c){

  switch(c){
    case 0x0D: // Enter -> Habilita Flag para procesar comando
      flagcommand=1;
      break;
    default: // Añade carácter recibido al Buffer
      cbuff[xbuff++]=c;
  }
}
 
 
 

 

 
 

   Como veis en el código anterior distinguimos en lo recibido si es cualquier cosa o es el carácter especial 0x0D en cuyo caso ponemos un flag en alto.
 

   Pero le vamos a dar un vuelta de tuerca más.  Mr. Green
 

   Ya que estamos interactuando con nuestro PIC vamos a hacerlo de forma mas completa. Por un lado vamos a implementar alguna forma de feed-back, algo que nos diga cómo va nuestro buffer llenándose, y algo mas de control sobre él. Por ejemplo una tecla para borrar el último carácter recibido y poder así corregir un error de digitación o incluso una tecla especial para borrar todo el buffer almacenado hasta el momento. Así convertiremos las teclas Backspace y Escape, códigos ASCII 0x08 y 0x1B respectivamente, en teclas especiales también junto a nuestro anterior 0x0D.
 

   Introducimos entonces una nueva función a la que vamos a llamar echo_sel() por "Eco selectivo" para monitorizar lo que estamos enviándole al PIC y también vamos a modificar nuestra add_2_cbuff() anterior para contemplar las nuevas posibilidades de borrado del buffer.
 

   La función echo_sel() la vamos a llamar después de guardar lo recibido en el buffer y así nos irá informando de cómo está el buffer y de si hemos pulsado alguna de las teclas especiales, mostrándonos el resultado sobre el buffer.
 

   El código queda entonces de la siguiente forma:
 
     
  ///////////////////////////////////////
// INTERRUPCIONES : RDA Recepción USART
///////////////////////////////////////

#int_rda
void serial_isr() { // Interrupción recepción serie USART

  char rcvchar=0x00; // último caracter recibido

  if(kbhit()){ // Si hay algo pendiente de recibir ...
    rcvchar=getc(); // lo descargo y ...
    add_2_cbuff(rcvchar); // lo añado al buffer y ...
    echo_sel(rcvchar); // hago eco selectivo (si procede).
  }
}

void add_2_cbuff(char c){

  switch(c){
    case 0x0D: // Enter -> Habilita Flag para procesar comando
      flagcommand=1;
      break;
    case 0x08: // Del -> Borra último caracter del Buffer
      if(xbuff>0) cbuff[--xbuff]=0x00;
      break;
    case 0x01B: // Esc -> Borra el Buffer completamente
      init_cbuff();
      break;
    default: // Añade caracter recibido al Buffer
      cbuff[xbuff++]=c;
  }
}

void echo_sel(char c){

  switch(c){
    case 0x0D: // Si he pulsado la tecla [Intro]
      printf("\r\n[Ent]\r\n");
      break;
    case 0x08: // Si he pulsado la tecla [Retroceso]
      printf("\r\n[Del]\r\n>%s",cbuff);
      break;
    case 0x1B: // Si he pulsado la tecla [Escape]
      printf("\r\n[Esc]\r\n>");
      break;
    default: // Echo de cualquier otro caracter
      putc(c);
  }
}
   
 
 

 

 
 

   Fijaos que al pulsar la tecla Backspace lo único que hacemos es decrementar la variable índice del buffer y ponemos esa posición a 0x00, mientras que por el contrario cuando pulsamos la tecla Escape lo que hacemos es borrar todo el buffer y poner dicho índice a cero.
 

   Esto último lo hacemos con la función init_cbuff()
 
     
  void init_cbuff(void){
  int i;

  for(i=0;i<lenbuff;i++){// Bucle que pone a 0 todos los
    cbuff[i]=0x00; // caracteres en el buffer
  }
  xbuff=0x00; // Inicializo el indice de siguiente caracter
}
   
 
 

 

 
 

   Con lo que ya lo tenemos casi todo. Solo constatar que el main() es hiper-simple ya que lo único que hacemos en él, aparte de habilitar la correspondiente interrupción es esperar a que el flag para procesar comando se ponga en alto, cosa que solo haremos en add_2_cbuff() cuando recibamos el 0x0D. En ese caso ejecutaremos la función commad_process() donde haremos lo que nos de la gana con lo recibido (en este ejemplo lo copiamos a otra variable y jugamos con los printf para mostrarlo)
 

 
     
  ///////////////////////////////////////
// MAIN
///////////////////////////////////////

void main() {

  init_cbuff(); // Borra buffer al inicio
  enable_interrupts(int_rda); // Habilita Interrupción RDA
  enable_interrupts(global); // Habilita interrupciones

  do {
    if(flagcommand) commad_process(); // Hay algo pendiente de procesar y lo procesa.
  } while (TRUE);

}
   
 
 

 

 
 
El programa completo incluye una presentación previa donde se explica lo que se puede hacer con este programa y alguna cosa más irrelevante para el funcionamiento descrito aquí.
 
Programa Fuente
 

   Recuerda que la cabecera es la misma para todos los programas y la tienes descrita en nuestra Introducción  de esta serie.

 
     
  ///////////////////////////////////////
// Constantes
///////////////////////////////////////

int const lenbuff=32; // Longitud máxima del buffer

///////////////////////////////////////
// RAM
///////////////////////////////////////

int xbuff=0x00; // Índice: siguiente char en cbuff
char cbuff[lenbuff]; // Buffer de recepción
int1 flagcommand=0; // Flag para comando disponible

///////////////////////////////////////
// Funciones de Buffer
///////////////////////////////////////

// Echo selectivo ----------------------

void echo_sel(char c){

  switch(c){
    case 0x0D: // Si he pulsado la tecla [Intro]
      printf("\r\n[Ent]\r\n");
      break;
    case 0x08: // Si he pulsado la tecla [Retroceso]
      printf("\r\n[Del]\r\n>%s",cbuff);
      break;
    case 0x1B: // Si he pulsado la tecla [Escape]
      printf("\r\n[Esc]\r\n>");
      break;
    default: // Echo de cualquier otro caracter
      putc(c);
  }
}

// Inicia a \0 cbuff -------------------

void init_cbuff(void){
  int i;

  for(i=0;i<lenbuff;i++){// Bucle que pone a 0 todos los
    cbuff[i]=0x00; // caracteres en el buffer
  }
    xbuff=0x00; // Inicializo el indice de siguiente caracter
}

// Añade a cbuff -----------------------

void add_2_cbuff(char c){

  switch(c){
    case 0x0D: // Enter -> Habilita Flag para procesar comando
      flagcommand=1;
      break;
    case 0x08: // Del -> Borra último caracter del Buffer
      if(xbuff>0) cbuff[--xbuff]=0x00;
      break;
    case 0x01B: // Esc -> Borra el Buffer completamente
      init_cbuff();
      break;
    default: // Añade caracter recibido al Buffer
      cbuff[xbuff++]=c;
  }
}

///////////////////////////////////////
// Procesador de Comandos
///////////////////////////////////////

void commad_menu(void){

  printf("\r\nTyP_Serie_TTL\r\n");
  printf("Método : Recibiendo sobre Buffer\r\n\n");
  printf("[Enter] Procesa el buffer recibido.\r\n");
  printf("[Escape] Borra todo el buffer.\r\n");
  printf("[Delete] Borra último carácter del buffer.\r\n");
  printf("\r\n\r\n>");

}

void commad_process(void){

  int i;
  char cmd[lenbuff]; // Comando

  flagcommand=0; // Desactivo flag de comando pendiente.
  printf("Procesando ...\r\n");

  strcpy(cmd,cbuff); // Lo copio para procesarlo
  printf("Rec. Buffer <%s>\r\n",cmd); // ... y lo muestro

  init_cbuff(); // Borro buffer.
  printf("Procesado.\r\n\r\n>"); // Monitorizo procesado.
}

///////////////////////////////////////
// INTERRUPCIONES : RDA Recepción USART
///////////////////////////////////////

#int_rda
void serial_isr() { // Interrupción recepción serie USART

  char rcvchar=0x00; // último caracter recibido

  if(kbhit()){ // Si hay algo pendiente de recibir ...
    rcvchar=getc(); // lo descargo y ...
    add_2_cbuff(rcvchar); // lo añado al buffer y ...
    echo_sel(rcvchar); // hago eco selectivo (si procede).
  }
}

///////////////////////////////////////
// MAIN
///////////////////////////////////////

void main() {

  delay_ms(2000); // Espero a estabilizar antes de actuar
  commad_menu(); // Nos presentamos
  init_cbuff(); // Borra buffer al inicio
  enable_interrupts(int_rda); // Habilita Interrupción RDA
  enable_interrupts(global); // Habilita interrupciones

  do {
    if(flagcommand) commad_process(); // Hay algo pendiente de procesar y lo procesa.
  } while (TRUE);

}

///////////////////////////////////////
// Fin de programa
///////////////////////////////////////
 
 

Descargar typ_serie_ttl_04_comando_buffer_1.c

 
 

   Aquí podéis ver un ejemplo de este programa funcionando. Un primera parte donde se presenta nuestro PIC y nos informa de sus posibilidades, es la parte de la función commad_menu() y después un ejemplo de escribir una serie de caracteres pulsando a continuación [Escape] para borrar todo lo escrito, y otro con la eliminación del último caracter escrito y su posterior procesado.

 
 

 

Esta página se modificó el 27/12/2008


Esta página usa la letra Ñ

Nota pública importante sobre las consultas al Webmaster de PicManía.


Sugerencias a Picmanía... (que serán leídas pero seguramente no podrán ser contestadas)

Esta página pertenece al grupo de páginas de Diego RedRaven

 

 



Nota: Esta página Web esta repleta de imágenes, textos, logotipos y demás material extraídos de los mas variados medios de los que no soy ni autor ni depositario de los correspondientes derechos de autor, uso y/o reproducción. Si Ud. es depositario de dichos derechos y desea que el material correspondiente sea eliminado de esta Web no dude en ponerse en contacto conmigo mediante e-mail y será inmediatamente retirado. Gracias.
 
Visitas
Totales : 7720 Hoy: 1 Activas: 1 Vistas: 7720

Esta página fue modificada el 07-08-2010 15:42:16

           
 DmSoft WAMP Escribir Unreal