desktop

Problema con cambio de giro en motor DC con PIC16F887

Hola a todos. Verán, me han pedido el siguiente circuito con las siguientes características:

El circuito debe de permitir el control de un motor de CD para poder girar en los dos sentidos, debe contar con tres botones de pulsación: el 1º para poder girar a la derecha, el 2º giro a la izquierda y el 3º paro.
Restricciones: una vez que se encuentre girando en algún sentido, no podrá cambiar su sentido, a menos que ya se haya realizado el paro. Es necesaria etapa de potencia.

Ya he realizado el código en ensamblador:

PHP:
LIST        P=16F887
 #INCLUDE    <P16F887.inc>

; __config 0x3FF7
 __CONFIG _CONFIG1, _FOSC_EXTRC_CLKOUT & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_ON & _IESO_ON & _FCMEN_ON & _LVP_ON
; CONFIG2
; __config 0x3FFF
 __CONFIG _CONFIG2, _BOR4V_BOR40V & _WRT_OFF


;*******************************************************************************
 ORG      0x00
 
            BANKSEL    PORTB
     CLRF       PORTB
     BANKSEL    ANSEL
     CLRF       ANSEL
     BANKSEL    PORTD
     CLRF       PORTD
     BANKSEL    ANSEL
     CLRF       ANSEL
     BCF        STATUS,RP1
     BANKSEL    TRISD
     MOVLW      B'11111111'
     MOVWF      TRISD
     BANKSEL    TRISB
     MOVLW      B'00000000'
     MOVWF      TRISB
     BCF        STATUS,RP1
     
GP
     
     BTFSC PORTD,0
     GOTO GIROD
     BTFSC PORTD,1
     GOTO GIROI
     GOTO GP
PARO
     
     CLRF PORTB
     GOTO GP
          
GIROD
     
     BTFSC PORTD,2
     GOTO PARO
     MOVLW B'00000001'
     MOVWF PORTB
     GOTO GIROD
     
GIROI 
     
     BTFSC PORTD,2
     GOTO PARO
     MOVLW B'00000010'
     MOVWF PORTB
     GOTO GIROI
     
 END
Pero a la hora de cargarlo en el PIC, éste no hace ninguna acción, no sé si hay errores en mi código y si alguno de ustedes pueda ayudarme a corregirlo.

Gracias por su atención.

P.D. : En la etapa de potencia tengo un L293D.
 
Última edición por un moderador:
Creo que el error está en la instrucción que te marco en rojo, deberia ser BSF en realidad. Pero además la palabra de configuración no me gusta, la fuente de reloj es una generada en forma externa? o es con un cristal? "_FOSC_EXTRC_CLKOUT", porque está configurada cualquier otra cosa. También veo que está habilitado el Master Clear "_MCLRE_ON", el cual si no lo trabajas adecuadamente al pin te resetea constantemente el PIC, si no lo estas usando te recomiendo deshabilitarlo. Verifica esas cosas.
Código:
LIST        P=16F887
 #INCLUDE    <P16F887.inc>
 
; __config 0x3FF7
 __CONFIG _CONFIG1, _FOSC_EXTRC_CLKOUT & _WDTE_OFF &  _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF  & _BOREN_ON & _IESO_ON & _FCMEN_ON &  _LVP_ON
; CONFIG2
; __config 0x3FFF
 __CONFIG _CONFIG2, _BOR4V_BOR40V & _WRT_OFF
 
 
;*************************************************  ******************************
 ORG      0x00
 
            BANKSEL    PORTB
     CLRF       PORTB
     BANKSEL    ANSEL
     CLRF       ANSEL
     BANKSEL    PORTD
     CLRF       PORTD
     BANKSEL    ANSEL
     CLRF       ANSEL
     [COLOR=Red]BCF[/COLOR]        STATUS,RP1
     BANKSEL    TRISD
     MOVLW      B\'11111111\'
     MOVWF      TRISD
     BANKSEL    TRISB
     MOVLW      B\'00000000\'
     MOVWF      TRISB
     BCF        STATUS,RP1
 
GP
 
     BTFSC PORTD,0;
     GOTO GIROD;
     BTFSC PORTD,1;
     GOTO GIROI;
     GOTO GP;
PARO
 
     CLRF PORTB;
     GOTO GP
 
GIROD
 
     BTFSC PORTD,2;
     GOTO PARO;
     MOVLW B\'00000001\';
     MOVWF PORTB;
     GOTO GIROD;
 
