Pasar de ASM a C este programa controla motor

Hola:

router-zyxel-850073.png


Partiendo de este esquema, es un PIC16F84A escrito en ensamblador y quiero pasarlo a C, sea con el CCS o el XC8. Para ser sencillo a simple vista, me he comido la cabeza en 5 días para acabarlo proque partes del asm se me había olvidado y tuve que practicar y pedir ayuda al foro. Gracias colaboradores. :apreton:.

No estoy familiarizado en C ssobre microcontroladores y debo aprenderlo con tutoriales, en mi caso quiero saber su equivalencia, y el que quiera puede ayudar adaptar el código asm a C. No tienes que saber asm pàra pasarlo a C, simplemente explico el circuito, a lo mejor lo saca más rápido que asm.

Se trata de un microcontrolador PIC16F84A que tiene 5 pulsadores en el cual al pulsarlo se activa un temporizado fijo. Un motor DC de 12V de salida, siempre funciona en la misma dirección.

Pulsador 1 = 5 minutos.
Pulsador 2 = 10 minutos.
Pulsador 3 = 20 minutos.
Pulsador 4 = Stop.
Pulsador 5 = Reset del PIC.
Cada Led encensido corresponde a su pulsador.

Su funcioinamiento debe ser así ya que en el asm no me sale.

Al darle fuente alilmentación al PIC, el motor y los Led deben estar apagados. Si pulso el pulador P2, es decir, Pulsador 2, se enciende el motor dc durante 10 minutos y el Led 2. Si pulso el Pulsador 1 cuando esté o no el de 10 minutos activo, simplemente cuenta de nuevo desde cero y dura 5 minutos el motor activado. Espero que se entienda loq ue quiero decir. El Pulsdor 4 es el Stop. Si el motor está activo y Led, detiene el motor y Led. El Reset resetea el PIC y se coporta como si fuera el pulsador de Stop.

¿Parece fácil, verdad?

Les dejo el asm del 16F84A y espero que me ayuden a pasarlo a C queno tengo idea, sea a código y ya compilado.

Para los atrevidos, buena suerte.

Código:
;
;**********http://www.forosdeelectronica.com***********
;
; ZONA DE DATOS **********************************************************************

    LIST        P=16F84A        ; Procesador.
    INCLUDE        <P16F84A.INC>   ; Definición de las etiquetas del PIC.
    __CONFIG    _CP_OFF &  _WDT_OFF & _PWRTE_ON & _XT_OSC
    __IDlOCS    0001            ; Versión del programa.

Variables UDATA_SHR
RAM     RES 1
RAM_1   RES 1
RAM_2   RES 1
RAM_3   RES 1
RAM_4   RES 1
RAM_5   RES 1
RAM_6   RES 1
RAM_7   RES 1
RAM_8   RES 1
RAM_9   RES 1
RAM_10  RES 1
RAM_11  RES 1
RAM_12  RES 1
RAM_13  RES 1
RAM_14  RES 1
RAM_15  RES 1
RAM_16  RES 1
RAM_17  RES 1

#DEFINE Pulsador_1    PORTA,4        ; Pulsador conectado a RA4.
#DEFINE Pulsador_2  PORTA,3     ; Pulsador conectado a RA3.
#DEFINE Pulsador_3  PORTA,2     ; Pulsador conectado a RA2.
#DEFINE Pul_STOP    PORTA,1     ; Pulsador de parada del motor.
#DEFINE Motor        PORTB,7        ; Línea donde se conecta el motor.
#DEFINE Led_1       PORTB,6     ; Led 1.
#DEFINE Led_2       PORTB,5     ; Led 2.
#DEFINE Led_3       PORTB,4     ; Led 3.

; ZONA DE CÓDIGOS ********************************************************************

    ORG    0                        ; El programa comienza en la dirección 0.
Inicio
     bsf        STATUS,RP0            ; Acceso al Banco 1.
    bsf        Pulsador_1            ; La línea RA4 se configura como entrada.
    bsf        Pulsador_2            ; La línea RA3 se configura como entrada.
    bsf        Pulsador_3            ; La línea RA2 se configura como entrada.
    bsf        Pul_STOP            ; La línea RA1 se configura como entrada.
    bcf        Motor                ; Se configura como salida.
    bcf     Led_1               ; Led de aviso 5 minutos en activo.
    bcf     Led_2               ; Led de aviso 10 minutos en activo.
    bcf     Led_3               ; Led de aviso 20 minutos en activo.
    bcf        STATUS,RP0            ; Acceso al Banco 0.
    bcf        Motor                ; En principio Motor apagado igual
    bcf     Led_1               ; que los Leds.
    bcf     Led_2
    bcf     Led_3

Principal
    btfsc    Pulsador_1            ; ¿Pulsador presionado?, ¿(Pulsador)=0?
    goto    Fin                    ; No. Vuelve a leerlo.
    call    Retardo20ms            ; Espera que se estabilicen los niveles de tensión.
    btfsc    Pulsador_1            ; Comprueba si es un rebote.
    goto    Fin                    ; Era un rebote y sale fuera.
    bsf     Motor               ; Activa el motor y
    bsf     Led_1               ; enciende el Led 1 que significa
    call    Retardo5m              ; los 5 minutos encendido.
    bcf     Motor               ; Apaga el motor y
    bcf     Led_1               ; el Led 1.
EsperaDejePulsar_1
    btfss    Pulsador_1            ; ¿Dejó de pulsar?. ¿(Pulsador)=1?
    goto    EsperaDejePulsar_1    ; No. Espera que deje de pulsar.
Fin

    btfsc    Pulsador_2            ; ¿Pulsador presionado?, ¿(Pulsador)=0?
    goto    Fin2                ; No. Vuelve a leerlo.
    call    Retardo20ms            ; Espera que se estabilicen los niveles de tensión.
    btfsc    Pulsador_2            ; Comprueba si es un rebote.
    goto    Fin2                ; Era un rebote y sale fuera.
    bsf     Motor               ; Activa el motor y
    bsf     Led_2               ; enciende el Led 2 que significa
    call    Retardo10m          ; los 10 minutos encendido.
    bcf     Motor               ; Apaga el motor y
    bcf     Led_2               ; el Led 2.
EsperaDejePulsar_2
    btfss    Pulsador_2            ; ¿Dejó de pulsar?. ¿(Pulsador)=1?
    goto    EsperaDejePulsar_2    ; No. Espera que deje de pulsar.
Fin2

    btfsc    Pulsador_3            ; ¿Pulsador presionado?, ¿(Pulsador)=0?
    goto    Fin3                ; No. Vuelve a leerlo.
    call    Retardo20ms            ; Espera que se estabilicen los niveles de tensión.
    btfsc    Pulsador_3            ; Comprueba si es un rebote.
    goto    Fin3                ; Era un rebote y sale fuera.
    bsf     Motor               ; Activa el motor y
    bsf     Led_3               ; enciende el Led 3 que significa
    call    Retardo20m          ; los 10 minutos encendido.
    bcf     Motor               ; Apaga el motor y
    bcf     Led_3               ; el Led 3.
EsperaDejePulsar_3
    btfss    Pulsador_3            ; ¿Dejó de pulsar?. ¿(Pulsador)=1?
    goto    EsperaDejePulsar_3    ; No. Espera que deje de pulsar.
Fin3    goto    Principal

; Subrutinas ****************************************************************

Retardo20ms
            ;199993 cycles
    movlw    0x3E
    movwf    RAM_8
    movlw    0x9D
    movwf    RAM_9
Retardo20ms_0
    decfsz    RAM_8, f
    goto    $+2
    decfsz    RAM_9, f
    goto    Retardo20ms_0

            ;3 cycles
    goto    $+1
    nop

            ;4 cycles (including call)
    return

Retardo5m
            ;299999995 cycles
    movlw    0x54
    movwf    RAM_10
    movlw    0xA1
    movwf    RAM_11
    movlw    0xFD
    movwf    RAM_12
    movlw    0x02
    movwf    RAM_13
Retardo5m_0
    decfsz    RAM_10, f
    goto    $+2
    decfsz    RAM_11, f
    goto    $+2
    decfsz    RAM_12, f
    goto    $+2
    decfsz    RAM_13, f
    goto    Retardo5m_0

            ;1 cycle
    nop

            ;4 cycles (including call)
    return

Retardo10m
            ;599999992 cycles
    movlw    0xA9
    movwf    RAM_4
    movlw    0x41
    movwf    RAM_5
    movlw    0xFA
    movwf    RAM_6
    movlw    0x04
    movwf    RAM_7
