Fecha de publicación: Dec 27, 2018 12:41:29 AM
INTRODUCCION
Los microcontroladores, basan su estructura fundamental y características básicas, en una unidad que dispone de bloques esenciales (procesador, memoria de datos y de instrucciones, líneas de E/S, oscilador de reloj y módulos controladores de periféricos); Sin embargo, no todos los dispositivos tienen los mismos recursos idóneos para la aplicación que queremos desarrollar…
Aunque inicialmente los microcontroladores adoptaron la arquitectura clásica Von Neumann, en el presente se impone la arquitectura hardware.
La arquitectura Von Neumann se caracteriza por disponer de una sola memoria principal donde se almacenan tanto datos como instrucciones. A dicha memoria se acede a través de un sistema de buses únicos (direcciones, datos y control).
La arquitectura HARDWARE dispone de dos memorias independientes: una que contiene solo instrucciones y otra, solo datos. Ambas disponen de sus respectivos buses de acceso y es posible realizar operaciones de acceso (lectura o escritura) simultáneamente en ambas memorias.
Los microcontroladores PIC, usan la arquitectura Hardware.
Dentro de esta arquitectura, microchip, implementa una orientación en cuanto a funcionalidad del procesador, del tipo RISC (Computadores de juego de instrucciones reducido).
En estos procesadores el repertorio de instrucciones maquina es muy reducido y las instrucciones son simples y generalmente se ejecutan en un ciclo (en realidad cuatro, pero secuencialmente, de forma que a cada ciclo de reloj se termina la ejecución de una instrucción excepto emn las instrucciones de salto).
La sencillez y rapidez de las instrucciones permiten optimizar el hardware y el software del procesador…
Los microcontroladores PIC, tienen una serie de registros que funcionan como una especie de RAM de propósito general. Los registros de propósito específico para los recursos de hardware disponibles dentro del propio chip, también están direccionados en la RAM.
Si bien la direccionalidad de la memoria varía dependiendo la línea u gama del dispositivo, por lo general, las funciones especiales tienen similares características las distintas funciones de hardware lo cual se puede corroborar por las dudas, con la hoja de datos del PIC a trabajar…
En el siguiente artículo, pretendo mostrarle como sacarle más provecho a sus microcontroladores PIC, mediante una programacion que juegue con el valor de determinados registros, para tener funcionalidades de hardware que quizás por líneas de software no se puedan generar u bien, no nos den un resultado óptimo en su funcionabilidad…
Para ello, intentare explicarles un par de recursos especiales del PIC, tales como los temporizadores (TIMER), Conversor A/D, CCP en sus tres modos de configuración (Compare, Contador, PWM) y para finalizar, veremos un ejemplo práctico de como diseñar nuestros propios generadores de pulsos, con control de FRECUENCIA Y DUTY de hasta 10Khz, que cmo ya sabran, esta es la parte donde nos caracteriza por implementar la metodologia LEO, APLICO,APRENDO de nuestros cursos y articulos…
Uso de PWM
PWM, en inglés significa Modulación por Ancho de Pulso. En una señal de onda cuadrada, tenemos dos eventos que define el estado en que se encuentra la señal en un periodo (ALTO – BAJO)...
La modulación.
Para entender mejor el evento, me parece útil arrancar desde el principio para que entendamos mejor.
Supongamos que tenemos una señal de onda cuadrada con una frecuencia de 100 Hz; Esto significará que la señal estará 100 veces ALTO y 100 veces BAJO en 1 segundo.
Para saber cuál es el tiempo de 1 periodo en una señal de 100 Hz, tenemos que:
T = 1 / F
Si queremos el resultado en milisegundos: T = 1000 / F
Si queremos el resultado en microsegundos: T = 1000000 / F
T = 10 ms en 100 Hz.
Como vimos en la imagen anterior, en ese ejemplo particular vemos que los tiempo en estado ALTO y BAJO son iguales entre si, entonces tenemos que para el estado ALTO tenemos 5ms y para el estado BAJO otros 5ms...o sea, como la definición del periodo son estos dos estados, tenemos que T = 5ms+5ms = 10ms
Para saber la cantidad de periodos de la señal que tenemos en 1 segundo (1000 ms) tenemos que:
1000ms / 10ms = 100 o sea, la señal estuvo 100 veces en estado bajo y 100 veces en estado ALTO.
Supongamos que intentamos controlar un motor DC con un simple transistor NPN...
Como sabrán, emplear la técnica de modulación de pulsos (PWM) para el control de velocidad de motores, es una técnica muy implementada dado que esta característica nos permite realizar una salida de voltaje controlado para alimentar varios dispositivos; En particular, motores de corriente continua.
Visualicemos una señal PWM en nuestra imaginación de 100Hz, y supongamos que el ancho del pulso tiene un periodo de 10ms... Si yo varío el tiempo de estado alto y bajo dentro de ese periodo, puedo lograr un efecto de variación de velocidad en el motor... Dicho de otra manera, si yo presiono rápidamente un switch conectado a una lámpara muchas veces dentro de un segundo, la variación de su luminosidad se verá reflejada en el tiempo ALTO en que yo mantuve presionado el switch...
Veámoslo de la siguiente manera:
Tomando el primer ejemplo de 1 periodo de 10ms para una señal de 100 Hz, nosotros podemos acelerar o decrementar la velocidad del motor aumentando o achicando el tiempo del estado ALTO:
PERIODO: 10ms (Tiempo ESTADO ALTO + Tiempo ESTADO BAJO)
TIEMPO ESTADO ALTO: 7ms
TIEMPO ESTADO BAJO: 3ms
Lo multiplicamos por la frecuencia:
100 x 7 = 700 ms
100 x 3 = 300 ms
Y tenemos que el tiempo de trabajo “útil”, o sea, tiempo en ALTO es de 700ms y el tiempo de estado bajo será de 300ms.
Todo esto significa que si notros variamos el tiempo de estado alto, tendremos un cambio en la velocidad del motor.
Ahora, esta técnica, nosotros podemos realizarla con nuestro microcontrolador de varias manera, la más sencilla es programando un cambio de estado de un puerto determinado con un par de líneas, a lo cual, se lo denomina PWM por software, u bien, podemos emplear el comando apropiado para dicha función.
Manejando siempre la misma hipótesis de que el periodo es de 10ms, en el siguiente ejemplo, podemos ver un sencillo PWM a 100Hz por software con un ciclo de trabajo útil (DUTY) del 50%. Para lograr esto, manejamos el tiempo que permanecerá en estado ALTO y BAJO el puerto B.0 de la siguiente manera:
INICIO:
HIGH PORTB.0 ; Poner en estado ALTO PuertoB.0
PAUSE 5 ; retardo de 5ms
LOW PORTB.0 ; Poner en estado BAJO PuertoB.0
PAUSE 5 ; retardo de 5ms
GOTO INICIO
Entonces tenemos que el DUTY, es el ciclo de trabajo (ESTADO ALTO) dentro del periodo...
Miremos otro programa con un DUTY de 80%
INICIO:
HIGH PORTB.0 ; Poner en estado ALTO PuertoB.0
PAUSE 8 ; retardo de 8ms
LOW PORTB.0 ; Poner en estado BAJO PuertoB.0
PAUSE 2 ; retardo de 2ms
GOTO INICIO
Como hemos visto en los ejemplos anteriores, aumentamos el Duty (TIEMPO ALTO-CICLO UTIL DE TRABAJO) de 50% a 80%, y el valor del TIEMPO BAJO cayo de 50% a 20% automáticamente, siempre dentro de un de 10 ms para que no cambie la forma de nuestra señal de 100Hz.
Vamos a ponerle un poquito más de emoción a nuestro programa principal, y vamos a variar el DUTY de la señal PWM con pulsadores.
; Programa: PWM por software con pulsador de control.
TrisA=%00000000 ; Definimos todo el puerto A como salida
TrisB=%00000011 ; Definimos B.0 y B.1 como entradas y el resto como salidas
TrisC=%00000000 ; Definimos todo el puerto C como salida
TrisD=%00000000 ; Definimos todo el puerto D como salida
PortA=0 ; Poner en estado bajo los pines del puerto configurados como salida
PortB=0 ; Poner en estado bajo los pines del puerto configurados como salida
PortC=0 ; Poner en estado bajo los pines del puerto configurados como salida
PortD=0 ; Poner en estado bajo los pines del puerto configurados como salida
B_MAS VAR PORTB.0 ; Le asignamos el nombre “B_MAS” al puerto de entrada B.0
B_MENOS VAR PORTB.1 ; Le asignamos el nombre “B_MENOS” al puerto de entrada B.1
SALIDA VAR PORTC.0 ; Le asignamos el nombre “SALIDA” al puerto C.0
RETARDO VAR BYTE ; Creamos una variable tipo BYTE (0-255) llamada retardo
RETARDO = 5 ; Le asignamos un valor a la variable
INICIO:
IF B_MAS = 0 THEN ;Si el pulsador en el puerto B.0 es igual a “0”(Logica Negativa)
RETARDO = RETARDO +1 ;Variable “retardo” es igual a su valor mas 1
IF RETARDO >10 THEN RETARDO =10 ;Si la Variable supera el valor de 10, poner valor de 10
PAUSE 150 ;Generamos un retardo/pause de 150ms
ENDIF ;Fin de la sentencia
IF B_MENOS =0 THEN ;Si el pulsador en el puerto B.1 es igual a “0”(Logica Negativa)
RETARDO = RETARDO -1 ;Variable “retardo” es igual a su valor menos 1
IF RETARDO =255 THEN RETARDO =0 ;Si la Variable al restar desborda y llega a 255, poner valor de 10
PAUSE 150 ;Generamos un retardo/pause de 150ms
ENDIF ; Fin de la sentencia
HIGH SALIDA ; Poner en estado ALTO el puerto C.0
PAUSE RETARDO ; Generar un tiempo retardo “T_on” con valor de variable “retardo”
LOW SALIDA ; Poner en estado BAJO el puerto C.0
PAUSE (10 - RETARDO) ; Generar un tiempo retardo “T_off” con valor de variable “retardo”
GOTO INICIO
END
PWM Pin, Duty, Cycle
Donde:
PWM PIN, es el número de puerto por donde queremos que salga nuestro PWM (de 0 a 7)
DUTY, es el tiempo de trabajo proporcionado donde el valor corre de 0 a 255.
255 seria 100%, 127 seria 50% y cero el 0%)... El valor equivalente podemos colocarlo implementando la siguiente formula
Duty =% Duty x 255/100
CYCLE, es la cantidad de veces que queremos que se repita el periodo... Por ejemplo:
PWM PortC.0, 127, 200 ;PWM en PortC.0 con DUTY50% 200 periodos.
Ahora, noten que cada comando, línea extra o retardo que sumemos a nuestro programa, interrumpirá nuestro PWM
En el programa del ejemplo anterior, pudimos ver cómo afecta la salida PWM cuando presionamos el pulsador o bien, cuando lee las sentencias, compara valores de variables u cuando finaliza todas las líneas del programa y vuelve al inicio por el comando GOTO le dice saltar a dicha etiqueta en la línea “GOTO INICIO”, o sea, vuelve arrancar la lectura del software desde la arriba para abajo nuevamente...
Por este resultado, podríamos decir que no podemos mostrarlo como un método de generación PWM muy ventajoso que digamos, pero no se asusten, el compilador de PBP nos brinda otro comando que justamente sirve para ejecutar en un “PUERTO ESPECIFICO”, una señal PWM independiente a lo que el microcontrolador esté haciendo en el programa principal.
Este comando se llama HPWM (PWM por Hardware) y dependiendo el microcontrolador, este puede tener un pin especifico (CCP) para esta función (por ejemplo el PIC 16F628), dos salidas de PWM por HARDWARE (Ejemplo los PIC 16F876-16F877) u tres en otras gamas... CCP significa que es un puerto con tres funciones especiales; O sea, a este se lo puede configurar como COMPARADOR, COMO CONTADOR, COMO PWM, o bien, implementarlo para otras funcionalidades comunes (datos, puerto de entrada, salida, etc...). Cada función especial, trabaja con un TIMER diferente, que más adelante entraremos en ese tema para entenderlos mejor y ver la practicidad que hay en emplearlos como herramientas...
Para todas las arquitecturas, la frecuencia de los PWM de salida por HARDWARE, comparten una misma frecuencia seteado por el registro PR2, pero la variación del ciclo de trabajo útil (DUTY), puede ser modificada independiente un puerto del otro...
El Modulo CCP (Compare-Capture-PWM)
Como mencionamos anteriormente, cada módulo CCP tiene un registro de 16 BITS que puede configurar dicho puerto especial como:
_ MODO CAPTURE
_ MODO COMPARE
_ MODO PWM
Los módulos CCP1 y CCP2 son idénticos excepto en la operación “Especial Event Trigger” (Disparo por Evento Especial)
El módulo CCP1 tiene el registro de trabajo CCPR1= CCPR1H:CCPR1L de 16 BITS controlado por el registro
“REG_CCP1CON”. El disparo especial es generado por un COMPARE y resetea el TIMER1 (TMR1)
El módulo CCP2 tiene el registro de trabajo CCPR2= CCPR2H:CCPR1L controlado por el registro “REG_CCP2CON”. El disparo especial es generado por un COMPARE, resetea el TIMER1 y arranca la conversión A/D
MODOS DE OPERACIÓN y TIMER ASOCIADOS A CADA UNO
• MODO CAPTURE - TIMER1
• MODO COMPARE- TIMER1
• MODO PWM - TIMER2
INTERACCIÓN ENTRE LOS DOS MÓDULOS:
• CAPTURE, CAPTURE
• CAPTURE, COMPARE
• PWM, PWM
• PWM, CAPTURE
• PWM, COMPARE
Uso de HPWM
Para usar la función HPWM, debemos configurar algunos registros del microcontrolador primero. Quizás en el primer intento no vueles, no lo entiendas, pero ten paciencia y lee reiteradamente estas líneas metiendo mano en tu programa para que puedas entenderlo....
Bien, como dijimos, el puerto especial CCP, puede ser configurado en varios modos; Según su configuración, veremos que este puerto se asocia a distintos timer según función. Por ejemplo, cuando se configura como PWM, utiliza el timer2 como un módulo de sincronización para calcular el Ton y Toff...
ECUACIONES DEL TEMPORIZADOR:
[1]_Con esta ecuación, se calcula la frecuencia del temporizador.
Frecuencia = Frec_crystal / 4 * prescaler * resolucion)
[2]_Con esta ecuación, se calcula el periodo de la frecuencia
Periodo = 1 / Frecuencia
[3]_Con esta ecuación, se calcula el número de pasos que marque el cronometro hasta que llegue el momento "t", que es la especificada por prescaler y frecuencia del crystal
N= ( t * Frec_crystal ) / ( 4 * prescaler )
El Periodo depende del valor de PR2 (8 BITS), de Tosc del cristal y del prescaler del TMR2:
Periodo = [(PR2)+1] * 4 * Tosc * (prescaler TMR2)
Cuando TMR2 = PR2, tenemos que:
TMR2 ES BORRADO y toma el valor de 0
El registro TMR2 se pone en 0 y vuelve a contar desde 0 hasta que se hace igual nuevamente al valor del registro PR2 tras lo cual nuevamente se borra; este lapso de tiempo para que ocurra esto es lo que constituye el periodo de la señal PWM.
RC2/CCP1 = 1 (pone en alto Portc.2 o sea, CCP1)
El pin CCPx se pone a 1, que es lo mismo que decir que se obtiene un alto por este pin, menos cuando el ciclo de trabajo del modo PWM sea del 0%, en este caso este pin no se pondrá a 1 y estará en estado lógico 0.
EL VALOR DE CCPR1L SE CARGA EN CCPR1H
El valor almacenado en el registro CCPRxL que es el valor que representa el ciclo de trabajo de la señal PWM esto es el tiempo que la señal obtenida por el pin CCPx se mantiene a 1, se cargará en el registro CCPxH.
El valor del registro CCPxH se compara permanentemente con el valor que va tomando el registro TMR2 y cuando se hacen iguales el pin CCPx se pondrá a 0, de esta manera se fija el ancho de pulso, y como el TMR2 seguirá aumentando de valor hasta que este se haga igual nuevamente al valor almacenado en el registro PR2, momento en el cual el registro TMR2 se hará igual a 0 y el ciclo anterior volverá a repetirse.
Los 10 bits de resolución, se cargan en el registro CCPR1L y en CCP1X:CCP1Y (CCP1CON)
El ciclo de trabajo útil, se calcula con la formula
DUTY = (CCPR1L:CCP1CON<5:4) * Tosc * (prescaler TMR2)
Entonces al utilizar el CCP PIC modo PWM para obtener una salida PWM por el pin CCPx se tienen que cumplir 2 cosas, establecer el periodo de la señal mediante un valor cargado en el registro PR2 el cual no tendrá que ser cambiado y establecer un ciclo de trabajo mediante un valor cargado en el registro CCPRxL el cual si puede ser cambiado para obtener en el pin CCPx tensiones medias variables para el control de diverso dispositivos
PASOS PARA CONFIGURAR MODO PWM:
1. PONER PERIODO PROGRAMADO EN PR2
2. PONER CICLO DE TRABAJO ESCRIBIENDO EN CCPR1L Y EN LOS BITS CCP1X:CCP1Y DEL REGISTRO CCP1CON
3. COLOCAR PIN RC2/CCP1 COMO SALIDA (TRISC)
4. PONER VALOR AL PRESCALER DEL TMR2 Y HABILITAR TMR2 EN EL REGISTRO T2CON
5. CONFIGURAR MÓDULO CCP1 PARA PWM
1. Cuando el módulo CCP opera configurado como PWM, como mencionamos anteriormente, emplea por defecto el Timer2. Este Timer es un temporizador de 8bits, o sea, su resolución corre en un valor que va de 0 a 255.
El TIMER2 nos ofrece una herramienta con el cronometro que nos permite dividir una frecuencia de entrada; Esta herramienta se la llama PRESCALER del TMR2 y nos ofrece 16 divisores. Para entender mejor esta parte, miremos como podemos emplear el PRESCALER para obtener la frecuencia de salida más baja en nuestro PWM. Suponiendo que empleamos un Crystal de 20Mhz, tenemos que:
20.000.000Mhz / (4*16/256)=1220,7Hz (el periodo nos da aproximadamente 81,9ms)
Este ejemplo, significa que en nuestro puerto CCP, la frecuencia más baja para la operación del PWM que se puede obtener es de 1220,7Hz, empleando un cristal de 20Mhz, prescaler configurado en 16 y una resolución de 256.
2. Poner Ciclo de Trabajo escribiendo en CCPR1L y en los BITS CCP1X:CCP1Y del registro CCP1CON, Para ello, teniendo en cuenta que el valor del duty tiene una resolución de 10 bits, deberemos calcularlo de la siguiente manera:
DutyVAR = (PR2 + 1) * 4 * %
DutyVAR = (49 + 1) x 4 x 50/100
El resultado de esta fórmula, se debe almacenar en una variable tipo WORD y el registro CCPR1L debe tomar este mismo valor... Los dos bits más significantes, deben ser colocados en los 4 y 5 del registro CCP1CON
CCP1CON.4 = DutyVAR.0
CCP1CON.5 = DutyVAR.1
CCPR1L = DutyVAR >> 2
3. Establecer el pin CCPx utilizado como una salida digital mediante su registro TRISC, o el que le corresponda de acuerdo a microcontrolador utilizado y luego, configurar el módulo CCP en modo PWM para que el módulo CCP trabaje como PWM por Hardware...
La salida HPWM, además de trabajar en todo momento en segundo plano, también podemos activar esta función o desactivar en cualquier momento de nuestro programa según lo requieran...
Para la activación de la señal HPWM, se deben cambiar los valores de los bits 2 y 3 del registro CCP1CON. Si queremos activar el otro canal (CCP2), se trabajara sobre el registro CCP2CON.
PWM_ON:
CCP1CON.2=1
CCP1CON.3=1
RETURN
PWM_OFF:
CCP1CON.2=0
CCP1CON.3=0
RETURN
4. Poner Valor al PRESCALER del TMR2 y habilitar TMR2 en el registro T2CON
El temporizador timer2 cuenta con lo que se conoce como prescaler y también con un postcaler pero el postcaler solo hace su trabajo cuando el timer2 es utilizado con interrupciones; Por ahora se comentará como utilizar tanto el prescaler como el postcaler, lo que hacen es que la frecuencia de trabajo FOSC se divida por este prescaler y a la vez por el postcaler si se utilizan ambos a la vez se logra que el temporizador timer2 tarde un poco mas en aumentar su valor en una unidad.
El bit7 no se utiliza por lo que se le pone a 0.
Los bits de 6 al 3 mediante las combinaciones de estos bits se eligen el postscaler, el postscaler puede tener los valores del 1 al 16.
• 0000 = 1:1 POSTSCALE
• 0000 = 1:2 POSTSCALE
• 0000 = 1:3 POSTSCALE
•
•
• 1111 = 1:16 POSTSCALE
El bit2 al poner este bit a 1 se habilita el uso del timer2, si se pone a 0 el timer2 estará deshabilitado.
Los bits 1 y 0 mediante las combinaciones de estos bits se elige el prescaler, el prescaler puede tener los valores del 1, 4 y 16
• 00 = 1:1 PRESCALER
• 01 = 1:4 PRESCALER
• 1X = 1:16 PRESCALER
Si el prescaler elegido es por ejemplo de 4 y el postcale de 16 cuando la frecuencia del oscilador es de 4Mhz (FOSC=4Mhz), entonces la frecuencia de trabajo del temporizador (Ftemp) será de:
Ftemp = FOSC / (4*prescaler*postcale)
El tiempo que tardará ahora el temporizador timer2 en aumentar una unidad será la inversa de este valor lo que se conoce como periodo del temporizador
Ttemp = (4*prescaler*postcale) / (FOSC)
Ttemp = (4*4*16) / (4Mhz)
Ttemp = 64us
Esto quiere decir que ahora el temporizador aumentará en una unidad cada 64us y en este caso entonces el registro TMR2 para ir de 0 hasta el valor cargado en el registro PR2=150 tardará 150*Ttemp=150*64us lo que es igual a 9600us=9,6ms así para los demás prescaler y postcale.
Al utilizar los prescaler y los postcale se tiene la ventaja de temporizar tiempos más largos pero muchas veces se vuelven demasiado largos, por lo que para lograr las temporizaciones que se quieren por ejemplo de 50ms se tendría que utilizar un prescaler y un postscaler adecuado además de cargar en el registro PR2 un valor también adecuado.
Utilizando una regla de 3 simple se llega a la siguiente ecuación que ayudará a encontrar el valor inicial adecuado a cargar en el registro PR2 para obtener las temporizaciones buscadas.
PR2 = (Tretardo*Fosc)/(4*prescaler*postcale)
Donde PR2 es el valor cargar en este registro para obtener el tiempo buscado, Tretardo es el tiempo que se quiere obtener en el temporizador, Fosc es la frecuencia del oscilador o del cristal utilizado, prescaler y postcale será el prescaler y postcale elegido según la tabla anterior.
La ecuación mostrada anteriormente se cumple como se dijo en un inicio si el timer2 es utilizado con interrupciones, para el caso de no usar interrupciones el postscaler no tiene efecto y la ecuación se reducirá a la siguiente.
PR2 = (Tretardo*Fosc)/(4*prescaler)
Esta será la que se usará para el ejemplo del uso del timer2 sin interrupciones, el valor máximo del prescaler según los registros que vimos anteriormente es de 16, además PR2 tiene que ser menor o igual a 255, si se usa un cristal de 4Mhz, se puede hallar el Tretardo máximo que se puede lograr con estas condiciones
Tretardomaximo=4*PR2*prescaler/Fosc=4*255*16/4
Tretardomaximo=4080us (Aproximadamente 4ms)
Cuando se trabaja con las interrupciones del timer2 se logran tiempos de retardos mucho mayores porque allí sí que influye el postcale. Por ejemplo para obtener 4ms lo que sería el tiempo de retardo sin usar interrupciones, con una FOSC de 4Mhz, un prescaler de 16 se tendría:
PR2 = (4ms)(4Mhz)/(4*16)
PR2 = 250
Este sería el valor a cargar en el registro PR2 para obtener 4ms con el timer2, ocurrirá que el timer2 PIC aumentará de 0 a 250 en 4ms, luego se resetea a 0 al alcanzar este valor.
Los resultados obtenidos serán usados en el ejemplo de la utilización del timer1 pic como temporizador.
Este proceso será el que se seguirá cuando se quiera utilizar el timer2 PIC como temporizador sin interrupciones.
5. Configurando CCP en modo PWM (Registro CCPxCON)
Mediante este registro se elige en modo de trabajo del módulo CCPx, en la siguiente imagen se muestra el registro con los respectivos nombres de los bits que lo conforman.
REGISTRO CCP1CON
•Los bits 7 y 6 de este registro no se utilizan por lo que se les pone a 0.
• Los bits 5 y 4 (CCPxX:CCPxY) en el uso del módulo CCP PIC modo PWM, estos bits son los 2 bits menos significativos del ciclo de trabajo del módulo CCP PIC modo PWM el cual es de 10 bits, los 8 bits mas significativos se encuentran en el registro CCPRxL
• Los bits 3, 2, 1 y 0 (CCPxM3 al CCPxM0) son los que se utilizarán para elegir el modo de trabajo del módulo CCP, si estos 4 bits se ponen a 0 el módulo CCP estará deshabilitado; para el uso del módulo CCP PIC modo PWM los valores asignados a estos pines serán como se indican en la siguiente tabla.
• 0000 = CCP1 DESHABILITADO
• 0100 = CAPTURE, CADA FLANCO DE BAJADA EN RC2/CCP1
• 0101 = CAPTURE, CADA FLANCO DE SUBIDA EN RC2/CCP1
• 0110 = CAPTURE, CADA 4º FLANCO DE SUBIDA EN RC2/CCP1
• 0111 = CAPTURE, CADA 16º FLANCO DE SUBIDA EN RC2/CCP1
• 1000 = COMPARE, SALIDA =1 (CCPIF =1)
• 1001 = COMPARE, SALIDA =0 (CCPIF =1)
• 1010 = COMPARE, SE GENERA INTERRUPCIÓN (CCPIF =1)
• 1011 = COMPARE, DISPARO ESPECIAL, DIFERENTE A CCP2
• 110X = PWM
Si queremos modificar los valores de cualquier bit en este registro, podemos implementar unas lineas en cualquier seccion de nuestro programa y editar los valores en forma de forma separada.
Para habilitar el módulo CCP en modo PWM
CCP1CON.1=0
CCP1CON.2=1
CCP1CON.3=1
Como se ve al poner los bits 3 y 2 a 1 es suficiente para indicar que se ha elegido utilizar el módulo CCP PIC modo PWM, siendo indiferente lo que se coloque en los bits 1 y 0, pero se acostumbra a ponerlos a 0.
Para encender o apagar el pwm en nuestro programa, como ya mencionamos anteriormente, cambiando el estado del bit 3 y 2, logramos tal cometido
PWM ENCENDIDO:
CCP1CON.2=1
CCP1CON.3=1
PWM APAGADO:
CCP1CON.2=0
CCP1CON.3=0
Para el caso de los bit 5 y 4, Estos se cargan teniendo en cuenta que para cargar el valor del ciclo de trabajo, necesitaremos una variable de 10 bits, donde los dos más significativos (bit0 y bit1) se cargan en los bit 5 y 4 del registro CCP1CON y los 8 bits restantes, en el registro CCPR1L
CCP1CON.4 = VariableWORD_DUTY.0
CCP1CON.5 = VariableWORD_DUTY.1
CCPR1L = VariableWORD_DUTY>>2
Entiendo que llegados a estas líneas, muchas cosas quizás no quedaron claras, así que por las dudas, vallamos a nuestra técnica favorita del famoso “LEO, APLICO, APRENDO” y juguemos con algunos valores en el siguiente proyecto:
'***************************************************************
' Name : ETI-PWMtimerCCP.pbp
' Author : prof.martintorres@educ.ar
' Notice : Copyright (c) 2018/19 - ETI (Educacion Tecnica Informal)
' : All Rights Reserved
' Date : 26/12/2018
' Version : 1.0 (Version Analogica) + 1.2 (Version Digital)
' Notes : Ejemplo Practico del Articulo PWM,TIMERyCCP, de como crear
' : un generador de señal con frecuencia y duty controlado por
' : pulsadores (DIGITAL) o potenciometros (ANALOGICO)
'***************************************************************
DEFINE OSC 4
'************* Configuracion puertos IO ***************
TRISA=%00000011 ;PortA 0, 1 entradas - resto salidas
ADCON1 = 4 ;PortA 0, 1 entradas A/D (potenciometros)
TRISB=%11111000 ;PortB 0, 1 entradas DIG (pulsadores)
CMCON=7
TRISC=%00000000 ;PortC todo salidas
TRISD=%00000000 ;PortD todo salidas
'PIN HARDWARE PIC16F877A
PARAR VAR PORTB.3
B_MAS VAR PORTB.4
B_MENOS VAR PORTB.5
B_ENTER VAR PORTB.6
B_MENU VAR PORTB.7
'************* Configuracion canal ADC ***************
Define ADC_BITS 8 ;Establece el número de bits en el resultado
Define ADC_CLOCK 2 ;Ajuste el reloj de origen (rc=2)
Define ADC_SAMPLEUS 50 ;Establezca el tiempo de muestreo en uS
'*************** PreConfiguracion HPWM ***************
DEFINE CCP1_REG PORTC ;Seteamos puerto Hpwm1
DEFINE CCP1_BIT 2 ;bit 2 para configurar portC.2 como Hpwm seleccionado
T2CON = %00000110 ;
PR2=124 ;
'***************** Configuracion LCD *****************
DEFINE LCD_DREG PORTD ;Configuracion bus datos display
DEFINE LCD_DBIT 4 ;portD.4/5/6/7 conectado a D4/5/6/7 del LCD
DEFINE LCD_RSREG PORTD
DEFINE LCD_RSBIT 2 ;PortD.2 conectado a pin RS LCD
DEFINE LCD_EREG PORTD
DEFINE LCD_EBIT 3 ;PortD.3 conectado a pin E LCD
DEFINE LCD_BITS 4 ;Modo 4 bits
DEFINE LCD_LINES 2 ;Display de 2 lineas
'******************* VARIABLES ********************
POT_DUTY VAR byte
POT_FREC VAR WORD
FRECUENCIA vAR WORD
FRECUENCIA2 VAR WORD
PRVAR var byte
DUTY VAR BYTE
HAM_DUTY VAR WORD
DUTYVAR var byte
NIVEL_FREC VAR BYTE
PWMin con 5 ;porcentaje Minimo de PWM
LB var BYTE
adVal var BYTE
aVal var BYTE
Aux_W VAR WORD
Aux_Y var word
AUX1 VAR BYTE
AUX2 VAR word
AUX3 VAR BYTE
AUX4 VAR BYTE
I VAR WORD
W VAR BYTE
EEPROM 0, [ 1,2,3,4 ] ;cargar la memoria EEPROM desde la dirección 0 en adelante
EEPROM 6,[20,24] ;contenido inicial de la EEPROM temperatura
PORTA=0
PORTB=0
PORTC=0
PORTD=0
AUX1 = 0
AUX2 = 500
DUTY=50
LCDOUT $FE,1
'---------------------------------------------------------------------------
;OPTION_REG =%00111111
INTCON=%10100001
TMR0=0
ON INTERRUPT GoTo ATENCION
'---------------------------------------------------------------------------
'****************************************************************
'****************************************************************
' Programa PRINCIPAL
'****************************************************************
'****************************************************************
INICIO:
LCDOUT $FE,$80,"(+)modo ANALOGICO"
LCDOUT $fe,$C0,"(-)modo DIGITAL"
IF B_MAS = 0 THEN ;SI EL PULSADOR "MAS" ESTA CERRADO, ENTONCES...
WHILE B_MAS = 0 ;WHILE+WEND ES PARA TENER UN ANTIREBOTE
WEND ;QUE SOLO SIGUE SI SOLTAS EL PULSADOR
LCDOUT $FE,1 ;LIMPIA DISPLAY LCD
GOSUB PWM_ON ;ENCIENDE MODULO CCP-HPWM
goto PWM_analogico ;SALTA AL SUBPROGRAMA CONTROL DE PWM POR POTENCIOMETROS
endif ;FIN DE SENTENCIA
IF B_MENOS = 0 THEN ;SI EL PULSADOR "MENOS" ESTA CERRADO, ENTONCES...
WHILE B_MENOS = 0 ;WHILE+WEND ES PARA TENER UN ANTIREBOTE;WHILE+WEND ES PARA TENER UN ANTIREBOTE
WEND ;QUE SOLO SIGUE SI SOLTAS EL PULSADOR
LCDOUT $FE,1 ;LIMPIA DISPLAY LCD
goto PWM_digital ;SALTA AL SUBPROGRAMA CONTROL DE PWM POR PULSADORES
endif ;FIN DE SENTENCIA
PAUSE 10
GOTO INICIO
'****************************************************************
'****************************************************************
' Subprogramas Control DIGITAL***********************************
' En esta seccion veremos como controlar el DUTY y la FRECUENCIA
' por intermedio de la lectura de cuatro pulsadores conectados a:
' PULSADOR PARAR (PORTB.3) Apaga el PWM
' PULSADOR MAS (PORTB.4) Incrementa valor a la variable
' PULSADOR MENOS (PORTB.5) Decrementa valor a la variable
' PULSADOR ENTER (PORTB.6) Selecciona y asigna valor a variable
' PULASDOR MENU (VAR PORTB.7) Reinicia y va al MENU
'****************************************************************
'****************************************************************
PWM_digital:
LCDOUT $FE,$80,"PWM modo DIGITAL"
LCDOUT $fe,$C0,"F:",#FRECUENCIA2," Hz D%:",#DUTYvar
IF PARAR = 0 THEN ;SI EL PULSADOR "PARAR" ESTA CERRADO, ENTONCES...
WHILE B_MAS = 0 ;WHILE+WEND ES PARA TENER UN ANTIREBOTE
WEND ;QUE SOLO SIGUE SI SOLTAS EL PULSADOR
LCDOUT $FE,1 ;LIMPIA DISPLAY LCD
GOSUB PWM_OFF ;APAGA PWM
goto PWM_digital ;SALTA AL PROGRAMA PRINCIPAL (MENU)
endif ;FIN DE SENTENCIA
IF B_enter = 0 THEN ;SI EL PULSADOR "PARAR" ESTA CERRADO, ENTONCES...
WHILE B_enter = 0 ;WHILE+WEND ES PARA TENER UN ANTIREBOTE
WEND ;QUE SOLO SIGUE SI SOLTAS EL PULSADOR
READ 0,PRvar ;lee la EEPROM 0 y lo guarda en PR2
READ 7,DUTY ;lee la EEPROM 1 y lo guarda en DUTY
gosub duty1
pr2=prvar
GOSUB PWM_ON ;enciende PWM
goto PWM_digital
endif ;FIN DE SENTENCIA
IF B_MENU = 0 THEN ;SI EL PULSADOR "PARAR" ESTA CERRADO, ENTONCES...
WHILE B_MENU = 0 ;WHILE+WEND ES PARA TENER UN ANTIREBOTE
WEND ;QUE SOLO SIGUE SI SOLTAS EL PULSADOR
LCDOUT $FE,1 ;LIMPIA DISPLAY LCD
GOSUB inicio
endif
IF B_MAS = 0 THEN ;SI EL PULSADOR "PARAR" ESTA CERRADO, ENTONCES...
WHILE B_Mas = 0 ;WHILE+WEND ES PARA TENER UN ANTIREBOTE
WEND ;QUE SOLO SIGUE SI SOLTAS EL PULSADOR
LCDOUT $FE,1 ;LIMPIA DISPLAY LCD
GOSUB PWM_OFF
GOto programacion
endif
IF B_Menos = 0 THEN ;SI EL PULSADOR "PARAR" ESTA CERRADO, ENTONCES...
WHILE B_Menos = 0 ;WHILE+WEND ES PARA TENER UN ANTIREBOTE
WEND ;QUE SOLO SIGUE SI SOLTAS EL PULSADOR
LCDOUT $FE,1 ;LIMPIA DISPLAY LCD
GOSUB PWM_OFF
GOto programacion
endif
goto PWM_digital
;**************************************************************
programacion:
LCDOUT $FE,1
LCDOUT $FE,$80,"ProgDuty?-> (-)"
LCDOUT $FE,$C0,"ProgFrec?-> (+)"
IF B_MENOS=0 THEN
WHILE B_MENOS=0
WEND
LCDOUT $FE,1
GOTO programacionDUTY
ENDIF
IF B_MAS = 0 THEN
WHILE B_MAS = 0
WEND
LCDOUT $FE,1
GOTO programacionFRECUENCIA_
ENDIF
PAUSE 200
goto programacion
IF B_ENTER=0 THEN ; FREC sumar unidad
WHILE B_ENTER=0
WEND
gosub pwm_on
ENDIF
;**************************************************************
programacionFRECUENCIA_:
if duty > 0 then duty= 0
prvar=124
programacionFRECUENCIA:
LCDOUT $fe,$80,"-Enter Guardar-"
LCDOUT $FE,$C0,"ProgFrec:",#FRECUENCIA2,"Hz"
gosub progFREC
IF B_ENTER=0 THEN
WHILE B_ENTER=0
WEND
LCDOUT $FE,1
pause 100
goto grabarFREC
ENDIF
goto programacionFRECUENCIA
progFREC:
IF B_MAS=0 THEN ; FREC sumar unidad
;WHILE FREC_SUBIR=0
;WEND
PRVAR = PRvar-1 ;PR2=PR2-1
IF PRVAR<25 THEN PRVAR=25 ;IF PR2<25 THEN PR2=25
ENDIF
IF B_MAS=0 THEN ; FREC sumar unidad
;WHILE FREC_SUBIR=0
WEND
PRvar=PRvar-1
IF PRvar<25 THEN PRvar=25
ENDIF
IF B_MENOS=0 THEN ; FREC restar unidad
;WHILE FREC_BAJAR=0
;WEND
PRvar=PRvar+1
IF PRvar>124 THEN PRvar=124
ENDIF
IF PRvar<25 THEN PRvar=25
IF PRvar>124 THEN Prvar=124
HAM_DUTY=(PRvar+1)*DUTY/25
CCP1CON.4=ham_DUTY.0
CCP1CON.5=HAM_DUTY.1
CCPR1L=HAM_DUTY>>2
FRECUENCIA2=62500/(PRVAR+1)
return
grabarFREC:
pr2=prvar
LCDOUT $fe,$80,"Frecuencia",#frecuencia2,"Hz"
LCDOUT $FE,$C0," -ALMACENADA- "
WRITE 0,PRVAR ;escribir en la dirección 0 de la EEPROM
pause 1500
LCDOUT $FE,1
GOTO PWM_digital
;**************************************************************
programacionDUTY:
LCDOUT $fe,$80,"-Enter Guardar-"
LCDOUT $FE,$C0,"ProgDUTY: ",#dutyvar," %"
IF B_MENOS=0 THEN
WHILE B_MENOS=0
WEND
GOTO programacionDUTY
ENDIF
gosub progDUTY
IF B_ENTER=0 THEN
WHILE B_ENTER=0
WEND
LCDOUT $FE,1
pause 100
goto grabarDUTY
ENDIF
goto programacionDUTY
progDUTY:
IF B_MAS =0 THEN
WHILE B_MAS=0
wend
aux3=0
DUTYvar=DUTYvar+1
IF DUTYvar=101 THEN DUTYvar=100
gosub duty1
W=1
IF aux3=>50 THEN
W=0
aux3=50
DUTYVAR=DUTYVAR+1
GOSUB DELAY
IF DUTYVAR=101 THEN DUTYVAR=100
ENDIF
gosub duty1
W=0
aux3=0
ELSE
W=0
aux3=0
ENDIF
IF B_MENOS=0 THEN
WHILE B_MENOS=0
wend
aux3=0
DUTYVAR=DUTYVAR-1
IF DUTYVAR=255 THEN DUTYVAR=0
gosub duty1
W=1
IF aux3=>30 THEN
W=0
aux3=30
DUTYVAR=DUTYVAR-1:GOSUB DELAY
IF DUTYVAR=255 THEN DUTYVAR=0
ENDIF
gosub duty1
W=0
ELSE
W=0
aux3=0
ENDIF
RETURN
grabarDUTY:
LCDOUT $fe,$80,"DUTY ",#DUTYVAR,"%"
LCDOUT $FE,$C0," -ALMACENADA- "
WRITE 1,DUTYVAR ;escribir en la dirección 1 de la EEPROM
pause 1500
LCDOUT $FE,1
pause 100
GOTO PWM_digital
duty1:
IF PRVAR<25 THEN PRVAR=25
IF PRVAR>124 THEN PRVAR=124
HAM_DUTY=(PRVAR+1)*DUTYVAR/25
CCP1CON.4=ham_DUTY.0
CCP1CON.5=HAM_DUTY.1
CCPR1L=HAM_DUTY>>2
return
'****************************************************************
'****************************************************************
' Subprogramas Control ANALOGICO*********************************
' En esta seccion veremos como controlar el DUTY y la FRECUENCIA
' por intermedio de la lectura de dos potenciometros conectados
' a PORTA.0 y portA.1
'****************************************************************
'****************************************************************
PWM_analogico:
IF PARAR = 0 THEN ;SI EL PULSADOR "PARAR" ESTA CERRADO, ENTONCES...
WHILE B_MAS = 0 ;WHILE+WEND ES PARA TENER UN ANTIREBOTE
WEND ;QUE SOLO SIGUE SI SOLTAS EL PULSADOR
LCDOUT $FE,1 ;LIMPIA DISPLAY LCD
GOSUB PWM_OFF ;APAGA PWM
goto INICIO ;SALTA AL PROGRAMA PRINCIPAL (MENU)
endif ;FIN DE SENTENCIA
LCDOUT $FE,$80,"PWM modo ANALOGICO"
LCDOUT $fe,$C0,"Hz:",dec5 FRECUENCIA," D:",dec3 DUTY,"%"
GOSUB CALCULO_FRECUENCIA
GOSUB SET_DUTY
gOSUB CALCULO_FRECUENCIA
GOSUB DUTY_CONTROL
GOSUB FREC_CONTROL
GOTO PWM_analogico
FREC_CONTROL:
ADCON0 = $41
PAUSEUS 50
ADCON0.2 = 1
WHILE ADCON0.2
WEND
PR2 = ADRESH
GOSUB CALCULO_FRECUENCIA
gosub SET_DUTY
IF PR2<5 THEN PR2=5
IF PR2>255 THEN PR2=255
RETURN
;*********************************************************
DUTY_CONTROL:
ADCON0 = $49
PAUSEUS 50
ADCON0.2 = 1
WHILE ADCON0.2
WEND
DUTYvar = ADRESH
POT_DUTY = DUTYvar
if aval<>POT_DUTY then
LB = (255/100)*PWMin
if POT_DUTY >= LB then
DUTY=(POT_DUTY - LB)/((255 - LB)/100) ;CONVERTIMOS EL VALOR EN PORCENTAJE
IF DUTY > 100 THEN DUTY = 100
IF DUTY < 2 THEN DUTY = 0
endif
ENDIF
aval=POT_DUTY
AUX3=0
gosub SET_DUTY
W=1
IF AUX3=>50 THEN
W=0
AUX3=50
DUTY=DUTY+1
GOSUB DELAY
IF DUTY > 100 THEN DUTY=99
ENDIF
GOSUB SET_DUTY
W=0
AUX3=0
W=1
IF AUX3=>30 THEN
W=0
AUX3=30
DUTY=DUTY-1
GOSUB DELAY
IF DUTY < 3 THEN DUTY = 0
ENDIF
GOSUB SET_DUTY
W=0
AUX3=0
RETURN
'****************************************************************
'****************************************************************
' Subprogramas para Control de SALIDA del PWM por HARDWARE
'****************************************************************
'****************************************************************
CALCULO_FRECUENCIA:
FRECUENCIA=62500/(PR2+1)
RETURN
DELAY: ;retardos generados para sumar a TMR0 actualice correctamente
FOR I=0 TO 255
NEXT
RETURN
DELAY1:
FOR I=0 TO 150
NEXT
RETURN
SET_DUTY:
IF DUTY > 99 THEN
HIGH PORTC.1
PAUSEUS 1
ELSE
IF PR2<5 THEN PR2=5
IF PR2>255 THEN PR2=255
HAM_DUTY=(PR2+1)*DUTY/25
CCP1CON.4=HAM_DUTY.0
CCP1CON.5=HAM_DUTY.1
CCPR1L=HAM_DUTY>>2
ENDIF
return
;*********************************************************
PWM_ON:
CCP1CON.2=1
CCP1CON.3=1
RETURN
PWM_OFF:
CCP1CON.2=0
CCP1CON.3=0
low PORTC.1
low PORTC.2
RETURN
;*********************************************************
;++++++++++++++++++++ INTERRUPCION +++++++++++++++++++++++
;*********************************************************
DISABLE
ATENCION:
IF W=1 THEN
AUX3=AUX3+1
IF AUX3=101 THEN AUX3=0
ENDIF
INTCON.2=0
RESUME
ENABLE
END
;*********************************************************
;*********************************************************
Control PWM en Modo DIGITAL
En construccion (Falta hablar de los Timer1 y 0)