CERTIFICADOS Calidad en nuestros productos. Tecnología a su Servicio
ISO 9001:2008
PROGRAMA DE CAPACITACIÓN SENA BOGOTA SEMANA 22 AL 25 DE ABRIL TEMA: PROGRAMACIÓN MICROCONTROLADORES MICROCHIP
1 – MATERIALES NECESARIOS
-
Programadores ICSP PICKIT3
-
Kit Explorer 16. Referencia DM240001
-
Kit m_touch. Referencia 183026-2
-
Starter kit PIC32. Referencia DM320001
-
Kit TRACME 2013 (GPS y GSM). Referencia
2 – TEMAS
Abril 22 -
Nueva plataforma de trabajo MPLABX de MICROCHIP
-
Nuevos compiladores XC8, XC16 y XC32 de MICROCHIP para el trabajo con lenguaje C
-
Programas básicos en lenguaje ensamblador y en lenguaje C con el PIC 16F1937 utilizando el kit m_touch
Abril 23 -
Programas en el PIC de 16 bits 24FXXXX utilizando la tarjeta EXPLORER 16 y los programadores PICKIT3
Abril 24 -
Programas en el dsPIC de 16 bits 33Fxxxx utilizando la tarjeta EXPLORER EXPLORER 16 y los programadores PICKIT3
Abril 25 -
Trabajo con el Starter kit PIC32
-
Demostración con el kit TRACME 2013 (GPS Y GSM)
Preparado por: Luis Guillermo Montoya Diaz Asesor Profesional SUCONEL S.A
Abril 23 -
Programas en el PIC de 16 bits 24FXXXX utilizando la tarjeta EXPLORER 16 y los programadores PICKIT3
Abril 24 -
Programas en el dsPIC de 16 bits 33Fxxxx utilizando la tarjeta EXPLORER EXPLORER 16 y los programadores PICKIT3
Abril 25 -
Trabajo con el Starter kit PIC32
-
Demostración con el kit TRACME 2013 (GPS Y GSM)
Preparado por: Luis Guillermo Montoya Diaz Asesor Profesional SUCONEL S.A
Descripción detallada de las clases: Introducción a las nuevas herramientas de Microchip, tanto en Hardware como en Software Instalación de los siguientes programas: -
MPLABX Ver. 1.60 Compilador XC8 de Microchip para la la programación en lenguaje C de los microcontroladores de la familia de 8 bits
Lo primero que vamos a realizar, luego de instalar el software necesario, será aprender a manejar la nueva plataforma de MICROCHIP llamada MPLABX, para eso, debemos seguir el paso a paso que se presenta a partir de la siguiente página. Adicional a esto se iniciará el curso con 2 programas básicos en el manejo de entradas y salidas, tanto en lenguaje ensamblador como en lenguaje C, para así poder continuar con propiedad el resto del curso.
Paso a paso para el manejo del MPLABX Este paso a paso se realiza con un primer ejemplo, el cual enseña el manejo de entradas y salidas en el PIC 16F887. Se utilizará la versión 1.60 que es la última en la web de Microchip en este momento. Se utilizará el compilador XC8 para el trabajo en lenguaje C y el mpasm 5.48 para el trabajo en lenguaje ensamblador.
Luego de abrir el MPLABX utilizando el icono que se crea automáticamente en el escritorio, es bueno verificar si los compiladores a utilizar están instalados. Para eso se ingresa por la pestaña Tools y luego en el ítem options, se llega al siguiente cuadro de diálogo.
En éste, en la opción Embedded, verificamos que efectivamente, tanto el compilador para ensamblador mpasm 5.48 como el compilador para lenguaje C XC8, están instalados. En caso de no hallarse, se debe hacer click en la pestaña Scan for Build Tools y automáticamente, buscará los compiladores en el PC, siempre y cuando se hallan instalado previamente. Tanto el MPLABX como el compilador XC8 se bajan gratuitamente de la página www.microchip.com/MPLABX Si todo está listo se comienza el ejemplo en lenguaje ensamblador creando un nuevo proyecto como lo indica la figura siguiente:
File y luego New Project
Sale el primer paso que es elegir el tipo de proyecto a realizar se elige Microchip Embedded y Standalone Project click en Next.
En el paso dos se elige el dispositivo, en este caso en la familia de medio rango de 8 bits de Microchip se selecciona la referencia PIC16F877. Click en Next.
El paso tres es opcional y solo aparece para aquellos microcontroladores que poseen alguna herramienta de simulación. El paso cuatro entonces es la selección de la herramienta para la programación y/o simulación del proyecto. En este caso se elige el PICKIT3, si ya está conectado a un puerto USB del PC, aparece con el
respectivo número de serie como se aprecia en el cuadro de diálogo. Click en Next.
El paso seis permite seleccionar el compilador, inicialmente, elegimos mpasm 5.48 porque trabajaremos en ensamblador. Click en Next.
Como paso séptimo y último, damos nombre al proyecto y elegimos la carpeta donde almacenaremos nuestros archivos. Click en Finish.
Ya está terminado el proyecto donde se almacenarán los archivos fuente y ejecutable de la aplicación. Seleccionamos en el nombre del proyecto la opción Source File, luego New y por último la opción Other.
Acá se encuentran las diferentes extensiones a usar en ensamblador, en este caso se elige Assembly.asm y click en Next.
Para facilitar las cosas, le damos el mismo nombre al archivo fuente y se almacenará automáticamente en la carpeta donde está ubicado el Proyecto. Click en Finish.
Aparece entonces el editor para comenzar con el código de nuestra aplicación. Lo primero será elegir los bits de configuración entrando por la pestaña Window luego la opción Pic Memory Views y finalmente, Configuration Bits.
Por el momento solo se necesita el oscilador XT para trabajar a 4MHZ, deshabilitar el perro guardián WDT y la programación a bajo voltaje, es decir, el bit LVP en OFF. Luego de realizar la selección se crea la palabra de configuración en la pestaña Generate Source Code to Output
Se selecciona la palabra de configuración, se copia y se pega en la parte inicial del editor.
Inicio el código y al finalizar lo compilo del icono Clean and Build (Escoba y martillo). Si no hay errores debe aparecer la frase Loading Completed. Ahora se procede con la programación. Si el programador está conectado, como en este caso que tenemos seleccionado y conectado a nuestra aplicación el PICKIT3, se debe habilitar la alimentación a través del puerto USB donde está conectado el PICKIT3, esto se hace si la aplicación no tiene alimentación independiente. Si alimentamos a través del PICKIT3, se debe verificar que el consumo de corriente de la aplicación no supere los 500 mA para no poner en riesgo el puerto USB del PC.
La programación se hace desde el icono Make and Programming Device (Flecha verde hacia abajo). El aviso en rojo aparece cuando la aplicación no posee alimentación y debemos habilitarla a través del puerto USB del PICKIT3 así:
Vamos a propiedades del projecto con File y luego Project Properties
Selecciono PICKIT3 PICKIT3 y y luego en Option Categories elijo Categories elijo Power Power y y coloco el chulo en Power Target circuit from PICKIT3. PICKIT3. Luego Apply y OK.
Volvemos entonces a programar y aparece el aviso de precaución preguntando si el dispositivo trabaja a 5VDC, click en OK.
Al finalizar la programación Programming/Verify complete
en
forma
correcta,
aparece
el
aviso
Se verifica entonces en el hardware. Ahora veamos los pocos cambios que se deben realizar para la aplicación en lenguaje C.
Iniciamos el proyecto nuevo
Se elige el tipo de proyecto. Click en Next.
Se elige la herramienta de simulación y/o programación. En este caso PICKIT3. Como está conectado aparece el número de serie. Click en Next Next..
En este caso se elige el compilador para lenguaje C llamado XC8. La versión 1.12 es la última al momento de realizar este ejercicio. Click en Next.
Le doy el nombre al proyecto y selecciono la carpeta para almacenarlo. Click en Finish.
Con el proyecto listo a la izquierda de tu PC, se selecciona Source File luego New y finalmente C source file si está presente, sino es así, se selecciona Other y se busca C Source File.
Se da el nombre al archivo fuente, la extensión no es necesaria, ya está implícita. Click en Finish.
Aparece el editor y lo primero será la configuración de bits tal como se hizo en ensamblador para obtener la palabra de configuración. Window luego la opción Pic Memory Views y finalmente, Configuration Bits.
Por el momento solo se necesita el oscilador XT para trabajar a 4MHZ, deshabilitar el perro guardián WDT y la programación a bajo voltaje, es decir, el bit LVP en OFF. Luego de realizar la selección se crea la palabra de configuración en la pestaña Generate Source Code to Output.
Se copia y se pega al inicio del editor.
Se define la velocidad del oscilador a 4000000 HZ y se da inicio al código en C con la función principal void main()
Al terminar el código, se compila y se debe obtener, si no hay errores, el mensaje Loading Completed. Puede verse el funcionamiento en el simulador Proteus o directamente en el Hardware. Para programar se da click al icono Make and Programming (Flecha verde hacia abajo)
Si no hay problemas, debe aparecer el aviso Programming/Verify complete.
ENTRADAS Y SALIDAS EN EL MICROCONTROLADOR 16F887
Lo primero será entonces conocer el PIC 16F887 en sus funciones básicas de configuración y funcionamiento. Para ello, se trabajarán algunos de los pines de sus puertos como simples líneas de entrada o salida. Se debe tener en cuenta inicialmente, que este dispositivo posee 5 puertos llamados A, B, C, D y E como lo muestra la siguiente figura y que cada uno de ellos tiene un número de pines determinado, para ser utilizados como entrada digital, salida digital ó con una de sus funciones alternas, por ejemplo entrada para conversión análoga a digital, salida de PWM, transmisión o recepción de datos por comunicación serial, etc.
Figura 1. Diagrama de pines del PIC 16F887 Las líneas físicas con las que el microcontrolador se comunica con el mundo exterior se llaman puertos, en este caso se tienen: PORTA, PORTB, PORTC, PORTD Y PORTE y su correspondiente registro de configuración, es decir, quien
decide si los pines del puerto serán entrada o salida, se llaman TRIS así: TRISA, TRISB, TRISC, TRISD y TRISE. Recuerde que a diferencia de otros microcontroladores como los ATMEL AVR y los FREESCALE, en los PIC de MICROCHIP las entradas se configuran con unos y las salidas con ceros, por ejemplo si se configura el registro TRISA como 01001011, el microcontrolador tendrá los pines RA0, RA1, RA3 Y RA6 con la impedancia respectiva para el trabajo como entradas y los demás pines podrán trabajarse como salidas. Como se ve en el diagrama de pines, las líneas que se utilizan para convertir señales análogas a digitales son 14 y están ubicadas en los puertos A, B y E, denotados como AN0, AN1…AN13, los registros encargados de configurar los canales análogos se llaman ANSEL y ANSELH, éstos vienen preparados de fábrica para recibir señales análogas, por lo tanto, se deben limpiar (Cargar con cero) si no se va a realizar ninguna conversión A/D, así se podrán trabajar todos los pines como entrada o salida digital. En el capítulo dedicado a la conversión análogo a digital se tratará más a fondo el trabajo de estos registros. Con estos conceptos básicos se da comienzo al primer ejemplo que simplemente, permite contar de 0 a 9 los pulsos generados desde el pin RD4 del puerto D, visualizando en el puerto A, a través de leds y en el puerto C, mediante un display de siete segmentos de cátodo común conectado a un decodificador BCD a 7 segmentos. Ver plano electrónico. La cuenta solo se incrementará con flanco de subida, así aseguramos que se incremente solo en uno cada que se presiona el pulsador.
R2 220
R3 220
R4 220
R5 220
D1
U1 1
LED-RED
D2 LED-RED D3
LED-RED
D4 LED-RED
2 3 4 5 6 7 14 13 33 34 35 36 37 38 39 40
RE3/MCLR/VPP
RC0/T1OSO/T1CKI RC1/T1OSI/CCP2 RA0/AN0/ULPWU/C12IN0RC2/P1A/CCP1 RA1/AN1/C12IN1RC3/SCK/SCL RA2/AN2/VREF-/CVREF/C2IN+ RC4/SDI/SDA RA3/AN3/VREF+/C1IN+ RC5/SDO RA4/T0CKI/C1OUT RC6/TX/CK RA5/AN4/SS/C2OUT RC7/RX/DT RA6/OSC2/CLKOUT RA7/OSC1/CLKIN RD0 RD1 RB0/AN12/INT RD2 RB1/AN10/C12IN3RD3 RB2/AN8 RD4 RB3/AN9/PGM/C12IN2RD5/P1B RB4/AN11 RD6/P1C RB5/AN13/T1G RD7/P1D RB6/ICSPCLK RB7/ICSPDAT RE0/AN5 RE1/AN6 RE2/AN7
U2 15 16 17 18 23 24 25 26
7 1 2 6 4 5 3
A B C D BI/RBO RBI LT
QA QB QC QD QE QF QG
13 12 11 10 9 15 14
7448 19 20 21 22 27 28 29 30
R6
Q1 2N2222
2.7K
8 9 10
PIC16F887
R1 10k
Figura 2. Plano electrónico para el ejemplo de manejo de entradas y salidas ;********************************************************************************************* Programa en lenguaje ensamblador ;********************************************************************************************* ; Se incluye archivo .inc que contiene los registros y bis especiales del PIC ;********************************************************************************************* #include "p16F887.inc" ;********************************************************************************************* ; Palabras de Configuración de bits generadas automáticamente por el software ;********************************************************************************************* ; CONFIG1 ;__config 0xEFF1 __CONFIG _CONFIG1, _FOSC_XT & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_ON & _IESO_ON & _FCMEN_ON & _LVP_OFF ; CONFIG2 ; __config 0xFFFF
__CONFIG _CONFIG2, _BOR4V_BOR40V & _WRT_OFF ;******************************************************************************************* ; Bloque para registros de propósito general ;********************************************************************************************* CBLOCK 0X20
; Inicio del bloque de registros generales
REG1, REG2, CONT
; Estos se ubican luego de la posición 0x20 de la RAM
ENDC
; Fin del bloque de registros
;********************************************************************************************* ORG 00 ; Primera posición de la memoria de programa GOTO INICIO
; Voy a la etiqueta de inicio
ORG
; Salvo el vector de interrupción
05
;********************************************************************************************* ; Subrutina de retardo para milisegundos ;********************************************************************************************* RETARDO ; el literal que viene en W es el número de milisegundos del retard o MOVWF REG1 DOS
MOVLW .110 MOVWF REG2
UNO
NOP NOP NOP NOP NOP NOP DECFSZ REG2 GOTO UNO
DECFSZ REG1 GOTO DOS RETURN ;********************************************************************************************* ; Programa principal ;********************************************************************************************* INICIO
LIMPIAR
PREG
BANKSEL TRISA
; Voy al banco 1 para configurar puertos
CLRF TRISA
; Puerto A como salidas
CLRF TRISC
; Puerto C como salidas
MOVLW B'00010000'
; RD4 entrada y los demás
MOVWF TRISD
; pines del puerto D son salidas
BANKSEL ANSEL
; Voy al banco 3 para configurar ANSEL
CLRF ANSEL
; Todos los pines digitales
CLRF ANSELH
; Todos los pines digitales
BANKSEL PORTD
; Regreso al banco 0
BSF
; Habilito transistor para cátodo del display
PORTD,0
CLRF CONT
; Limpio contador
MOVF CONT,W
; Paso contador a W
MOVWF PORTC
; Paso W al puerto C (0 en 7 segmentos)
MOVWF PORTA
; Paso W al puerto A (Leds apagados)
BTFSC PORTD,4
; Pregunto si RD4 está en 0, pulsador ; presionado?
GOTO $-1
; Si no, vuelvo a preguntar
MOVLW .200
; Si RD4 está en 0, retardo de 200 ms
CALL RETARDO
; para evitar rebote de contacto
BTFSS PORTD,4
; Pregunto si vuelve a 0 para iniciar conteo
GOTO $-1
; por flanco de bajada, sino, continuo ; preguntando
INCF CONT
; Si está en 0, incremento contador
MOVLW 0X0A
; Cargo W con 10 para comparación
XORWF CONT,0
; Xor de W con Contador y resultado en W
BTFSC STATUS,2
; Pregunto por la bandera Z
GOTO LIMPIAR
; Si es uno, es porque el contador está en ; 10 y debo ir a limpiar contador
MOVF CONT,W
; Si no, Paso contador a W
MOVWF PORTC
; Paso W al puerto C (7 segmentos)
MOVWF PORTA
; Paso W al puerto A (Leds)
GOTO PREG
; Pregunto nuevamente por el pulsador.
END //*********************************************************************************************
Programa en lenguaje C //********************************************************************************************* #include
//Se incluye la libreria xc.h necesaria por contener los // registros y bits especiales del micro.
//********************************************************************************************* // Palabras de configuración de bits generadas automáticamente por el compilador // ******************************************************************************************** // CONFIG1 #pragma config FOSC = XT #pragma config WDTE = OFF
// Oscillator Selection bits XT oscillator // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF
// Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON
// RE3/MCLR pin function is MCLR
#pragma config CP = OFF #pragma config CPD = OFF #pragma config BOREN = ON #pragma config IESO = ON #pragma config FCMEN = ON #pragma config LVP = OFF
// Code Protection bit (protection is disabled) // Data Code Protection bit (protection is disabled) // Brown Out Reset Selection bits // Internal External Switchover Enable // Fail-Safe Clock Monitor Enabled bit // HV on MCLR must be used for programming
// CONFIG2 #pragma config BOR4V = BOR40V // Brown-out Reset Reset set to 4.0V #pragma config WRT = OFF
// Flash Program Memory Self Write Enable bits
//********************************************************************************************* // Definición de la velocidad del oscilador // ******************************************************************************************** #define _XTAL_FREQ 4000000 // ********************************************************************************************
// Declaración de variables // ******************************************************************************************** char cont = 0; // Declaro variable cont como un char y la inicio en 0 // ******************************************************************************************** void main() { TRISA=0;
//Puerto A como salidas
TRISC=0;
//Puerto C como salidas
TRISD=0X10;
// RD4 entrada los demás salida
ANSEL=0;
// Todos los pines digitales
ANSELH=0;
// Todos los pines digitales
PORTA=0;
// Limpio puerto A
PORTC=0;
// Limpio puerto C
RD0=1;
// Habilito salida del transistor para cátodo del display
while(1)
// Inicio ciclo infinito
{ if(cont<10)
// Pregunto si contador es menor que 10
{ if (!RD4)
// Pregunto si RD4=0
{ __delay_ms(200); // Retardo para evitar rebote de contacto while(!RD4)
// Mientras RD4 sea cero no haga nada
continue;
// Si pasa a uno continua
cont=cont+1;
// Incremento contador por flanco de subida
PORTC=cont;
// Muestro el conteo en display de 7 segmentos
PORTA=cont;
// Muestro el conteo en los leds
} } else { cont=0;
// Si el contador no es menor que 10, lo limpio
} } }
Algunas variaciones para optimizar el código en lenguaje C pueden ser:
1 – Definir las entradas y salidas con nombres diferentes a los pines y los puertos así: #define suiche RD4
// Nombro el pin RD4 como suiche
#define display PORTC
// Nombro el puerto C como display
#define leds PORTA
// Nombro el puerto A como leds
#define Q1
// Nombro el pin RD0 como Q1
RD0
De esta manera se puede realizar el código más fácilmente y a la hora de cambiar un pin o un puerto por otro, simplemente se realiza en la definición y no en todo el programa. 2 – Se pueden crear funciones, éstas son importantes porque si se utilizan varias veces, solo se tiene que realizar el llamado. Por ejemplo, La parte de código que incrementa y muestra el contador en los puertos en el ejemplo anterior, se puede sacar en la siguiente función: void incremente (void) {
cont=cont+1; display=cont; leds=cont; }
Y se hace el llamado con la instrucción Incremente(); // El nombre de la función puede ser cualquiera cualquiera La variable cont la declaramos como char, ya que esta va solo hasta 9 y el char es de 8 bits, pero se debe tener en cuenta que si declaramos solo char esta irá desde -127 hasta 128 porque es variable signada, si necesitamos variables mayores a 128 y menores a 255 se debe declarar como: unsigned char cont; // Variable son signo, es decir, con rango desde 0 hasta 255 Para números mayores a 255, las variables se deben declarar como enteros así: Int cont;
// Esta variable irá desde -32767 hasta 32768
Unsigned int
// Esta variable ira desde 0 hasta 65535
El código completo con los cambios es el siguiente: // PIC16F887 Configuration Bit Settings //********************* //******************************* ********************* ******************** ********************* ********************** ******************** ******************** ********** // Inclusión de la libreria xc.h y configuración de bits //********************* //******************************* ********************* ******************** ********************* ********************** ******************** ******************** ********** #include // CONFIG1 #pragma config FOSC = XT #pragma config WDTE = OFF #pragma config PWRTE = OFF
// Oscillator Selection bits XT oscillator // Watchdog Timer Enable (WDT disabled) // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON #pragma config CP = OFF
// RE3/MCLR pin function is MCLR // Code Protection bit (protection is disabled)
#pragma config CPD = OFF #pragma config BOREN = ON #pragma config IESO = ON #pragma config FCMEN = ON #pragma config LVP = OFF
// Data Code Protection bit (protection is disabled) // Brown Out Reset Selection bits // Internal External Switchover Enable // Fail-Safe Clock Monitor Enabled bit // HV on MCLR must be used for programming
// CONFIG2 #pragma config BOR4V = BOR40V // Brown-out Reset Reset set to 4.0V #pragma config WRT = OFF
// Flash Program Memory Self Write Enable bits
//********************* //******************************* ********************* ******************** ********************* ********************** ******************** ******************** ********** // Definición de la velocidad del oscilador //********************* //******************************* ********************* ******************** ********************* ********************** ******************** ******************** ********** #define _XTAL_FREQ 4000000 //********************* //******************************* ********************* ******************** ********************* ********************** ******************** ******************** ********** Definición de nombres para las variables //********************* //******************************* ********************* ******************** ********************* ********************** ******************** ******************** ********** #define suiche RD4
// Nombro el pin RD4 como suiche
#define display PORTC
// Nombro el puerto C como display
#define leds PORTA
// Nombro el puerto A como leds
#define Q1
// Nombro el pin RD0 como Q1
RD0
//********************* //******************************* ********************* ******************** ********************* ********************** ******************** ******************** ********** // Declaración de variables //********************* //******************************* ********************* ******************** ********************* ********************** ******************** ******************** ********** char cont=0; // Declaro variable cont como char y la inicio en 0
//********************************************************************************************* // Declaración de funciones //********************************************************************************************* void incremente (void) // Declaro y realizo la función incremente { cont=cont+1;
// Incremento el contador
display=cont;
// Muestro el contador por display de 7 segmentos (PORTC)
leds=cont;
// Muestro contador por leds (PORTA)
} //********************************************************************************************* void main() { TRISA=0;
//Puerto A como salidas
TRISC=0;
//Puerto C como salidas
TRISD=0X10;
// RD4 entrada los demás salida
ANSEL=0;
// Todos los pines digitales
ANSELH=0;
// Todos los pines digitales
leds=0;
// Limpio puerto A
display=0;
// Limpio puerto C
Q1=1;
// Habilito salida del transistor
while(1)
// Inicio ciclo infinito
{ if(cont<10) { if (!suiche) // Pregunto si suiche está presionado, en este caso = 0
{ __delay_ms(200);// Retardo para evitar rebote de contacto while(!suiche) // Mientras suiche esté en cero no haga nada continue; // Si pasa a uno incrementa contador por flanco de subida incremente(); // Llamo la función incrementar } } else { cont=0; // Si cont no es menor que 0, entonces lo limpio. } } } Puede comparar ambos programas e ir notando las diferencias entre un compilador y otro. Aunque soy gran amigo del lenguaje ensamblador, el hecho de no tener que direccionar bancos de memoria de datos, ni tener en cuenta en qué posición de memoria comienzan los registros de propósito general, porque en C simplemente se declaran las variables, además de la facilidad del procesamiento matemático, hace que generalmente me decida por el lenguaje C para realizar mis aplicaciones.
Realización de algunos programas con microcontroladores de 8 bits
-
Demostración con el PIC 16F1937
Materiales necesarios -
Programador ICSP PICKIT3 Kit mTouch Referencia DM183026-2 Extensiones Televisor o Video Beam
LOS MICROCONTROLADORES PIC DE 6 PINES
Existe en MICROCHIP la referencia de microcontroladores PIC de 6 pines llamada 10F20X, la cual incluye cuatro modelos: 10F200, 10F202, 10F204 y 10F206, estos difieren entre sí, básicamente, por el tamaño de sus memorias de datos y programa.
Tabla comparativa para la referencia de microcontroladores 10F20X Obviamente, con tan pocos pines, no existe la posibilidad de conectar un oscilador externo, éste siempre deberá programarse internamente, así las cosas, quedan los dos pines de alimentación y 4 líneas, una de ellas para la conexión del reset ó MCLR, que también puede ser configurada como entrada y las otras tres pueden ser configuradas como entrada o salida. El usuario debe tener en cuenta que estos micros en encapsulado DIP poseen 8 pines, pero dos de ellos no se conectan, en montaje superficial, estas referencias si tienen los seis pines exactos como puede verse en la figura siguiente que nos enseña los diagramas de pines.
Diagrama de pines de los PIC 10F20X (Encapsulado DIP y SOIC) Creo que hay muchos aficionados a los PIC que poseen aplicaciones con dispositivos de 8 pines, donde solo utilizan 2 ó 3 líneas de entrada y salida, encareciendo así su producto para el usuario final y quizás disminuyendo las posibilidades de competir en el mercado, simplemente, porque desconocen la existencia de los 10F20X. El primer programa será en lenguaje C. Simplemente, detectará un nivel lógico alto en el pin GP3 (Solo puede ser MCLR o pin de entrada) para activar las otras tres salidas, es decir, GP0,1,2 y 3.
D1
R1 220
U1
D2
GP0 GP1 GP2/T0CKI/FOSC4 GP3/MCLR
R2 220
D3
PIC10F200
R3 220
R4 10k
Plano Electrónico
Programa en lenguaje C
// Se incluye la librería principal con los bits y registros especiales del micro //******************************************************************************************** #include
// Se incluye librería principal con los SFR y sus bits
//******************************************************************************************** // Palabra de configuración creada automáticamente //*********************************************************************************************
#include
// CONFIG #pragma config WDTE = OFF #pragma config CP = OFF
// Watchdog Timer (WDT disabled) // Code Protect (Code protection off)
#pragma config MCLRE = OFF // GP3/MCLR pin fuction is digital //******************************************************************************************** // Se define la velocidad del oscilador //******************************************************************************************** #define _XTAL_FREQ 4000000 //******************************************************************************************** // Programa principal //******************************************************************************************** void main() { TRIS=0x08;
// Configuro GP3 como entrada. GP2, 1 y 0 como salida
GPIO=0;
// Limpio el Puerto único en este micro
OPTION=0B00000000; // Necesario para el trabajo del pin GP2 //******************************************************************************************** while(1)
// Inicio del ciclo infinito
{ if (GP3==1) // Pregunto por el estado del pin GP3 { GPIO=7; }
// Si está en uno activo GP2, 1 y 0
else { GPIO=0;
// si no está en uno apago las salidas GP2, 1 y 0
} } }
El anterior es el código en lenguaje C, utilizando el compilador XC8, que es el último aprobado y revisado para todas las familias de 8 bits de MICROCHIP (10F, 12F, 16F Y 18F). Este puede descargarse en forma gratuita, bajo su versión libre, al igual que la nueva plataforma MPLABX de la página www.microchip.com/mplabx A continuación el código en lenguaje ensamblador ; Se incluye la librería de cabecera con los registros y bits especiales del micro ;********************************************************************************************* #INCLUDE ;********************************************************************************************* ; Palabra de configuración de bits ;********************************************************************************************* __CONFIG _WDTE_OFF & _CP_OFF & _MCLRE_OFF ;********************************************************************************************* ; Bloque para registros de propósito general si los hay ;********************************************************************************************* CBLOCK 0X10 ENDC ;********************************************************************************************* ORG
00
GOTO
MAIN ; Voy a programa principal
ORG
05
; Salvo el vector de interrupciones
MOVLW
B'1000'
; Configuro GP3 como entrada y GP2,1 y 0
TRIS
GPIO
; como salidas
MOVLW
B'0000'
; Limpio el option pafra el buen trabajo del
MAIN
OPTION PREG
OFF
; pin GP2
BTFSS
GPIO,3
; Pregunto por el estado del pin GP3
GOTO
OFF
; Si está en cero voy a apagar salidas
MOVLW
B'111'
; Si está en uno activo las salidas GP2,1, 0
MOVWF
GPIO
GOTO
PREG
; y retorno a preguntar por GP3
CLRF
GPIO
; Apago las salidas
GOTO
PREG
; y retorno a preguntar por GP3
END
VISUALIZACIÓN DE MENSAJES FIJOS Y VARIABLES EN LCD
LCD1 LM016L
S D E 0 1 2 3 4 5 6 7 S D E S W V V V R R E D D D D D D D D 1 2 3
4 5 6
7 8 9 0 1 2 3 4 1 1 1 1 1
El LCD y sus pines de conexión Cuando se trabaja con diseño de circuitos electrónicos, muchas veces se tiene la necesidad de visualizar cosas como: Instrucciones de manejo de una máquina, la hora en un sistema de tiempo real, el monitoreo de una determinada variable, etc. Una opción muy interesante es el display de cristal líquido alfanumérico, estos están formados por una matriz de caracteres de 5x7 o 5x10 puntos cada uno, organizados en 1, 2, 3 ó 4 filas que pueden ir desde 16 hasta 40 caracteres. El proceso de visualización está controlado por un microcontrolador instalado en su parte posterior. Todos poseen 16 pines. La luz de fondo está instalada en los pines 15 y 16. Los demás tienen funciones específicas que se describen en el cuadro siguiente:
Funciones de cada uno de los pines del LCD Los bits RS, WR y E son los que permiten el control del LCD, aunque el bit WR, generalmente se encuentra conectado a GND, debido a que siempre estamos escribiendo en el LCD y para eso este bit debe estar en 0. La función de lectura es utilizada para consultar la bandera de ocupado o Busy Flag del LCD, pero como el tiempo máximo que tarda éste en realizar una operación, ya sea de configuración o visualización de un carácter es de 1,64 ms, simplemente, damos un retardo de 2 ms cada que se requiera una operación y se evita así la consulta del Busy Flag. El RS por el contrario, tiene un trabajo muy importante que es el de decidir si el dato enviado al LCD es para configuración del mismo, es decir, si queremos que trabaje a una o dos líneas, a cuatro u ocho bits, con cursor visible o no, etc. O si el dato es para visualizar. En el primer caso, este bit debe estar en 0 y en segundo caso debe estar en 1. El bit enable (E) es para autorizar cualquiera de las 2 operaciones anteriores en el LCD. Para permitir la operación el bit E debe estar en 1 y para terminarla, debe ponerse en 0. Para configurar el LCD se utiliza la matriz que se ve en el cuadro siguiente:
Matriz para la configuración del modo de trabajo del LCD
Significado de cada uno de los bits de la matriz de configuración Por ejemplo si deseo seleccionar funciones en el LCD, me debo ubicar en la fila 4 de la matriz donde están los bits DL, N y F los cuales significan: DL es el ancho del bus de datos, en 1 es de 8 bits y en 0 es de 4 bits N es el número de líneas, si es 1 es trabajo a 2 líneas, si es 0 es trabajo a 1 línea. F es es tamaño de los caracteres, si es 1 es 5x7, si es 0 es 5x10 Así, si deseo trabajar a 8 bits, 2 líneas y caracteres de 5x7 la palabra a enviar al LCD debe ser 00111000. Recuerde que el 1 que hay en la matriz es obligatorio, en
este caso el bit 5, porque es quien permite al microcontrolador del LCD ubicarse en la columna correspondiente. El dato en decimal es 56, este número no puede estar en ninguna de las otras filas de la matriz, por la diagonal de unos obligatoria que está presente en ella. Ahora viene el programa en lenguaje C para el primer ejercicio de escribir mensajes fijos en el LCD. // Programa para escribir un mensaje fijo en un LCD de 2 líneas x 16 caracteres //********************************************************************************************* // Se incluye librería xc.h y palabras de configuración de bits, todo esto generado // automáticamente por el compilador XC8 //********************************************************************************************* #include __CONFIG(FOSC_XT & WDTE_OFF & PWRTE_OFF & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_ON & IESO_ON & FCMEN_ON & LVP_OFF); __CONFIG(BOR4V_BOR40V & WRT_OFF); //********************************************************************************************* // Defino la velocidad del oscilador necesaria para el cálculo de los delay //********************************************************************************************* #define _XTAL_FREQ 4000000 //********************************************************************************************* // Defino nombres propios para pines y puerto del PIC usados para RS, E y el dato //********************************************************************************************* #define
LCD_RS
RD6
#define
LCD_EN
RD7
#define
LCD_DATA PORTB
//********************************************************************************************* // Declaro funciones para el LCD
//********************************************************************************************* void lcd_init (void);
// Inicialización del LCD
void set_lcd (void);
// Configuración del LCD
void lcd_puts(const char * s);
// Cadenas de caracteres al LCD
void lcd_goto(unsigned char pos);
// Direcciones en el LCD
void lcd_write(unsigned char c); // Escritura en el LCD
void main() { TRISD=0;
// Puerto D como salidas para bits RS (RD6) y E (RD7)
TRISB=0;
// Puerto B como salidas para enviar el dato al LCD
PORTB=0; // Limpio Puerto B PORTD=0; // Limpio Puerto D ANSEL=0;
// Todos los pines digitales
ANSELH=0; // Todos los pines digitales
lcd_init();
// Llamo funcón de inicialización
while(1) { lcd_goto(0); // selecciono primera línea lcd_puts(" BIENVENIDOS "); // Mensaje para la primera línea lcd_goto(0x40); lcd_puts("
// Selecciono segunda línea
LIBRO PIC
"); // Mensaje para la segunda línea
while(1) // Ciclo while para no hacer nada. Ya mostró el mensaje.
continue;
} } void lcd_init (void) // función de inicialización del LCD { LCD_DATA=2;
// Mando el dato 2 al Puerto para iniciar el LCD
set_lcd();
// Llamo la función de configuración
LCD_DATA=56;
// Mando el dato 56 al Puerto para 8 bits, 2 líneas y 5x7
set_lcd();
// Llamo función de configuración
LCD_DATA=15;
// Mando el dato 15 para prender LCD con cursor
set_lcd(); LCD_DATA=6; set_lcd(); LCD_DATA=1; set_lcd(); }
void set_lcd (void) // Función de configuración { LCD_RS=0;
// RS en 0 para indicar al LCD que es configuración
LCD_EN=1;
// Habilito la operación
__delay_ms(2); // Retardo necesario para la operación LCD_EN=0; }
// Termina la operación
void lcd_goto(unsigned char pos)
// Función de direcciones
{ LCD_RS = 0;
// RS en 0 para configuración
lcd_write(0x80+pos);
// Sumo 80H a pos que viene con un dato
} void lcd_write(unsigned char c)
// Función de escritura en el LCD
{ LCD_EN=1;
// Habilito la operación
LCD_DATA = ( c );
// Mando al puerto el dato que hay en c.
__delay_ms(2);
// Retardo necesario para operación
LCD_EN=0;
// Termina la operación
} /* Escribo una cadena de caracteres en el LCD */ void lcd_puts(const char * s) { LCD_RS = 1;
// Habilito la operación
while(*s)
// Mientras haya caracteres en la cadena enviada
lcd_write(*s++);
// Pase al siguiente
} Todas las funciones utilizadas pueden formar un archivo de cabecera .h para anexar al proyecto y dejar el programa principal más corto.
LCD1 LM016L
U1 S D E 0 1 2 3 4 5 6 7 S D E S W V V V R R E D D D D D D D D 1 2 3
4 5 6
7 8 9 0 1 2 3 4 1 1 1 1 1
1
RE3/MCLR/VPP
RC1/T1OSI/CCP2
2
RA0/AN0/ULPWU/C12IN0-
3
RA1/AN1/C12IN1-
4
RA2/AN2/VREF-/CVREF/C2IN+
5
RA3/AN3/VREF+/C1IN+
6 7 14 13
35 36
39 40
RC3/SCK/SCL RC4/SDI/SDA RC5/SDO RC6/TX/CK
RA5/AN4/SS/C2OUT
RC7/RX/DT
RA6/OSC2/CLKOUT RD0 RD1
34
38
RC2/P1A/CCP1
RA4/T0CKI/C1OUT
RA7/OSC1/CLKIN
33
37
RC0/T1OSO/T1CKI
RB0/AN12/INT
RD2
RB1/AN10/C12IN3-
RD3
RB2/AN8
RD4
RB3/AN9/PGM/C12IN2-
RD5/P1B
RB4/AN11
RD6/P1C
RB5/AN13/T1G
RD7/P1D
RB6/ICSPCLK RB7/ICSPDAT
RE0/AN5 RE1/AN6 RE2/AN7
15 16 17 18 23 24 25 26 19 20 21 22 27 28 29 30 8 9 10
PIC16F887
Simulación mensaje fijo
MENSAJE VARIABLE EN EL LCD Es muy sencillo mostrar mensajes fijos en el LCD, pero la versatilidad de estos dispositivos es visualizar datos variables. En el ejemplo siguiente anexaremos un conteo desde 0 a 999 al programa anterior y luego se monitoreará la variable voltaje cambiando desde 0 hasta 5 voltios. // Programa para mostrar un mensaje variable en un display LCD de 2 x 16 //********************************************************************************************* #include //********************************************************************************************* __CONFIG(FOSC_XT & WDTE_OFF & PWRTE_OFF & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_ON & IESO_ON & FCMEN_ON & LVP_OFF); __CONFIG(BOR4V_BOR40V & WRT_OFF); //********************************************************************************************* #define _XTAL_FREQ 4000000
//********************************************************************************************* #define
LCD_RS RD6
#define LCD_EN RD7 #define LCD_DATA PORTB //********************************************************************************************* char centenas, decenas, unidades; // Defino variables char. Solo van de 0 a 9 int cont=0, aux=0; // Defino variables int. Van desde 0 hasta 999 void bin_bcd (void) // Función binario a BCD { aux=cont;
// paso cont a aux para no dañar el proceso
centenas=0; // Inicializo variables en 0; decenas=0; unidades=0; while(aux>=100) // Inicio restas sucesivas para Binario BCD { aux=aux-100; centenas=centenas+1; } while(aux>=10) { aux=aux-10; decenas=decenas+1; } unidades=aux; }
void lcd_init (void); void set_lcd (void); void lcd_puts(const char * s); void lcd_putch(char c); void lcd_goto(unsigned char pos); void lcd_write(unsigned char c); void main() { TRISD=0; TRISB=0; PORTB=0; PORTD=0; PORTC=0; ANSEL=0; ANSELH=0;
lcd_init(); while(1) { lcd_goto(0); // selecciono primera línea lcd_puts(" CONTADOR lcd_goto(0x40);
");
// Selecciono segunda línea
lcd_puts(" IGUAL A: while(cont<999)
");
{ cont++; bin_bcd(); lcd_goto(0x4C);
// Ubico centenas en posición 4C del LCD
lcd_putch(centenas+48); // Sumo 48 para pasar a ASCII lcd_goto(0x4D);
// Ubico decenas en posición 4D del LCD
lcd_putch(decenas+48); // Sumo 48 para pasar a ASCII lcd_goto(0x4E);
// Ubico unidades en posición 4D del LCD
lcd_putch(unidades+48); // Sumo 48 para pasar a ASCII __delay_ms(500); } } }
void lcd_init(void) { LCD_DATA=2; set_lcd(); LCD_DATA=56; set_lcd(); LCD_DATA=15; set_lcd(); LCD_DATA=6; set_lcd(); LCD_DATA=1;
// Incremento cuenta cada 500 ms
set_lcd(); }
void set_lcd (void) { LCD_RS=0; LCD_EN=1; __delay_ms(2); LCD_EN=0; }
/* * Voy a una posición específica */ void lcd_goto(unsigned char pos) { LCD_RS = 0; lcd_write(0x80+pos); }
void lcd_write(unsigned char c) {
LCD_EN=1; LCD_DATA = ( c );
__delay_ms(2); LCD_EN=0;
}
/* Escribo una cadena de caracteres en el LCD */
void lcd_puts(const char * s) { LCD_RS = 1; while(*s) lcd_write(*s++); }
/* Escribo un caracter en el LCD */
void lcd_putch(char c) { LCD_RS = 1; lcd_write( c ); }
// write characters
LCD1 LM016L
U1 S D E 0 1 2 3 4 5 6 7 S D E S W V V V R R E D D D D D D D D 1 2 3
4 5 6
7 8 9 0 1 2 3 4 1 1 1 1 1
1 2 3 4 5 6 7 14 13 33 34 35 36 37 38 39 40
RE3/MCLR/VPP
RC0/T1OSO/T1CKI RC1/T1OSI/CCP2 RA0/AN0/ULPWU/C12IN0RC2/P1A/CCP1 RA1/AN1/C12IN1RC3/SCK/SCL RA2/AN2/VREF-/CVREF/C2IN+ RC4/SDI/SDA RA3/AN3/VREF+/C1IN+ RC5/SDO RA4/T0CKI/C1OUT RC6/TX/CK RA5/AN4/SS/C2OUT RC7/RX/DT RA6/OSC2/CLKOUT RA7/OSC1/CLKIN RD0 RD1 RB0/AN12/INT RD2 RB1/AN10/C12IN3RD3 RB2/AN8 RD4 RB3/AN9/PGM/C12IN2RD5/P1B RB4/AN11 RD6/P1C RB5/AN13/T1G RD7/P1D RB6/ICSPCLK RB7/ICSPDAT RE0/AN5 RE1/AN6 RE2/AN7 PIC16F887
Simulación de mensaje variable
15 16 17 18 23 24 25 26 19 20 21 22 27 28 29 30 8 9 10
CONVERSIÓN ANÁLOGO A DIGITAL EN EL PIC 16F887
Bloque ADC del PIC16F887 El módulo del conversor en la mayoría de los microcontroladores de 8 bits de MICROCHIP es de 10 bits, por lo tanto, su resolución será: Resolución = Vreferencia / # de cuantificaciones (1023) El microcontrolador 16F887 posee 14 canales análogos llamados AN0, AN1…AN13 distribuidos en los puertos A, B y E, los registros que permiten la selección individual de cada canal son ANSEL y ANSELH que vienen configurados de fábrica para recibir señales análogas, es por eso que en los programas anteriores siempre se ponían a 0 cuando en ellos iba a intervenir algún pin de los puertos A, B ó E.
Registros ANSEL Y ANSELH Si observan el diagrama de pines del 16F887, pueden notar que los canales AN0 a AN7 están ubicados en los puertos A y E, por lo tanto, el ANSEL tiene que ver con la conversión en cualquiera de esos canales. Los canales 8 al 13 están ubicados en el puerto B y por eso es el ANSELH quien se encargará de ellos. Por ejemplo, si deseo configurar el canal 3 para la conversión A/D de una señal análoga a digital, debo poner en uno el bit 3 del registro ANSEL y obviamente configurar como entrada el bit 3 del registro TRISA para que quede como entrada el bit 3 del puerto A. ANSEL= 0B00001000; // En hexadecimal 0x08; TRISA = 0B00001000; Adicionalmente, existen otros registros relacionados con la conversión análogo a digital como son: ADCON0, ADCON1, ADRESH y ADRESL, los dos últimos son los que almacenan el resultado digital de la conversión, ya que el módulo de conversión es a 10 bits, esos 10 bits del resultado se pueden alinear a izquierda o a derecha con la configuración del bit ADFM del registro ADCON1.
Alineación del resultado digital de la conversión A/D Los registros ADCON0 y ADCON1 son los de control de la conversión A/D, en ellos se configura la velocidad del conversor, el canal elegido, la alineación del
resultado, el voltaje de referencia, el bit de inicio de la conversión que igualmente sirve como bandera de indicación de la finalización del proceso. Se planteará entonces un ejercicio básico para entender la conversión A/D y luego se trabajará con una señal de voltaje visualizada en en LCD y una señal de temperatura enviada serialmente al PC. Para todos los ejemplos se utiliza la alimentación como voltaje de referencia, así las cosas la resolución será: Resolución = 5V / 1023 = 0,00488 V/cuantificación Señal análoga = Señal digital * resolución Se utiliza un potenciómetro conectado en el pin E0 del microcontrolador, que pertenece al canal análogo AN5. Lo primero es configurar los registros ANSEL y TRISE así: ANSEL = 0B00100000; // Canal AN5 análogo TRISE = 0B00000001; Ahora el registro ADCON0
// Bit 0 del puerto E como entrada
Registro ADCON0 Para el ejercicio, si queremos velocidad Fosc/8, canal 5 y habilitar el módulo de conversión, el ADCON0 queda así: ADCON0 = 0B01010101; Por último el ADCON1
Registro ADCON1 Si el voltaje de referencia es el de alimentación y se quiere alinear el resultado a la derecha, el registro ADCON1 queda así: ADCON1 = 0B10000000; Programa de conversión análogo a digital //********************************************************************************************* // Se incluye archivo de cabecera xc.h y las palabras de configuración //********************************************************************************************* #include __CONFIG(FOSC_XT & WDTE_OFF & PWRTE_OFF & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_ON & IESO_ON & FCMEN_ON & LVP_OFF); __CONFIG(BOR4V_BOR40V & WRT_OFF); //********************************************************************************************* // Se define al velocidad del oscilador //********************************************************************************************* #define _XTAL_FREQ 4000000
//********************************************************************************************* void main() { TRISE=0X01;
// Bit 0 del puerto E como entrada
TRISB=0;
// Puerto B como salida para resultado digital LSB en leds
TRISC=0;
// Puerto C como salida para resultado digital MSB en leds
ADCON0=0X55; // Fosc/8, canal 5 y habilitación del módulo de conversión ADCON1=0X80; // Vref 5V y alineación del resultado a derecha ANSEL=0X20;
// Canal AN5 análogo
ANSELH=0;
// Todos los demas pines digitales
PORTB=0;
// Limpio Puerto B
PORTC=0;
// Limpio Puerto B
while(1) { GO=1;
// Inicio el proceso de conversión
while(GO==1) // Mientras este bit este en uno está aún en el proceso continue;
// Si cambia a 0 terminó la conversión
PORTB=ADRESL;
// Paso parte baja del resultado al puerto B
PORTC=ADRESH; // Paso parte alta del resultado al puerto C __delay_ms(200); } }
// Conversión cada 200 ms
D1 LED-RED D2
R1 LED-RED D3
LED-RED D4
U1 1
220
R2
2 3 4 5 6 7 14 13
220
R3 220
LED-RED D5
R4 220
R5 LED-RED D6
LED-RED D7
33 34 35 36 37 38 39 40
220
R6 220
R7 220
LED-RED D8
R8
LED-RED D9
LED-RED
D10
RC0/T1OSO/T1CKI RC1/T1OSI/CCP2 RA0/AN0/ULPWU/C12IN0RC2/P1A/CCP1 RA1/AN1/C12IN1RC3/SCK/SCL RA2/AN2/VREF-/CVREF/C2IN+ RC4/SDI/SDA RA3/AN3/VREF+/C1IN+ RC5/SDO RA4/T0CKI/C1OUT RC6/TX/CK RA5/AN4/SS/C2OUT RC7/RX/DT RA6/OSC2/CLKOUT RA7/OSC1/CLKIN RD0 RD1 RB0/AN12/INT RD2 RB1/AN10/C12IN3RD3 RB2/AN8 RD4 RB3/AN9/PGM/C12IN2RD5/P1B RB4/AN11 RD6/P1C RB5/AN13/T1G RD7/P1D RB6/ICSPCLK RB7/ICSPDAT RE0/AN5 RE1/AN6 RE2/AN7
15 16 17 18 23 24 25 26
C0 C1
19 20 21 22 27 28 29 30 U1(RE0/AN5) V=4.45
8 9 10
PIC16F887
220
R9
RE3/MCLR/VPP
C0
220
R10
RV1 C1
220
LED-RED
% 9 8
1k
Figura 6. Plano Electrónico Como se puede ver en la simulación el resultado digital en los leds es de 909, así confirmamos el valor de voltaje a la entrada multiplicando por la resolución Señal análoga = 909 * 0.00488 = 4.44V que es lo que nos muestra el medidor a la entrada.
MONITOREO DE VOLTAJE CON VISUALIZACIÓN EN EL LCD En esta oportunidad combinaremos la visualización en el LCD con la conversión A/D para realizar así, algunas aplicaciones particulares. A continuación el lenguaje en lenguaje C con su respectiva documentación // Se incluye el archivo de cabecera y las palabras de configuración generadas automáticamente //******************************************************************************* #include //******************************************************************************* __CONFIG(FOSC_XT & WDTE_OFF & PWRTE_OFF & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_ON & IESO_ON & FCMEN_ON & LVP_OFF); __CONFIG(BOR4V_BOR40V & WRT_OFF); //******************************************************************************* // Definición de la velocidad del oscilador //******************************************************************************* #define _XTAL_FREQ 4000000 //******************************************************************************* // Nombres a pines y puerto del PIC para el trabajo en el LCD //******************************************************************************* #define
LCD_RS
RD6 // Llamo LCD_RS al pin RD6
#define
LCD_EN
RD7 // Llamo LCD_E al pin RD7
#define
LCD_DATA PORTB // Llamo LCD_DATA al puerto B
//******************************************************************************* // Declaración de variables //******************************************************************************* Unsigned int voltaje, digital,temp; // Declaro variables enteras sin signo
char diezmil, miles, centenas, decenas, unidades; // Declaro variables char ���������������������������������������������������������������������������������
// Declaración de funciones ���������������������������������������������������������������������������������
void binbcd (void); // Función para conversión de binario a BCD void lcd_init (void); // 6 funciones necesarias para trabajar el LCD void set_lcd (void); void lcd_puts(const char * s); void lcd_putch(char c); void lcd_goto(unsigned char pos); void lcd_write(unsigned char c);
void main() { TRISD=0;
// Puerto D como salidas para pines RS (RD6) y E (RD7)
TRISB=0;
// Puerto B como salidas para envío del dato al LCD
PORTB=0;
// Limpio Puerto B
PORTD=0;
// Limpio Puerto D
TRISE=0X01;
// Bit 0 del Puerto E como entrada. Canal análogo AN5
ADCON0=0X55;
// Velocidad Fosc/8, Canal 5, Módulo conversor en ON
ADCON1=0X80;
// Vref = 5V, Alineación del resultado a derecha
ANSEL=0X20;
// Selección unicamente canal 5 como análogo
ANSELH=0;
// los demás pines digitales
lcd_init();
// Llamo función de inicialización del LCD
while(1)
// Inicio ciclo infinito
{ lcd_goto(0);
// selecciono primera línea
lcd_puts (" EL VOLTAJE DEL "); // Mensaje para la primera línea lcd_goto (0x40);
// Selecciono segunda línea
lcd_puts ("PROCESO ES: . "); // Mensaje para la segunda línea GO=1;
// Inicio el proceso de conversión
while(GO==1)
// Mientras GO=1, está en proceso
continue;
// Si pasa a 0 continuo
digital=(ADRESH*256)+ADRESL; // Algoritmo cálculo dato digital voltaje=digital*49;
// Multiplico por resolución
binbcd();
// Voy a conversión BIN a BCD
lcd_goto(0x4C);
// Ubico entero en CC del LCD
lcd_putch(diezmil+48);
// Sumo 48 para convertir a ASCII
lcd_goto(0x4E);
// Ubico decimal en CE del LCD
lcd_putch(miles+48);
// Sumo 48 para convertir a ASCII
lcd_goto(0x4F);
// Ubico otro decimal en CF del LCD
lcd_putch(centenas+48);
// Sumo 48 para convertir a ASCII
__delay_ms(500);
// Repito proceso cada 500 ms
} } void lcd_init(void)
// Función de inicialización del LCD
{ LCD_DATA=2;
// Ver capítulo de manejo del LCD
set_lcd(); LCD_DATA=56; set_lcd(); LCD_DATA=15; set_lcd(); LCD_DATA=6; set_lcd(); LCD_DATA=1; set_lcd(); } void set_lcd (void) { LCD_RS=0; LCD_EN=1; __delay_ms(2); LCD_EN=0; }
void lcd_goto(unsigned char pos) { LCD_RS = 0; lcd_write(0x80+pos); } void lcd_write(unsigned char c) {
LCD_EN=1; LCD_DATA = ( c ); __delay_ms(2); LCD_EN=0;
} /* Escribo una cadena de caracteres en el LCD */ void lcd_puts(const char * s) { LCD_RS = 1; while(*s) lcd_write(*s++); } /* Escribo un caracter en el LCD */ void lcd_putch(char c) { LCD_RS = 1;
// write characters
lcd_write( c ); } void binbcd (void) { temp=voltaje;
// Paso voltaje a temperatura para no dañar el resultado
diezmil=0;
// Inicializo variables en 0
miles=0; centenas=0; decenas=0;
unidades=0; while(temp>10000) { temp=temp-10000; diezmil=diezmil+1; } while(temp>1000) { temp=temp-1000; miles=miles+1; } while(temp>100) { temp=temp-100; centenas=centenas+1; } while(temp>10) { temp=temp-10; decenas=decenas+1; } unidades=temp; }
// Inicio restas sucesivas para obtener datos en BCD
Simulación
COMUNICACIÓN SERIAL A TRAVÉS DEL MÓDULO USART A pesar de los tantos protocolos de comunicación existentes en la actualidad, el protocolo de comunicación serial bajo la norma RS232 sigue estando vigente para muchas de las aplicaciones que requieren de un envío o recepción de datos. Los dispositivos programables nos facilitan el trabajo porque ahora incluyen en su mayoría, un módulo llamado USART o a veces solo UART, debido a que la opción síncrona ha dejado de usarse por ser solo Hall Duplex y cada vez es más necesario estar enviando y recibiendo datos al tiempo, esto se consigue con la opción asincróna que permite el trabajo bidireccional también conocido como Full Duplex. El módulo UART particularmente en los PIC, solo requiere que el dato sea puesto en un registro de transmisión y listo. Las tramas ya están calculadas por los registros de desplazamiento TSR para la transmisión y RSR para la recepción y la velocidad está garantizada con la configuración acertada del registro generador de baudios. Los registros asociados al proceso de transmisión y recepción con el módulo UART del PIC 16F887 son: TXREG: Registro donde se almacena el dato a enviar RCREG: Registro donde se almacena el dato recibido TXSTA: Registro de control de la transmisión RCSTA: Registro de control de la recepción SPBRG: Generador de baudios Hablemos de TXSTA, RCSTA y SPBRG para entender bien el proceso.
Registro de control de la transmisión TXSTA Registro TXSTA Para realizar una transmisión a 8 bits debemos tener en cuenta en este registro, el bit 5 TXEN = 1 para habilitar la transmisión, el bit 2 BRGH para calcular la palabra de configuración del registro generador de baudios SPBRG así: Si BRGH = 0 se tiene una constante K = 64 para desarrollar la fórmula, pero si el bit BRGH = 1, se tiene una constante K = 16. SPBRG = [Fosc (Hz) / ( K * Velocidad en baudios)] – 1
Por ejemplo si queremos realizar una comunicación a 9600 bps y tenemos un oscilador de 20 Mhz y configuramos el bit BRGH en 0. La palabra a enviar al registro SPBRG será: SPBRG = [20000000 / (64*9600)] – 1 = 31.552 = 32 Generalmente, hay un error en la comunicación, debido a que el dato a cargar en el SPBRG es un entero aproximado, entonces la velocidad será un poco más o menos de lo deseado. Calculemos el error para el ejemplo anterior así: Error = [(Vel. Calculada – Vel. Deseada) / Vel. Deseada] * 100 La velocidad deseada es 9600, pero la real calculada es: Vel (bps) = [Fosc (Hz) / (K*(SPBRG+1))] = [20000000 Hz / (64 * 32+1)] = 9469.7 Error = [(9469.7 – 9600) / 9600] * 100 = - 1.357% Estos datos se pueden confirmar en las tablas que hay en las figuras 3 y 4 de este capítulo. Por último se debe tener en cuenta la bandera de finalización de la transmisión TRMT, la cual se pone en uno cuando el registro de desplazamiento de la transmisión TSR está vació indicando que se puede enviar otro dato. Para el primer ejercicio se trabajará con frecuencia de oscilación de 4 Mhz y con una velocidad de 9600 baudios, con el bit BRGH del registro TXSTA en 1. Por lo tanto la palabra para cargar el SPBRG debe ser: SPBRG = [4000000 / (16 * 9600)] – 1 = 25 Tenemos entonces 2 registros listos TXSTA = 0X24;
// Hablito transmisión y BRGH en 1
SPBRG = 25 ;
// Velocidad 9600 bps
Registro de control de la recepción RCSTA Aunque solo vamos a transmitir, el bit de habilitación del puerto serial se encuentra en el registro RCSTA (bit 7 llamado SPEN). Por lo tanto, se debe poner ese bit a 1 SPEN = 1;
Tabla para configurar SPBRG con bit BRGH en 0
Tabla para configurar SPBRG con bit BRGH en 1 Hagamos uso de los registros configurados para el primer ejemplo que será simplemente enviar un carácter al PC. // Programa de comunicación serial básico //********************************************************************************************* // Se incluye librería xc.h y palabras de configuración de bits //********************************************************************************************* #include //********************************************************************************************* __CONFIG(FOSC_XT & WDTE_OFF & PWRTE_OFF & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_ON & IESO_ON & FCMEN_ON & LVP_OFF); __CONFIG(BOR4V_BOR40V & WRT_OFF); //********************************************************************************************* // Definción de la velocidad del oscilador //********************************************************************************************* #define _XTAL_FREQ 4000000 //********************************************************************************************* void main() {
TRISC=0;
// Puerto C como salidas para el pin de transmisión
TXSTA=0X24;
// Habilito la transmission y bit BRGH en 1
SPBRG=25;
// Velocidad a 9600 bps
SPEN=1;
// Habilito el Puerto serial del PIC
while(1) { TXREG=65;
// Envío la letra a en ASCII
while(TRMT==0)
// Pregunto si TSR está vacío para enviar nuevamente
continue; __delay_ms(500);
// Envío cada 500 ms
} }
Simulación Cuando deseamos enviar cadenas de caracteres existe la instrucción printf que hace parte de la librería stdio.h.
Veamos un ejemplo donde se envía una cadena de caracteres y una variable. //********************************************************************************************* // Programa serial para envió mediante la instrucción printf al PC. //********************************************************************************************* // Se incluyen las librerías necesarias //********************************************************************************************* #include #include //********************************************************************************************* // Palabras de configuración de bits generadas automáticamente por el software //********************************************************************************************* __CONFIG(FOSC_XT & WDTE_OFF & PWRTE_OFF & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_ON & IESO_ON & FCMEN_ON & LVP_OFF); __CONFIG(BOR4V_BOR40V & WRT_OFF); //********************************************************************************************* // Definición de la velocidad del oscilador //********************************************************************************************* #define _XTAL_FREQ 4000000 //********************************************************************************************* // Definición de variables y funciones //********************************************************************************************* char cont; void putch (unsigned char byte); //********************************************************************************************* void main()
{ TRISC=0;
// Puerto C como salidas para pin de transmisión
SPEN=1;
// Habilitación del Puerto serial del PIC
SPBRG=25;
// Velocidad 2400 bps
TXSTA=0X20;
// Habilito la transmisión y bit BRGH en 0
while(1) { for(cont=0;cont<10;cont++) // for para el conteo de uno a 10 { printf("\r Contador = %d\n",cont); // Envío del mensaje y la variable cont __delay_ms(1000);
// Envío cada segundo
} } } void putch (unsigned char byte) // Función para envío con printf { while(!TRMT)
// Pregunto si TRMT cambio a 1
continue; TXREG=byte; }
// Envío el siguiente byte
Simulación Por último, vamos a utilizar la comunicación para monitorear una variable análoga y enviarla al PC // Programa de monitoreo de temperatura en el PC //********************************************************************************************* // Se incluyen las librerías necesarias y las palabras de configuración de bits //********************************************************************************************* #include #include __CONFIG(FOSC_XT & WDTE_OFF & PWRTE_OFF & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_ON & IESO_ON & FCMEN_ON & LVP_OFF); __CONFIG(BOR4V_BOR40V & WRT_OFF); //********************************************************************************************* // Definición de la velocidad del oscilador //*********************************************************************************************
#define _XTAL_FREQ 4000000 //********************************************************************************************* // Declaración de variables y funciones //********************************************************************************************* int digital; float temperatura; void putch (unsigned char byte); //********************************************************************************************* void main() { TRISE=0X02;
// Bit 1 del Puerto E como entrada. Canal análogo AN6
TRISC=0;
// Puerto C como salida para pin de transmisión
ADCON0=0X59; // Velocidad de conversion Fosc/8, canal 6, módulo A/D ON ADCON1=0X80; // Vref = 5V y alineación del resultado digital a derecha ANSEL=0X40;
// Canal 6 análogo
ANSELH=0;
// los demás pines digitales
TXSTA=0X26;
// Habilito transmisión y bit BRGH en 1
SPBRG=25;
// Velocidad 9600 bps
RCSTA=0X80; // Habilitación del puerto serial del PIC while(1) { GO=1;
// Inicio la conversion A/D
while(GO==1) // Mientras esté en uno continua la conversión continue; digital=(ADRESH*256)+ADRESL; // Unifico el valor digital del resultado
temperatura=((digital*0.488)-50); // Algoritmo para cálculo de la temperatura printf("\r La temperatura es:%2.2f\n",temperatura); // Envío de la cadena de // caracteres y la variable. __delay_ms(200);
// Cada 200 ms
} } void putch (unsigned char byte)
// Función para el trabajo con printf
{ while(!TRMT) continue; TXREG=byte; }
Simulación
// Envío de cada byte de la cadena de // caracteres
RECEPCIÓN DE DATOS POR INTERRUPCIÓN Generalmente hablamos de transmitir datos, pero nunca nos ocupamos de la recepción. En este ejemplo se verá una forma muy práctica de recibir datos utilizando la interrupción por recepción. Se enviará un dato desde un microcontrolador a otro, donde se comparará y se anunciará en dos leds si es mayor o menor que el dato elegido en el receptor. Si la lectura del puerto A que tiene 3 entradas, es decir, que puede estar entre 0 y 7, es mayor a 4 que fue el número elegido para comparar en el receptor, se activará RA0, pero si es menor a 4, se activará RA1. El número recibido serialmente por medio de una interrupción por recepción siempre se muestra en el display de siete segmentos.
En la simulación superior se puede ver que la lectura del puerto A es 3, ya que los pulsadores ubicados en RA0 y RA1 no están presionados y la polarización de estos es a 5V, por lo tanto se leen unos, el pulsador RA2 está presionado, es decir que entra un 0. La lectura es 3, es menor a 4 y por eso se activa RA1. En la simulación inferior se puede ver que la lectura del puerto A es 7, ya que los 3 pulsadores no están presionados y la polarización de estos es a 5V, por lo tanto se leen unos. La lectura es 7, es mayor a 4 y por eso se activa RA0. Mientras no haya interrupción por recepción del dato, el PIC permanece activando y desactivando la salida RA2. Programa de transmisión
//********************************************************************************************* // Se incluye la librería xc.h con bits y registros especiales del micro //********************************************************************************************* #include //********************************************************************************************* // Palabras de configuración de bits //*********************************************************************************************
// CONFIG1 #pragma config FOSC = XT #pragma config WDTE = OFF
// XT oscillator // Watchdog Timer Disable
#pragma config PWRTE = OFF
// Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON
// pin function is MCLR
#pragma config CP = OFF #pragma config CPD = OFF #pragma config BOREN = ON #pragma config IESO = ON #pragma config FCMEN = ON #pragma config LVP = OFF
// Program memory code protection is disabled // Data memory code protection is disabled // BOR enabled // Internal External Switchover // Fail-Safe Clock Monitor Enabled bit // HV on MCLR must be used for programming
// CONFIG2 #pragma config BOR4V = BOR21V // Brown-out Reset set to 2.1V #pragma config WRT = OFF
// Flash Program Memory Disable
//********************************************************************************************* // Definición de la velocidad del oscilador //********************************************************************************************* #define _XTAL_FREQ 4000000 //********************************************************************************************* // Declaración de variables //********************************************************************************************* char aux=0; //********************************************************************************************* void main()
{ TRISC=0X00;
// Puerto C como salidas para pin TX
TRISA=0XFF;
// Puerto A como entradas para lectura de pulsadors+es
TXSTA=0X26;
// Habilito transmisión y bit BRGH en 1
SPBRG=25;
// Velocidad a 9600 bps
SPEN=1;
// Habilito Puerto serial del PIC
ANSEL=0;
// Todos los pines digitales
ANSELH=0;
// Todos los pines digitales
while(1) { aux=PORTA; // Leo el puerto A y lo llevo al registro aux TXREG=aux; // Llevo el dato al registro de transmisión while(TRMT==0) // Espero a que termine el envío del dato continue;
// Para continuar
__delay_ms(5000); // Retardo de 5 segundos } }
Programa de recepción //********************************************************************************************* // Se incluye librería con bits y registros especiales //********************************************************************************************* #include //*********************************************************************************************
// Palabras de configuración de bits //********************************************************************************************* // CONFIG1 #pragma config FOSC = XT #pragma config WDTE = OFF
// XT oscillator // Watchdog Timer Disable
#pragma config PWRTE = OFF
// Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON
// pin function is MCLR
#pragma config CP = OFF #pragma config CPD = OFF #pragma config BOREN = ON #pragma config IESO = ON #pragma config FCMEN = ON #pragma config LVP = OFF
// Program memory code protection is disabled // Data memory code protection is disabled // BOR enabled // Internal External Switchover // Fail-Safe Clock Monitor Enabled bit // HV on MCLR must be used for programming
// CONFIG2 #pragma config BOR4V = BOR21V // Brown-out Reset set to 2.1V #pragma config WRT = OFF
// Flash Program Memory Disable
//********************************************************************************************* // Definición de la velocidad del oscilador //********************************************************************************************* #define _XTAL_FREQ 4000000 //********************************************************************************************* // Declaración de variables //********************************************************************************************* char temp=4; char aux;
//********************************************************************************************* void main() { TRISC=0X80;
// Puerto C como salidas para display solo C7 entrada para RX
TRISA=0;
// Puerto A como salidas para los leds indicadores
TRISD=0;
// Puerto D como salidas para habilitar transistor de display
TXSTA=0X26;
// Habilito transmisión y bit BRGH en 1
SPBRG=25;
// Velocidad 9600 bps
RCSTA=0X90; // Habilito puerto serial y recepción de datos INTCON=0XC0; // Habilito interrupciones periféricas RCIE=1;
// Habilito interrupción por recepción
ANSEL=0;
// Todos los pines digitales
ANSELH=0;
// Todos los pines digitales
PORTA=0;
// Limpio Puerto A
PORTD=0;
// Limpio Puerto D
PORTC=0;
// Limpio puerto C
RD0=1;
// Habilito transistor para el display
while(1) { RA2=~RA2;
// Mientras no hay interrupción, hay intermitencia en
__delay_ms(200);
// salida RA2 cada 200 ms
} } void interrupt isr() // Función de interrupción {
PORTC=RCREG;
// Paso dato recibido al Puerto C para mostrar
aux=RCREG;
// Paso dato recibido al registro aux para comparación
if(aux>temp)
// Comparo dato recibido con la constante temp
{ RA0=1;
// Si dato recibido es mayor activo RA0 por un segundo
__delay_ms(1000); RA0=0; } else
// Si es menor, active RA1 por un segundo
{ RA1=1; __delay_ms(1000); RA1=0; } RCIF=0; // Limpio bandera de interrupción __delay_ms(100); }
MODULACIÓN DE ANCHO DE PULSO - PWM La modulación de ancho de pulso es una técnica que suministra potencia a una carga cambiando rápidamente entre los estados ON y OFF, es decir carga completa y cero carga. La señal PWM se asemeja a una onda cuadrada donde la porción alta de la señal es considerada el estado ON y la porción baja el estado OFF. La porción alta también conocida como ancho de pulso puede variar en tiempo y es definida por pasos. Un alto número de pasos extiende el ancho de pulso y aplica mayor potencia a la carga, disminuir el número de pasos implica acortar el ancho de pulso y por lo tanto disminuir la potencia a la carga. El período PWM es definido como la duración de un ciclo completo o la cantidad total de tiempo combinada en alto y bajo. La resolución PWM, define el máximo número de pasos que pueden estar presentes en un período PWM. Una resolución alta permite un control más preciso del tiempo del ancho de pulso y por ende de la potencia aplicada a la carga. El término Duty Cycle determina la proporción del tiempo en ON y OFF y es expresado en porcentaje, donde 0% es estado OFF y 100% es estado ON, por ejemplo, si tenemos el 40% de Duty Cycle, significa que el ancho de pulso (Estado ON) es del 40% de la onda y el 60% es el estado OFF ó bajo de la onda. En otras palabras un Duty Cycle bajo determina menos potencia aplicada a la carga y un Duty Cycle alto significa más potencia aplicada a la carga. La técnica PWM es muy utilizada para el control de motores, control de iluminación entre otros. MODULACIÓN DE ANCHO DE PULSO EN LOS MICROCONTROLADORES PIC Aprovechemos la presencia en el mercado de los nuevos microcontroladores PIC de MICROCHIP y elijamos una de estas referencias nuevas, llenas de grandes características para practicar con este tema. Para este caso vamos a trabajar con un PIC de 18 pines referencia 16F1827 que posee entre otras cosas 4 módulos CCP, quiere decir que con cada módulo yo puedo trabajar Comparación, Captura o PWM, en este caso nos dedicaremos al tema de modulación de ancho de pulso en el primer módulo, es decir el CCP1, el cual se puede trabajar a 10 bits.
Podemos ver en el diagrama de pines que el módulo CCP1 tiene salida por los pines RB0 ó por el pin RB3. Se selecciona en el registro APFCON.
El período, el Duty Cycle y la resolución son controladas por los siguientes registros: PRx: Registro de 8 bits en el que se almacena el período que deseo para la modulación TxCON: Control para los timer 2, 4 y 6
CCPRxL: Registro donde se almacenan los 8 bits más significativos para el ancho de pulso que se desea. CCPxCON: Registro que define el trabajo del módulo CCP, si es PWM, los 4 bits menos significativos son los que tienen que ver con él. Los bits 4 y 5 son los 2 bits menos significativos para completar los 10 bits del proceso.
Obviamente, el correspondiente registro TRISB deberá ser limpiado en RB0 ó RB3, según la salida que vayamos a utilizar para la modulación. Veamos un ejemplo para explicar de una mejor manera la técnica PWM
#include // CONFIG1 #pragma config FOSC = HS
// Oscillator Selection HS Oscillator, High-speed
#pragma config WDTE = OFF
// Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF
// Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON
// MCLR Pin Extern
#pragma config CP = OFF #pragma config CPD = OFF
// Flash Program Memory Code Protection disable // Data Memory Code Protection disabled
#pragma config BOREN = ON
// Brown-out Reset Enable
#pragma config CLKOUTEN = OFF // Clock Out Disable #pragma config IESO = ON
// Internal/External Switchover
#pragma config FCMEN = ON
// Fail-Safe Clock Monitor Enable
// CONFIG2 #pragma config WRT = OFF
// Flash Memory Self-Write Protection
#pragma config PLLEN = OFF
// PLL Enable (4x PLL disabled)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable #pragma config BORV = LO
// Brown-out Reset Voltage Selection
#pragma config LVP = OFF
// Low-Voltage Programming Disable
#define _XTAL_FREQ 20000000 unsigned int i; void main () { TRISB=255; //Deshabilito la salida del módulo CCP1, mientras se //realiza la configuración de los registros APFCON0=0;
//Elijo RB3 para salida CCP1, en 1 es RB0
PR2=255;
// Período para la señal PWM + 2 bits del oscilador int
CCPTMRS=0;
// Bits 0 y 1 para elegir el timer para CCP1. TMR2=0;
CCPR1L= 128;
// Ancho de pulso 8 MSB
CCP1CON=0X0C; // Bits 4 y 5 LSB para ancho de pulso y bits 0,1,2,3 // 11xx = para modo PWM TMR2IF=0; // Limpio bandera de desbordamiento del TMR2 T2CON=0B00000010; // Preescala y activación del timer2 TRISB=0;
// Habilito el módulo CCP1
while(1) { TMR2=0; for (i=0;i<250;i++) { TMR2ON=1; // bit 2 del T2CON se activa TMR2 while (TMR2IF==0) continue; TMR2IF=0; } } } Las fórmulas para hallar los diferentes parámetros son las siguientes: 1 – Período PWM = (PRx + 1) * 4 * Tosc * Preescala del TIMER 2 – Ancho de pulso = CCPRxL:CCPxCON(4:5) * Tosc * Preescala del TIMER 3 – Duty Cycle = {CCPRxL:CCPxCON(4:5) } / { 4(PRx + 1)} 4 – Resolución = log {4 (PRx + 1)} / log (2)
5 – Frecuencia PWM = 1 / Período PWM Ejemplo: Supongamos que tenemos el PIC 1827 trabajando a una Fosc de 20 MHZ, un periodo PWM máximo configurado en el registro PR2 = 255 y un ancho de pulso configurado como 10000000 00 en el registro CCPR1L y en los bits 4 y 5 del registro CCP1CON, es decir un ancho de pulso de 512, además de una preescala para el TIMER2 de 16 configurada en el registro T2CON. Así las cosas, entremos a calcular cada uno de los parámetros: 1 – Período PWM = (255 + 1) * 4 * 1/Fosc * 16 = 256 * 4 * 0,05us * 16 = 819us 2 – Ancho de pulso = 512 * 0,05us * 16 = 410us 3 – Duty cycle = ( 512 / 1024 ) * 100 = 50% ON y 50% OFF 4 – Resolución = log (1024) / log(2) = 10 bits 5 – Frecuencia PWM = 1 / 819us = 0,00122 MHZ = 1,22 KHZ La base de tiempo para la modulación por CCP1 será el Timer2, es decir, el TMR2 se inicia y empieza a compararse con el valor de ancho de pulso configurado, el nivel de salida en el pin CCP1 inicia en alto, cuando son igulaes el TMR2 y el ancho de pulso configurado, la salida del CCP1 pasa a nivel bajo, el TMR2 sigue incrementándose, pero esta vez se compara con el período configurado, cuando son iguales, el TMR2 se hace 0 y la salida del CCP1 vuelve a nivel alto para iniciar un nuevo ciclo. Los valores se pueden confirmar en la simulación en proteus mostrada en la figura siguiente:
Si se quiere ir incrementando el ancho de pulso poco a poco, simplemente se inicia el registro que tiene que ver con el ancho de pulso, es decir el CCPR1L en 0 y se va incrementando en uno en el programa principal. El código para ese programa quedaría así: void main () { TRISB=255; //Deshabilito la salida del módulo CCP1, mientras se //realiza la configuración de los registros APFCON0=0; PR2=255;
//Elijo RB3 para salida CCP1, en 1 es RB0
// Período para la señal PWM + 2 bits del oscilador int
CCPTMRS=0;
// Bits 0 y 1 para elegir el timer para CCP1. TMR2=0;
CCPR1L= 0; // Ancho de pulso 8 MSB se inicia en 0. CCP1CON=0X0C; // Bits 4 y 5 LSB para ancho de pulso y bits 0,1,2,3
// 11xx = para modo PWM TMR2IF=0; // Limpio bandera de desbordamiento del TMR2 T2CON=0B00000010; // Preescala y activación del timer2 TRISB=0;
// Habilito el módulo CCP1
while(1) { TMR2=0; for (i=0;i<250;i++) { TMR2ON=1; // bit 2 del T2CON se activa TMR2 while (TMR2IF==0) continue; TMR2IF=0; } CCPR1L = CCPR1L +1; Se incrementa ancho de pulso en uno } }
Introducción a la familia de dispositivos de 16 bits de Microchip
-
Los microcontroladores de 16 bits referencia 24FXXXXX Programación en lenguaje C de una aplicación I/O sobre la tarjeta de entrenamiento Explorer 16 Conversión A/D en los PIC de 16 bits Comunicación serial en los PIC de 16 bits Demostración de estas características en la tarjeta de entrenamiento Explorer 16
Materiales necesarios
-
Kit de entrenamiento Explorer 16 Programador ICSP PICKIT3 Extensiones para 120VAC Televisor ó Video Beam
Veamos inicialmente, algunas de las características principales de los microcontroladores de 16 bits, serie 24F y en particular el PIC 24FJ256GA10
Programación en la tarjeta EXPLORER 16 de programas básicos de entradas y salidas y la conversión A/D
Trabajo con los dsPIC de Microchip, particularmente, con el DSP 33FJ256GP710
-
Introducción al procesamiento digital de señales con los DSP de MICROCHIP Demostración con el DSP 33FXXXX
CONVERSIÓN A/D EN 10 BITS EN EL DSP 33FJ256GA710 La demostración básica del proceso de conversión A/D se hará en un DSP33F256GA710, aprovechando la tarjeta de entrenamiento EXPLORER 16. La tarjeta posee una resistencia variable conectada en el pin RB0, que es el canal análogo AN0, permitiendo variar voltaje entre 0 y 5V. Veamos algunos detalles importantes del tema antes de hablar de la configuración de los registros.
El TAD es la mínima unidad para definir los tiempos de conversión. La velocidad del módulo de conversión A/D de 10 bits en el DSP 33FJ256GA710, puede ser de hasta 1 millón de muestras por segundo (1Msps), pero esas velocidades altas requieren, para su correcto funcionamiento, el voltaje de referencia conectado en los pines VREF+ y VREF- del DSP. En nuestro caso, el voltaje de referencia será de 5V y estará conectado a los pines AVDD y AVSS, podremos elegir una velocidad de 500 Ksps (500 mil muestras por segundo) con un tiempo mímino de conversión de 2 us y un TAD de 154 ns como lo indica la figura en la página anterior. Con el valor del TAD y la frecuencia de oscilación a la que estará conectado el DSP, se puede calcular el valor que representa los tiempos de conversión y que debe ir en los 6 bits ADCS del registro de control ADCON3. Ver figura siguiente:
El cálculo anterior es para una velocidad de conversión de 500Ksps, es decir, con un tiempo mínimo de conversión de 2us por muestra. Como bien lo dice la teoría, el tiempo mínimo de conversión, en sus etapas de cuantificación y codificación es también equivalente a 12 TAD y el tiempo mínimo en la etapa de adquisición es 1TAD. En conclusión el tiempo mínimo total de conversión es de 13 TAD.
Así las cosas: 12TAD x 154 ns = 1,848us (Cuantificación y codificación) 1TAD x 154 ns = 15nss = 0,154us (Adquisición) Total = 1,848 + 0,154 = 2,002us (Cumple perfectamente con el requerimiento de velocidad del conversor A/D, o sea, 500 Ksps)
Ejemplo: Una señal de audio cuya frecuencia de muestreo es de 44100 HZ se debe tratar en un DSP 30F4012 a una velocidad de 500Ksps. La frecuencia de oscilación en el DSP es de 80MHZ. Hallar los tiempos de adquisición y muestreo y el parámetro para los bits ADCS del registro de control ADCON3.
Solución: Tiempo de muestreo es 1/44,1KHZ = 0,0226 ms, = 22,6 us TAD = 154 ns TCY = 50 ns ADCS = 2 (TAD / TCY) – 1 = 2 (154/50) - 1= 5,16 se aproxima hacia arriba ADCS = 6 TAD real de trabajo = [(ADCS + 1) * TCY] / 2 = (7 * 50 ns) / 2 = 175 ns Tiempo de conversión (Cuantificación y Codificación) = 12 x 175 = 2,1 us Tiempo de adquisición = 22,6 us – 2,1 us = 20,5 us
Los registros que tienen que ver con el módulo de conversión A/D de los DSP 33F son: ADCON1 ADCON2 ADCON3 ADPCFG ADCSSL ADCHS ADCBUF0 A ADCBUFF (16 registros que almacenan el resultado de la conversión A/D, se pueden almacenar hasta 16 resultados de 16 muestras) ADPCFG es quien dice cuales son entradas análogas (ceros) y cuales son entradas o salidas digitales (unos). En nuestro ejemplo necesitamos solamente RB0 como análoga, por lo tanto, el registro ADPCFG quedará en el programa así: ADPCFG = 0xFFFE; Así mismo el TRISB debe configurarse para que el pin RB0 del puerto B sea entrada TRISB = 0x0001; ADCHS simplemente, se configura con el número del canal análogo a utilizar, en este caso cero.
ADCHS = 0; ADCSSL se utiliza para configurar los canales A/D a escanear, si se van a utilizar varios, si es solo uno, se configura con cero. ADCSSL = 0; Ahora veamos los registros de control: 1 – ADCON1
El registro quedará configurado en cero para nuestro ejemplo, es decir: ADCON1 = 0; Por las siguientes razones: Aún no vamos a habilitar el módulo de conversión A/D, lo haremos en el programa principal, por lo tanto ADON = 0. No entraremos al estado pasivo (IDLE), por lo tanto, no hay problema con el ADSIDL = 0. El formato numérico a utilizar será entero, entonces los bits FORM = 00. Los 3 bits SSRC estarán en cero, porque limpiando el bit SAMP, finalizaremos el muestreo e iniciará la conversión. ASAM = 0, ya que el muestreo comenzará cuando se ponga el bit SAMP en uno. SAMP inicialmente lo dejaremos en cero e iniciaremos el muestreo en el programa principal y DONE es la bandera que me indica, poniéndose en uno, si la conversión A/D terminó, la iniciaremos entonces en cero.
2 - ADCON2
ADCON2 = 0 Por las siguientes razones:
Voltaje de referencia para el conversor A/D será el de alimentación, como es solo una entrada a CH0, no habrá escaneo de varios canales, el buffer de almacenamiento de las muestras estará configurado para recibir datos de 16 bits y no utilizaremos interrupciones por un determinado número de muestras, simplemente, cada que una muestra es convertida a digital la enviará al ADCBUF0 y de ahí la enviaremos al puerto B. Su trabajo será enviarla serialmente a alguna terminal serial en el PC. 3 – ADCON3
Como no vamos a tratar una señal con una frecuencia muy exigente, entonces el parámetro que me permite configurar los tiempos de adquisición y conversión puede estar al máximo, es decir los 6 bits ADCS = 3F, como el método de conversión es manual, o sea poniendo a 1 el bit SAMP iniciará el muestreo y luego de un retardo, poniendo este mismo bit a cero, finalizará el muestreo e iniciará la conversión, los bits de tiempo para el método automático no los voy a utilizar, entonces SAMC = 0, el reloj base para la conversión será derivado de la frecuencia de oscilación principal, por lo tanto ADRC = 0,
En conclusión ADCON3 = 0x003F; El programa completo de conversión A/D de una señal de 0 a 5V es el que sigue: #include
"p30f4012.h"
void delay(void); delay(void); /*Declaro la funcion delay*/ delay*/ int main
(void)
{ TRISB=0X0001; PORTB=0; ADPCFG=0XFFFE; ADCON1=0X2000; ADCON2=0; ADCON3=0X003F; ADCHS=0X0000; ADCSSL=0; while(1) { ADCON1bits.ADON=1; ADCON1bits.SAMP=1; delay(); ADCON1bits.SAMP=0; while(ADCON1bits.DONE==0) continue; PORTB=ADCBUF0; ADCON1bits.DONE==0; }
} void delay(void) { unsigned long i; for(i=50;i>0;i--); }
Introducción a la familia de dispositivos de 32 bits de Microchip
-
Los microcontroladores de 32 bits referencia 32FXXXXX Programación en lenguaje C de una aplicación I/O sobre la tarjeta de entrenamiento PIC STARTER 32
Materiales necesarios -
Kit Starter Kit 32 Programador ICSP PICKIT3 Extensiones para 120VAC Televisor ó Video Beam
Ejemplos básicos 1. Manejo de entradas y salidas void main() { // 0. initialization DDPCONbits.JTAGEN = 0; // disable JTAGport, libre PORTA TRISA = 0x0000;
// todo PORTA como saida
TRISB = 0xffff; T1CON = 0x8030;
// TMR1 on, prescale 1:256
PR1 = 0xFFFF; AD1PCFG =0XFFFF;
// 1. Loop principal while( 1) { if (PORTBbits.RB2==0) { //1.1 todos los LED ON PORTA = 0xff; } else { // 1.2 todos los LED OFF PORTA = 0; }}}
2. Manejo de los Timers /* ** Loops.c */
#include
//#define DELAY 3600 #define DELAY 5
// 256ms delay // reduced delay for simulation
main() { // 0. initialization DDPCONbits.JTAGEN = 0; // disable JTAGport, free up PORTA TRISA = 0xff00;
// all PORTA as output
T1CON = 0x8030; PR1 = 0xFFFF;
// TMR1 on, prescale 1:256 PB=36MHz // set period register to max
// 1. main loop while( 1) { //1.1 turn all LED ON PORTA = 0xff; TMR1 = 0; while ( TMR1 < DELAY)