# Modulo PWM y transmicion RS232 con PIC18F4550



## rodalt (Jun 24, 2010)

Este circuito es una practica que nos dejaron en una ocasion en la materia de Microprocesadores y microcontroladores en sexto semestre de la carrera ing. electronica en el ITLM 2010, se las voy a compartir para que armen sus propios proyectos.
Esta practica consta de utilizar el modulo de PWM del PIC18F4550 para variar la velocidad de giro de un motor.
Esto funciona asi: El circuito consta de 3 botones, inicio-paro, incremento y decremento, al activar el boton inicio el ancho del pulso se ira incrementando de tal forma que al llegar los 15 segundos alcanze una velocidad del 50% del giro del motor (los botones incremento y decremento son inutiles hasta que se alcanza esta velocidad), una vez que se alcanzo el 50% de la velocidad podemos incrementar o decrementar la velocidad del motor en un 5%, con velocidad minima del motor del 30% (lo limite con el sofware) y velocidad maxima del 90%, al precionar el boton inicio-paro la velocidad del motor se ira decrementando en saltos (el salto depende del porcentaje de la velocidad en la que se encuentre el motor al momento de precionar inicio-paro) de tal forma que alcanze una velocidad de 0% en 15 segundos, esto que acabo de explicar lo hice con 3 interrupciones externas para los 3 botones y una interrupcion interna configurada como timer a 1 segundo. Tambien necesitabamos medir las revoluciones por minuto del motor esto lo hicimos con un optoacoplador ranurado por donde pasaban las aspas de motor (de ahi conectado al pin b7 del PIC).
La practica tambien necesitaba que estubiesemos sensando la temperatura y que prendieramos un extractor a los 40°C y se apagara al regresar a los 30°C (Histeresis), para la lectura utilizamos el sensor LM35 y el ADC a 10 bits del PIC .
Lo siguiente que hicimos fue mostrar la temperatura las rpm's y el ciclo de trabajo del PWM en respectivo orden en una pantalla LCD 16x2, y de la misma forma transmitirlo a la PC por medio de RS-232(con el circuito integrado MAX232), para leerlo en la PC hice un pragrama en visual basic 6 acoplado con measurement studio para los indicadores (este programa es para que en visual basic puedas tener indicadores como tacometros, termometros, velocimetros, led's, etc).
Para la programacion del pic utilize el programa de CCS: PIC C Compiler (utiliza programacion en C :E ), y utilize el programa Isis de Proteus 7 para la simulacion.
Todo va incluido en el archivo en RAR que esta adjunto en esta pagina.

Nota:
Es mi primer aporte, dejen comentarios, si ahi algun problema para abrir los programas, simulacion y/o cualquier duda pregunten, me gustaria un tema nuevo sobre comunicacion PIC a PIC I2C pues no lo enseñaron y me gustaria aprender.
El programa tiene comentarios "paso a paso".


----------



## fernandoae (Jun 25, 2010)

Esta bueno, felicitaciones


----------



## underwol8443 (Jul 2, 2010)

rodalt dijo:


> Este circuito es una practica que nos dejaron en una ocasion en la materia de Microprocesadores y microcontroladores en sexto semestre de la carrera ing. electronica en el ITLM 2010, se las voy a compartir para que armen sus propios proyectos.
> Esta practica consta de utilizar el modulo de PWM del PIC18F4550 para variar la velocidad de giro de un motor.
> Esto funciona asi: El circuito consta de 3 botones, inicio-paro, incremento y decremento, al activar el boton inicio el ancho del pulso se ira incrementando de tal forma que al llegar los 15 segundos alcanze una velocidad del 50% del giro del motor (los botones incremento y decremento son inutiles hasta que se alcanza esta velocidad), una vez que se alcanzo el 50% de la velocidad podemos incrementar o decrementar la velocidad del motor en un 5%, con velocidad minima del motor del 30% (lo limite con el sofware) y velocidad maxima del 90%, al precionar el boton inicio-paro la velocidad del motor se ira decrementando en saltos (el salto depende del porcentaje de la velocidad en la que se encuentre el motor al momento de precionar inicio-paro) de tal forma que alcanze una velocidad de 0% en 15 segundos, esto que acabo de explicar lo hice con 3 interrupciones externas para los 3 botones y una interrupcion interna configurada como timer a 1 segundo. Tambien necesitabamos medir las revoluciones por minuto del motor esto lo hicimos con un optoacoplador ranurado por donde pasaban las aspas de motor (de ahi conectado al pin b7 del PIC).
> La practica tambien necesitaba que estubiesemos sensando la temperatura y que prendieramos un extractor a los 40°C y se apagara al regresar a los 30°C (Histeresis), para la lectura utilizamos el sensor LM35 y el ADC a 10 bits del PIC .
> ...



