# Usando PWM - mini tutorial



## Marcelo

Usando PWM (Pulse with Modulation).

Casi todos los que lean este post, habrán hecho en algún momento, un proyecto para prender un led o accionar un motor mediante un microcontrolador o por medio de cualquier otro circuito.

Pero que sucede si queremos controlar la luminosidad del led que estamos encenciendo o deseamos regular la velocidad del motor?.

Pudiéramos pensar que si prendemos y apagamos la señal de alimentación de la carga (led o motor) lo suficientemente rápido como para que el parpadeo no se note, podríamos “simular” la variación de  luminosidad de un led o el cambio en la velocidad del motor:







Esto funciona siempre y cuando no hagamos este “switcheo” más allá de 30 veces por segundo. A partir de allí. El "blink" del led se empezará a notar y El ojo humano captará ese parpadeo. En el caso de un motor, éste se moverá en una forma pulsante.

La idea general del PWM es esta, solo que soluciona este problema de tiempo.  

La forma de lograrlo es dejar el pulso fijo en el tiempo y variar su amplitud.

Supongamos que logramos ajustar el período T a su valor óptimo mínimo  en el cual un led no parpadee y un motor no salte.

Esto es aproximadamente a una frecuencia de 30 pulsos o ciclos por segundos para el caso de un led. En el caso del motor habrá que determinarlo empíricamente ya que depende de sus características eléctricas y mecánicas,

Volviendo al led, quiere decir que trabajamos con un período de tiempo de:

f= 30 cps  ==> T=1/f  ==> T=1/30 ==> T= 0.0333 s ==> T=33.3 ms






El esquema anterior representa un pulso con un “duty cycle” o ciclo de servicio igual al 50% es decir, la mitad del período está a 0 y la otra mitad está a Vcc.

Lo que se hace con PWM es variar dinámicamente el “duty cycle” de manera que el tiempo de alta disminuya o aumente y en proporción inversa, el de baja aumente o disminuya dependiendo de si queremos una led más atenuado o más brillante, o un motor más lento o más rápido, respectivamente.






LED MENOS ILUMINADO






LED MAS ILUMINADO

Recuerden que este período se repite constantemente en el tiempo:






De esta forma tenemos 2 formulitas muy sencillas para el cálculo de los tiempos:

1)	Si variamos, fijamos o controlamos t alta entonces:  t baja= T- t alta
2)	Si variamos, fijamos o controlamos t baja entonces:  t alta= T- t baja
Y el ciclo de servicio o “Duty Cycle” lo calculamos así:

DT= t alta / (t alta + t baja)

En una próxima entrega codificaremos esto en Assembler para PIC.

Saludos,
Marcelo.


----------



## Marcelo

1) Manejo de los tiempos

Ahora que sabemos como es la teoría básica del PWM, vamos a programarlo en un PIC 16F84A.  Para simplificar un poco la explicación y no hacerla tan larga, supondremos que se poseen conocimientos básicos de cómo funciona un PIC.

La forma de aplicación con la que podemos usar las rutinas PWM son básicamente 2:

1)	“Stand Alone” o programas que corren sin instrucciones de comando externos. Estos se utilizan normalmente en sistemas autómata, los cuales reaccionan a estímulos externos como por ejemplo un robot que choca contra un obstáculo o el seguimiento por parte del robot de una línea guía en el suelo, pero el programa en si se autocontrola y toma sus propias decisiones (bueno, las que le programamos).

2)	Modo Maestro - Esclavo, que utiliza un controlador externo que le dice a un aparato que es lo que debe hacer. Por ejemplo, un circuito que controla un motor que a la vez es comandado desde un computador bien sea por el puerto serial, paralelo, usb, infrarrojo o cualquier otro. En estos casos, el computador “conversa” con el circuito, decide que se debe hacer e instruye al esclavo para que lo haga.