Retardo10m_0
    decfsz    RAM_4, f
    goto    $+2
    decfsz    RAM_5, f
    goto    $+2
    decfsz    RAM_6, f
    goto    $+2
    decfsz    RAM_7, f
    goto    Retardo10m_0

            ;4 cycles
    goto    $+1
    goto    $+1

            ;4 cycles (including call)
    return

    cblock
    RAM
    RAM_1
    RAM_2
    RAM_3
    endc

Retardo20m
            ;1199999995 cycles
    movlw    0x54
    movwf    RAM_14
    movlw    0x82
    movwf    RAM_15
    movlw    0xF3
    movwf    RAM_16
    movlw    0x08
    movwf    RAM_17
Retardo20m_0
    decfsz    RAM_14, f
    goto    $+2
    decfsz    RAM_15, f
    goto    $+2
    decfsz    RAM_16, f
    goto    $+2
    decfsz    RAM_17, f
    goto    Retardo20m_0

            ;1 cycle
    nop

            ;4 cycles (including call)
    return

    END

En C se que el código es muchísimo menor. :D

Ánimos y adelante. Luego tengo qu eestudiar el código para analizarlo y entender el concepto.

Saludo.
 
Hola Meta, hacer el programa en asm no es muy complicado, para el caso solo hay que utilizar las interrupciones, más concretamente la interrupción del timer0. El C sería más practico si tendrías operaciones matemáticas y especialmente con números con punto flotante, LCDs, memorias externas, etc., obviamente en asm también se puede pero es algo más trabajoso, asi que "para recordar viejos tiempos" me puse a hacer el programa en asm con todas las prestaciones requeridas, "por el momento no puedo hacer nada en C ya que desinstale el CCS PICC y el MIKROC y no recuerdo donde deje los instaladores", pero estoy seguro que alguien más podrá ayudarte "aparentemente más de medio mundo trabaja con C en este foro".
Código:
    include <p16f84a.inc>
    list    p=16f84a
;***************************************
;Declaracion de variables y constantes
;***************************************
#define p1        PORTA,4
#define p2        PORTA,3
#define p3        PORTA,2
#define p4        PORTA,1
#define    motor        PORTB,7
#define led1        PORTB,6
#define led2        PORTB,5
#define led3        PORTB,4
ctte_5_min        equ    .5        ; constante para 5 minutos
ctte_10_min        equ    .10        ; constante para 10 minutos
ctte_20_min        equ    .20        ; constante para 20 minutos
ctte_min        equ    .60        ; para 1 minuto
ctte_timer         equ    .16        ; para 1 segundo        
carga_timer        equ    .12        ;
cblock 0x020
cont_timer                
cont_seg                    ; contador de segundos
cont_min                    ; contador de minutos
tiempo_fijado            
PDel0
PDel1
W_TEMP
STATUS_TEMP
endc
;**************************************
    org    0x00
    goto    configuracion
    org    0x04
;**********************************************************************
;    Rutinas de interrupciones
;**********************************************************************    
rutina_de_interrupcion
PUSH 
    MOVWF W_TEMP                 ; Copy W to TEMP register,
    SWAPF STATUS,W                 ; Swap status to be saved into W
    MOVWF STATUS_TEMP
    
    btfss    INTCON,T0IF            ;verifica si es interrupción temporizada
    goto    salida_timer0            ;sale de la rutina de interrupción
    movlw    carga_timer            ;
    movwf    TMR0                ;carga al timer0 para reiniciar cuenta
    movfw    cont_timer            ;
    xorlw    ctte_timer            ;compara si llego al segundo
    btfss    STATUS,Z            
    goto    salida_timer0            ;sale de la rutina de interrupción si no es 1 segundo
    clrf    cont_timer            ;
    incf    cont_seg            ;se incrementa cada segundo
    movfw    cont_seg
    xorlw    ctte_min            ;compara si es un minuto
    btfss    STATUS,Z
    goto     salida_timer0            ;sale de la rutina de interrupción
    clrf    cont_seg
    incf    cont_min            ;se incrementa cada minuto
salida_timer0
    incf    cont_timer
    bcf    INTCON,T0IF
POP 
    SWAPF STATUS_TEMP,W             ;Swap nibbles in STATUS_TEMP register and place result into W
    MOVWF STATUS                 ;Move W into STATUS register (sets bank to original state)
    SWAPF W_TEMP,F                 ;Swap nibbles in W_TEMP and place result in W_TEMP
    SWAPF W_TEMP,W
    retfie
;***********************************************
;Subrutinas
;***********************************************
reiniciar_tiempo
    movlw    carga_timer
    movwf    TMR0
    clrf    cont_timer
    clrf    cont_seg
    clrf    cont_min
    banksel    OPTION_REG
    bcf    OPTION_REG,T0CS        ; timer0 inicia la cuenta
    banksel    PORTA
    bsf    INTCON,GIE        ; interrupciones habilitadas
    bsf    motor
    return
;*************************************************************
pulsador1
    call    retardo_10ms
    btfsc    p1
    return
    movlw    ctte_5_min
    movwf    tiempo_fijado
    clrf    PORTB
    call    reiniciar_tiempo
    bsf    led1
    return
;*************************************************************
pulsador2
    call    retardo_10ms
    btfsc    p2
    return
    movlw    ctte_10_min
    movwf    tiempo_fijado
    clrf    PORTB
    call    reiniciar_tiempo
    bsf    led2
    return
;*************************************************************
pulsador3
    call    retardo_10ms
    btfsc    p3
    return
    movlw    ctte_20_min
    movwf    tiempo_fijado
    clrf    PORTB
    call    reiniciar_tiempo
    bsf    led3
    return
;*************************************************************
pulsador4
    call    retardo_10ms
    btfsc    p4
    return
    call    detener_tiempo
    return
;*************************************************************    
detener_tiempo
    clrf    PORTB            
    banksel    OPTION_REG
    bsf    OPTION_REG,T0CS    ; timer0 detenido
    banksel    PORTA
    bcf    INTCON,GIE        ; interrupciones desactivadas
;*************************************************************
retardo_10ms
    movlw   .8
        movwf   PDel0
PLoop1
    movlw   .249
        movwf    PDel1
PLoop2
    clrwdt
        clrwdt
        decfsz  PDel1,1
        goto    PLoop2
        decfsz  PDel0,1
        goto    PLoop1
PDelL1  
    goto    PDelL2
PDelL2
    clrwdt
        return
;**********************************************
configuracion
;**********************************************
; Configuración de puertos de entrada y salida
;**********************************************
    clrf    PORTA        ;porta=0
    clrf    PORTB        ;portb=0
    banksel    TRISA        ;cambio de banko
    movlw    0xff        ;w=255
    movwf    TRISA        ;porta como entradas
    clrf    TRISB        ;portb como salidas
;***********************************************
;Configuraciond de las interrupcion temporizada
;***********************************************
    movlw    b'11110111'    ;prescaler asignado a timer0, prescaler=256
    movwf    OPTION_REG
    banksel    INTCON
    movlw    b'00100000'    ;
    movwf    INTCON        ;interrupciones globales desactivados e interrupción timer0 activado
    clrf    TMR0
;**********************************************
bucle    
    btfss    p1
    call    pulsador1
    btfss    p2
    call    pulsador2
    btfss    p3
    call    pulsador3
    btfss    p4
    call    pulsador4
    movfw    cont_min
    xorwf    tiempo_fijado,W
    btfss    STATUS,Z
    goto    bucle
    incf    cont_min
    call    detener_tiempo        
    goto    bucle
;***********************************************
    end
 

Adjuntos

  • ej.rar
    29.5 KB · Visitas: 11
Última edición:
Hola:

Por cierto, en el CBLOCK el PIC16F84A empieza desde 0xC0. :).

He modificado la parte de las variables en modo código recolectable para que se vea la cantidad me RAM usada en este imagen. De otro modo no puedes, se ve como vacío.

Router-ZyxEL.png

Código abajo.
Código:
    LIST    P=16F84A        ; Procesador.
    INCLUDE    <P16F84A.INC>   ; Definición de las etiquetas del PIC.
    __CONFIG    _CP_OFF &  _WDT_OFF & _PWRTE_ON & _XT_OSC
      __IDlOCS    0001            ; Versión del programa.
    ErrORLEVEL    -302
;***************************************
;Declaracion de variables y constantes
;***************************************
#define p1        PORTA,4
#define p2        PORTA,3
#define p3        PORTA,2
#define p4        PORTA,1
#define    motor    PORTB,7
#define led1    PORTB,6
#define led2    PORTB,5
#define led3    PORTB,4
ctte_5_min        equ    .5        ; constante para 5 minutos
ctte_10_min        equ    .10        ; constante para 10 minutos
ctte_20_min        equ    .20        ; constante para 20 minutos
ctte_min        equ    .60        ; para 1 minuto
ctte_timer         equ    .16        ; para 1 segundo        
carga_timer        equ    .12        ;