hola mui interesante tu proyecto tengo que hacer uno parecido al que tienes solo que con 16f877a
podras acerme el favor de convertirlo al pic 16f877


----------



## letylu (Jul 2, 2010)

Gracias por publicarlo  es de gran ayuda


----------



## underwol8443 (Jul 3, 2010)

hola hasta el momento elogrado hacer que funcione con el pic 16f877 pero faltan detalles  lo puedes chequear  un punto es que cuando decremento baja al 10% y retorna  al 30% quisiera que no retornara a 30% al menos que pulsara el boton de in cremento

el otro punto es para cambiar cuando inicia al 50% a uno de acuerdo ala nececidad del proyecto
el codigo 


```
#include <16F877A.h>
#device adc=10
#use delay(clock=8000000)
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES XT                       //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

int x=0, y=0,z=0,h=0,a1=0,a2=0,ciclo2=0,vent=0;
float read1=0,temp=0,ciclo=0,porc=0,dc2=0;
long dc=0,rev=0,vel=0,pulso=0,pulso2=0;
int1 a=0,b=0,c=0,n=0,cambio=0;
#int_TIMER0
TIMER0_isr()   //timer en cada segundo
{

set_adc_channel(0);  //lectura del convertidor analogo digital
read1=read_adc();



pulso2=pulso*60;   //esto es para sacar las revoluciones por minuto,cada segundo
pulso=0;           //se reinicia para tener una lectura correcta
a=1;           //esta variable es para que en el while infinito mande los datos por    
               //tx cada segundo solamente
if(y==1&&b==0) //este if sirve para el encendido, b es para limitarlo a 15seg y 
{              //si es 1 es encendido
x+=1;          //cada segundo se incrementa en 1

if(x<15)       //al llegar a los 15 segundos el ciclo de trabajo es igual al 50%
{
dc+=34.1;      //dc y dc2 son del mismo valor siempre pero son de diferente tipo de
dc2+=34.1;     //variable, una long y otra float
               //este incremento es para que en el encendido de 15seg se valla incrementando   
               //la velocidad en forma de rampa
}
else
{
dc=511.5;     //en caso de que pasen los 15seg el ciclo de trabajo es igual al 50%  
dc2=511.5;

b=1;          //b es la variable que nos permite salir del ciclo de encendido
}
}

if(c==1)      //esta parte es para el apagado     
{
if(n==0)      
{
porc=dc/15;   //esto es para saber que porcentaje se decrementa cada segundo durante el  
n=1;          //apagado del motor
} 

z+=1;          //z es para contar los 15seg de apagado
dc-=porc;      //es el decremento que hace 
dc2-=porc;

if(z>=15)      //ya que pasaron los 15seg del apagado se reinician todas las variables 
{              //para asi poder volverla a prender en forma de rampa
y=0;
b=0;
z=0;
dc=0;
dc2=0;
ciclo=0;
c=0;
x=0;
porc=0;
n=0;
}
}
}



#int_TIMER1
TIMER1_isr() 
{


}

#int_EXT //interrupcion externa para encendido y apagado
EXT_isr() 
{

y=1;

if(b==1)
y+=1;

if(b==1&&y==2)
{
c=1;
}


}


#define LCD_TYPE 2
#include <lcd.c>
void main()
{
   lcd_init();
   setup_adc_ports(RA0_RA1_RA3_ANALOG);
  setup_adc(ADC_CLOCK_DIV_8);
   //setup_adc_ports(AN0_TO_AN1|VSS_VDD);
   setup_adc(ADC_CLOCK_DIV_8);
   setup_psp(PSP_DISABLED);
   setup_spi(FALSE);
   //setup_wdt(WDT_OFF);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_32);
   setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1);
   setup_timer_2(T2_DIV_BY_16,255,1);
   //setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
   //setup_ccp1(CCP_PWM_FULL_BRIDGE|CCP_SHUTDOWN_AC_L|CCP_SHUTDOWN_BD_L);
   setup_ccp1(ccp_pwm);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   enable_interrupts(INT_TIMER0);
   enable_interrupts(INT_TIMER1);
   enable_interrupts(INT_EXT);
   //enable_interrupts(INT_EXT1);
   //enable_interrupts(INT_EXT2);
   enable_interrupts(GLOBAL);
   //setup_oscillator(OSC_8MHZ|OSC_INTRC|OSC_31250|OSC_PLL_OFF);

   // TODO: USER CODE!!
set_tris_b(0xff);
#use fixed_io(a_outputs=PIN_A2, PIN_A3)    /*para utilizar solo unos pines del 
puerto a como salidas*/

while(1)
{
if(input(pin_b6)&&cambio==0)  //contador de cambios de estados para contar las rpm
{
ciclo2=ciclo;
if(b==1&&y==1)  //solo si ya alcanzo el 50%
{
delay_ms(120);
if(ciclo>10)     //decrementa en 5%
{
dc-=51.15;
dc2-=51.15;
}

if(ciclo2<=10&&b==1&&y==1)  //limite menor del 30%
{
ciclo=10;
dc=306.9;
dc2=306.9;
}

}
}


if(input(pin_b7)&&cambio==0)  //contador de cambios de estados para contar las rpm
{
ciclo2=ciclo;
if(b==1&&y==1) //solo si ya alcanzo el 50% del ciclo de trabajo
 {
delay_ms(120);
if(ciclo<100)
{
dc+=51.15;     //aumenta en 5%  
dc2+=51.15;

}

if(ciclo2>=100&&b==1&&y==1) //limite maximo del ciclo de trabajo
ciclo=100;


 }


}

 if(!input(pin_b7)&&cambio==1)//con la variable cambio se detecta el cambio de estado 
 //y asi sacamos las rpm
{
cambio=0;
}


ciclo=dc2/10.23;    //para saber a cuanto equivale cada 1%
a1=temp;
a2=ciclo;

if(a==1)        //se hace 1 en el timer interno
{
printf("$%i|%lu/%i",a1,pulso2,a2); //manda datos por tx
a=0;                               //la iguala a cero para esperar a que pase un segundo mas
}
vent=temp;        //esto es para encender el ventilador si la temperatura pasa de 40 grados 
if(vent>=40)
output_high(pin_a2);

if(vent<=10)       //histeresis
output_low(pin_a2);


//TEMPERATURA
lcd_gotoxy(1,1);
lcd_putc("T:");

temp=((read1*0.0048875855327468))*100;  //lectura del adc de la temperatura

lcd_gotoxy(3,1);
printf(lcd_putc,"%i \xdfC %lu rpm        \n %i%%    ",a1,pulso2,a2);/*impresion
de temperatura, rpm y ciclo de trabajo*/
//PWM


set_pwm1_duty(dc);  //porciento del ciclo de trabajo



}

}
```