Para empezar recordemos que PWM en realidad controla TIEMPO. Por consiguiente es necesario tener un conocimiento relativamente alto de cómo se manejan los tiempos en un PIC 16F84A.
En otros integrados de esa familia de semiconductores, ya existen librerías programadas para manejar PWM.
Este no es el caso del 16x84, por lo que el control de tiempo hay que hacerlo “a mano”.

 La frecuencia de trabajo de un microcontrolador es un parámetro primordial a la hora de determinar a que velocidad se ejecutan las instrucciones dentro de él.
En estos PICs cada instrucción consume 4 ciclos de reloj que llamaremos Q1, Q2, Q3 y Q4.

1) Con el pulso Q1 se incrementa el “contador de programa”.
2) Con los pulsos Q2 y Q3 se decodifica la instrucción y se ejecuta
3) Durante Q4 se busca el código que corresponde a la próxima instrucción en la memoria del PIC y se carga en el “registro de instrucciones”.






Las instrucciones que generan un “salto” se llevan dos ciclos de instrucciones. Fíjense que pareciera que no cuadra lo de los pulsos y esto se debe a que las dos fases que comprenden las instrucciones  se realizan en paralelo y en realidad cada instrucción toma 2 ciclos en ejecutarse. Esto se denomina técnica de segmentación y se le llama “pipeline”; ya la deben de haber escuchado más de una vez.






Las instrucciones de salto llevan 2 ciclos porque no se conoce la instrucción que sigue luego de cada salto, por consiguiente el ciclo en el cual el procesador debería buscar la próxima instrucción secuencial, es sustituido por un ciclo sin operación. (vean la figura anterior)

Si la instrucción es de salto condicional es decir, salta si se cumple una condición como decfss o decfsc por ejemplo, la instrucción puede durar 1 ciclo, si no se cumple la condición o 2 ciclos si la condición de salto se cumple. Para el cálculo tomamos 2 ciclos que es el peor de los casos.

La frecuencia fundamental de operación del PIC viene dada por el oscilador que utilizamos para su configuración.

Así por ejemplo, un programa que tiene 500 instrucciones de las cuales 120 son de saltos y se configura con una frecuencia típica de 4 Mhz, tardará en ejecutarse el siguiente tiempo (recuerden que el 16F84A se puede manejar hasta con 20Mhz):

Tiempo del Ciclo de reloj (Qi) = 1/f = 1/4.000.000 = 250 ns (nano segundo)
Tiempo del Ciclo de Instrucción = 4 veces Ciclo de reloj = 4 * 250ns = 1.000 ns = 1 us (micro segundo)

Tiempo del programa = Instrucciones de 1 ciclo * Ciclo de Instrucción + Instrucciones de 2 ciclos * 2 veces Ciclo de Instrucción

Tiempo del programa = (500 – 120) * 1 + 120 * 2 =  620 us

Nuestro programa tardará en ejecutarse 620 micro segundos.

En la próxima entrega vamos a entrar en la lógica que usaremos para la rutina y su codificación.

Saludos.
Marcelo.


----------



## Marcelo

La lógica en la programación del PWM

Muchas son las formas, algoritmos e ideas que podemos aplicar para programar nuestra rutina y este no es un caso particular.  

A cada uno de nosotros se nos ocurrirán formas más o menos complicada, más o menos largas de codificar y más o menos eficientes para escribir nuestro programa. pero todas igual de válidas.

Como la idea de este tutorial no es demostrar nada sino retransmitir lo poco que se sabe a fin de que se mejore el conocimiento medio de todos nosotros, lo que trataremos de hacer es reducir al máximo la complejidad sin hacerle mucho caso a la eficiencia, a fin de que cualquiera que lo lea lo pueda entender, aplicar y mejorar.
A ustedes les dejo el perfeccionamiento del firmware del PIC.

Tampoco consideraremos cual debería ser el tiempo óptimo del pulso, sino que ustilizaremos un tiempo bastante corto en el cual el motor no salte y además tenga tiempo suficiente para responder a la solicitud de movimiento. 