Variables    UDATA_SHR    0xC0
cont_timer    RES    1            
cont_seg    RES    1        ; contador de segundos
cont_min    RES    1            ; contador de minutos
tiempo_fijado    RES    1        
PDel0    RES    1
PDel1    RES    1
W_TEMP    RES    1
STATUS_TEMP    RES    1

;**************************************
    org    0x00
    goto    configuracion
    org    0x04
;**********************************************************************
;    Rutinas de interrupciones
;**********************************************************************    
rutina_de_interrupcion
PUSH 
    MOVWF W_TEMP                 ; Copy W to TEMP register,
    SWAPF STATUS,W                 ; Swap status to be saved into W
    MOVWF STATUS_TEMP
    
    btfss    INTCON,T0IF            ;verifica si es interrupción temporizada
    goto    salida_timer0        ;sale de la rutina de interrupción
    movlw    carga_timer            ;
    movwf    TMR0                ;carga al timer0 para reiniciar cuenta
    movfw    cont_timer            ;
    xorlw    ctte_timer            ;compara si llego al segundo
    btfss    STATUS,Z            
    goto    salida_timer0        ;sale de la rutina de interrupción si no es 1 segundo
    clrf    cont_timer            ;
    incf    cont_seg            ;se incrementa cada segundo
    movfw    cont_seg
    xorlw    ctte_min            ;compara si es un minuto
    btfss    STATUS,Z
    goto     salida_timer0        ;sale de la rutina de interrupción
    clrf    cont_seg
    incf    cont_min            ;se incrementa cada minuto
salida_timer0
    incf    cont_timer
    bcf        INTCON,T0IF
POP 
    SWAPF STATUS_TEMP,W         ;Swap nibbles in STATUS_TEMP register and place result into W
    MOVWF STATUS                 ;Move W into STATUS register (sets bank to original state)
    SWAPF W_TEMP,F                 ;Swap nibbles in W_TEMP and place result in W_TEMP
    SWAPF W_TEMP,W
    retfie
;***********************************************
;Subrutinas
;***********************************************
reiniciar_tiempo
    movlw    carga_timer
    movwf    TMR0
    clrf    cont_timer
    clrf    cont_seg
    clrf    cont_min
    banksel    OPTION_REG
    bcf        OPTION_REG,T0CS    ; timer0 inicia la cuenta
    banksel    PORTA
    bsf        INTCON,GIE        ; interrupciones habilitadas
    bsf        motor
    return
;*************************************************************
pulsador1
    call    retardo_10ms
    btfsc    p1
    return
    movlw    ctte_5_min
    movwf    tiempo_fijado
    clrf    PORTB
    call    reiniciar_tiempo
    bsf        led1
    return
;*************************************************************
pulsador2
    call    retardo_10ms
    btfsc    p2
    return
    movlw    ctte_10_min
    movwf    tiempo_fijado
    clrf    PORTB
    call    reiniciar_tiempo
    bsf        led2
    return
;*************************************************************
pulsador3
    call    retardo_10ms
    btfsc    p3
    return
    movlw    ctte_20_min
    movwf    tiempo_fijado
    clrf    PORTB
    call    reiniciar_tiempo
    bsf        led3
    return
;*************************************************************
pulsador4
    call    retardo_10ms
    btfsc    p4
    return
    call    detener_tiempo
    return
;*************************************************************    
detener_tiempo
    clrf    PORTB            
    banksel    OPTION_REG
    bsf        OPTION_REG,T0CS    ; timer0 detenido
    banksel    PORTA
    bcf        INTCON,GIE        ; interrupciones desactivadas
;*************************************************************
retardo_10ms
    movlw   .8
    movwf   PDel0
PLoop1
    movlw   .249
    movwf    PDel1
PLoop2
    clrwdt
    clrwdt
    decfsz  PDel1,1
    goto    PLoop2
    decfsz  PDel0,1
    goto    PLoop1
PDelL1  
    goto    PDelL2
PDelL2
    clrwdt
    return
;**********************************************
configuracion
;**********************************************
; Configuración de puertos de entrada y salida
;**********************************************
    clrf    PORTA        ;porta=0
    clrf    PORTB        ;portb=0
    banksel    TRISA        ;cambio de banko
    movlw    0xff        ;w=255
    movwf    TRISA        ;porta como entradas
    clrf    TRISB        ;portb como salidas
;***********************************************
;Configuraciond de las interrupcion temporizada
;***********************************************
    movlw    b'11110111'    ;prescaler asignado a timer0, prescaler=256
    movwf    OPTION_REG
    banksel    INTCON
    movlw    b'00100000'    ;
    movwf    INTCON        ;interrupciones globales desactivados e interrupción timer0 activado
    clrf    TMR0
;**********************************************
bucle    
    btfss    p1
    call    pulsador1
    btfss    p2
    call    pulsador2
    btfss    p3
    call    pulsador3
    btfss    p4
    call    pulsador4
    movfw    cont_min
    xorwf    tiempo_fijado,W
    btfss    STATUS,Z
    goto    bucle
    incf    cont_min
    call    detener_tiempo        
    goto    bucle
;***********************************************
    end
Gracias por tu tiempo, que rapidés te ha salido.
 
Hola.
Igual aporto... está realizado en el XC8 y algo detallado (sin tanta estructura) para que se pueda entender paso a paso que hace...

He agregado un LED en RB0 solo a modo de prueba, parpadea por cada segundo (1s encendido, 1s apagado). El osciloscópio indica que el tiempo esta en aprox 992ms, casi 1s jeje, (es el detalle del Timer que tambien depende de la frecuencia del cristal).

Código:
//------------------------------------------------------------------------------
//Timer0 Registers  
// - Prescaler = 256 - TMR0
// - Preset = 178 - Freq = 50.08 Hz - Period = 0.019968 seconds
// - Utiliza un contador para: 50.08Hz por 0.019968s = 0.999s... casi 1s (segundo) como base de tiempos.
//------------------------------------------------------------------------------

// Importa librarias
#define _XTAL_FREQ 4000000  // Cristal 4Mhz para calculos de tiempo
#include <xc.h>

// Configuración de Fuses
#pragma config FOSC = XT            // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config CP = OFF

//------------------------------------------------------------------------------
// Definiciones y macros.
#define LED1 PORTBbits.RB6  
#define LED2 PORTBbits.RB5
#define MOTOR PORTBbits.RB7
#define P1 PORTAbits.RA4
#define P2 PORTAbits.RA3
#define P3 PORTAbits.RA2
#define P4 PORTAbits.RA1

#define On 1        // Util
#define True 1
#define Off 0
#define False 0

//------------------------------------------------------------------------------
// Declaración de prototipos
void AntiDebounce(void);
void OnMotor(void);
void OffMotor(void);

//------------------------------------------------------------------------------
// Declaración de variables
unsigned char cont;     // Contador
unsigned char seg;      // Segundos
unsigned char min;      // Minutos
unsigned char SetPoint; // Tiempo límite
unsigned char FinCont;  // True indica que ya se cumpió el tiempo.

//------------------------------------------------------------------------------
// Zona de Interrupción
void interrupt timer_tick(void){
    if(INTCONbits.TMR0IE && INTCONbits.TMR0IF){
        if(++cont >= 50){               // 50 veces 19.968ms (1s aprox.)
            cont = 0;

            PORTBbits.RB0 = ~PORTBbits.RB0; /* TEST para Segundo */

            if(++seg > 59){             // Cuenta segundos
                seg = 0;
                if(++min >= SetPoint){   // Cuenta minutos, compara con los minutos programados
                    min = 0;
                    FinCont = True;     // Fin del conteo de minutos programados
                }
            }
        }

        TMR0 = 178;                 // preset for timer register
        INTCONbits.TMR0IF = 0;      // Limpia el Flag
    }
}