----------



## ricgarzon (Nov 26, 2010)

¿como seria el programa en c para pic 18f4550 un dimmer usando pwm con transmision serial al pc?


----------



## beto3574 (Ene 12, 2011)

hola alguien tiene algun tutorial de como usar el visual measurement studio con visual basic.net o basic 6.0

saludos


----------



## guasakk (Feb 23, 2011)

Gracias por tu aporte


----------



## arturouc (Mar 14, 2011)

beto3574 dijo:


> hola alguien tiene algun tutorial de como usar el visual measurement studio con visual basic.net o basic 6.0
> 
> saludos



Ya le preguntaste a san google?
hay muchos en la red....especificamente que necesitas?
habia un portal que se llamaba lawebdelprogramador ahi aprendi a programar en VB6


----------



## NewFenix (Mar 26, 2011)

Magnifico simplmente. soy de Ing. en Sistemas Computacionales y tengo rato tratando de hacer esto con el pic4550 para controlar luces con el puerto usb y con una salida PWM me parece que es posible. Gracias!!!!


----------



## thafode (Mar 31, 2011)

muxas gracias por el aporte, trataré de ejecutarlo con mi PIC apenas realice el cto.
Gracias


----------



## gabriel_sand (Mar 31, 2011)

Gracias por el aporte


