miércoles, 18 de enero de 2012

HolaMundo en Hitech-C || Parpadeo de un led



El primer programa que se suele afrontar a la hora de entrar en el mundo de los PIC es hacer parpadear un led. En primer lugar debemos ser conscientes del funcionamiento del Led. En éste caso, partimos de un led que funciona a un voltaje de 1,7V y una intensidad de 10mA.

Habitualmente, la salida del PIC es de unos 5V. Eso es casi 3 veces mas de lo que soporta nuestro LED, y de conectarlo directamente, se quemaría enseguida. Para evitar esta catástrofe, haremos uso de la ley de Ohm para calcular la resistencia que debemos utilizar. De ésta manera, nuestra resistencia sera el cociente de V / I, donde V es la tensión óptima en el ánodo del LED, e I la intensidad de la rama en cuestión.

Dejándonos de tecnicismos, 3,3V / 10 mA = 330Ω, que pasado a código de colores estándar de las resistencias es Naranja – Naranja – Marrón – tolerancia.


Recordad que los LED (Light Emmiting Diode) como su propio nombre indica, son diodos, lo cual denota polaridad. Para que conduzcan, el ánodo ha de ser más positivo que el cátodo.

ATENCIÓN: Tanto para éste tutorial como para los demás, se parte de un PIC modelo 16F887 salvo que se especifique lo contrario. Los programas y las conexiones pueden variar entre modelos, por lo que, en caso de utilizar un dispositivo diferente al mencionado, deberéis comprobar que todo esté correcto antes de alimentar el circuito. 

Conectaremos a la pata 2 (RA0) de nuestro PIC el LED en serie con la resistencia de 330Ω y finalmente a GND.

Ya tenemos los conocimientos necesarios sobre el circuito. Ahora vamos con el programa:
#include <htc.h>
#define _XTAL_FREQ 8000000

void main(){

    ANSELH = 0;
    ANSEL = 0;
    TRISA = 0;
    PORTA = 0;

    while(1){
        RA0 = 1;
        __delay_ms(500);
        RA0 = 0;
        __delay_ms(500);
    }
}


Breve explicación del código:


  • Si no se establecen los valores de ANSELH y ANSEL, el programa no funciona, ya que si un PIN está seleccionado como analógico, automáticamente pasa a estar configurado como entrada. Por tanto, una modificación por software sobre PORTA en este caso, no tendría ningún efecto. Ésto pasa en éste modelo de PIC, al menos. He trabajado con su antecesor, el 16F877 y carece de éstos dos registros. No obstante, éstas configuraciones pueden comprobarse en el Datasheet, en el apartado de "I/O Ports".
  • Acerca de la librería <htc.h>, es la que define los nombres de registros, los nombres de los pines y algunas de las funciones estándar de hitech-c que se utilizan comúnmente como __delay_ms(). Por eso es necesario incluirla SIEMPRE.
  • La directiva #define _XTAL_FREQ hertzs es necesaria para la utilización de los delays, ya que lo que éstos hacen es generar instrucciones en función de la frecuencia a la que funciona el PIC. Tendréis que convivir con ella.
  • La función __delay_ms() lleva dos barras bajas al principio. Aún no me he molestado en indagar por que utilizan nombres tan feos para algunas cosas. Simplemente realiza una espera activa de los milisegundos pasados por parámetro.

Y dicho todo esto, ahora podemos simular nuestro proyecto con MPLAB SIM observando el valor del registro PORTA con un punto de debug en las instrucciones RA0 = 1 y RA0 = 0. Si todo está correcto, el bit menos significativo del puerto A debería alternar entre 0 y 1.

Probablemente algunos habréis pensado en simular con animación. Cuando utilicéis en vuestros programas la función __delay_ms o __delay_us, descartad inmediatamente ésta opción. La explicación es sencilla:

Cada paso del simulador es una instrucción. Cada instrucción dura medio microsegundo real (recordad: 8Mhz y 4 ciclos por instrucción). Si echamos cuentas, un delay de 500 milisegundos equivaldría a ¡un millón de instrucciones! Si ahora suponemos que vuestro simulador avanza una instrucción cada medio segundo, tendríamos que esperar la bonita cifra de 5,78 días para ver que nuestro LED cambia de apagado a encendido, y otro tanto para volver a apagarse.