De igual manera y a fin de simplificar aun más las cosas, trataremos de no utilizar en la rutina de PWM interrupciones, watch dog ni TMR0.

Antes de empezar a diseñar la rutina deberemos establecer como vamos a conectar nuestro PIC con el mundo exterior y de que manera lo vamos a controlar.

Como circuito de práctica y lineamientos generales haremos que nuestro PIC cumpla con estas condiciones:

1 )	Controlaremos un motor DC
2 )	Usaremos una frecuencia de 4 Mhz
3 )	Usaremos la puerta B
4 )	Pin de control del motor RB4 (SALIDA)
5 )	Pin de control del motor RB5 (SALIDA)
6 )	El pin RB6 indicará con un LED uno de los dos sentidos de giro (SALIDA)
7 )	El pin RB7 indicará con un LED el otro sentido de giro (SALIDA)
8 )	Haremos que el control sea externo es decir, desde un computador. Para esto usaremos los siguientes pines (ojo, porque a veces esto confunde un poco):
a.	RB1: Recepción DESDE el Puerto Serial. (Deberá conectarse a la pata Tx del serial – pin 2 DB9). Este pin como ENTRADA.
b.	RB2: Transmisión HACIA el Puerto Serial. (Debera conectarse a la pata Rx del serial – pin 3 DB9). Este pin como SALIDA. 
9)	RB0/INT la dejamos en standby a ver si la usamos luego para indicar o producir algún evento.

Lógica de la rutina, el algoritmo:

Supongamos que tenemos una palabra de 8 bits para indicar el Duty Cycle de nuestros pulsos es decir, un byte. Por consiguiente tendríamos 2^8 posibles valores = 256 (desde 0 hasta 255)

Lo que vamos a hacer es normalizar a 1 nuestra temporización. Esto quiere decir que si consideramos que 1 es el tiempo total de un pulso completo, podemos afirmar que:

TALTA= CICLO/256
TBAJA=1-TALTA

Donde CICLO varía desde 0 hasta 255. (El 256 del divisor indica los 256 posibles valores)

CICLO es una variable que usaremos al enviar el valor para la determinación del tiempo de alta. 

La idea es contar desde 0 hasta CICLO manteniendo la alimentación del motor encendida y el tiempo restante, hasta llegar a 256 se colocará la salida en 0.

Usemos el acumulador del PIC (W) como contador, teniendo entonces que:

W=W + CICLO  con CICLO = 0, 1, 2, 3, …. 255 y conteniendo el valor deseado por nosotros. 

Habíamos dicho que no usaríamos interrupciones ni desbordes de temporizadores, pero necesitamos una forma de saber cuando el contador llegó a 256 o mejor dicho, cuando terminó de dar una vuelta completa.

Una forma de hacerlo es utilizando la bandera de CARRY (bit de acarreo) del registro de ESTADO del PIC.

Con esto en mente:

1)      Si CICLO vale 0, nunca ocurrirá un carry y la salida siempre estará a 0.
2)	Si CICLO vale 1 el carry se activará cuando el acumulador W, luego de haber empezado a contar desde 0, llegue a 0xFF y pase de nuevo a 0x00 (de 255 a 0). Entonces la salida estará alimentando al motor la 1/256ava parte del tiempo total.
3)	Si CICLO vale 2, W hará un rollover (giro sobre si mismo o vuelta) dos veces es decir, ocurrirán 2 carries y el tiempo de alimentación será la 2/256ava parte del tiempo total.
4)	Etc. Etc.

Vemos que el carry ocurre siempre excepto cuando CICLO vale 0 en donde el motor está apagado. Si se quiere el motor “siempre” excitado entonces enviaremos CICLO=255, en donde el tiempo de alta será 255/256.

No por casualidad se usaron los valores 0 a 255 que corresponden a la codificación de caracteres ASCII. Esto va a servirnos de mucho cuando programemos nuestro software principal en el PC pues deberemos mandar códigos ASCII a nuestra interfaz.

