uControl
Junio 18, 2013, 03:45:07 *
Bienvenido(a), Visitante. Por favor, ingresa o regístrate.
¿Perdiste tu email de activación?

Ingresar con nombre de usuario, contraseña y duración de la sesión
 
   Inicio   Ayuda Buscar Ingresar Registrarse  
Páginas: [1]   Ir Abajo
  Imprimir  
Autor Tema: Mini curso "Programación de micros en C desde 0"  (Leído 5206 veces)
0 Usuarios y 1 Visitante están viendo este tema.
lmtreser
Moderador
PIC18F
*****
Desconectado Desconectado

Sexo: Masculino
Mensajes: 1338



WWW
« : Mayo 12, 2010, 12:39:06 »

Introducción

Hola, hoy empiezo este mini curso de programación de microcontroladores PIC en lenguaje C desde 0. La idea es aprender paso a paso, realizar algunos proyectos simples y sumar conocimientos.

Voy a trabajar sobre el sistema operativo Ubuntu, con software libre o gratuito. Para todos aquellos que utilizan Windows no van a tener inconvenientes porque los paquetes de software son multiplataforma. Voy a utilizar como entorno de desarrollo MPLAB X en conjunto con el compilador XC8. No me voy a detener en la instalación y configuración del IDE y del compilador ya que existen muchos tutoriales sobre esto (por ejemplo).

El curso lo voy realizando sobre la marcha, en parte leyendo libros, en parte dudas consultadas a los expertos en el foro y en parte en experiencias propias. Por este motivo lo verán formarse "online" y a medida que el tiempo me lo permita ire sumando contenido. Les recomiendo que lean el tutorial sobre XC8 que escribió Suky que es un buen punto de partida y el "Tutorial MPLAB C18 Desde Cero". También es de mucha utilidad tener a mano los ejemplos de Microchip para consulta: Microchip Code Examples (12F & 16F).

Para realizar los primeros ensayos voy a utilizar el microcontrolador PIC16F648A (compatible con el PIC16F627 y PIC16F628). Dejo abierto el post para que realicen comentarios, dudas, aportes y criticas. Y uno más para ir colgando librerías o código útil.

Indice:

1.1. Estructura de un programa en C
1.2. ¡Hola Mundo! en C (o como hacer destellar un LED)
1.3. Leer un pulsador
1.4. Utilizando PWM
1.5. Uso de funciones
1.6. Varibles y tipos de datos
1.7. Usando una interrupción por timer0
1.8. Ejemplo de uso PIC18F4550, delays y USART
« Última modificación: Mayo 19, 2013, 10:24:04 por lmtreser » En línea

lmtreser
Moderador
PIC18F
*****
Desconectado Desconectado

Sexo: Masculino
Mensajes: 1338



WWW
« Respuesta #1 : Mayo 12, 2010, 12:45:46 »

1.1. Estructura de un programa en C

C es el lenguaje de programación que utilizaremos. Un programa C está compuesto por una o varias funciones, dentro de las cuales tendremos una o más instrucciones. Existe una función llamada "main" donde tendremos nuestro código principal.

Comentarios: Los comentarios son de mucha utilidad para entender lo que escribimos. Para realizar un comentario anteponemos en la línea de código "//" y el compilador la ignorará. También podemos comentar bloques de código utilizando "/*" para abrir y "*/" para cerrar.

Includes: utilizando "#include" incluimos en nuestro programa archivos de funciones o librerías que nos permitirán utilizar características especiales.

Ejemplo:

Código:
/*
 * File:   main.c
 * Author: lucas
 * Created on 1 de abril de 2013, 22:20
 *
 * ESTO ES UN BLOQUE DE COMENTARIOS
 */

#include <xc.h> // Incluimos la librería XC8

// ESTO ES UN COMENTARIO DE UNA LINEA

// Función principal
void main ()
{
    OSCCONbits.IRCF = 0b110; // Instrucción

}

IMPORTANTE:

* Todas las instrucciones deben terminar si o si en ";".
* Los bloques de instrucciones empiezan con "{" y terminan con "}".
* C es case sensitive, es decir que distingue minúsculas de mayúsculas.
« Última modificación: Abril 02, 2013, 12:28:37 por lmtreser » En línea

lmtreser
Moderador
PIC18F
*****
Desconectado Desconectado

Sexo: Masculino
Mensajes: 1338



WWW
« Respuesta #2 : Abril 01, 2013, 10:24:46 »

1.2. ¡Hola mundo! en C (o como hacer destellar un LED)

Hacer destellar un LED es muy sencillo. Tanto como crear un bucle infinito, escribir en un pin, generar una demora y volver a escribir. El ejemplito:

Código:
/*
 * File:   main.c
 * Author: lucas
 * Created on 1 de abril de 2013, 22:20
 * Microcontrolador: PIC16F648A
 *
 * ¡Hola Mundo! en C (o como hacer destellar un LED)
 */

#include <stdio.h>
#include <stdlib.h>
#include <xc.h> // Librería XC8

#define _XTAL_FREQ 4000000 // Indicamos a que frecuencia de reloj esta funcionando el micro

// PIC16F648A Configuration Bit Settings
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF      // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = ON       // Brown-out Detect Enable bit (BOD enabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

// FUNCION PRINCIPAL
void main ()
{
     TRISB = 0b00000000; // Configuro puerto B como salidas
     while (1) // Bucle infinito
     {
         PORTBbits.RB0 = 0; // Apago pin RB0
         __delay_ms(500);
         PORTBbits.RB0 = 1; // Enciendo pin RB0
         __delay_ms(500);
     }
}

* Podríamos hacer el cambio de estado del pin RB0 (toggle) utilizando la siguiente instrucción: PORTBbits.RB0 ^= 1;
« Última modificación: Abril 02, 2013, 01:06:54 por lmtreser » En línea

lmtreser
Moderador
PIC18F
*****
Desconectado Desconectado

Sexo: Masculino
Mensajes: 1338



WWW
« Respuesta #3 : Abril 02, 2013, 12:27:32 »

1.3. Leer un pulsador

Utilizando una estructura condicional "if" podemos leer un pulsador conectado en RB0 para encender o apagar un LED en el pin RB4.

Código:
/*
 * File:   main.c
 * Author: lucas
 * Created on 1 de abril de 2013, 22:20
 * Microcontrolador: PIC16F648A
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <xc.h> // Librería XC8

#define _XTAL_FREQ 4000000 // Indicamos a que frecuencia de reloj esta funcionando el micro

// PIC16F648A Configuration Bit Settings
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF      // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = ON       // Brown-out Detect Enable bit (BOD enabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

// FUNCION PRINCIPAL

void main() {

    TRISB = 0b00000001; // Configuro puerto B
    PORTB = 0b00000000;

    if (PORTBbits.RB0 == 1) {
        PORTBbits.RB4 = 1;
    } else {
        PORTBbits.RB4 = 0;
    }
}
« Última modificación: Abril 02, 2013, 12:11:28 por lmtreser » En línea

lmtreser
Moderador
PIC18F
*****
Desconectado Desconectado

Sexo: Masculino
Mensajes: 1338



WWW
« Respuesta #4 : Abril 02, 2013, 01:35:10 »

1.4. Utilizando PWM

Vamos a utilizar una señal PWM de 8 bits para controlar el brillo de un LED. Para configurar el módulo CCP1 en modo PWM solo basta con escribir 0x0C en el registro CCP1CON.

Frecuencia PWM: el periodo de la onda PWM lo determina el tiempo que dura el conteo del Timer2 desde 0 hasta el valor cargado en el registro PR2. Y como la frecuencia es la inversa del período podemos deducir:

Frecuencia = \frac{FOSC}{4*(PR2 + 1) * Prescaler}



Donde:

* PR2 es el valor del registro PR2 (entre 0 y 255)
* FOSC es la frecuencia del cristal utilizado
* Prescaler es el prescaler del Timer2 (1, 4 ó 16). Se configura en el registro T2CON.

Ciclo de trabajo (duty cicle): es la cantidad de tiempo que en un periodo la salida PWM permanece en estado alto. El valor es determinado por el contenido del registro CCPR1L. Podemos deducir el tiempo utilizando la formula:

Ciclo de Trabajo = \frac{4*CCPR1L*Prescaler}{FOSC}



Donde:

* CCPR1L es el valor del registro CCPR1L (entre 0 y 255)
* FOSC es la frecuencia del cristal
* Prescaler   es el prescaler del Timer2 (1, 4 ó 16)

Ejemplo dimerizado de un LED conectado a RB3

Código:
/*
 * File:   main.c
 * Author: lucas
 * Created on 1 de abril de 2013, 22:20
 * Microcontrolador: PIC16F648A
 *
 * Utilizando PWM para dimerizar un LED
 */