//------------------------------------------------------------------------------
// Flujo Principal
void main(void){
    OPTION_REGbits.T0CS = 0;    // Configura el Timer0
    OPTION_REGbits.T0SE = 0;
    OPTION_REGbits.PSA = 0;
    OPTION_REGbits.PS2 = 1;     // Prescaller 1:256
    OPTION_REGbits.PS1 = 1;
    OPTION_REGbits.PS0 = 1;

    PORTB = 0x00;               // Inicia todo desactivado
    TRISA = 0x1E;
    TRISB = 0x00;
    
    INTCONbits.TMR0IE = 1;      // Activa el Flag para interrupción del Timer0

    //-- BUcle principal
    while(1){
        if(!P1){                // On motor 5 minutos
            SetPoint = 5;       //  programa el tiempo
            OnMotor();          //  activa el motor
            AntiDebounce();     //  y espera a que suelte el pulsador
            // >> El conteo ya se está ejecutando ahúnque se mantenga presionado el pulsador.
        }
        else if(!P2){           // On motor 10 minutos
            SetPoint = 10;
            OnMotor();
            AntiDebounce();
        }
        else if(!P3){           // On...

        }
        else if(!P4){           // STOP
            OffMotor();         // Detiene el motor
            AntiDebounce();
        }

        if(FinCont == True){    // Detiene el Motor al final del conteo
            FinCont = False;
            OffMotor();
        }
    }
}

//------------------------------------------------------------------------------
// Funciones.
//-> Espera a que suelten el pulsador
void AntiDebounce(void){
    while(!P1 && !P2 && !P3 && !P4){    // Espera que los 4 esten libres
        __delay_ms(5);
    }
    __delay_ms(5);          // Simple anti-rebotes
}

//-> Activa el motor por tiempo
void OnMotor(void){
    MOTOR = On;
    LED2 = On;
    cont = seg = min = 0;   // Inicia las variables de conteo
    TMR0 = 178;             // Pre carga el timer
    INTCONbits.TMR0IF = 0;
    INTCONbits.GIE = On;    // Activa interrupciones (Timer)
}

//-> Desactiva el motor
void OffMotor(void){
    INTCONbits.GIE = Off;   // Desactiva interrupciones (Timer)
    INTCONbits.TMR0IF = 0;
    MOTOR = Off;            // Apaga motor
    LED2 = Off;
}

Saludos.
 

Adjuntos

  • iwatch.jpg
    iwatch.jpg
    32.1 KB · Visitas: 9
Buenas:

Nunca había compilado un programa en C con XC8, si con CCS y C18. El código funciona, no puede interrumpir cuando tienes pulsado el pulsador 2 de 10 minutos, en ese momento que el motor está encendido, si pulsas el Pulsador 1 de 5 minutos, no se cambia, sigue donde estás. Si puedes cancelarlo con el botón de STOP.

La idea es, que aunque el motor esté en marcha por 10 minutos, sen la mitad de tiempo se me ocurre pulsar el de 20 minutos, el contador empieza desde cero y se pone a contas los 20 minutos. Sólo faltó eso en C.

Otra cosa, el P3 no hace nada.

A pesar de que no entiendo el XC8, me está empezando a gustar.
http://ww1.microchip.com/downloads/en/DeviceDoc/50002173A.pdf

http://ww1.microchip.com/downloads/en/DeviceDoc/52053B.pdf

Por lo demás, está bien hecho.

Gracias por la participación.
 
Última edición:
Que raro... en mi simulador si cambia...

En cualquier momento en pleno conteo se puede cambiar entre los 5 min a 10 min (viceversa) y parar. El de 20 min lo he dejado así para que lo completes... al igual que los efectos con el resto de LEDs...

Adjunto el proyecto... MPLAB-X + XC8 modo PRO, prueba solo el *.hex antes de compilar...
 

Adjuntos

  • Demo_F84A.X.rar
    47.4 KB · Visitas: 24
  • simF84.jpg
    simF84.jpg
    108.1 KB · Visitas: 14
Última edición:
Hola:

Pasos:

1. He probado el hex con mi propio esquema, no funciona el P3 y no cambia los botones cuando el temporizador está activo.

2.
He probado el hex en archivo.hex de nuestro amigo Saint_ arriba, y funciona de maravilla.

3. He encontrado un posible motivo. De lo poco que se de C para PIC y gracias a tus ayudas, estoy comprendiendo algo.

router-zyxel-852000.png

4. Faltaba el códig de 20 minutos que no has puesto nada. EJejeje, parace un ejercicio para aprender. :D.

router-zyxel-852003.png


5.
Bajo mi punto de vista, los Led no tienen que estar en la sección de motor.
router-zyxel-852008.png

6. Me sigue funcionando desde el principio. TEngo el Proteus 7.10 SP0. No se si esto tiene algo que ver, me refiero a que falla. Cuando pueda instaldo el Proteus 8.1 a ver que pasa. El código que he modificado es el siguiente. Lo puedes probar.

Código:
//------------------------------------------------------------------------------
//Timer0 Registers
// - Prescaler = 256 - TMR0
// - Preset = 178 - Freq = 50.08 Hz - Period = 0.019968 seconds
// - Utiliza un contador para: 50.08Hz por 0.019968s = 0.999s... casi 1s (segundo) como base de tiempos.
//------------------------------------------------------------------------------

// Importa librarias
#define _XTAL_FREQ 4000000  // Cristal 4Mhz para calculos de tiempo
#include <xc.h>

// Configuración de Fuses
#pragma config FOSC = XT            // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config CP = OFF

//------------------------------------------------------------------------------
// Definiciones y macros.
#define LED1 PORTBbits.RB6
#define LED2 PORTBbits.RB5
#define LED3 PORTBbits.RB4
#define MOTOR PORTBbits.RB7
#define P1 PORTAbits.RA4
#define P2 PORTAbits.RA3
#define P3 PORTAbits.RA2
#define P4 PORTAbits.RA1

#define On 1        // Util
#define True 1
#define Off 0
#define False 0

//------------------------------------------------------------------------------
// Declaración de prototipos
void AntiDebounce(void);
void OnMotor(void);
void OffMotor(void);

//------------------------------------------------------------------------------
// Declaración de variables
unsigned char cont;     // Contador
unsigned char seg;      // Segundos
unsigned char min;      // Minutos
unsigned char SetPoint; // Tiempo límite
unsigned char FinCont;  // True indica que ya se cumpió el tiempo.

//------------------------------------------------------------------------------
// Zona de Interrupción
void interrupt timer_tick(void){
    if(INTCONbits.TMR0IE && INTCONbits.TMR0IF){
        if(++cont >= 50){               // 50 veces 19.968ms (1s aprox.)
            cont = 0;

            PORTBbits.RB0 = ~PORTBbits.RB0; /* TEST para Segundo */

            if(++seg > 59){             // Cuenta segundos
                seg = 0;
                if(++min >= SetPoint){   // Cuenta minutos, compara con los minutos programados
                    min = 0;
                    FinCont = True;     // Fin del conteo de minutos programados
                }
            }
        }

        TMR0 = 178;                 // preset for timer register
        INTCONbits.TMR0IF = 0;      // Limpia el Flag
    }
}

//------------------------------------------------------------------------------
// Flujo Principal
void main(void){
    OPTION_REGbits.T0CS = 0;    // Configura el Timer0
    OPTION_REGbits.T0SE = 0;
    OPTION_REGbits.PSA = 0;
    OPTION_REGbits.PS2 = 1;     // Prescaller 1:256
    OPTION_REGbits.PS1 = 1;
    OPTION_REGbits.PS0 = 1;

    PORTB = 0x00;               // Inicia todo desactivado
    TRISA = 0x1E;
    TRISB = 0x00;

    INTCONbits.TMR0IE = 1;      // Activa el Flag para interrupción del Timer0

    //-- BUcle principal
    while(1){
        if(!P1){                // On motor 5 minutos
            SetPoint = 5;       //  programa el tiempo
            OnMotor();          //  activa el motor
            LED1 = On;
            LED2 = Off;
            LED3 = Off;
            AntiDebounce();     //  y espera a que suelte el pulsador
            // >> El conteo ya se está ejecutando ahúnque se mantenga presionado el pulsador.
        }
        else if(!P2){           // On motor 10 minutos
            SetPoint = 10;
            OnMotor();
            LED1 = Off;
            LED2 = On;
            LED3 = Off;
            AntiDebounce();
        }
        else if(!P3){           // On...
            SetPoint = 20;
            OnMotor();
            LED1 = Off;
            LED2 = Off;
            LED3 = On;
            AntiDebounce();
        }
        else if(!P4){           // STOP
            OffMotor();         // Detiene el motor
            LED1 = Off;
            LED2 = Off;
            LED3 = Off;
            AntiDebounce();
        }

        if(FinCont == True){    // Detiene el Motor al final del conteo
            FinCont = False;
            OffMotor();
        }
    }
}

//------------------------------------------------------------------------------
// Funciones.
//-> Espera a que suelten el pulsador
void AntiDebounce(void){
    while(!P1 && !P2 && !P3 && !P4){    // Espera que los 4 esten libres
        __delay_ms(5);
    }
    __delay_ms(5);          // Simple anti-rebotes
}