Como debemos comunicarnos con nuestro motor, utilizaremos unos número de códigos que reservaremos del rango 0 a 255.
Dependiendo de como desarrollemos nuestro "firmware", habrá que tener cuidado de no usar esos caracteres específicos para definir un valor de velocidad para el PWM desde nuestro programa de computador, pues se utilizarán para conocer el estado de nuestro circuito y enviar comandos y recibir respuestas.
En nuestro caso, si podremos usar los 256 valores posible porque las comparaciones de comunicación las haremos antes de enviar el caracter de velocidad. 

Por ejemplo:
1)	Envio del carácter 100 desde el computador: Solicita estado de la conexión.
2)	Envío de carácter 102 para dirección de giro 1 
3)	Envío de carácter 104 para dirección de giro 1 
4)	El PIC responderá: con 100, indicando que la interfaz está conectada y comunicada.
5)	El PIC enviará el código 104 para indicar que se está moviendo en cada bucle de 256.
6)	El PIC enviará el código 102 para indicar que el motor paró su movimiento


En la próxima, el listado del programa.


----------



## Marcelo

Aca estamos de vuelta.

Ahora que ya tuve tiempo para hacer el circuito de prueba y terminar el programa, se los voy a pasar.

Si lo quieren bajar hagan click en estos links (*botón derecho del mouse y luego "guardar destino como"*). Recuerden bajar también el Rs232low.inc que lo van a necesitar cuando quieran hacer un cambio en el programa y tengan que reensamblarlo.

MyPWM - assembler : https://www.forosdeelectronica.com/upload/MarceloFiles/PWM/MiPWM.asm

MyPWM - código HEX : https://www.forosdeelectronica.com/upload/MarceloFiles/PWM/MiPWM-HEX.zip

rs232low.inc : https://www.forosdeelectronica.com/upload/MarceloFiles/PWM/rs232low.zip

Palabra de configuración para el PIC16F84A: 
OSCILADOR: XT
WDT: Off
Power Up Timer: Off (Si usan 16C84 ponganlo en On)
CodeProtect: Off

Aqui les voy a dar una breve explicación de lo que hace el programa pues creo que el código está lo suficientemente comentado como para que se entienda paso a paso.

Recuerden que la intención de este tutorial es aprender así, paso a paso;  por lo que muchísimas cosas en el programa se pueden realizar con menos instrucciones de las que tienen e inclusive omitir algunas.

También tiene como idea, alentar a aquellos que le tienen algo de miedo al assembler y hacerles ver que es relativamente fácil programarlo.

La forma en que se estructura la codificación está hecha de la manera más secuencial posible para que podamos entenderlo a cabalidad.

En resumen el programa hace lo siguiente:

1) Cuando desde el computador enviamos el caracter "d" (ASCII Decimal 100 - Hexadecimal 64), le preguntamos a nuestro circuito: ¿TIENES COMUNICACIÓN?, a lo que la interfaz (es decir, el PIC) reaccionará enviando un 100 al computador como respuesta. Esto sirve para poder comprobar que la interfaz está interconectada al PC. Si no tienen respuesta es que hay algún problema.

2) Cuando queremos decirle a la interfaz que mueva el motor en la dirección A, enviaremos el caracter  "f"  (ASCII Decimal 102 - Hexadecimal 66). La interfáz quedará en standby esperando que le enviemos el valor de la velocidad que deseamos. En este punto debemos enviar cualquier caracter desde 0 a 255, siendo 0=Parado y 255=Full Velocidad.  Cuando enviamos el valor de velocidad, la interfaz mandará el caracter "h" (ASCII Decimal 104 - Hexadecimal 68) para decirle al computador "ME ESTOY MOVIENDO" y cuando termine el ciclo de movimiento la interfaz mandará el caracter "f" (ASCII Decimal 102 - Hexadecimal 66) para informaciónrmar "ME DETUVE".