#include <stdio.h>
#include <stdlib.h>
#include <xc.h> // Librería XC8

#define _XTAL_FREQ 4000000 // Indicamos a que frecuencia de reloj esta funcionando el micro

// PIC16F648A Configuration Bit Settings
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF      // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = ON       // Brown-out Detect Enable bit (BOD enabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

// FUNCION PRINCIPAL
void main(void) {
    TRISB = 0;                  // Puerto B como salidas
    PORTB = 0;                  // Limpio el puerto B

// CONFIGURANDO PWM  
    CCP1CON = 0b00001100;       // Activamos el modo PWM
    PR2 = 250;                  // Frecuencia 250Hz
    T2CONbits.T2CKPS = 0b10;    // Prescaler del timer 2 en 1:16
    T2CONbits.TMR2ON = 1;       // Arranca el PWM      

// BUCLE INFINITO
    unsigned char i;           // Declaramos una variable
    while (1){
    for(i=0; i=50; i++)
    {
      CCPR1L = CCPR1L++;        // Seteando el ciclo de trabajo
      __delay_ms (100);    
    }
    i=0;                       // Reiniciamos la variable para comenzar el ciclo de nuevo
    }
    }
« Última modificación: Abril 02, 2013, 02:55:03 por lmtreser » En línea

lmtreser
Moderador
PIC18F
*****
Desconectado Desconectado

Sexo: Masculino
Mensajes: 1338



WWW
« Respuesta #5 : Abril 02, 2013, 05:18:44 »

1.5. Uso de funciones

Las funciones sirven para modularizar un programa. La idea es dividir nuestro código en distintos bloques, y asignarle una tarea especifica a cada uno. Esto nos ayudará a comprender el funcionamiento de nuestro programa y a hacerlo más ordenado.

Si bien todavía no hablamos para nada de variables, tenemos que tener en cuenta que juega un papel muy importante la forma en que las declaramos. Un poco más adelante lo veremos.

La sintaxis de una función es la siguiente:

tipo_de_datos nombre_de_la_funcion (tipo_y_nombre_de_argumentos) {
    instrucciones
    instrucciones
}

 
donde:

tipo_de_datos: es el tipo de dato que devolverá esa función.
nombre_de_la_funcion: es el identificador que le damos a nuestra función.
tipo_y_nombre_de_argumentos: son los parámetros que recibe la función.

No todas las funciones reciben argumentos. En caso que posean se tratan simplemente de variables locales que reciben un valor. Este valor se lo enviamos al hacer la llamada a la función.

Un sencillo ejemplo:

Código:
// FUNCION "EJEMPLO". NO RECIBE ARGUMENTOS
void ejemplo (void){
    PORTBbits.RB1 = 1;    // High pin RB1
    __delay_ms (1700);    // Demora
    PORTBbits.RB1 = 0;    // Low pin RB1
}

