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



## kurt cobain (Mar 7, 2013)

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: 


```
#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;
}
}
}
}
```


----------



## rachelies (Mar 8, 2013)

Por lo que veo se queda siempre en el primer "while(1)" ¿cómo lo sacas de ahi?


----------



## kurt cobain (Mar 8, 2013)

rachelies dijo:


> Por lo que veo se queda siempre en el primer "while(1)" ¿cómo lo sacas de ahi?



Ahh ese fue un error mio al poner el código pero ignora ese "while (1)" de echo creo que debe de tener un Do-while, o me equivoco?


----------



## kurt cobain (Mar 11, 2013)

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:

```
#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);
         }
}
```


----------



## rachelies (Mar 12, 2013)

Es que esta parte del código deberías ponerla fuera del "while"

```
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


----------



## agustinzzz (Mar 12, 2013)

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.

```
#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);
		}
}
```


----------



## kurt cobain (Mar 13, 2013)

rachelies dijo:


> Es que esta parte del código deberías ponerla fuera del "while"
> 
> ```
> output_low(PIN_C2);
> ...



Si te explicas bien, muchas gracias tienes razón, no había pensado en eso  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...





agustinzzz dijo:


> 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".
> ...



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.


----------



## rachelies (Mar 13, 2013)

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.


----------



## agustinzzz (Mar 13, 2013)

kurt cobain dijo:


> 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.



kurt cobain dijo:


> 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;
> ...



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.


----------



## rachelies (Mar 14, 2013)

El timer se usa para que el pwm sepa que ancho de pulso tiene que generar ¿o me equivoco?


----------



## agustinzzz (Mar 14, 2013)

rachelies dijo:


> El timer se usa para que el pwm sepa que ancho de pulso tiene que generar ¿o me equivoco?



Pero en ningún momento toma la lectura del TIMER o el mismo dispara alguna interrupción.


----------



## rachelies (Mar 16, 2013)

El mismo lo hace todo. Si lees el manual de ccs te le explica bien


----------



## miglo (Jun 7, 2015)

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.


```
#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;} 
         
   }
 }
```


----------



## D@rkbytes (Jun 7, 2015)

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?


----------



## miglo (Jun 8, 2015)

D@rkbytes dijo:


> 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.
> ...



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.


----------



## D@rkbytes (Jun 9, 2015)

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.


----------



## miglo (Jun 9, 2015)

D@rkbytes dijo:


> 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.


----------



## Eckor (Mar 26, 2016)

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.

```
#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.


----------



## D@rkbytes (Mar 26, 2016)

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.


----------



## Eckor (Mar 26, 2016)

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.


----------



## D@rkbytes (Mar 26, 2016)

Saludos.

Aquí en el Foro hay varios programas que te pueden servir, es cosa de buscar un poco.
También tienes el documento de ayuda del compilador.
Ahí es más fácil que encuentres explicación a tus dudas y también tiene referencia a los ejemplos.
Los ejemplos se encuentran en la carpeta "Examples" en el directorio de instalación.


----------



## yorsk2004 (Mar 26, 2016)

Eckor: Si necesitas hacer PWM por software, es decir sin usar pines dedicados a ello (CCP), lo mejor es hacerlo por interrupciones de un Timer. Tal como me enseño D@rkbytes y TRILO-BYTE en el siguiente hilo https://www.forosdeelectronica.com/f24/pic12f675-entrada-analogica-pwm-141235


----------