3) Si queremos mover el motor en el sentido contrario (Dirección B), deberemos enviarle a la interfaz el caracter "h" (ASCII Decimal 104 - Hexadecimal 68) y las respuestas serán iguales a las explicada en el punto 2.

Si esto les pareció complicado, monten el circuito en un protoboard y utilicen un programa terminal como el  Comm Port Toolkit o cualquier otro (inclusive el Hyperterminal de Windows) para enviar los carateres y ver como responde.

Este envio y recepción de caracteres le permitirá saber que está haciendo el motor y actuar en consecuencia desde el programa de su PC.

Este tipo de programas y controladoras (me refiero al circuito) son muy comunes en robótica y control asistido por computadora, por lo que es muy interesante ponerse a experimentar y realizar infinidades de cosas con ellas.

El código va a quedar un poco descuadrado en la pantalla por lo de cortar y pegar, pero sigue siendo bastante legible.

Para la próxima... El circuito.

Bueno, aqui les va... y Saludosl


		Código:
	

;++++++++++++ PROGRAMA PARA CONTROLAR UN MOTOR DC
;++++++++++++ INCLUYE RUTINA PWM
;++++++++++++ INCLUYE RUTINA DE COMUNICACIÓN SERIAL
;++++++++++++ Marcelo Saavedra - 06/09/2005

		List	p=16F84A;Tipo de procesador
		include	"P16F84A.INC"	;Definiciones de registros internos

;
;Declaración de Variables.
;
CICLO		equ	0x21		;Duración del tiempo de servicio
RECIBIDO	equ	0x22		;Guarda el carácter recibido por el serial
M1		equ	0x23		;Bandera del motor. Con un solo pin podemos controlar.
BANDERA	equ	0x24		;Contador de bucle
NVECES		equ	0x25		;Variable de control de bucle para reenviar a PWM
Rs232_var	equ	0x0C		;Inicio de las variables para rutinas RS232low.inc para comunicación

;
;Parámetros de la rutina de comunicación
;
CLKIN	equ	.4000000	;Frecuencia 
BAUDIOS	equ	.9600		;Velocidad de comunicación
T_MODO	equ	1		;Transmite primero bit LSB
R_MODO	equ	1		;Recibir primero bit LSB
T_Nbit	equ	8			;Transmite caracteres de 8 bits
R_Nbit	equ	8			;Recibe caracteres de 8 bits
Sbit	equ	1			;Transmite 2 bits de stop
					
		org	0	
		goto	INICIO
		org 4			;La Interrupción comienza aquí.
		nop		
					
	include	"RS232LOW.INC"	;Incluir rutinas de comunicación
;
;********Rutina de Inicio
;
INICIO
						;Desabilita e impide todas las interrupciones
			bcf	INTCON,GIE	;GIE=0
			bcf	INTCON,EEIE	;EEIE=0
			bcf	INTCON,T0IE	;T0IE=0
			bcf	INTCON,INTE	;INTE=0
			bcf	INTCON,RBIE	;RBIE=0
			bcf	INTCON,T0IF	;T0IF=0
			bcf	INTCON,INTF	;INTF=0
;
;********Configuración de los BYTES de STATUS y OPTION
	bsf	STATUS,RP0			;Pone el RP0 a 1 - Seleccionando BANCO 1 de datos
	movlw	b'11010000'			;Coloca el Byte de OPTION en W
						;- Prescaler en 000
						;- Prescaler al TMR0 - 0
						;- Incremento TMR0 con flanco ascendente - 1
						;- Pulsos por Fosc/4 - 0
						;- Flanco ascendente para la interrupción - 1
						;- Pull-up desactivadas - 1
	movwf	OPTION_REG		;Coloca el valor anterior de W en el literal OPTION_REG

	movlw	b'00000011'			;Establece en W, el Byte de configuración para PORTB
						;RB0=Sensor (ENTRADA) - 1
						;RB1= Recibir desde TX del serial(ENTRADA) – 1
						;RB2= Enviar hacia RX del serial  (SALIDA)  - 0
						;RB3=Sin conexión (SALIDA) - 0
						;RB4=MOTOR 1 (SALIDA) - 0
						;RB5= MOTOR 2 (SALIDA) - 0
						;RB6= LED para indicar sentido 1 (SALIDA) - 0
						;RB7= LED para indicar sentido 2 (SALIDA) - 0
	movwf	TRISB				;Se asignan los puertos RBi salvando W en TRISB
	bcf	STATUS,RP0			;Pone el RP0 a 0 para regresar al BANCO 0 de datos.