// FUNCION PRINCIPAL
void main(void) {
    TRISB = 0b00000001;
    PORTB = 0;                       // Limpio el puerto B

    while (1){                         // Bucle infinito   
    if (PORTBbits.RB0 == 1){    // Chequeo estado de RB0
        ejemplo();                    // Llamado a función "ejemplo"
    }
    }
}
« Última modificación: Abril 06, 2013, 01:28:15 por lmtreser » En línea

lmtreser
Moderador
PIC18F
*****
Desconectado Desconectado

Sexo: Masculino
Mensajes: 1338



WWW
« Respuesta #6 : Abril 06, 2013, 01:05:17 »

1.6. Variables y tipos de datos

TIPOS DE DATOS. Siempre que arranquemos a estudiar un nuevo compilador lo primero que debemos analizar, a mi entender, son los tipos de datos disponibles. Ello nos permitirá tener control sobre el dimensionamiento de las variables determinando que tamaños y rangos de datos podremos almacenar en ellas.

Los puntos a tener en cuenta sobre los tipos de datos son los siguientes:

* Nombre del tipo y su correspondiente nombre estandarizado
* Existencia de tipos para almacenar números enteros y reales
* Tamaño en bits
* Tipo aritmético (si es con o sin signo)
* Comportamiento del tipo aritmético por defecto (si no especificamos si el tipo es con o sin signo ¿cual es el comportamiento?)
* Rango de valores que podremos almacenar

En XC8 tenemos los siguientes tipos para almacenar datos numéricos "enteros" (sin decimales), a saber:


En la tabla pueden ver que puse el nombre estandarizado de cada tipo. Ya que es más fácil de visualizar un int16 que un signed int o int32 que signed long (ya veremos como utilizar los nombres estandarizados en nuestro código).

Hay que tener en cuenta que los tipos de datos: bit y short long no son tipos estandar de C. Y el que tipo long long es C99 Standard. El tipo bit tiene ciertas limitaciones que ya veremos.

Tipos con signo o sin signo. Si el signo no se especifica junto al tipo de dato, el tipo de dato por defecto será signado con excepción del tipo char que por defecto es unsigned o sin signo. El tipo bit siempre se lo toma no signado.


Los rangos disponibles nos permitirán elegir eficientemente que tipo debemos utilizar al diseñar nuestro código. Por ejemplo para almacenar los días dentro de un mes (de 1 a 31) con un tipo char (int8) nos alcanzará. Pero si queremos almacenar los días consecutivos dentro de un año (de 1 a 365) ya no nos alcanzará debiendo utilizar un signed int (int16).

Para almacenar el kilometraje de un auto ya no nos alcanzará con un signed int (int16) y deberemos elegir un tipo mayor como ser signed short long (int24). Y si queremos almacenar los habitantes de un país nos quedamos cortos con un short long (int24) debiendo utilizar para ello un unsigned long long (int32) pudiendo almacenar hasta 4.294.967.295 habitantes.

En XC8 también contamos con tipos para almacenar datos numéricos "reales" o flotantes, a saber: 24-bit y 32-bit floating-point types. Por ahora sólo debemos saber que existen además float y double. Más adelante ampliaremos.

Gracias a Jukinch por el excelente aporte a este capítulo!

* registros-timer0.png (42.13 KB - descargado 364 veces.)
* prescaler.png (8.65 KB - descargado 348 veces.)
* tabla51.jpg (119.38 KB - descargado 161 veces.)
* tablarangostipos.jpg (119 KB - descargado 155 veces.)
« Última modificación: Mayo 19, 2013, 10:10:21 por lmtreser » En línea

lmtreser
Moderador
PIC18F
*****
Desconectado Desconectado

Sexo: Masculino
Mensajes: 1338



WWW
« Respuesta #7 : Abril 13, 2013, 02:36:20 »

1.7. Usando una interrupción por Timer 0

El PIC16F648A cuenta con un temporizador programable que efectúa una interrupción al desbordar su cuenta. Esto es muy útil para gran cantidad de artilugios.

Para trabajar con el Timer 0 debemos hacer uso de algunos registros y bits de configuraciones. A saber:


Registro TMR0: almacena el valor del contador en tiempo real. Se puede alterar su contenido.
Registro INTCON: configuración de interrupciones. Los siguientes bits están asociados al Timer0:

- T0IF: bandera que se pone a "1" al producirse un desbordamiento del timer.
- T0IE: habilita la interrupción por desbordamiento del timer.
- GIE: habilita las interrupciones globalmente.

Registro OPTION: contiene varios bits de control asociados a nuestro timer:

- PS0, PS1 y PS2: bits de configuración del prescaler (divisor de pulsos).
 

- PSA: bit de asignación de prescaler, si está en "0" se asigna al TMR0.
- T0SE: bit de selección del tipo de flanco para el TMR0. No lo vamos a usar por ahora.
- T0CS: selecciona la entrada de reloj del TMR0, colocar a "0" para incrementar por ciclo de reloj interno.

El próximo paso será saber el tiempo que necesitamos para producir la interrupción por desborde del timer. Para hacer este calculo utilizamos la siguiente fórmula que relaciona las distintas variables:

Interrupcion = 4*\frac{1}{FOSC}*(256-TMR0)*Prescaler



Veamoslo en un ejemplo. Cada 65 ms desbordará el timer alterando el estado del pin RB0 donde colocamos un LED para hacerlo destellar.

Código:
/*
 * File:   main.c
 * Author: lucas
 * Created on 1 de abril de 2013, 22:20
 * Microcontrolador: PIC16F648A
 *
 * Uso de interrupción por Timer 0
 */

#include <stdio.h>
#include <stdlib.h>
#include <xc.h> // Librería XC8

#define _XTAL_FREQ 4000000 // Indicamos a que frecuencia de reloj esta funcionando el micro
#define LED PORTBbits.RB0

// PIC16F648A Configuration Bit Settings
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF      // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = ON       // Brown-out Detect Enable bit (BOD enabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

unsigned char cuenta = 0;   // Declaro una variable "cuenta"

// FUNCION DE INTERRUPCION
void interrupt ISR(void) {
    cuenta++;                   // Incremento variable
    INTCONbits.TMR0IF = 0;      // Limpiamos bandera de desborde
}

// FUNCION PRINCIPAL
void main () {
    TRISB = 0;                   // Puerto B como salidas
    PORTB = 0;

    // Configuración del timer & interrupcion
    TMR0 = 0;
    INTCONbits.TMR0IE = 1;
    INTCONbits.GIE = 1;
    OPTION_REGbits.PS0 = 1;
    OPTION_REGbits.PS1 = 1;
    OPTION_REGbits.PS2 = 1;
    OPTION_REGbits.PSA = 0;
    OPTION_REGbits.T0CS = 0;

    // Bucle infinito
    while (1){
        if (cuenta == 10){
            LED ^= 1;
            cuenta = 0;
        }
    }
}
En línea

lmtreser
Moderador
PIC18F
*****
Desconectado Desconectado

Sexo: Masculino
Mensajes: 1338



WWW
« Respuesta #8 : Mayo 19, 2013, 10:21:42 »

1.8. Ejemplo de uso PIC18F4550, delays y USART

Un completo ejemplo de uso sobre el puerto serie que incorpora este microcontrolador. El proyecto completo en un ZIP, probado y compilado en Windows 7 y Ubuntu 10.04.

Código:
/*
programa: prueba oscilador interno y módulo usart
pic: 18f4550
crystal: NO
CPU: 8Mhz (valor establecido dentro de main cambiando los bits IRCF2, IRCF1 e IRCF0 del registro OSCCON)
en RA6 sale la frecuencia de Fosc/4   ------->   8Mhz/4 = 2Mhz


CONEXIONES: los cambios se pueden hacer en el archivo configuracion_hard.c
1 led en port b0 con una resistencia en serie de 470ohms
1 led en port b1 con una resistencia en serie de 470ohms

Los leds cambian de estado cada 1 segundo. Uno enciende y el otro se apaga cada vez.
*/

