Problema de código en C para motor DC con PWM y PIC

Hola a todos, un cordial saludo, bueno me surgió un problema al momento de poner el PWM en mi código. Estoy implementando el control de un motor DC con PWM el cual tiene 6 pulsadores (arranque, paro, sentido de giro y velocidad) pero al momento de poner el PWM no responde ningún pulsador y siendo sincero no soy muy bueno programando y pues espero alguien me pueda hacer saber mi error. Aquí esta el código y la simulación de como lo estoy conectando:

Código:
#include <16F877A.h>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, NOPUT,
#use delay(clock = 4000000)

void main()
{

   output_low(PIN_C2);
   setup_ccp1(CCP_PWM);
   setup_timer_2(T2_DIV_BY_16, 124, 1);
   set_pwm1_duty(0);
   delay_ms(1000);
   
   long ciclo=0;


while(1){
         if(input(PIN_A0)){          
         ciclo++;
         delay_ms(10);
         if(ciclo>254)           
            ciclo=255;            
         }
         if(input(PIN_A1)){
         if(ciclo>0){
         ciclo--;
         delay_ms(10);
         
         }
         
set_pwm1_duty(ciclo);
delay_ms(10);
}
    set_tris_A(0b111111); 
   set_tris_B(0b00000000);
   output_B(0b00000000);
                  
{

input_A();
 if ((input(pin_A2)==1) ){
    x=1;
 }
 if ((input(pin_A3)==1) & (x==1 || x==3)){
    x=2;
 }
 if ((input(pin_A4)==1) & (x==2) ){
    x=3;
 }
 if ((input(pin_A5)==1) ){
    x=4; 
 }
if(x==1){
       output_high(PIN_B2);
        output_low(PIN_B3);       // enciende el motor y gira a la derecha
}
if(x==2){
          output_high(PIN_B3);
          output_low(PIN_B2) ;      // gira hacia la izquierda 
          
}
if(x==3){
          output_high(PIN_B2);
          output_low(PIN_B3);      //GIRA HACIA LA DERECHA         
}

if(x==4){
          output_low(PIN_B2);  
          output_low(PIN_B3);       //paro
        x=0;
}
}
}
}
 

Adjuntos

  • Motor dc con pwm.rar
    18.4 KB · Visitas: 70
Última edición por un moderador:
He modificado el código de la siguiente manera, ya funciona el arranque (ra0), paro (ra3),
y sentido de giro (ra1 y ra2) pero la velocidad lo que es el pwm no funciona (ra4 y ra5),
y no encuentro el error en ello.

Código:
Código:
#include <16F877A.h>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, NOPUT,
#use delay(clock = 4000000)

int x=0;

void main()
{
 set_tris_A(0b111111); 
   set_tris_B(0b000000);
   output_B(0b00000000);

while (1){

input_A();
 if ((input(pin_A0)==1) ){
    x=1;
 }
 if ((input(pin_A1)==1) & (x==1 || x==3)){
    x=2;
 }
 if ((input(pin_A2)==1) & (x==2) ){
    x=3;
 }
 if ((input(pin_A3)==1) ){
    x=4; 
 }
if(x==1){
       output_high(PIN_B2);
        output_low(PIN_B3);       // enciende el motor y gira a la derecha
}
if(x==2){
          output_high(PIN_B3);
          output_low(PIN_B2) ;      // gira hacia la izquierda 
          
}
if(x==3){
          output_high(PIN_B2);
          output_low(PIN_B3);      //GIRA HACIA LA DERECHA         
}

if(x==4){
          output_low(PIN_B2);  
          output_low(PIN_B3);       //paro
        x=0;
       
}
}
{
output_low(PIN_C2);
   setup_ccp1(CCP_PWM);
   setup_timer_2(T2_DIV_BY_16, 124, 1);
   set_pwm1_duty(0);
   delay_ms(1000);
   
   long ciclo=0;
{
         if(input(PIN_a4)){          
         ciclo++;
         delay_ms(10);
         if(ciclo>254)           
            ciclo=255;            
         }
         if(input(PIN_a5)){
         if(ciclo>0){
         ciclo--;
         delay_ms(10);
         }
         }
         }
                  
set_pwm1_duty(ciclo);
delay_ms(10);
         }
}
 