;
;********Inicialización pines de Rx y Tx
		bsf	Txd_pin		;Línea de transmisión a "1" en RS232Low.Inc
		bsf	Rxd_pin		;Línea de recepción a "1" en RS232Low.Inc
;
;********Motor parado
		bcf	M1,0		;Inicializamos la bandera del motor a 0 (Solo usamos el bit 0)
		movlw	0xAA		;Número de veces que vamos a reenviar a PWM - Esto es para Compensación
					;y pueden ajustarlo para que el encendido total sea mayor o menor (de 0 a ff)
		movwf	NVECES		;Cargamos la variable.
;
;********Rutina de recepción de datos
RECEPCION
;
;*************Apagamos todo
		bcf	PORTB,4		;Apagamos pin RB4 de PORTB
		bcf	PORTB,5		;Apagamos pin RB5 de PORTB	
		bcf	PORTB,6		;Apagamos el led 1
		bcf	PORTB,7		;Apagamos el led 2
;
;*************Transmitimos "Motor Parado"
		movlw	0x66		;Coloca 102 (0x66) en W – Señal de motor parado
		movwf	Txdreg		;Carga W en Txdreg para transmitirlo
		call	T		;y lo transmite indicando que los motores están parados.
;
;*************Escuchamos el puerto serial
ESCUCHAR
		call	R		;Llama la rutina de recepción en RS232Low.Inc
		movf	Rxdreg,W	;Coloca el caracter recibido por Rxdreg en W
		movwf	RECIBIDO	;y lo salva en RECIBIDO
;
;*********Rutina de comparación del caracter recibido
							;Empieza la comparación.
		movlw	0x66		;Coloca 102 (h66) en W – Es el sentido de giro 1?
		subwf	RECIBIDO,0	;Resta W (h66) del caracter recibido y el resultado lo almacena en W
		btfss	STATUS,Z	;Está a 1 el bit ZERO de STATUS? (Si está a 1 la resta anterior es 0)
		goto	SALTAR1	;No, no está a 1, vete a SALTAR1
		bsf	M1,0		;Si, Z está a 1, entonces pon M1 a 1
		goto	MOVIMIENTO	;y luego ve a MOVIMIENTO para seguir con el programa.
SALTAR1				
		movlw	0x68		;Coloca 104 (h68) en W – Es el sentido de giro 2?
		subwf	RECIBIDO,0	;Resta W (h68) del caracter recibido y el resultado lo almacena en W
		btfss	STATUS,Z	;Está a 1 el bit ZERO de STATUS? (Si está a 1 la resta anterior es 0)
		goto	SALTAR2	;No, no está a 1, vete a SALTAR2
		bcf	M1,0		;Si, Z está a 1, entonces pon M1 a 0
		goto 	MOVIMIENTO	;y luego ve a MOVIMIENTO para seguir con el programa.
SALTAR2
		movlw	0x64		;Coloca 100 (h64) en W – Me preguntan si hay conexión?
		subwf	RECIBIDO,0	;Resta W (h64) del caracter recibido y el resultado lo almacena en W
		btfss	STATUS,Z	;Está a 1 el bit ZERO de STATUS? (Si está a 1 la resta anterior es 0)
		goto	ESCUCHAR	;No,ZERO esta a 0 entonces se va a buscar otro BYTE VÁLIDO.