//-> Activa el motor por tiempo
void OnMotor(void){
    MOTOR = On;
    cont = seg = min = 0;   // Inicia las variables de conteo
    TMR0 = 178;             // Pre carga el timer
    INTCONbits.TMR0IF = 0;
    INTCONbits.GIE = On;    // Activa interrupciones (Timer)
}

//-> Desactiva el motor
void OffMotor(void){
    INTCONbits.GIE = Off;   // Desactiva interrupciones (Timer)
    INTCONbits.TMR0IF = 0;
    MOTOR = Off;            // Apaga motor
}

Por cierto, hay muchos if else. ¿No crees que en este caso es mejor usar un Switch - Case?
Es una sugerencia.

Un saludo.
 
Última edición:
Hola Meta, hacer el programa en asm no es muy complicado, para el caso solo hay que utilizar las interrupciones, más concretamente la interrupción del timer0. El C sería más practico si tendrías operaciones matemáticas y especialmente con números con punto flotante, LCDs, memorias externas, etc., obviamente en asm también se puede pero es algo más trabajoso, asi que "para recordar viejos tiempos" me puse a hacer el programa en asm con todas las prestaciones requeridas, "por el momento no puedo hacer nada en C ya que desinstale el CCS PICC y el MIKROC y no recuerdo donde deje los instaladores", pero estoy seguro que alguien más podrá ayudarte "aparentemente más de medio mundo trabaja con C en este foro".
Código:
    include <p16f84a.inc>
    list    p=16f84a
;***************************************
;Declaracion de variables y constantes
;***************************************
#define p1        PORTA,4
#define p2        PORTA,3
#define p3        PORTA,2
#define p4        PORTA,1
#define    motor        PORTB,7
#define led1        PORTB,6
#define led2        PORTB,5
#define led3        PORTB,4
ctte_5_min        equ    .5        ; constante para 5 minutos
ctte_10_min        equ    .10        ; constante para 10 minutos
ctte_20_min        equ    .20        ; constante para 20 minutos
ctte_min        equ    .60        ; para 1 minuto
ctte_timer         equ    .16        ; para 1 segundo        
carga_timer        equ    .12        ;
cblock 0x020
cont_timer                
cont_seg                    ; contador de segundos
cont_min                    ; contador de minutos
tiempo_fijado            
PDel0
PDel1
W_TEMP
STATUS_TEMP
endc
;**************************************
    org    0x00
    goto    configuracion
    org    0x04
;**********************************************************************
;    Rutinas de interrupciones
;**********************************************************************    
rutina_de_interrupcion
PUSH 
    MOVWF W_TEMP                 ; Copy W to TEMP register,
    SWAPF STATUS,W                 ; Swap status to be saved into W
    MOVWF STATUS_TEMP
    
    btfss    INTCON,T0IF            ;verifica si es interrupción temporizada
    goto    salida_timer0            ;sale de la rutina de interrupción
    movlw    carga_timer            ;
    movwf    TMR0                ;carga al timer0 para reiniciar cuenta
    movfw    cont_timer            ;
    xorlw    ctte_timer            ;compara si llego al segundo
    btfss    STATUS,Z            
    goto    salida_timer0            ;sale de la rutina de interrupción si no es 1 segundo
    clrf    cont_timer            ;
    incf    cont_seg            ;se incrementa cada segundo
    movfw    cont_seg
    xorlw    ctte_min            ;compara si es un minuto
    btfss    STATUS,Z
    goto     salida_timer0            ;sale de la rutina de interrupción
    clrf    cont_seg
    incf    cont_min            ;se incrementa cada minuto
salida_timer0
    incf    cont_timer
    bcf    INTCON,T0IF
POP 
    SWAPF STATUS_TEMP,W             ;Swap nibbles in STATUS_TEMP register and place result into W
    MOVWF STATUS                 ;Move W into STATUS register (sets bank to original state)
    SWAPF W_TEMP,F                 ;Swap nibbles in W_TEMP and place result in W_TEMP
    SWAPF W_TEMP,W
    retfie
;***********************************************
;Subrutinas
;***********************************************
reiniciar_tiempo
    movlw    carga_timer
    movwf    TMR0
    clrf    cont_timer
    clrf    cont_seg
    clrf    cont_min
    banksel    OPTION_REG
    bcf    OPTION_REG,T0CS        ; timer0 inicia la cuenta
    banksel    PORTA
    bsf    INTCON,GIE        ; interrupciones habilitadas
    bsf    motor
    return
;*************************************************************
pulsador1
    call    retardo_10ms
    btfsc    p1
    return
    movlw    ctte_5_min
    movwf    tiempo_fijado
    clrf    PORTB
    call    reiniciar_tiempo
    bsf    led1
    return
;*************************************************************
pulsador2
    call    retardo_10ms
    btfsc    p2
    return
    movlw    ctte_10_min
    movwf    tiempo_fijado
    clrf    PORTB
    call    reiniciar_tiempo
    bsf    led2
    return
;*************************************************************
pulsador3
    call    retardo_10ms
    btfsc    p3
    return
    movlw    ctte_20_min
    movwf    tiempo_fijado
    clrf    PORTB
    call    reiniciar_tiempo
    bsf    led3
    return
;*************************************************************
pulsador4
    call    retardo_10ms
    btfsc    p4
    return
    call    detener_tiempo
    return
;*************************************************************    
detener_tiempo
    clrf    PORTB            
    banksel    OPTION_REG
    bsf    OPTION_REG,T0CS    ; timer0 detenido
    banksel    PORTA
    bcf    INTCON,GIE        ; interrupciones desactivadas
;*************************************************************
retardo_10ms
    movlw   .8
        movwf   PDel0
PLoop1
    movlw   .249
        movwf    PDel1
PLoop2
    clrwdt
        clrwdt
        decfsz  PDel1,1
        goto    PLoop2
        decfsz  PDel0,1
        goto    PLoop1
PDelL1  
    goto    PDelL2
PDelL2
    clrwdt
        return
;**********************************************
configuracion
;**********************************************
; Configuración de puertos de entrada y salida
;**********************************************
    clrf    PORTA        ;porta=0
    clrf    PORTB        ;portb=0
    banksel    TRISA        ;cambio de banko
    movlw    0xff        ;w=255
    movwf    TRISA        ;porta como entradas
    clrf    TRISB        ;portb como salidas
;***********************************************
;Configuraciond de las interrupcion temporizada
;***********************************************
    movlw    b'11110111'    ;prescaler asignado a timer0, prescaler=256
    movwf    OPTION_REG
    banksel    INTCON
    movlw    b'00100000'    ;
    movwf    INTCON        ;interrupciones globales desactivados e interrupción timer0 activado
    clrf    TMR0
;**********************************************
bucle    
    btfss    p1
    call    pulsador1
    btfss    p2
    call    pulsador2
    btfss    p3
    call    pulsador3
    btfss    p4
    call    pulsador4
    movfw    cont_min
    xorwf    tiempo_fijado,W
    btfss    STATUS,Z
    goto    bucle
    incf    cont_min
    call    detener_tiempo        
    goto    bucle
;***********************************************
    end

Hola de nuevo:

En cuanto a tu código, quiero agregarle un zumbador piezoelectrico, para que suene un pitido corto cuando pulsas cualquier pulsador. También al final cuando se acaba el temporizador, suene un pitido como lo hace un microondas en la cocina.

Se usará el puerto RB3 para el altavoz y el RB2 para el zumbador de 5V al mismo tiempo. El prototipo final para una PCB, el usuario decidirá instalar físicamente uno de los dos tipos de sonidos, sea solo el zumbador, solo el altavoz o los dos al mismo tiempo. La programación debe estar programado para los dos.

router-zyxel-852043.png


Ejemplo:
Código:
    call    Pitido                    ; Tres pitidos indican final de la temporización.
    call    Retardo_500ms    ; Retardo se 500 mili segundos en silencio.
    call    Pitido                   ; Suena pitido durante 200 ms.
    call    Retardo_500ms    ; Silencio durante 500 ms.
    call    PitidoLargo          ; Pitido durante 500 ms.
    call    Retardo_500ms     ; Silencio durante 500 ms.
Código:
; Subrutinas "PitidoLargo", "Pitido" y "PitidoCorto".
;
PitidoLargo
    bsf        Zumbador
    call    Retardo_500ms
Pitido
    bsf        Zumbador
    call    Retardo_200ms
PitidoCorto
    bsf        Zumbador
    call    Retardo_20ms
    bcf        Zumbador
    return
Un saludo.

Edito:
He modificado tu código. Al final he puestosubrutinas de tiempos, retardos para los pitidos de los pulsadores. Desde quepulses cualquier botón, se oye un pitido corto. Estoy haciendo pruebas con el P1, pero no se activa ni el altavoz, ni el zumbador aunque me deje zumbado.