#define _XTAL_FREQ 8000000 // Linea necesario para los cálculos de la función
                           // de delay. CUIDADO. no es para la configuración
                           // de la frecuencia de trabajo del cpu del pic.
                           // eso se determina en otro lado. :)



/*Includes globales*/
#include <pic18.h>
#include <xc.h>
#include <delays.h> /* Para utilizar demoras en nuestro código debemos incluir la librería delays.h.*/
#include <plib/usart.h> //Libreria para el manejo del modulo USART

/*Includes locales*/
#include "configuracion_de_fuses.c"
#include "configuracion_hard.c"


/*declaración de variables globales*/

char CaracterRx;
char MensajeTx[] = "COMUNICACION SATISFACTORIA";

/*declaración de funciones*/
void MyMsDelay(int ms);
//void interrupt Interrupcion();

///////////////////////////////////////////////////////////////////////////////
//                     Programa Principal                                    //
///////////////////////////////////////////////////////////////////////////////


void main(void)
{
// cambiamos la frecuencia del oscilador interno del valor por defecto de 32khz
// a 8mhz mediante los bits del registro OSCCON
    OSCCONbits.IRCF2 = 1;
    OSCCONbits.IRCF1 = 1;
    OSCCONbits.IRCF0 = 1;

    ADCON0 = 0X00,ADCON1 = 0X0F,CMCON = 0X07; //puerto A con todos los pines digitales
    TRISA = 0X00; // puertos A B y C como salida. Recordar Tip: el 0 es una o de ouput y el 1 una I de input!!!
    TRISB = 0X00;
    TRISC = 0X00;
    LATA = 0X00; // ponemos los puertos en cero
    LATB = 0X00;
    LATC = 0X00;
    PINLED0 = 0; // Seteamos el pin como salida para el LED
    PINLED1 = 0; // Seteamos el pin como salida para el LED

// configuramos el puerto serie
 OpenUSART(USART_TX_INT_OFF &
            USART_RX_INT_ON &       //Activar la interrupcion por la recepcion de dato del buffer de Rx del USART
            USART_ASYNCH_MODE &     //Modo asincrono (fullduplex)
            USART_EIGHT_BIT &       //8 bits de datos
            USART_CONT_RX &         //Recepción continua
            USART_BRGH_HIGH, 51);  //9600 Baudios

 // (frecuencia a la que trabaja el cpu/dbaudrate)/16)-1
 // (8.000.000/9600)/16)-1=51






    INTCONbits.PEIE = 1; //Activamos interrupcion de perifericos
    INTCONbits.GIE = 1;  //Activamos las interrupciones globales

    while(BusyUSART());     //Se espera a que el buffer de Tx este libre
    putsUSART(MensajeTx);   //Se envía un string de bienvenida

    while(1){   //Bucle infinito

            LED0 = ~LED0; // Intercambiamos el estado del pin del led (Toggle LED)
            Delay10KTCYx(200); //ver como se hacen los cálculos del delay más abajo
            LED1 = ~LED1; // Intercambiamos el estado del pin del led (Toggle LED)
            }


}

void interrupt Interrupcion()   //Funcion que atiende las interrupciones
{
    CaracterRx = ReadUSART();   //Se lee el dato que esta en el buffer de Rx del USART

    while(BusyUSART());
    putsUSART("\n\rUsted digito la tecla: ");
    while(BusyUSART());
    WriteUSART(CaracterRx);
     PIR1bits.RCIF = 0;  //Desactivamos la bandera de recepción en el buffer de entrada del USART
}




void MyMsDelay(int ms)
{
    while(ms--)
    {
        __delay_ms(1);
    }
}