;
;*********Rutina de enviar confirmación de LINK de la interfaz
					;Si llega aquí se recibió el 100, solicitando la confirmación de LINK
		movlw	0x64		;y comienza el ECO del caracter 100 (0x64) para decir SI, HAY LINK.
					;Carga 100 en W
		movwf	Txdreg		;Carga W en Txdreg para transmitirlo
		call	T		;lo transmite.
		goto	ESCUCHAR	;y regresa a RECEPCION a esperar otro carácter.
;
;*********Rutina de MOVIMIENTO / PARO
MOVIMIENTO
					;ESPERAMOS EL VALOR DE CICLO. Ya tenemos el sentido de giro.
		call	R		;Llama la rutina de recepción en RS232Low.Inc
		movf	Rxdreg,W	;Coloca el caracter recibido por Rxdreg en W
		movwf	CICLO		;y lo salva en CICLO
		btfsc	STATUS,Z	;Si se activo el bit Z de STATUS no se ha recibido nada (W está en 0)
		goto 	MOVIMIENTO	;y esperamos el caracter de CICLO. Si Z=0 entonces saltamos este paso.
;		
					;Enviamos el caracter 104 para indicar que el motor se va a mover.
		movlw	0x68		;Coloca 104 (0x68) en W – Señal de motor en movimiento
		movwf	Txdreg		;Carga W en Txdreg para transmitirlo
		call	T		;y lo transmite indicando que los motores se están moviendo.
;
;*********Encendido del LED
		btfsc	M1,0		;Si M1 es 0, salta el próximo paso
		goto 	LED2		;Si M1 es 1 salta a LED2
		bsf	PORTB,6		;Prendemos el led 1
		bcf	PORTB,7		;Apagamos el led 2
		goto 	ARRANCAR
LED2			
		bcf	PORTB,6		;Apagamos el led 1
		bsf	PORTB,7		;Prendemos el led 2
;
;*********Comienzo del bucle
ARRANCAR
		clrf	BANDERA	;Borrar contador de bucle para recorrer 256 veces el bucle	
		call 	PWM		;llamamos la rutina PWM
		decfsz	NVECES,f	;Decrementamos la rutina de compensación
		goto 	ARRANCAR	;Mientras no llegue a 0, nos mantenemos en el bucle
		goto 	RECEPCION	;Cuando NVECES sea 0 regresamos a esperar otro character.
;
;*********Rutina PWM
PWM
;
;*********Chequeo del CARRY y suma de W
		addwf	CICLO, w 		; W=W+CICLO
		btfss	STATUS, C		;Chequeamos el CARRY
		goto	APAGAR			;Si no hay CARRY apagamos el motor
		btfsc 	STATUS, C		;Chequeamos el CARRY		
		goto	PRENDER			;Si hay CARRY prendemos el motor (pasamos de 255 a 0)
		goto	SEGUIR
;
;*********
PRENDER						;ENCENDIDO DE MOTOR
		btfsc	M1,0		;Si M1 es 0, salta el próximo paso
		goto 	REVERSA		;Si M1 es 1 se va a REVERSA
		nop					;Los nop están para compensar los tiempos de la comparación y los saltos
							;COMO EJERCICIO CALCULEN LOS TIEMPOS DE LA RUTINA PWM!!!.
		bcf		PORTB,4		;Apagamos pin RB4 de PORTB		
		bsf		PORTB,5		;Prendemos pin RB5 de PORTB
		goto	SEGUIR		;y se va a SEGUIR
REVERSA			
		bsf		PORTB,4		;Prendemos pin RB4 de PORTB
		bcf		PORTB,5		;Apagamos pin RB5 de PORTB
		goto	SEGUIR
APAGAR		
		nop
		nop
		nop					;APAGADO DE MOTOR
		bcf		PORTB,4		;Apagamos pin RB4 de PORTB
		bcf		PORTB,5		;Apagamos pin RB5 de PORTB
		nop
		nop
SEGUIR
							;Si es necesario un Delay colcarlo aquí
		decfsz	BANDERA,f	;Decrementamos BANDERA y saltamos si es cero. Hacerlo 256 veces.
		goto	PWM
		return