Última edición por un moderador:
Es que esta parte del código deberías ponerla fuera del "while"
Código:
output_low(PIN_C2);
   setup_ccp1(CCP_PWM);
   setup_timer_2(T2_DIV_BY_16, 124, 1);
   set_pwm1_duty(0);
   delay_ms(1000);

Esta es la configuracion del PWM y poner el duty a (0), y más abajo cargas el valor del ciclo, pero cada vez que hace el "while" configuras de nuevo el PWM y pones el ciclo a 0.
No se si me he explicado bien.
Saludos
 
Primero te recomendaría ordenar el código.
Por otro lado te adjunto el mismo con modificaciones.

La funcion setup_ccp1(CCP_PWM) se ejecuta una vez ya que configura el PIN para usarlo como PWM, una vez configurado no necesita una "reconfiguración".

¿Para que usas este TIMER? setup_timer_2(T2_DIV_BY_16, 124, 1);
Por lo menos en el código no veo su función así que lo deje comentado.

Prueba si te funciona.
Código:
#include <16F877A.h>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, NOPUT,
#use delay(clock = 4000000)

void main()
{
	int x=0;
	long ciclo=0;
	set_tris_A(0b111111); 
	set_tris_B(0b000000);
	output_B(0b00000000);
	
	output_low(PIN_C2);
	setup_ccp1(CCP_PWM);
	//setup_timer_2(T2_DIV_BY_16, 124, 1);
	set_pwm1_duty(0);
	delay_ms(1000);

	while (1) {

		input_A();
		if (input(pin_A0) == 1)
			x=1;
		if ((input(pin_A1)==1) & (x==1 || x==3))
			x=2;
		if ((input(pin_A2)==1) & (x==2))
			x=3;
		if (input(pin_A3) == 1)
			x=4;

		if(x == 1) {
			output_high(PIN_B2);
			output_low(PIN_B3);       // enciende el motor y gira a la derecha
		}
		if(x == 2) {
			output_high(PIN_B3);
			output_low(PIN_B2) ;      // gira hacia la izquierda 
		}
		if(x == 3) {
			output_high(PIN_B2);
			output_low(PIN_B3);      //GIRA HACIA LA DERECHA         
		}

		if(x==4){
			output_low(PIN_B2);  
			output_low(PIN_B3);       //paro
			x=0;
		}
		if(input(PIN_A4)) {          
			if(ciclo < 255)
				ciclo++;
			set_pwm1_duty(ciclo);
			delay_ms(10);
		}
		if(input(PIN_A5)) {
			if(ciclo > 0)
				ciclo--;
			set_pwm1_duty(ciclo);
			delay_ms(10);
		}
}
 
Es que esta parte del código deberías ponerla fuera del "while"
Código:
output_low(PIN_C2);
   setup_ccp1(CCP_PWM);
   setup_timer_2(T2_DIV_BY_16, 124, 1);
   set_pwm1_duty(0);
   delay_ms(1000);

Esta es la configuracion del PWM y poner el duty a (0), y más abajo cargas el valor del ciclo, pero cada vez que hace el "while" configuras de nuevo el PWM y pones el ciclo a 0.
No se si me he explicado bien.
Saludos

Si te explicas bien, muchas gracias tienes razón, no había pensado en eso :D Pero tengo una duda: Al momento de iniciar el programa el pulsador de arranque no funciona hasta que presiono el amento de velocidad, aquí adjunto la simulación...



Primero te recomendaría ordenar el código.
Por otro lado te adjunto el mismo con modificaciones.

La funcion setup_ccp1(CCP_PWM) se ejecuta una vez ya que configura el PIN para usarlo como PWM, una vez configurado no necesita una "reconfiguración".

¿Para que usas este TIMER? setup_timer_2(T2_DIV_BY_16, 124, 1);
Por lo menos en el código no veo su función así que lo deje comentado.

Prueba si te funciona.
Código:
#include <16F877A.h>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, NOPUT,
#use delay(clock = 4000000)

void main()
{
	int x=0;
	long ciclo=0;
	set_tris_A(0b111111); 
	set_tris_B(0b000000);
	output_B(0b00000000);
	
	output_low(PIN_C2);
	setup_ccp1(CCP_PWM);
	//setup_timer_2(T2_DIV_BY_16, 124, 1);
	set_pwm1_duty(0);
	delay_ms(1000);

	while (1) {

		input_A();
		if (input(pin_A0) == 1)
			x=1;
		if ((input(pin_A1)==1) & (x==1 || x==3))
			x=2;
		if ((input(pin_A2)==1) & (x==2))
			x=3;
		if (input(pin_A3) == 1)
			x=4;

		if(x == 1) {
			output_high(PIN_B2);
			output_low(PIN_B3);       // enciende el motor y gira a la derecha
		}
		if(x == 2) {
			output_high(PIN_B3);
			output_low(PIN_B2) ;      // gira hacia la izquierda 
		}
		if(x == 3) {
			output_high(PIN_B2);
			output_low(PIN_B3);      //GIRA HACIA LA DERECHA         
		}

		if(x==4){
			output_low(PIN_B2);  
			output_low(PIN_B3);       //paro
			x=0;
		}
		if(input(PIN_A4)) {          
			if(ciclo < 255)
				ciclo++;
			set_pwm1_duty(ciclo);
			delay_ms(10);
		}
		if(input(PIN_A5)) {
			if(ciclo > 0)
				ciclo--;
			set_pwm1_duty(ciclo);
			delay_ms(10);
		}
}

Si, la configuración del PWM debe ir fuera del while para que quede establecido.

Y como le comentaba a rachelies el pulsador de arranque no funciona hasta que se presiona el de aumento de velocidad. Le adjunte la simulación por si gustas verla.

El setup_timer_2(T2_DIV_BY_16, 124, 1); son las configuraciones de los valores que tendrá el timer, explico:

setup_timer_2(modo, periodo, postcaler);
esta función inicializa el timer2;

Modo: especifica el divisor del reloj del oscilador.

Periodo: es un número comprendido entre 0-255, y determina el momento en el que el valor del
reloj se resetea a 0.

Postscale es un número de 0 a 15, que determina cuántos reset del
timer se han producido antes de una interrupción. 0 significa 1 reset, 1 significa 2 reset,
y así sucesivamente.

Saludos.
 

Adjuntos

  • Motor DC con PWM (3).rar
    37 KB · Visitas: 294
Última edición:
Otra cosa que se me habia olvidado el otro día. Cuando compruebas el estado de una entrada, tienes que tener en cuenta los rebotes del pulsador y poner un retardo tras la pulsacion para evitar estos rebotes, y además comprobar que has soltado el pulsador, porque si no, con pulsar una vez el programa, con la velocidad con que se ejecuta, lo verá pulsado muchas veces y te llegará a 0 o 255 el ciclo con pulsar una sola vez.
 
Y como le comentaba a rachelies el pulsador de arranque no funciona hasta que se presiona el de aumento de velocidad. Le adjunte la simulación por si gustas verla.

No arranca porque al principio de todo se llama a la función set_pwm1_duty(0), la cual hace que el PWM no funcione o sea cero el período.
Podrías modificarlo así:
long ciclo=10;
.
.
.
set_pwm1_duty(ciclo);


Y de esa manera el valor inicial de ciclo, define la velocidad inicial.

El setup_timer_2(T2_DIV_BY_16, 124, 1); son las configuraciones de los valores que tendrá el timer, explico:

setup_timer_2(modo, periodo, postcaler);
esta función inicializa el timer2;

Modo: especifica el divisor del reloj del oscilador.

Periodo: es un número comprendido entre 0-255, y determina el momento en el que el valor del
reloj se resetea a 0.

Postscale es un número de 0 a 15, que determina cuántos reset del
timer se han producido antes de una interrupción. 0 significa 1 reset, 1 significa 2 reset,
y así sucesivamente.

Saludos.

La pregunta que te hacía era:
¿Para que lo seteas el TIMER si no tiene ninguna función en este código?
No hay ninguna rutina de atención del TIMER.
 
Hola. Quiero hacer las siguientes preguntas que no termino de entender.

He hecho un control y utilizo un teclado al cual a cada tecla le he asignado una función.
Pues bien, a la tecla 9 le he asignado que sea 1022 porque si le asigno 1023 y la pulso, luego cuando pulso cualquier otra tecla, se queda parado.

Tengo que decir que esto es con Proteus, no lo he probado en físico.

Mi pregunta es sencilla. ¿Por qué pasa esto?
He intentado hacerlo con switch para que no hayan tantos if y no me aclaro.
Mi otra pregunta es. ¿Cómo he de hacerlo con switch?

Adjunto archivos.

Código:
#include <16f876.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4MHz)
#include <kbd.c>


char k;
long ciclo=0;

void main(){
 
 setup_ccp1(CCP_PWM);
  setup_timer_2(T2_DIV_BY_16,255,1);
  output_c(0x00);
 
  kbd_init();
  port_b_pullups(true);

while(true){

k=kbd_getc();
set_pwm1_duty(ciclo);

 

 if (k=='*')
      {ciclo+=20;}
   
  else if(k=='#')
     {ciclo+=100;}             
     
  else if(k=='0')
     {ciclo=0;}     

  else if(k=='1')  
    {ciclo=80;}
 
  else if(k=='2')
    {ciclo=160;}
 
  else if(k=='3') 
    {ciclo=225;}
    
  else if(k=='4')
    {ciclo=356;}
    
  else if(k=='5')
    {ciclo=412;} 
 
  else if(k=='6')
    {ciclo=550;} 
      
  else if(k=='7')
    {ciclo=680;} 
      
  else if(k=='8')
    {ciclo=850;} 
      
  else if(k=='9')
    {ciclo=1022;} 
         
   }
 }
 

Adjuntos

  • Motor controlado PWM.doc
    28 KB · Visitas: 20
Última edición por un moderador:
Los parámetros de configuración del Timer 2, no son correctos.
Para una frecuencia del oscilador de 4 MHz. la frecuencia PWM es de 245 Hz. como mínimo.
Entonces los parámetros deberían ser así: setup_timer_2(T2_DIV_BY_16,254,1);
Y con esa configuración, el valor máximo del ciclo activo para set_pwm1_duty() al 100 % es 255.

Entonces... ¿Cómo es que se te ocurre que puedes usar 1022 para establecer el ciclo activo?
 
Última edición:
Los parámetros de configuración del Timer 2, no son correctos.
Para una frecuencia del oscilador de 4 MHz. la frecuencia PWM es de 245 Hz. como mínimo.
Entonces los parámetros deberían ser así: setup_timer_2(T2_DIV_BY_16,254,1);
Y con esa configuración, el valor máximo del ciclo activo para set_pwm1_duty() al 100 % es 255.

Entonces... ¿Cómo es qué se te ocurre que puedes usar 1022 para establecer el ciclo activo?

Gracias D@rbytes por responder, sobre lo del timer2 lo habia sacado de informaciones por hay por lo que no me habia parado en hacer el calculo.

Sobre lo de usar 1022 en vez de 1023, se me ocurrio al azar, pero por que estaba con la iea del ADC10 y lo mezcle todo.
 
OK. Pero no dejas nada en claro.
¿Cambiarás los valores? ¿Corregirás los parámetros del Timer 2? ¿Realizarás pruebas físicamente?

Recuerda que al trabajar con señales PWM en ISIS, lo debes hacer con el osciloscopio y que el diseño tenga únicamente los componentes para poder simular las señales, ésto es para reducir la sobrecarga de la simulación.
 
OK. Pero no dejas nada en claro.
¿Cambiarás los valores? ¿Corregirás los parámetros del Timer 2? ¿Realizarás pruebas físicamente?

Siii, voy a cambiar los parametros del timer, de hecho ya los he cambiado e hize los calculos, cosa que se me sigue atragantando un poco pero ya lo voy entendiendo, y ahora va como yo tenia pensado.

Claro que realizare las pruebas fisicas y si me aclaro en subirlo pues subire un mini-video.

Gracias por estar hay D@rkbytes.
 
Hola. Muy buenos días, tardes, noches. Soy nuevo en el foro y nuevo en esto de programar PIC y quisiera saber si me ayudarían con mi problema, el cual es el siguiente.

Necesito controlar la velocidad de un motor de DC de 5V con un PIC16F887
Sé que tiene sus terminales para esto, pero necesito hacerlo por cualquier otra terminal, menos la que es para el PWM.
Sí logro encenderlo y todo eso, pero no logro cómo hacer que entre en la otra función del if para controlar su otra velocidad con el código que adjunto a continuación.
PHP:
#include <16f887.h>
#fuses intrc_io, nowdt, noprotect, nolvp
#use delay(clock=8M)
int x=2;
void main()
{
while (true)
{
if (input(pin_a0)==1)
{
while(x>1)
{
output_high(pin_b0);
delay_ms(500);
output_low(pin_b0);
delay_ms(500);
}
}

if (input(pin_a0)==2)
{
while(x>1)
{
output_high(pin_b0);
delay_ms(30);
output_low(pin_b0);
delay_ms(30);
}
}
}
}
Ya lo he intentado de muchas maneras, pero la verdad ya no sé qué hacer.
Espero me puedan ayudar. Si necesitan más información, háganmelo saber para que me pueda sacar esta duda, se los agradecería infinítamente.

De antemano, muchas gracias y que tengan un excelente día.
 
Última edición por un moderador:
Esa es la peor manera de generar PWM por software.
El compilador PIC C tiene instrucciones para hacerlo por software y con salida en otros pines.

Ahora mira lo siguiente:
Si la variable x tiene establecido el valor 2 y luego entras a un bucle comparando si (x>1), nunca saldrá.
Y no puedes comparar que un pin pueda tener el valor 2
Cada puerto tiene 8 bits que en total es un Byte, y cada pin equivale a un bit.
Entonces no puedes hacer: if(input(PIN_A0)==2) porque RA0 nunca tendrá ese valor.
Cada bit únicamente puede contener un 1 o un 0, pero nunca un 2.

Puedes comparar los estados de esta forma:
// Cuando se espere un 1
if(input(PIN_A0)==1)
O así:
if(input(PIN_A0))

// Cuando se espere un 0
if(input(PIN_A0)==0)
O así, utilizando el operador de negación "!":
if(!input(PIN_A0))

Y recuerda que si usas retardos, tendrás que esperar la respuesta del pulsador hasta que se cumplan.
Por eso no son recomendables, ya que detienen la ejecución de los demás procesos.
 
Última edición:
gracias por tu respuesta D@rkbytes la verdad desconocía que en pic c hubiera instrucciones para asarlo no sabes si ay algún lugar o algo donde las pueda ver para darme una idea y me imagine que no podría hacer lo de meter un 2 por una sola entrada del pic, lo malo es que tengo que aserlo con solo 2 entradas del pic y una sola salida cada ves que presione un botón en este caso A0 aumenta su velocidad y cuando presionara A1 disminuyera su velocidad aun no agregaba las funciones al código para disminuir su velocidad por que trataba de realizar primero el aumento y ya de ay aplicaba lo mismo pero a la inversa para el otro botón y disminuir su velocidad igual si pudieras orientarme o ayudarme con alga si te lo agradecería mucho de antemano muchas gracias por tu atención y que tengas un buen día.
 
Atrás
Arriba