GIROI 
 
     BTFSC PORTD,2;
     GOTO PARO;
     MOVLW B\'00000010\';
     MOVWF PORTB;
     GOTO GIROI;
 
 END
 
Hola, muchas gracias por responder. El reloj no lo estoy usando puesto que sólo se trata de detener y cambiar el giro del motor o al menos eso es lo que creo. Y para el registro "STATUS,RP1" vi en el data sheet, que solo para cambiar el puerto A a digital; ahora estoy probando con los puertos A y B, e intentaré deshabilitar el master clear como sugiere y le comento si funcionó.
 
Me parece que a ambos les hace falta estudiar mejor la hoja de datos.
El registro STATUS es el encargado del cambio de bancos, usando los bits 7 (IRP = Direccionamiento indirecto), 6 y 5 (RP0, RP1 = Direccionamento directo)
Este registro no tiene nada que ver con la configuración del conversor AD.
Y cuando se usa la instrucción "BANKSEL" (Selección de Banco), el uso de ese registro resulta redundante dentro del código.

Los registros involucrados en la configuración del conversor AD, son los registros ANSEL y ANSELH que se encuentran en el mismo banco. (Bank 3)
Y ésto es únicamente cuando no se usará el conversor AD.
De otra forma, también se tienen que configurar los registros ADCON0 y ADCON1

Deshabiltar el uso del pin Master Clear, hace que ese pin se convierta en entrada únicamente.
Esta opción es importante, ya que a muchos se les olvida conectar ese pin a VCC y por defecto es activo (RESET) si no se declara como OFF en la palabra de configuración.

Cuando tengas problemas sobre la ejecución de tu programa, entra en modo de depuración y podrás ver lo que hace.
Y si tienes un programador con modo ICD, podrás ejecutar y depurar tu programa en tiempo real físicamente.

A simple vista, parece que tienes un problema de estructura en tu programa, que generará un bucle mal orientado.

---------- Actualizado ----------

PD:
Al usar el oscilador interno, se tiene que configurar el registro OSCCON.
En éste PIC (PIC16F887) la frecuencia de operación por defecto, es de 4 MHz.
 
Última edición:
Mala mia. Respondi sin siquiera tener la intension de ver el datasheet, fue algo rapidito. Como bien dice Dark, haces uso redundante de la selccion de bancos. Pero me parece que el mayor problema viene por la configuracion de la palabra.
 
El uso de los bancos ya me quedó claro junto con el registro ANSEL y ANSELH, pero si en el deupurador de MPLAB realiza bien la simulación, es decir, los giros, paro, todo entonces el problema radica en la configuración inicial? Y el oscilador importa si no lo uso?

P.D. :Gracias por la aclaración de los bacos.
 
Última edición:
¿Y el oscilador importa si no lo uso?
Siempre tienes que usar un oscilador, pero tienes que determinar de qué tipo.
Si seleccionas usar el interno, por defecto se ejecutará a 4 MHz. (PIC16F887)
Si requieres que funcione a otra frecuencia, por ejemplo; a 8 MHz, entonces tendrás que configurar el registro OSCCON.
 
Hey amigos, no había podido comentar, cambié mi código siguiendo sus recomendaciones, pero el error que tenía eran las resistencias ahora las tengo en pull down y ya funciona correctamente, gracias por su tiempo.
 
Hola a toda la comunidad.
Espero que me puedan ayudar a solucionar mi problema el cual les explico a continuación.
Tengo que hacer un programa en C para controlar un motor DC con 2 botones.
El primer botón al momento de presionarlo, tiene que hacer que el motor gire 8 segundos hacia la derecha, luego que se detenga 1 segundo y por último 4 segundos a la izquierda y el segundo botón, tiene que parar el motor en cualquier segundo en el que vaya el motor.
Ya hice lo del primer botón con un WHILE para que me esté repitiendo la secuencia y un FOR para que me lleve el conteo de los segundos.
Mi problema es que no puedo hacer el botón de PARO, no sé cómo romper el ciclo WHILE para que se pare el motor.
Espero que me puedan ayudar.

Les dejo mi programa:
C:
#include <16F877A.H>

#fuses XT, NOWDT

#use delay (clock= 4 MHz)

#include <LCD_C.c>

#use standard_io(B)