Código:
;
;
; Oscilador externo cristal de cuarzo a 4 Mhz.
;
    LIST    P=16F84A        ; Procesador.
    INCLUDE    <P16F84A.INC>   ; Definición de las etiquetas del PIC.
    __CONFIG    _CP_OFF &  _WDT_OFF & _PWRTE_ON & _XT_OSC
      __IDlOCS    0001            ; Versión del programa.
    ErrORLEVEL    -302
;***************************************
;Declaracion de variables y constantes
;***************************************
#define p1          PORTA,4     ; Pulsador 1.
#define p2          PORTA,3     ; Pulsador 2.
#define p3          PORTA,2     ; Pulsador 3.
#define p4          PORTA,1     ; Pulsador 4.
#define motor       PORTB,7     ; Motor DC.
#define led1        PORTB,6     ; Diodo Led 1.
#define led2        PORTB,5
#define led3        PORTB,4
#DEFINE Altavoz     PORTB,3     ; Altavoz.
#DEFINE Zumbador    PORTB,2     ; Zumbador piezoeléctrico.

ctte_5_min    equ    .5        ; constante para 5 minutos
ctte_10_min    equ    .10        ; constante para 10 minutos
ctte_20_min    equ    .20        ; constante para 20 minutos
ctte_min    equ    .60        ; para 1 minuto
ctte_timer     equ    .16        ; para 1 segundo
carga_timer    equ    .12        ;

Variables    UDATA_SHR    0xC0
cont_timer    RES    1
cont_seg    RES    1        ; contador de segundos
cont_min    RES    1            ; contador de minutos
tiempo_fijado    RES    1
PDel0       RES    1
PDel1       RES    1
W_TEMP      RES    1
STATUS_TEMP    RES    1
RAM         RES 1
RAM_1       RES 1
RAM_2       RES 1
RAM_3       RES 1
RAM_4       RES 1
RAM_5       RES 1
RAM_6       RES 1

;**************************************
    org    0x00
    goto    configuracion
    org    0x04
;**********************************************************************
;    Rutinas de interrupciones
;**********************************************************************
rutina_de_interrupcion
PUSH
    MOVWF W_TEMP                 ; Copy W to TEMP register,
    SWAPF STATUS,W                 ; Swap status to be saved into W
    MOVWF STATUS_TEMP

    btfss    INTCON,T0IF            ;verifica si es interrupción temporizada
    goto    salida_timer0        ;sale de la rutina de interrupción
    movlw    carga_timer            ;
    movwf    TMR0                ;carga al timer0 para reiniciar cuenta
    movfw    cont_timer            ;
    xorlw    ctte_timer            ;compara si llego al segundo
    btfss    STATUS,Z
    goto    salida_timer0        ;sale de la rutina de interrupción si no es 1 segundo
    clrf    cont_timer            ;
    incf    cont_seg            ;se incrementa cada segundo
    movfw    cont_seg
    xorlw    ctte_min            ;compara si es un minuto
    btfss    STATUS,Z
    goto     salida_timer0        ;sale de la rutina de interrupción
    clrf    cont_seg
    incf    cont_min            ;se incrementa cada minuto
salida_timer0
    incf    cont_timer
    bcf        INTCON,T0IF
POP
    SWAPF STATUS_TEMP,W         ;Swap nibbles in STATUS_TEMP register and place result into W
    MOVWF STATUS                 ;Move W into STATUS register (sets bank to original state)
    SWAPF W_TEMP,F                 ;Swap nibbles in W_TEMP and place result in W_TEMP
    SWAPF W_TEMP,W
    retfie
;***********************************************
;Subrutinas
;***********************************************
reiniciar_tiempo
    movlw    carga_timer
    movwf    TMR0
    clrf    cont_timer
    clrf    cont_seg
    clrf    cont_min
    banksel    OPTION_REG
    bcf        OPTION_REG,T0CS    ; timer0 inicia la cuenta
    banksel    PORTA
    bsf        INTCON,GIE        ; interrupciones habilitadas
    bsf        motor
    return
;*************************************************************
pulsador1
    call    retardo_10ms
    btfsc    p1
    return
    movlw    ctte_5_min
    movwf    tiempo_fijado
    clrf    PORTB
    call    reiniciar_tiempo
    call    PitidoCorto
    bsf        led1
    return
;*************************************************************
pulsador2
    call    retardo_10ms
    btfsc    p2
    return
    movlw    ctte_10_min
    movwf    tiempo_fijado
    clrf    PORTB
    call    reiniciar_tiempo
    bsf        led2
    return
;*************************************************************
pulsador3
    call    retardo_10ms
    btfsc    p3
    return
    movlw    ctte_20_min
    movwf    tiempo_fijado
    clrf    PORTB
    call    reiniciar_tiempo
    bsf        led3
    return
;*************************************************************
pulsador4
    call    retardo_10ms
    btfsc    p4
    return
    call    detener_tiempo
    return
;*************************************************************
detener_tiempo
    clrf    PORTB
    banksel    OPTION_REG
    bsf        OPTION_REG,T0CS    ; timer0 detenido
    banksel    PORTA
    bcf        INTCON,GIE        ; interrupciones desactivadas
;*************************************************************
retardo_10ms
    movlw   .8
    movwf   PDel0
PLoop1
    movlw   .249
    movwf    PDel1
PLoop2
    clrwdt
    clrwdt
    decfsz  PDel1,1
    goto    PLoop2
    decfsz  PDel0,1
    goto    PLoop1
PDelL1
    goto    PDelL2
PDelL2
    clrwdt
    return
;**********************************************
configuracion
;**********************************************
; Configuración de puertos de entrada y salida
;**********************************************
    clrf    PORTA        ;porta=0
    clrf    PORTB        ;portb=0
    banksel    TRISA        ;cambio de banko
    movlw    0xff        ;w=255
    movwf    TRISA        ;porta como entradas
    clrf    TRISB        ;portb como salidas
;***********************************************
;Configuraciond de las interrupcion temporizada
;***********************************************
    movlw    b'11110111'    ;prescaler asignado a timer0, prescaler=256
    movwf    OPTION_REG
    banksel    INTCON
    movlw    b'00100000'    ;
    movwf    INTCON        ;interrupciones globales desactivados e interrupción timer0 activado
    clrf    TMR0
;**********************************************
bucle
    btfss    p1
    call    pulsador1
    btfss    p2
    call    pulsador2
    btfss    p3
    call    pulsador3
    btfss    p4
    call    pulsador4
    movfw    cont_min
    xorwf    tiempo_fijado,W
    btfss    STATUS,Z
    goto    bucle
    incf    cont_min
    call    detener_tiempo
    goto    bucle
;***********************************************

; Subrutinas "PitidoLargo", "Pitido" y "PitidoCorto" -----------------
;

PitidoLargo
    bsf     Altavoz
    bsf     Zumbador
    call    Retardo_500ms
Pitido
    bsf     Altavoz
    bsf     Zumbador
    call    Retardo_200ms
PitidoCorto
    bsf     Altavoz
    bsf     Zumbador
    call    Retardo_20ms
    bcf     Altavoz
    bcf     Zumbador
    return

; Subrutinas retardos *********************************

Retardo_500ms
            ;499994 cycles
    movlw    0x03
    movwf    RAM
    movlw    0x18
    movwf    RAM_1
    movlw    0x02
    movwf    RAM_2
Retardo_500ms_0
    decfsz    RAM, f
    goto    $+2
    decfsz    RAM_1, f
    goto    $+2
    decfsz    RAM_2, f
    goto    Retardo_500ms_0

            ;2 cycles
    goto    $+1

            ;4 cycles (including call)
    return

Retardo_200ms
            ;199993 cycles
    movlw    0x3E
    movwf    RAM_3
    movlw    0x9D
    movwf    RAM_4
Retardo_200ms_0
    decfsz    RAM_3, f
    goto    $+2
    decfsz    RAM_4, f
    goto    Retardo_200ms_0

            ;3 cycles
    goto    $+1
    nop

            ;4 cycles (including call)
    return

Retardo_20ms
            ;19993 cycles
    movlw    0x9E
    movwf    RAM_5
    movlw    0x10
    movwf    RAM_6
Retardo_20ms_0
    decfsz    RAM_5, f
    goto    $+2
    decfsz    RAM_6, f
    goto    Retardo_20ms_0

            ;3 cycles
    goto    $+1
    nop

            ;4 cycles (including call)
    return

    END         ; Fin de programa.
Desde que me funcione el puslador 1 o P1, tocaré los otros. ;)