/*
CÁLCULOS DE LOS RETARDOS

 Para utilizar demoras en nuestro código debemos incluir la librería delays.h. En ella tenemos 4 funciones:

Delay10TCYx(i)      ->    10.Tcy.i    genera una demora de 10 ciclos de instrucciones     *   i

Delay100TCYx(i)     ->   100.Tcy.i    genera una demora de 100 ciclos de instrucciones    *   i

Delay1KTCYx(i)      ->  1000.Tcy.i    genera una demora de 1000 ciclos de instrucciones   *   i

Delay10KTCYx(i)     -> 10000.Tcy.i    genera una demora de 10000 ciclos de instrucciones  *   i

i puede tomar un valor de 1 a 255. Si se toma valor 0 i es 256

NOTA: Para hacer los cálculos de los retardos debemos tener en cuenta la frecuencia a la que
trabaja la CPU del pic. Y ojo que la velocidad del CPU no siempre será la velocidad del cristal.
Podríamos tener un cristal de 4Mhz y hacer trabajar la CPU del pic a 48Mhz mediante el uso del PLL.
O trabajar con cristal interno a una frecuencia de 8Mhz y establecer una velocidad de 1 Mhz mediante los postcalers.

Comprendido esto podemos pasar a hacer los cálculos.


                                      1
1 ciclo de reloj es =  ---------------------------------
                         Frecuencia que le llega al CPU  (No la Frecuencia del cristal!!!)


1 TCY está formado por 4 ciclos de reloj. 4 ciclos de reloj tarda el pic en procesar una instrucción.

Entonces si queremos saber cuanto demora 1 TCY debemos multiplicar 4 veces lo que demora 1 ciclo del reloj del CPU.


                              1
1 TCY se calcula como  4 * --------
                             Fosc


donde fosc = frecuencia que llega a la CPU del pic (NO LA FRECUENCIA DEL CRISTAL!!!)



Cálculo de delay para generar 1 segundo con frecuencia de trabajo de CPU a 8mhz
---------------------------------------------------------------------------------
Las funciones de retardos usan como parametro los TCY. Entonces tenemos que calcular cuantos TCY hay que utilizar
para obtener 1 segundo.

Dijimos que:
                              1
1 TCY se calcula como  4 * --------
                             Fosc


Fosc= 8Mhz = 8*10^6 hz = 8.000.000hz

                               1           1
 por lo tanto 1 TCY =  4 * ---------- = ---------- = 0,0000005sec
                            8*10^6 Hz    2*10^6Hz


              1 TCY = 0,0000005seg = 5*10^-7 seg

Es decir que 1 TCY tarda 0,0000005seg.

Si dividimos 1 sobre TCY nos da la frecuencia en Hertz


              1
            ----- = frecuencia en hertz
             TCY


                    1
            -------------- = frecuencia en hertz
             0,0000005seg.


             2.000.000 Hertz = 2Mhz. Es decir que Fosc oscila 2.000.000 de veces durante 1 segundo


Entoces para calcular un segundo la formula es:

             1
  1seg * -----------     = 2.000.000 TCYs
          0,0000005 seg


Ahora que sabemos que necesitamos 2.000.000 TCYs para demorar un segundo debemos elegir una de las
funciones que nos brinda la librería delays.h debiendo tener presente que sólo reciben como parámetro
valores de i de 1 a 255. Si se toma 0 equivale a 256

Para este caso debemos usar la función Delay10KTCYx(i) ya que:

     2.000.000 TCYs
    ----------------- = nos da un valor de 200i
        10.000 TCY

Y con dicho valor 200 logramos el retardo de 1 segundo!

Delay10KTCYx(200); //demora de 1 seg

*/

Gracias a Jukinch por el excelente aporte a este capítulo!

* ejemplo3.X.zip (236.98 KB - descargado 11 veces.)
« Última modificación: Mayo 19, 2013, 10:25:15 por lmtreser » En línea

Páginas: [1]   Ir Arriba
  Imprimir  
 
Ir a:  

Impulsado por MySQL Impulsado por PHP Powered by SMF 1.1.18 | SMF © 2011, Simple Machines
SMFAds for Free Forums
XHTML 1.0 válido! CSS válido!
Página creada en 0.179 segundos con 29 consultas. (Pretty URLs adds 0.026s, 3q)