----------



## Rhodwolf (Abr 3, 2011)

orale es justo lo ke buscaba , gracias me servira de mucho para le proyecto que me pidieron de fin de semestre!!!


----------



## andres24 (Abr 17, 2011)

Esta muy bueno, lo estoy mirando, existe la posibilidad de que subas el mismo proyecto pero con comunicacion usb??, y manejado desde labview? es para guiarme, Gracias.


----------



## virgofenix (May 7, 2011)

que ay saludos a todos.....soy nuevo y quiero saber si el PWM que esta en el programa que que publicaron se puede usar para CA


----------



## martincruz (May 29, 2011)

Muy muy interesante proyecto, excelente material. Yo estoy intentando hacer un PWM con un 16F887, mi idea era hacerlo con una resistencia variable y el modulo ADC y así manejar el ancho de pulso... Cualquier cosa buna que salga la voy a publicar. Muchas gracias, tu material aporta mucho


----------



## natalichirinos (Jul 22, 2011)

hola soy estudiante de mecatronica y me intereza la programacion de un motor ac por (pwm) para un proyecto de porton automatico!!! agradezco a quien pueda aportar una pagina o manual que me pueda guiar, ah con pic 16f877


----------



## martincruz (Jul 27, 2011)

Muy buenas a todos. Tengo una duda. El programa que gentilmente comparte rodalt anda de mil maravillas. Ahora yo quiero hacer andar algo muy similar, pero con un 16F887 como ya puse. Llevo varias pruebas, pero lo que me pases es, primero arreglo los fuses para el 887, genial. Pero si dejo el programa tal cual está, sin modificar nada más que los fuses, el compilardor ccs me tira un error en las interrupciones de incremento y decremento del ancho de pulso.... Repito solo tocando los fuses... al no poder hacer andar esto, todavía ni me he puesto a ver si en vez de con dos botones lo hago con una resistencia variable a la modificación del ancho....Cualquier ayuda la agradezco. Saludos

Tengo una pregunta para @underwol8443, lo probaste a tu programa? Porque como el 877 está mucho más cerca del 887, intenté probarlo, pero me tira varios errores al compilarlo, y no me deja hacerlo, yo estoy usando PCWHD ccs para compilar.... Gracias Saludos

Tengo una duda más general: Hago andar el pwm sin problemas poniendole valores de entre 0 y 1023... Pero cuando quiero hacer que lo gobierne al módulo adc, me hace cualquier cosa.... Yo he visto que nadie hace ninguna conversión matemática sobre el tema.... o viendo los ejemplos no me doy cuenta donde está.... he visto ejemplos de otros post y la verdad no la caso, simplemente leen el canal del adc correspondiente y eso lo ponen en el duty cicle del pwm.... alguien me puede ilustrar un poco sobre el tema. Muchas gracias

Pude hacer lo que quería en breve lo subo, tengo que optimizar unas cosas, pero anda lindo.... Saludos


----------



## LuffyX (Nov 16, 2011)

Hola pues muy buen post, pero tengo unas dudas y ojala y puedas responder

El Max232 como es que lo conectas para poderte comunicar y que tipo de motores ocupaste para tu practica ya que por lo que yo sé, se ocupan drivers para asi poder entregar toda la corriente al motor y asi evitar que se te queme el pic


----------



## fernandoae (Nov 16, 2011)

Por que no aprovechan mejor los micros? un 18F4550 y usando puerto serie?
Este micro ya es de la gama alta y soporta USB, porque no lo usan asi?
Acá comparto un video de lo que yo hice:


----------



## galbert (May 2, 2012)

Buenas noches mi pana Fernandoae https://www.forosdeelectronica.com/miembros/11774-fernandoae/ sera que me puede dar informacion de la comunicacion por usb y todo lo relacionado a ese proyecto que muestras.. Gracias


----------