Saludo.
 
Última edición:
4. Faltaba el códig de 20 minutos que no has puesto nada. EJejeje, parace un ejercicio para aprender. :D.
No me olvidé de poner, mas o menos esa era la intensión :D .

6. Me sigue funcionando desde el principio. Tengo el Proteus 7.10 SP0. No se si esto tiene algo que ver, me refiero a que falla. Cuando pueda instaldo el Proteus 8.1 a ver que pasa. El código que he modificado es el siguiente. Lo puedes probar.

Si, ahora se parece más a como funciona en asm, pero no es confortable :confused: saber que sea solo por distintas versiones... tengo Proteus 8.1 SP1, adjunto el esquema para cuando tengas lo revisas.

Por cierto, hay muchos if else. ¿No crees que en este caso es mejor usar un Switch - Case?

Si, se puede acomodar de varias formas (me dijeron algunas vez... programar es como cocinar... cada quién lo adereza a su gusto :D ) pero técnicamente un Switch - Case puede ser algo más rápido que un If - Else (depende), solo que Switch aplica más para comprobar los valores de una variable y no por ejemplo para comprobar los estados de un Pin del PIC a menos que se lean los 4 pulsadores al mismo tiempo y se convierta en una variable de 4 bits... o poner todo el puerto en el Switch... pero ya es otro cantar...

Veré si se me ocurre otra estructura y la subo luego... o ya en el peor caso lo paso al CCS :D

Saludos.
 

Adjuntos

  • Demo F84 Simula.rar
    56.6 KB · Visitas: 18
Última edición:
Gracias, ni se te ocurra pasar al CCS, eso si acaso para el final, cuando XC8 esté completo y comparar.

Edito.

Si lo abro, el proteus 8.0 deja de funconar y se cierra, bajo windows 7.
 
Última edición:
Hola.
Ya con tiempo... trabajo con el Proteus 8.1 SP1 (problema con las versiones :unsure: es lo malo de proteus)... he hecho algunas modificaciones... algo estructurado.
Muestro solo el archivo C, pero adjunto el completo que utiliza dos archivos (main.c y main.h).

Código:
// Importa librarias
#define _XTAL_FREQ 4000000  // Cristal 4Mhz para calculos de tiempo
#include <xc.h>
#include "main.h"           // Otras declaraciones

// Configuración de Fuses
#pragma config FOSC = XT            // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config CP = OFF

//------------------------------------------------------------------------------
// Definiciones y macros.
#define DelayMs(x) __delay_ms(x)
#define DelayUs(x) __delay_us(x)

//------------------------------------------------------------------------------
// Declaración de prototipos
void AntiDebounce(void);
void OnMotor(void);
void OffMotor(void);
void Pitido(unsigned char np);

//------------------------------------------------------------------------------
// Declaración de variables
unsigned char cont;     // Contador
unsigned char seg;      // Segundos
unsigned char min;      // Minutos
unsigned char SetPoint; // Tiempo límite
unsigned char FinCont;  // True indica que ya se cumpió el tiempo.

unsigned char sCount;   // Contadores para los pitidos

//------------------------------------------------------------------------------
// Zona de Interrupción
void interrupt timer_tick(void){
    if(INTCONbits.TMR0IE && INTCONbits.TMR0IF){
        if(FinCont == False){               // Se asegura que esté permitido el conteo de tiempo
            if(++cont >= 50){               // 50 veces 19.968ms (1s aprox.)
                cont = 0;

                PORTBbits.RB0 = ~PORTBbits.RB0; /* TEST para Segundo */

                if(++seg > 59){             // Cuenta segundos
                    seg = 0;
                    if(++min >= SetPoint){  // Cuenta minutos, compara con los minutos programados
                        min = 0;
                        FinCont = True;     // Fin del conteo de minutos programados
                    }
                }
            }
        }

        TMR0 = 178;                 // preset for timer register
        INTCONbits.TMR0IF = 0;      // Limpia el Flag
    }
}

//------------------------------------------------------------------------------
// Flujo Principal
void main(void){
    OPTION_REGbits.T0CS = 0;    // Configura el Timer0
    OPTION_REGbits.T0SE = 0;
    OPTION_REGbits.PSA = 0;
    OPTION_REGbits.PS2 = 1;     // Prescaller 1:256
    OPTION_REGbits.PS1 = 1;
    OPTION_REGbits.PS0 = 1;

    PORTB = 0x00;               // Inicia todo desactivado
    TRISA = 0x1E;
    TRISB = 0x00;

    INTCONbits.TMR0IE = On;

    //-- Bucle principal
    while(1){
        if(!Button.BT1){                // On motor 5 minutos
            SetPoint = 5;               //  programa el tiempo
            OnMotor();                  //  activa el motor
            OUT.LEDs = OnLed1;
            Pitido(Corto);
            AntiDebounce();             //  y espera a que suelte el pulsador
        }
        else if(!Button.BT2){           // On motor 10 minutos
            SetPoint = 10;
            OnMotor();
            OUT.LEDs = OnLed2;
            Pitido(Corto);
            AntiDebounce();
        }
        else if(!Button.BT3){           // On...
            SetPoint = 20;
            OnMotor();
            OUT.LEDs = OnLed3;
            Pitido(Corto);
            AntiDebounce();
        }
        else if(!Button.BT4){           // STOP
            OffMotor();                 // Detiene el motor
            OUT.LEDs = Off;
            Pitido(Largo);
            AntiDebounce();
        }

        //-- Detiene el motor al finalizar el conteo

        if(FinCont == True){            // Detiene el Motor al final del conteo
            FinCont = False;
            OUT.LEDs = Off;
            Pitido(Triple);
            OffMotor();
        }
    }
}

//------------------------------------------------------------------------------
// Funciones.
//-> Espera a que suelten el pulsador
void AntiDebounce(void){
    while(Button.LIST != 0b1111){    // Espera que los 4 esten libres
        DelayMs(2);
    }
    DelayMs(5);             // Simple anti-rebotes
}

//-> Activa el motor por tiempo
void OnMotor(void){
    OUT.Motor = On;
    cont = seg = min = 0;   // Inicia las variables de conteo
    TMR0 = 178;             // Pre carga el timer
    OnTimerInt();           // Activa interrupciones (Timer)
}

//-> Desactiva el motor
void OffMotor(void){
    OffTimerInt();          // Desactiva interrupciones (Timer)
    OUT.Motor = Off;        // Apaga motor
}

//-> Pitidos de 900Hz aprox.
void Pitido(unsigned char tp){
    volatile unsigned char n, i, j;
    volatile unsigned int tmp;

    switch(tp){             // Ajusta el tiempo del pitido y la cantidad de repeticiones
        case Corto:
            tmp = 90;
            n = 1;
            break;

        case Largo:
            tmp = 255;
            n = 1;
            break;
        case Triple: 
            tmp = 90;
            n = 3;
            break;
    }

    for(i=0 ; i<n ; i++){       // Repite 'n' pitidos
        for(j=0 ; j<tmp ; j++){ // Generaonda cuadrada
            OUT.Sound1 = On;
            OUT.Sound2 = On;
            DelayUs(600);
            OUT.Sound1 = Off;
            OUT.Sound2 = Off;
            DelayUs(600);
        }

        if(tp == Triple){
            DelayMs(100);       // Espacio entre pitidos
        }
    }
}

Con el anterior, al parecer tenia algo raro con respecto a la lectura de pines porque la idea era que, ahúnque se mantenga presionado P1 por ejemplo, ya deberia de estar contando (interrupción es independiente) pero no lo hacia (el resto si funciona jeje)... bueno ahora está corregido. Seria mejor probar en uno real.

Vi lo anterior con respecto al pitido... los que simulan utilizando la salida de audio de PC son el SOUNDER (digital) y BUZZER (análogo)... el resto es de adorno. Para que suenen es necesario enviar un tren de pulsos a estos componentes...

Junto con la corrección he agregado un función Pitido() que hace casi lo que buscas... emite pulsos a un frecuencia de 900Hz aprox :unsure:
 

Adjuntos

  • V2_Demo_F84A.X.rar
    57.8 KB · Visitas: 39
Hola:

Pedazo de código, más que el asm. JEjejejeje.

Por cierto, quiero montarlo en el PIC16F88, ya que el PIC16F84A me di cuenta que no lo tengo físicamente.

¿Es fácil adaptarlo al PIC16F88?

¿Qué hay que hacer?

En el Proteus me funciona, con sonido raro pero funciona.

Voy a analizarlo más a fondo, a ver que tal.

Un saludo.

Edito:

Siguiendo este vídeo, intenté que me funcionase. En la demoboard no funciona, ejjeje. Había que intentarlo para aprender. Algo se me escapa, eso si, compila bien, pero no funciona.


El oscilador que uso para el PIC16F88 es el EC de 4 MHz. Dejo el proyecto completo, que en realidad es el mismo que el tuyo.

Saludo.
 

Adjuntos

  • PIC16F88_XC8_Motor_DC.X.zip
    74.9 KB · Visitas: 13
Última edición:
Meta te cometo que lo que hiciste esta bien y el buzzer suena correctamente, quizá al momento buscar el buzzer no elegiste el modelo activo. o no configuraste el voltaje de trabajo del mismo.
Por otro lado, ten en cuenta que el "transistor + el parlantito" no van a funcionar porque a diferencia del buzzer "el parlantito" para que suene necesita un onda distinta de DC así que para este habría que hacer una rutina que genere los tonos.
También le hice una pequeña modificación al programa para que "funcione mejor" al momento de presionar el pulsador.
PD. El tiempo corto de 20ms me parece muy corto.
 

Adjuntos

  • Dibujo1.JPG
    Dibujo1.JPG
    39.6 KB · Visitas: 8
  • Dibujo2.JPG
    Dibujo2.JPG
    51.9 KB · Visitas: 5
  • ej.rar
    38.1 KB · Visitas: 15
¿Es fácil adaptarlo al PIC16F88?
¿Qué hay que hacer?

Se tiene que ver que se utiliza en el F84.
- Fuses, pines digitales, Timer0 + Interrupciones.

> Tiene más bits de configuración... como usas cristal selecciona entre XT y HS, el resto es para usar reloj externo e interno.
Para el resto de fuses, revisa la hoja de datos.
> Los pines del 16F88 tienen más funciones y una de ellas es de entrada análoga... ésta se debe de desactivar (registro ANSEL).
> El registro de interrupción está algo modificado... es solo un bit, el PEIE que se tiene que activar.

El código lo puedes adaptar para la cantidad de PICs que quieras e incluso en un mismo archivo para n PICs... se puede usar algo como:

Código:
#ifdef _16F88
    INTCONbits.PEIE = On;       // Interrupción de periféricos
    ANSEL = 0;                  // Pines (I/O) digitales
    #endif

En #ifdef determina si se ha declarado el PIC16F88, si cumple entonces las líneas que están entre #ifdef - #endif se compila... de lo controario no.

Igual en los fuses... y para los cambios que requiera...
Código:
// Configuración de Fuses
//------------------------------------------------------------------------------
#ifndef _16F88
#pragma config FOSC = XT        // Configura para el 16F84A
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config CP = OFF
#else
// CONFIG2                      // Configura para el 16F88
#pragma config FOSC = XT      
#pragma config WDTE = OFF     
#pragma config PWRTE = OFF    
#pragma config MCLRE = ON     
#pragma config BOREN = ON     
#pragma config LVP = OFF      
#pragma config CPD = OFF      
#pragma config WRT = OFF      
#pragma config CCPMX = RB0    
#pragma config CP = OFF       

// CONFIG2
#pragma config FCMEN = ON     
#pragma config IESO = OFF     
#endif

Basta con cambiar de PIC en "Project Properties" y el resto se adapta....
 
Última edición:
Hola:

Probando esto, ni en el main, ni en cabeceras, lo acepta.

Código:
#ifdef _16F88     INTCONbits.PEIE = On;       // Interrupción de periféricos     ANSEL = 0;                  // Pines (I/O) digitales     #endif

Saint, gracias por decir lo del zumbador, aunque me deje zumbado. :D

Por cierto, no compila.
Código:
make -f nbproject/Makefile-default.mk SUBPROJECTS= .build-conf
make[1]: Entering directory `D:/Electronica/PIC/Motor DC PIC16F84A/ej/ej/ej_motor.X'
make  -f nbproject/Makefile-default.mk dist/default/production/ej_motor.X.production.hex
make[2]: *** No rule to make target `C:/Documents and Settings/henry/Escritorio/ej/ej_motor.X/ej_motor.asm', needed by `build/default/production/_ext/1042234281/ej_motor.o'.  Stop.
make[1]: *** [.build-conf] Error 2
make: *** [.build-impl] Error 2
make[2]: Entering directory `D:/Electronica/PIC/Motor DC PIC16F84A/ej/ej/ej_motor.X'
make[2]: Leaving directory `D:/Electronica/PIC/Motor DC PIC16F84A/ej/ej/ej_motor.X'
make[1]: Leaving directory `D:/Electronica/PIC/Motor DC PIC16F84A/ej/ej/ej_motor.X'

BUILD FAILED (exit value 2, total time: 314ms)

Debes tener el asm dentro del Source, aunque lo ponga dentro, no compila.

Gracias a los dos.
 
Probando esto, ni en el main, ni en cabeceras, lo acepta.
Código:
#ifdef _16F88     INTCONbits.PEIE = On;       // Interrupción de periféricos     ANSEL = 0;                  // Pines (I/O) digitales     #endif

Haz seleccionado el PIC respectivo??

Que es lo que dice?,
marca error,
no reconoce,
se pone de color Gris como si fuera comentario,
no compila...

Esto es una porción del código:
Código:
void main(void){
    OPTION_REGbits.T0CS = 0;    // Configura el Timer0
    OPTION_REGbits.T0SE = 0;
    OPTION_REGbits.PSA = 0;
    OPTION_REGbits.PS2 = 1;     // Prescaller 1:256
    OPTION_REGbits.PS1 = 1;
    OPTION_REGbits.PS0 = 1;

    PORTB = 0x00;               // Inicia todo desactivado
    TRISA = 0x1E;
    TRISB = 0x00;

    INTCONbits.TMR0IE = On;
    
    [COLOR="Blue"][B]#ifdef _16F88
    INTCONbits.PEIE = On;       // Interrupción de periféricos
    ANSEL = 0;                  // Pines (I/O) digitales
    #endif[/B][/COLOR]

    //-- Bucle principal
    while(1){
...

Igual en la zona de fuses... no hay mayor cambio.
Saludos.
 
Lo de no compila me refiero al proyecto de Saint_.

El tuyo si, me compila y el funionamiento no es el esperado. Por ejemplo. Si pulso el botón, se activa ese botón y se queda el LEd y motor activo, lo que si pulso otro en el momento que ya está acvtivo de antes, no se detiene y no empieza desde cero con otro botón.


Tampoco funciona el botón Stop.

Por ahora veo esto.
 
Adjunto... modificado sobre tu archivo, funciona con el F84A y F88 (Simulación).
Selecciona el PIC en Project Properties...

F88Sim.jpg
 

Adjuntos

  • Mod_PIC16F88_XC8_Motor_DC.X.rar
    65 KB · Visitas: 15
Hola:

Probando el programa en el proteus, me funciona el motor y los Led, probadno el PIC16F88 real, no me funciona bien, si pulso un botón, se queda el motor y el Led activo, luego no sale de ahí, debo apagar y encender el PIC de nuevo para que esté todo apagado y pulsar otro botón .

A lo mejor son el tema de los osciladores. Ya que us un resonador EC.

Ahora voy a probar un RC, resistencia y condensador..........

Tampoco funciona.
#pragma config FOSC = EXTRCIO

Tampoco con EXTRCCLK.

Lo curioso que en el Proteus si funciona, con lo que hice en el asm para el 16F88 a mi manera y asm si funciona. jejejejej.

Que cosa más curiosa. Que conste que tengo revisado mucho el montaje real.
 
Hola.
Proteus no simula todo... por ejemplo cuando se utiliza oscilador interno del PIC, salta avisos que indican que esa configuración no simula y que por defecto solo se utiliza la frecuencia programada... :)

Sobre los tipos de osciladores, soporta varios tipos (ver hoja de datos y comparar con la ventana de Configuration Bits en MPLABX).

Para resonador (cristal) externo se utiliza HS, XT y LP.
Para resistor + capacitor es RCIO (no recomendable).
Para Clock externo (utiliza pulsos de otro integrado), solo usa el CLKIN y el CLKOUT se convierte en en pin RA6. Modos EXTRC.
Para resonador (oscilador) interno son el INTRC, adicionalmente se debe de configurar el registro OSCCON que por defecto es a 8Mhz pero baja hasta 31.25khz (ver diagramas en el punto Oscillator Configuration de hoja de datos de F88).

Configura a XT (4Mhz), también está eso del switcheo de osciladores ya que puede usar el oscilador principal o secundario (del Timer1)... desactiva eso en los Fuses.
Luego eso del MCLR que puede trabajar como pin de entrada o pin de reset (ver)...

Saludos.
 
Atrás
Arriba