;**********Fin
		end


----------



## Marcelo

Montando el circuito:

Ahora que ya tenemos diseñado nuestro firmware, vamos a montar el circuito para probarlo.

La alimentación de la etapa lógica y de comunicaciones (PIC16F84 y MAX232) será a 5 voltios. 

Con respecto al control del motor hay que tener algunas consideraciones. Si alguien se está preguntando si puede conectar directamente las patas del motor a las salidas del PIC la respuesta es NO!.

Las señales de salidas (Motor1 y Motor2) del PIC se usarán como control para el circuito de potencia del motor. Aunque yo les voy a dar un esquema sugerido para un motor DC de 9-12V de alimentación y corriente de armadura de 250 mA (lo pueden forzar hasta 1,5 A pero disipen el calor en los transistores BD135), diseñado con elementos discretos (transistores, resistencias, condensadores, etc), queda en sus manos el desarrollo de esta etapa.
Para ello podrán emplear un buen número de integrados diseñados para el manejo de motores DC o basarse en cualquiera de los circuitos que podrán encontrar dedicados a eso (pregunten en este foro).

Para los que son un poco más avanzados en electrónica:
“Deberán poner atención en el diseño del circuito para el control de motores, pues tendrán que verificar que las salidas M1 y M2 deberán estar amortiguadas (con un buffer) mediante un circuito cuya ganancia sea igual a 1, a fin de evitar que las salidas (o los pines mejor dicho) se mantengan en régimen permanente afectando el voltaje entregado por el PWM.
Esto debió evitarse cambiando el firmware de manera tal que las salidas de PWM (Motor1 y Motor2) se coloquen como SALIDAS al momento de llamar a la rutina de movimiento y conmutándolas a ENTRADAS (estado de alta impedancia) inmediatamente después de que la rutina PWM haya terminado de realizar sus labores. Esto no está implementado. Aquí el “buffering” lo hice utilizando los optoacopladores en el puente H.” 

Fin de la cita.

Siguiendo con lo anterior, si desean probar el circuito sin utilizar un motor, podrán conectar (aquí si directamente) un LED en cada una de las salidas correspondientes al motor.

En los siguientes LINKS se pueden bajar los esquemas en EAGLE para que los modifiquen, los integren y realicen su circuito impreso.

Fuente de poder - Input AC: PowerSupply-DC.sch

Fuente de poder - Input DC: PowerSupply.sch

Esquema Parte Lógica: PWM.sch

Esquema Parte de Potencia del Motor: PuenteH.SCH

y aquí van los circuitos (discúlpenme si quedaron algo grandes):

Si disponen de un transformador DC (corriente contínua) de 12 voltios pueden utilizar la siguiente FUENTE DE PODER:






Si en cambio poseen un transformador de 12 voltios AC (corriente alterna), la pueden diseñar así:






El Circuito Lógico, que comprende el PIC y la comunicación, es el siguiente:






*En el circuito anterior, el PIN  5 del PIC debe ir a tierra y el PIN 14 a Vcc (5 voltios). OJO: No aparecen en el esquema.*

Y para controlar el motor, pueden usar algo como esto:






Ahora bien, lo único que falta para terminar el proyecto es construirnos un cable serial pin a pin para conectarlo al computador y escribir nuestro software de control. Para esto pueden utilizar este esquema:






Bueno amigos “Foristas” creo que esto concluye el mini tutorial de PWM y de todo un poco en realidad, pues hemos podido abarcar desde la teoría hasta la práctica, pasando por la lógica, la diagramación, el desarrollo y la construcción de nuestro proyecto, así es que también hemos podido ver una forma de diseño. Como escribí aquí en más de una oportunidad, mucho se puede hacer para mejorar este trabajo y es lo que deseo que hagamos todos. Espero que se animen a estudiar este y a escribir otros tutoriales, yo por mi parte los estaré esperando.

Saludos y hasta la próxima,

Marcelo.


----------