void main (){

port_b_pullups(TRUE);

lcd_init();

output_low(PIN_B3);

output_low(PIN_B4);

printf(lcd_putc,"\fApagado");

int16 a= 8, b= 4, c=1;

int8 i= 0;

while (TRUE){

if (input(PIN_B0)==0){

while (TRUE){

for(i=1;i<=a;i++){

output_low(PIN_B4);

output_high(PIN_B3);

printf(lcd_putc,"\fGirandoDERECHA");

printf(lcd_putc,"\nTiempo = %u",i);

delay_ms(1000);

}

for(i=1;i<=c;i++){

output_low(PIN_B4);

output_low(PIN_B3);

printf(lcd_putc,"\fDetenido");

printf(lcd_putc,"\nTiempo = %u",i);

delay_ms(1000);

}

for(i=1;i<=b;i++){

output_high(PIN_B4);

output_low(PIN_B3);

printf(lcd_putc,"\fGirandoIZQUIERDA");

printf(lcd_putc,"\nTiempo = %u",i);

delay_ms(1000);

}

for(i=1;i<=c;i++){

output_low(PIN_B4);

output_low(PIN_B3);

printf(lcd_putc,"\fDetenido");

printf(lcd_putc,"\nTiempo = %u",i);

delay_ms(1000);

}

}

}

if(input(PIN_B1==0)){

output_low(PIN_B4);

output_low(PIN_B3);

printf(lcd_putc,"\fPARO");

break;

}

}

}
 
¿Y el esquema o simulación?

Con tantos retardos en los bucles, se tendrá que esperar a que finalicen para poder actuar a cualquier otro evento.
Lo ideal sería usar una interrupción externa o aumentar los ciclos del bucle y reducir el retardo a 1 mS, usar un contador y dentro del bucle verificar otras cosas.
 
1550970296706.png
Esa es la simulación. Se supone que puse los retardos para que me vaya contando de uno en uno hasta que llegue a los 8 segundos que tiene que durar el motor girando. Mi duda es, donde meto el codigo para que al momento de apretar el boton de paro (PIN_B1) pues se pare el motor. Tambien puse los contadores para cada secuencia con los FOR (8 y 4 segundos). Pero ya no se que sigue xd
 
.... Soy malo explicando.. Te lo pueden asegurar por aquí.. Tu quita el pause y crea un reloj.. Creo que después jugando se te ocurrirá solo y de varias maneras.
 
No me gusta tanto delay , los delay no sirven más que para atorar el micro y dejarlo inútil el tiempo declarado.

Lo mejor que puedes usar es un timer.
Declaras un timer digamos a 1ms.
Y cuando llegue a 1000 ms es un segundo.

Ejemplo.

Timer 1ms
{
Contador1++
Contador2++
}

Void Main()
{
.......

If (contador1>= 1000)
{
Contador1=0
Tarea....
}

Ejecuta una tarea cada 1 segundo

If (contador2>= 4000)
{
Contador2=0
Tarea2....
}

Cada 4 segundos hace otra tarea

La idea de hacer esto es tratar de evitar hacer uso de los delays y en lugar de hacer un código monotarea a multitarea
 
Si la situación es de poca monta como este caso y sobre todo para quién esta aprendiendo los delay yo diría que son necesarios, pero no por eso hay que abusar ni de ellos ni de nada.
Digo esto, porque es evidente que esta principando, hacer eso no es difícil y si no le sale el bucle para que complicarlo?
Como digo siempre, hay muchos que saben programación, pero enseñar de manera gradual es otra historia
Cuando aprenda a manejar los bucles y demás, luego de ello que aprenda a mejorar y hacer más eficiente el código.
Hablar de multitarea cuando no la hay tampoco tiene sentido.
Hay situaciones y situaciones
Es lo mismo que cuando aprendieron a utilizar la regla de tres simple y compuesta, a más de uno le fue un dolor de cabeza
Pero cuando aprendimos proporciones, todo era más sencillo...
No se puede aprender a multiplicar si no se sabe sumar, no se puede aprender a dividir si no se sabe restar y asi...........

Dentro del lazo del contador agregar la condición de parada, es decir para que siga no debe haber alcanzado la cota y no debe estar la condición de stop
 
Bueno si.
Estoy de acuerdo pero hay que saber programar bien C antes de meterse con los micros.
Yo sabía programación en C me gustaba llegue hacer jueguitos en turbo C. Incluso llegue a programar un compilador basado en C para programar en ASM el pic16, basado en un analizador léxico y sintáctico.

Fue cuando Vi un libro sistemas embebidos en C fue cuando brinque a los micros .

Si sabes C solo con leer la hija de datos del micro puedes hacer muchas cosas.

Recomiendo que no es necesario aprender C para micros ayuda mucho más C para computadora es lo mismo y aprendes más
 
Atrás
Arriba