Es por eso, que  vale mas prevenir, y poner un STOP en esas dos líneas, y darle al play normal.

En caso de duda, comentad.

Saludos – MarcosR. @IAmRutiger

viernes, 6 de enero de 2012

La función printf en PIC


Aquí va un corto pero interesante artículo acerca de cómo utilizar la función printf de C para escribir en un LCD utilizando el compilador HITECH-C Lite. No tengo intención ahora mismo de explicar el procedimiento para escribir en un LCD dado que necesitaría una entrada enorme. Por éso ésta entrada está orientada a todos aquellos programadores de PICs que al igual que yo se han topado con los problemas de escribir, por ejemplo, un numero decimal en un display LCD, 8 segmentos, puerto serie, etc.

En el C "de toda la vida", para imprimir algo en la salida estándar, la manera más común es echar mano de la librería stdio.h. Entre otras muchas funciones que define ésta librería se encuentra la función printf.

Un pequeño ejemplo:

#include <stdio.h>

void main(){

int miEdad = 22;

printf("Mi edad es %d", miEdad);

getchar(); // Paramos la ejecución hasta que se pulse una tecla
}


Lo que nos interesa de éste pequeño código es la línea 4. Es decir, la línea en la que aparece el printf de marras. El resultado de éste programa mostraría por pantalla el texto "Mi edad es 22".
Para refrescar la memoria de aquellos que no se acuerden del uso exacto de ésta función, como primer parámetro se envía la cadena con los tokens %, y los demás parámetros son los valores o variables que deseamos que aparezcan en lugar de cada token respectivamente. Así %d es substituido por el valor de la variable miEdad en nuestro programilla.

Una vez entendido ésto, si lo pasamos a PIC C (a partir de ahora haremos referencia de ésta manera al lenguaje utilizado para el compilador HITECH C) nos encontramos con que al compilar se muestra un error que nos viene a explicar que falta la función "putch".

Por lo que he podido deducir de mis escasas experiencias, la función printf() se encarga de construir la cadena, realizando los cálculos necesarios en los valores pasados como parámetro, y posteriormente los sustituye. Digamos que crea una cadena con el formato que queremos. A continuación, llama a la función putch() una vez por cada carácter de la cadena en cuestión. Y simplemente, la función putch() envía el carácter recibido a la salida estándar.

Aquí viene el meollo de la cuestión. En C normal, la salida estándar viene predefinida como la consola de dos, bash...etc. Generalmente es lo más común a la hora de probar los programas. Digamos que ya viene así montado, y si quieres que esa información se envíe a otro sitio tienes que modificar la salida.

En cambio, en PIC C, la función putch() viene definida como vacía. No tiene código. De ésta manera somos nosotros quienes al crear nuestro programa, decidimos a dónde van a parar nuestros datos.

Se deduce entonces de la información anterior, que para escribir (por ejemplo) en el puerto B, solo hay que hacer 3 cosas:


  1. Incluir la libreria stdio.h.
  2. Definir la función void putch(char c)
  3. Llamar a printf() de la forma normal.


Para terminar de aclarar todo ésto, un ejemplo:
/* LA IDEA ES IMPRIMIR LA CADENA "Mi edad es 22" MEDIANTE LA FUNCIÓN PRINTF EN UN LCD, Y UTILIZANDO EL FORMATO DE CADENAS TÍPICO DE C (%d) /*

#include <htc.h>
#include <stdio.h>

#define _XTAL_FREQ 8000000
#include "C:\users\Marcos\Electronica\lib\lcd.h"

void putch(char c){ // DEFINIMOS LA FUNCIÓN PUTCH
lcd_putc(c); // ENVIAMOS EL CHAR AL LCD
}

void main(void){

int miEdad = 22; // DECLARAMOS UNA VARIABLE

printf("Mi edad es %d", miEdad); // IMPRIMIMOS

while(1); // NO HACER NADA
}
Cuando utilicéis la función printf tened en cuenta que el uso de memoria se va a disparar. Sobre todo cuando
utilicéis impresión de datos en coma flotante (%f). Si teneis alguna pregunta no dudéis en guardar silencio comentar aquí abajo.

Un saludo!!

Marcos R. - @IAmRutiguer