# Potenciometro para atrasar disparo



## marconikov (Mar 15, 2014)

lo que quiero es utilizar el potenciometro para generar disparos a un triac, se que hay una instruccion que permite leer el valor de resistencia y demas, pero la verdad es que no veo que pueda darle uso a eso..


----------



## Fogonazo (Mar 15, 2014)

marconikov dijo:


> lo que quiero es utilizar el potenciometro para generar disparos a un triac, se que hay una instruccion que permite leer el valor de resistencia y demas, pero la verdad es que no veo que pueda darle uso a eso..



No se comprende de que cosa estás hablando


----------



## marconikov (Mar 15, 2014)

me explico mejor, tengo un pic con el cual voy a generar disparos a un triac, la manera como lo estoy haciendo actualmente es mediante una interrupción presionando un pulsador.. (todo esto con su debido circuito detector de cruce por cero) pero no quiero hacerlo mediante un pulsador quiero saber si se existe la posibilidad de hacerlo con un potenciometro, es decir, el potenciometro tiene un valor decimal dependiendo de en que posicion este correcto ? por tanto si por ejemplo esta al 50 % de la resistencia, entonces eso equivaldria a 50% de recorte de la onda, en otras palabras el disparo deberia de dar cada pi/2 (ciclo +) y pi/2 (ciclo -), pero si muevo ahora el potenciometro a 75% entonces tendria otro recorte de onda y asi sucesivamente... me explique compañero ?


----------



## chclau (Mar 15, 2014)

El pic tiene entradas analogicas que miden tension. Hace un divisor reistivo con el pot y podras leer su posicion


----------



## marconikov (Mar 16, 2014)

creo que no me siguen.. a ver estaba viendo (corrijanme si me equivoco) una manera de hacer lo que dije pero no me da señal al simularlo en el proteus alguien sabra? :

DEFINE ADC_BITS 8 
DEFINE ADC_SAMPLEUS 50 
A VAR Byte
ADCON1 = %00000000
Inicio:
ADCIN 0, A 
PWM PORTB.0,A,100 
GoTo Inicio 
End


----------



## Saint_ (Mar 17, 2014)

Hola @marconikov, vamos por pasos.
1) creo comprender la idea que planteas.
- Variar el "ciclo de útil de trabajo" de cada semi-ciclo de la onda senoidal de la red eléctrica en función del valor resistivo de un potenciómetro, al final de cuentas un "dimer con PIC".
2) Si lo anterior es cierto, puedo comentarte lo siguiente.
Desde mi perspectiva lo que necesita no es un PWM (modulación por ancho de pulso) sino más bien un PPM (modulación por posición de pulso), esto tomando en cuenta que un triac solo necesita un pulso para dispararse.
Utilizando el ADC (conversor analógico a digital del pic) y conectándolo de la siguiente manera (figura) puedes determinar en que "porcentaje de giro" está el potenciómetro, por ejemplo:
En caso de que el potenciómetro este al 100% de su giro se obtendrá 5v y asumiendo que el voltaje de referencia del ADC también es de 5v y que estás trabajando con los 10 bits de resolución del ADC, el ADC leerá 1023, si el potenciómetro está al 50% de su giro el ADC leerá 511 y asi sucesivamente.
Con estos datos 1023,511,... etc., se puede calcular un "retardo" que dure desde el cruce por cero de la onda sinodal hasta el pulso de disparo para el TRIAC.
Con respecto al cruce por cero de la onda sinodal, el PIC tendría que detectarlo o quizá usar un circuito detector de cruce por cero externo que entregue al PIC un cambio de nivel o falco de subida o bajada por cada cruce por cero.

PD. Ni idea del compilador con el que estás trabajando pero dependiendo del compilador esta tarea podría ser más o menos difícil.


----------



## marconikov (Mar 17, 2014)

Excelente respuesta compañero, eso es básicamente lo que trataba de hacer, de hecho ya lo tengo y lo voy a publicar.


```
Define    LCD_DREG    PORTD
Define    LCD_DBIT    0
Define    LCD_RSREG    PORTD
Define    LCD_RSBIT    4
Define    LCD_EREG    PORTD
Define    LCD_EBIT    5
A var byte
i var byte
TRISB = %00000010
TRISD = %00000000
DEFINE ADC_BITS 8 ' Define la conversión A/D a 8 Bits
DEFINE ADC_SAMPLEUS 50 ' Tiempo de muestreo en el conversor A/D es 50 uS
lcdout $fe,1
Inicio:
ADCIN 0, A ' Inicia la conversión, almacena el resultado en "A"
if portb.1=1 then call triac
goto inicio


Triac:
call delay
high portb.0
pause 1/100
low portb.0
return

Delay:
for i=0 to A
pause 324/10000
next
return
```

Funciona tal como necesito, el único problema que vi es que no puedo acoplar al mismo PIC un LCD porque los tiempos que transcurren para operar con el LCD se interponen con los del manejo de ciclo útil.


----------



## marconikov (Mar 17, 2014)

Estoy usando el pic16f877a para una pequeña aplicación es la de variar el ciclo útil de trabajo de una onda para así mandar pulsos a un triac, la cuestión es que todo trabajo como debería!
Pero ahora quiero agregar unas líneas de códigos para mostrar cierta información por una pantalla LCD y al agregar esas líneas de códigos veo que el ciclo útil y por consiguiente la onda se distorsiona como si el delay aplicado se modificara  
Acá dejo una imagen con el problema detallado, agradecería su ayuda, como siempre me han sabido dar respuesta a este tipo de situaciones.

Antes:

```
A var byte
i var byte
TRISB = %00000010
DEFINE ADC_BITS 8 ' Define la conversión A/D a 8 Bits
DEFINE ADC_SAMPLEUS 50 ' Tiempo de muestreo en el conversor A/D es 50 uS
Inicio:
ADCIN 0, A ' Inicia la conversión, almacena el resultado en "A"
if portb.1=1 then call triac
goto inicio

Triac:
call delay
high portb.0
pause 1/100
low portb.0
return

Delay:
for i=0 to A
pause 324/10000
next
return


DESPUES:
Define    LCD_DREG    PORTD
Define    LCD_DBIT    0
Define    LCD_RSREG    PORTD
Define    LCD_RSBIT    4
Define    LCD_EREG    PORTD
Define    LCD_EBIT    5
A var byte
i var byte
TRISB = %00000010
TRISD = %00000000
DEFINE ADC_BITS 8 ' Define la conversión A/D a 8 Bits
DEFINE ADC_SAMPLEUS 50 ' Tiempo de muestreo en el conversor A/D es 50 uS
lcdout $fe,1
Inicio:
ADCIN 0, A ' Inicia la conversión, almacena el resultado en "A"
LCDOut $fe, 2 ' Posiciona el cursor en el inicio
LCDOUT "Grados de desf: " ' Muestra mensaje en la línea 1
LCDOUT $fe,$C0," ",dec A/100," " ' Muestra dato en la línea 2
if portb.1=1 then call triac
goto inicio

Triac:
call delay
high portb.0
pause 1/100
low portb.0
return

Delay:
for i=0 to A
pause 324/10000
next
return
```


----------



## Saint_ (Mar 17, 2014)

Para ese tipo de problemas "biene corriendo en caballo blanco las interrupciones".
Ya que los "tiempos se crusan" para el retardo y los tiempos del LCD, se puede utilizar una de las interrupciones temporizadas para el disparo de TRIAC, y asi la rutina pricipal se ocuparia del LCD.
Puedes crear un tiempo base de 0.1 ms, asi tendias resolucion de 1% para un semiperiodo de 10ms.


----------



## ByAxel (Mar 17, 2014)

Las líneas del LCD se ejecutan durante el tiempo, éste tiempo se suma y es muy provable que que el PIC pierda pulsos del cruce por cero. Opciones:

A) Puedes ajustar los delays para que vuelva a trabajar correctamente... pero el problema es que si quitas o agregas más líneas de código, estas van a sumar tiempo dando el mismo inconveniente.
B) Capturar el cruce por cero por interrupción y controlar al triac en la interrupción...


----------



## marconikov (Mar 17, 2014)

Ok, lo haré por la segunda opción, una interrupción por flanco alto.
Te cuento después como me va.

---------- Actualizado después de 1 hora ----------

Lo hice por el método que me dijiste. ¿Se supone que debería ocurrir esto, no?
Pasa por cero la onda y se interrumpe el programa, antes de que continué  todo hago un retardo dependiendo de la posición donde este el potenciómetro, después que sale de la interrupción debería mandar el  pulso.


```
A var byte
i var byte
TRISB = %00000001
DEFINE ADC_BITS 8 ' Define la conversión A/D a 8 Bits
DEFINE ADC_SAMPLEUS 50 ' Tiempo de muestreo en el conversor A/D es 50 uS
on interrupt goto Int
INTCON = %10010000
OPTION_REG.6 = 0

Inicio:
call triac
goto inicio

Triac:
call delay
high portb.1
pause 1/100
low portb.1
return

Delay:
for i=0 to A
pause 324/10000
next
return

Int:
disable
ADCIN 0, A ' Inicia la conversión, almacena el resultado en "A"
call delay 
INTCON = %10010000
enable
resume

end
```
Lo que está ocurriendo es que veo solo pulsos que no  cambian con el tiempo indiferentemente de la posición del potenciómetro,  no se ve ninguna onda de salida.


----------



## ByAxel (Mar 17, 2014)

Me referia a poner la rutina que controla al triac cuando sucede la interrupción, es decir que, se supone que el cruce por cero es el que manda, por lo tanto el PIC deberia de responder inmediatamente cuando hay flanco activo.

Algo asi:


```
Inicio:
ADCIN 0, A ' Inicia la conversión, almacena el resultado en "A"
' Otro delay...
' Más cosas
goto inicio

Delay:
for i=0 to A
pause 324/10000
next
return

Int:
disable

call delay
high portb.1
pause 1/100
low portb.1

INTCON = %10010000
enable
resume

end
```

Con eso la variable A se mantiene actualizada siempre (o también se puede actualizar en la interrupción), luego es usado en la interrupción cuando hay flanco.

Saludos


----------



## marconikov (Mar 18, 2014)

Estoy tratando de hacerlo por ese medio y de hecho estoy verificando la secuencia de las instrucciones con unos leds que conecté, pero al momento que ocurre el flanco alto en rb0 que pasa a la subrutina de interrupción el proteus se vuelve loco y no sale de la subrutina, sino que manda un montón de mensajes de "Stack overflow executing call instruction".

Logré solventar el problema quitando la instrucción call y colocando directamente la rutina.
¿Realmente no sé por qué ocurre eso? Otra cuestión, volví a colocar el código con mis líneas para el LCD y pasa lo mismo que te había comentado.
Anexo la imagen y el código:


```
Define    LCD_DREG    PORTD
Define    LCD_DBIT    0
Define    LCD_RSREG    PORTD
Define    LCD_RSBIT    4
Define    LCD_EREG    PORTD
Define    LCD_EBIT    5

A var byte
i var byte
TRISB = %00000001
DEFINE ADC_BITS 8 ' Define la conversión A/D a 8 Bits
DEFINE ADC_SAMPLEUS 50 ' Tiempo de muestreo en el conversor A/D es 50 uS
on interrupt goto Int
INTCON = %10010000
OPTION_REG.6 = 0

Inicio:
ADCIN 0, A 
LCDOut $fe, 2 
LCDOUT "Grados de desf: " 
LCDOUT $fe,$C0," ",dec A/100," "
goto inicio

Triac:
call delay
high portb.1
pause 1/100
low portb.1
return

Delay:
for i=0 to A
pause 324/10000
next
return

Int:
disable
for i=0 to A
pause 324/10000
next
high portb.1
pause 1/100
low portb.1
INTCON = %10010000
enable
resume

end
```


----------



## marconikov (Mar 18, 2014)

podrias facilitarme una guia o material teorico referente a eso ?  realmente no te capto


----------



## ByAxel (Mar 18, 2014)

mmm aquí me quedo, no estoy seguro pero por el comportamiento que describes es posible que las instrucciones para el LCD desactiven temporalmente las interrupciones... porque? puede que tenga como preferencia el envio de datos al LCD... veré si hay info al respecto o como configurar o si se me ocurre otra forma de tratar la lógica... pero parece que PicBasic se queda corto para lo que pretendes...

Sobre call, puede que pierda la dirección de retorno de la pila, por eso hay esos avisos... esto ya es cosa del compilador... pero intenta con GoSub...

Saludos.


----------



## marconikov (Mar 18, 2014)

ah, ya en otro tema estaba hablando con un compañero y me habia recomendado algo referente a interrupciones pero de manera diferente a como la estoy trabajando, quizas sabes a lo que me refiero, es de hacer uso de la interrupcion para que en ese tiempo trabaje con los triacs y mientras que no haya interrupcion trabaje con el LCD, pero no entendi muy bien..


----------



## fdesergio (Mar 18, 2014)

Se deben priorizar procesos, en tu caso la prioridad es el manejo del triac y despues el LCD, usa las INTs para la deteccion del cruce por cero y disparo del triac.


----------



## marconikov (Mar 18, 2014)

asi es como esta configurado compañero, la interrupcion se genera cuando pasa por cero, se hace un delay para luego disparar el TRIAC y sale de la interrupcion para volver al main; según el resultado que obtengo esa no es la manera compañero..


----------



## fdesergio (Mar 18, 2014)

Estas seguro que entre 2 pulso de cruce por cero podes hacer el manejo del LCD?? por ahi podes tener tu problema, debes segmentar el manejo del LCD, que muestras en el LCD??


----------



## marconikov (Mar 19, 2014)

estoy mostrando los grados de desfasaje, segmentar el manejo del LCD?? eso lo hago con insterrupciones ?


----------



## Saint_ (Mar 19, 2014)

markonikov, esta mi sugerencia del como podrías solucionar el problema con el LCD.
Asumiendo que tienes un detector de cruce por cero externo y que entrega una onda cuadrada de modo que cuando empieza un semi ciclo positivo genera un flanco de subida y cuando empieza un semi ciclo negativo genera un flanco de bajada.
Periodo de cada semi ciclo igual a 10ms, asumiendo que la frecuencia de línea es 50Hz.

Los procesos prioritarios para el microcontrolador son.
-detección de cruce por cero
-pulso de disparo para el triac.

Procesos que no son muy prioritarios
-visualización en el LCD
-lectura del conversor analógico a digital


```
En la rutina principal (main)
     Configurar la interrupción externa por flanco de subida
     Configurar la interrupción temporizada (por ejemplo el timer 0) a 100us.
     En bucle infinito (while=true)
          Lectura del adc
          Calculo de tiempo de disparo del triac en ente 1 y 90 en función del dato leído por el ADC
          Mostar en el LCD el mensaje deseado
     Fin de bucle infinito
Fin de main

Rutina de interrupción externa
     Si es flanco de subida
          Cambiar a flanco de bajada
     Si no
          Cambiar a flanco de subida
     Fin si
     Iniciar, activar, dispara al temporizador
Fin de interrupción externa

Rutina de interrupción temporizada
     Si variable de cuenta  = a tiempo de disparo del triac (1 y 90)
          Dispara el triac
          Reiniciar variable de cuenta
          Detener el temporizador
     Fin fi 
     Cargar los registros del temporizador para un tiempo de 100us
Fin de interrupción
```

Este pseudocodigo es funcional asumiendo que el compilador que usas no desactive las interrupciones cuando escribe mensajes en el LCD, de otro modo abría que buscar soluciones de mas bajo nivel como el manejo del LCD sin la ayuda de la librería.

PD. Normalmente trabajo en compiladores en C como el CCS PICC y Mikro C tambien en ASM,  por lo cual no puedo hacer mucho con el código que tienes.


----------



## marconikov (Mar 19, 2014)

yo tambien trabajo con assembler lo entiendo mas que los demas, solo que por facilidad uso basic.. intentare hacer lo que dices compañero, en todo caso gracias por la ayuda.

me surge una duda referente al código:
para establecer el vector de interrupción escribo "on interrupt goto >>etiqueta<<" pero si tengo 2 interrupciones :S ?? solo puedo definir una sola etiqueta no ?


----------



## Saint_ (Mar 20, 2014)

Una interrupcion en asm se vectoriz del siguente modo:


```
org 0x04

     btfsc INTCON,TMR0IF
     goto interrupcion_timer0
     btfsc INTCON,INTF
     goto interrupcion_externa
     .
     .
     .
interrupcion_timer
     codigo
interrupcion_externa
     codigo
```
obiamente antes de salir de la interrupcion hay que borrar el flag de interrupcion correspondiente y terminar con un _retfie_ para que regrese a la rutina principal.


----------



## fdesergio (Mar 20, 2014)

Saint_ dijo:


> Una interrupcion en asm se vectoriz del siguente modo:
> 
> 
> ```
> ...



mmm falta bastante, se debe guardar el contenido de los REGs auxiliares (W, STATUS y etc) porque si la rutina de INT los modifica se producen errores al retrornar al programa principal, ademas antes de salir de la INT se deben restaurar a su estado original dichos REGs, lo mejor copia esta parte  de la plantilla del pic que sugiere microchip, chauuuuuuu


----------



## Saint_ (Mar 20, 2014)

fdsergio, lo que dices es cierto, en el caso respodi a la forma vectorizar las interrupciones y obviamente di por hecho esos detalles, pero valga la observación.


----------



## Saint_ (Mar 21, 2014)

hola @marconikov, "pensandolo un poco, como que esta complicadito" hacer el programa es asm, pero a grandes problemas, grandes soluciones.
aqui va, fue hecho en MPLABX

```
include <p16f877.inc>
    list p=16f877
     __CONFIG _FOSC_XT & _WDTE_OFF & _PWRTE_ON & _CP_OFF & _BOREN_ON & _LVP_OFF & _CPD_OFF & _WRT_ON
;*****************************************************
;Declaracion de variables y constantes
;*****************************************************
#define     lcd     PORTD       ;puerto d para el el lcd
#define     rs      PORTC,0     ;
#define     en      PORTC,1     ;
cargar_timer equ .178
;****************************
;Para la rutina de divicion
;****************************
TRUE    equ     1       ;
FALSE   equ     0       ;
SIGNED  equ     FALSE   ;divicion sin signo
;****************************
udata   0x20
cont_timer  res 1
;****************************
;Para la rutina de divicion
;****************************
ACCaLO      res 1
ACCaHI      res 1
ACCbLO      res 1
ACCbHI      res 1
ACCcLO      res 1
ACCcHI      res 1
ACCdLO      res 1
ACCdHI      res 1
temp        res 1
sign        res 1
;*****************************************************
n1          res 1
W_TEMP      res 1
STATUS_TEMP res 1
PCLATH_TEMP res 1
;***************************************************
;Para la rutina de convercion bin16 a BCD
;***************************************************
count       res 1
;temp        res 1
H_byte      res 1
L_byte      res 1
R0          res 1
R1          res 1
R2          res 1
;***************************************************
PDel0       res 1   ;para el terardo de 10ms
PDel1       res 1   ;
n_lcd        res 1    ;contador de caracteres para el LCD



    org 0x00
    goto    inicio
    org 0x04
;**********************************************
;Bloque de interrupciones
;**********************************************
interrupciones
push
    MOVWF   W_TEMP
    SWAPF   STATUS,W
    CLRF    STATUS
    MOVWF   STATUS_TEMP
    MOVF    PCLATH,W
    MOVWF   PCLATH_TEMP
    CLRF    PCLATH

    btfsc   INTCON,INTF
    goto    interrupcion_externa
    btfss   INTCON,TMR0IF
    goto    salida_de_interrupcion
;************************************************
interrupcion_temporizada
    bcf     INTCON,TMR0IF
    btfss   PORTB,1
    goto    i0
    banksel OPTION_REG              ;bank 1
    bsf     OPTION_REG,T0CS         ;timer0 stop
    banksel PORTB                   ;bank 0
    bcf     PORTB,1
i0
    decfsz  n1,F
    goto    siguiente_carga
    bsf     PORTB,1
siguiente_carga
    movlw   cargar_timer
    movwf   TMR0
    goto    salida_de_interrupcion
;************************************************
interrupcion_externa
    movlw   cargar_timer+.12
    movwf   TMR0
    banksel OPTION_REG          ;bank1
    btfss   OPTION_REG,INTEDG
    goto    config_flanco_subida
config_fanco_bajada
    bcf     OPTION_REG,INTEDG
    goto    $+2
config_flanco_subida
    bsf     OPTION_REG,INTEDG
    bcf     OPTION_REG,T0CS     ;timer0 run
    banksel INTCON              ;bank0
    bcf     INTCON,INTF
    movfw   cont_timer
    movwf   n1
salida_de_interrupcion
pop
    MOVF    PCLATH_TEMP, W
    MOVWF   PCLATH
    SWAPF   STATUS_TEMP,W
    MOVWF   STATUS
    SWAPF   W_TEMP,F
    SWAPF   W_TEMP,W
    retfie
;*********************************************
inicio
;*********************************************
;Cionfiguracion de las interrupciones
;*********************************************
    movlw   b'10110000'
    movwf   INTCON
;*********************************************
;configuracion de puertos de entrada y salida
;*********************************************
    clrf    PORTB
    banksel TRISB           ;bank 1
    movlw   b'11111101'
    clrf    TRISD
    bcf     TRISC,0
    bcf     TRISC,1
    movwf   TRISB
;*********************************************
;Configuracion del ADC
;*********************************************
    banksel ADCON0          ;bank 0
    movlw   b'11000001'
    movwf   ADCON0
    banksel ADCON1          ;bank 1
    movlw   b'11001110'
    movwf   ADCON1
;*********************************************
    banksel ADCON0          ;bank 0
    call        limpiar_lcd
    call        c_der_quieto
    call        si_visual_no_cur_no_parpadeo
    call        cursor_home
    call        esc_mensaje
    call        desp_cur_iz
    call        desp_cur_iz
    call        desp_cur_iz
loop
    bsf     ADCON0,GO
    btfsc   ADCON0,GO
    goto    $-1
    movfw   ADRESH
    movwf   ACCbHI
    banksel ADRESL          ;bank 1
    movfw   ADRESL
    banksel PORTA           ;bank 0
    movwf   ACCbLO
    clrf    ACCaHI
    movlw   0x0a
    movwf   ACCaLO
    call    D_divS
    movfw   ACCbLO
    movwf   cont_timer
    movwf   L_byte
    clrf    H_byte
    call    B2_BCD
    call        desp_cur_iz
    call        desp_cur_iz
    call        desp_cur_iz
    swapf       R2,W
    andlw       0x0f
    iorlw       0x30
    call        escribir
    call        desp_cur_der
    movfw       R2
    andlw       0x0f
    iorlw       0x30
    call        escribir
    goto    loop
;*******************************************
;Subrutinas
;*******************************************
;subrutina de divicion
;*******************************************************************
;SIGNED  equ     FALSE           Set This To 'TRUE' if the routines
;                               ; for Multiplication & Division needs
;                               ; to be assembled as Signed Integer
;                               ; Routines. If 'FALSE' the above two
;                               ; routines ( D_mpy & D_div ) use
;                               ; unsigned arithmetic.
;*******************************************************************
;       Double Precision Divide ( 16/16 -> 16 )
;       ( ACCb/ACCa -> ACCb with remainder in ACCc ) : 16 bit output
; with Quotiont in ACCb (ACCbHI,ACCbLO) and Remainder in ACCc (ACCcHI,ACCcLO).
;   NOTE  :  Before calling this routine, the user should make sure that
;            the Numerator(ACCb) is greater than Denominator(ACCa). If
;            the case is not true, the user should scale either Numerator
;            or Denominator or both such that Numerator is greater than
;            the Denominator.
;********************************************************************
D_divS
    IF   SIGNED
    CALL    S_SIGN
    ENDIF
    call    setup
    clrf    ACCcHI
    clrf    ACCcLO
dloop
    bcf     STATUS,C
    rlf     ACCdLO, F
    rlf     ACCdHI, F
    rlf     ACCcLO, F
    rlf     ACCcHI, F
    movf    ACCaHI,W
    subwf   ACCcHI,W          ;check if a>c
    btfss   STATUS,Z
    goto    nochk
    movf    ACCaLO,W
    subwf   ACCcLO,W        ;if msb equal then check lsb
nochk
    btfss   STATUS,C    ;carry set if c>a
    goto    nogo
    movf    ACCaLO,W        ;c-a into c
    subwf   ACCcLO, F
    btfss   STATUS,C
    decf    ACCcHI, F
    movf    ACCaHI,W
    subwf   ACCcHI, F
    bsf     STATUS,C    ;shift a 1 into b (result)
nogo
    rlf     ACCbLO, F
    rlf     ACCbHI, F
    decfsz  temp, F         ;loop untill all bits checked
    goto    dloop
    IF    SIGNED
    btfss   sign,MSB        ; check sign if negative
    retlw   0
    goto    neg_B          ; negate ACCa ( -ACCa -> ACCa )
    ELSE
    retlw   0
    ENDIF
;*******************************************************************
setup
    movlw   .16             ; for 16 shifts
    movwf   temp
    movf    ACCbHI,W          ;move ACCb to ACCd
    movwf   ACCdHI
    movf    ACCbLO,W
    movwf   ACCdLO
    clrf    ACCbHI
    clrf    ACCbLO
    retlw   0
;*******************************************************************
neg_A
    comf    ACCaLO, F       ; negate ACCa ( -ACCa -> ACCa )
    incf    ACCaLO, F
    btfsc   STATUS,Z
    decf    ACCaHI, F
    comf    ACCaHI, F
    retlw   0
;*******************************************************************
;  Assemble this section only if Signed Arithmetic Needed
    IF    SIGNED
S_SIGN
    movf    ACCaHI,W
    xorwf   ACCbHI,W
    movwf   sign
    btfss   ACCbHI,MSB        ; if MSB set go & negate ACCb
    goto    chek_A
    comf    ACCbLO          ; negate ACCb
    incf    ACCbLO
    btfsc   STATUS,Z
    decf    ACCbHI
    comf    ACCbHI
chek_A
    btfss   ACCaHI,MSB        ; if MSB set go & negate ACCa
    retlw   0
    goto    neg_A
    ENDIF
;********************************************************************
;                  Binary To BCD Conversion Routine
;      This routine converts a 16 Bit binary Number to a 5 Digit
; BCD Number. This routine is useful since PIC16C55 & PIC16C57
; have  two 8 bit ports and one 4 bit port ( total of 5 BCD digits)
;       The 16 bit binary number is input in locations H_byte and
; L_byte with the high byte in H_byte.
;       The 5 digit BCD number is returned in R0, R1 and R2 with R0
; containing the MSD in its right most nibble.
;*******************************************************************;
B2_BCD
    bcf     STATUS,0                ; clear the carry bit
    movlw   .16
    movwf   count
    clrf    R0
    clrf    R1
    clrf    R2
loop16
    rlf     L_byte, F
    rlf     H_byte, F
    rlf     R2, F
    rlf     R1, F
    rlf     R0, F
    decfsz  count, F
    goto    adjDEC
    RETLW   0
adjDEC
    movlw   R2
    movwf   FSR
    call    adjBCD
    movlw   R1
    movwf   FSR
    call    adjBCD
    movlw   R0
    movwf   FSR
    call    adjBCD
    goto    loop16
adjBCD
    movlw   3
    addwf   0,W
    movwf   temp
    btfsc   temp,3          ; test if result > 7
    movwf   0
    movlw   30
    addwf   0,W
    movwf   temp
    btfsc   temp,7          ; test if result > 7
    movwf   0               ; save as MSD
    RETLW   0
;**************************************************************
; Libreria de subrutinas para el manejo de LCD alfanumerico
;**************************************************************
;                Retardo de 10ms para el LCD (Frec xtal=4MHz)
;Se deben configurar manualmente los puertos para que seran
;utilizados para el LCD
;**************************************************************
;cblock
;PDel0
;PDel1
;endc
;#define        lcd PORTB
;#define        rs PORTA,3
;#define        en PORTA,0
;*******************************************************
retardo     movlw     .15                        ;.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
;*******************************************************************
;            Habilita el regisyro de control del LCD
;*******************************************************************
comando
            bcf     rs
            movwf     lcd
            bsf     en
            nop
            nop
            bcf     en
            call     retardo
            return
;*******************************************************************
; Habilita el registro de datos del LCD requiere dato en w
;*******************************************************************
escribir
            bsf     rs
            movwf     lcd
            bsf     en
            nop
            nop
            bcf     en
            call     retardo
            return
;*******************************************************************
;            Comandos para el LCD
;*******************************************************************
limpiar_lcd
            movlw    b'00000001'
            call    comando
            return
;*******************************************************************
cursor_home
            movlw    b'00000010'
            call    comando
            return
;*******************************************************************
;            Modo de funcionamiento
;*******************************************************************
;    desplazamiento de cursor a la izquierda, lcd permanese quieto
;*******************************************************************
c_iz_quieto
            movlw    b'00000100'
            call    comando
            return
;********************************************************************
;    desplazamiento de cursor a la izquierda, lcd se desplaza
;********************************************************************
c_iz_desplaza
            movlw    b'00000101'
            call    comando
            return
;********************************************************************
;    desplazamiento de cursor a la derecha, lcd permanese quieto
;********************************************************************
c_der_quieto
            movlw    b'00000110'
            call    comando
            return
;********************************************************************
;    desplazamiento de cursor a la derecha, lcd permanese quieto
;********************************************************************
c_der_desplaza
            movlw    b'00000111'
            call    comando
            return
;********************************************************************
;            Comtrol ON/OFF
;********************************************************************
;No se visualiza datos, el cursor no se ve, cursor no parpadea
;********************************************************************
no_visual_no_cur_no_parpadeo
            movlw    b'00001000'
            call    comando
            return
;********************************************************************
;No se visualiza datos, el cursor no se ve, cursor parpadea
;********************************************************************
no_visual_no_cur_si_parpadeo
            movlw    b'00001001'
            call    comando
            return
;********************************************************************
;No se visualiza datos, el cursor se ve, cursor no parpadea
;********************************************************************
no_visual_si_cur_no_parpadeo
            movlw    b'00001010'
            call    comando
            return
;********************************************************************
;No se visualiza datos, el cursor se ve, cursor parpadea
;********************************************************************
no_visual_si_cur_si_parpadeo
            movlw    b'00001011'
            call    comando
            return
;********************************************************************
; Se visualiza datos, el cursor no se ve, cursor no parpadea
;********************************************************************
si_visual_no_cur_no_parpadeo
            movlw    b'00001100'
            call    comando
            return
;********************************************************************
; Se visualiza datos, el cursor no se ve, cursor parpadea
;********************************************************************
si_visual_no_cur_si_parpadeo
            movlw    b'00001101'
            call    comando
            return
;********************************************************************
;Se visualiza datos, el cursor se ve, cursor no parpadea
;********************************************************************
si_visual_si_cur_no_parpadeo
            movlw    b'00001110'
            call    comando
            return
;********************************************************************
;Se visualiza datos, el cursor se ve, cursor parpadea
;********************************************************************
si_visual_si_cur_si_parpadeo
            movlw    b'00001111'
            call    comando
            return
;********************************************************************
;    Desplazamienro de cursor/LCD
;********************************************************************
;    Se desplaza el cursor a la izquierda
;********************************************************************
desp_cur_iz
            movlw    b'00010000'
            call    comando
            return
;********************************************************************
;    Se desplaza el cursor a la derecha
;********************************************************************
desp_cur_der
            movlw    b'00010100'
            call    comando
            return
;********************************************************************
;    Se desplaza el LCD a la izquierda
;********************************************************************
desp_lcd_iz
            movlw    b'00011000'
            call    comando
            return
;********************************************************************
;    Se desplaza el LCD a la derecha
;********************************************************************
desp_lcd_der
            movlw    b'00011100'
            call    comando
            return
;********************************************************************
;                Transferencia de Informacion
;********************************************************************
;    Bus en modo de 4 y 8 bits
;********************************************************************
bus_4_bits
            movlw    b'00101000'
            call    comando
            return
;********************************************************************
bus_8_bits
            movlw    b'00111000'
            call    comando
            return
;*********************************************************************
;Acceso a la CGRam(cargar en w la direccion,64 direciones,8 caracteres)
;*********************************************************************
cg_ram
            iorlw    b'01000000'
            call     comando
            return
;*********************************************************************
; Acceso a la DDRam(cargar en w la direccion, 40 caracteres por linea)
;*********************************************************************
dd_ram_linea_1
            iorlw    b'10000000'
            call    comando
            return
;*********************************************************************
dd_ram_linea_2
            iorlw    b'11000000'
            call    comando
            return
;********************************************************************
;        Escribir un mensage el el LCD
;********************************************************************
;cblock
;n_lcd            ;contador de caracteres
;endc
;***********************************************************************
esc_mensaje
            clrf        n_lcd
            incf        PCLATH
lcd_0
            movfw         n_lcd
            call        men_0
            xorlw         0
            btfsc         STATUS,Z
            goto        lcd_1
            call         escribir
            incf         n_lcd
            goto         lcd_0
lcd_1
            return
;***************************************************
men_0
            addwf    PCL,F
            dt    "Disparo a: . ms.",0
;***************************************************
    end
```
te correspode agregarle el TRIAC y demas cosas que falten.


----------



## marconikov (Mar 23, 2014)

gracias compañero   , voy analizar el codigo para ver que tal, en el isis yo le coloco lo que falta para que este funcional


----------



## marconikov (May 1, 2014)

buenas a todos compañeros, me encuentro realizando la depuracion del siguiente codigo y me he encontrado con algo un tanto extraño... y es que la interrupcion por medio del temporizador no esta ocurriendol, he revisado el codigo y encuanto a configuraciones todo esta bien realmente no lo entiendo.. puedo ver que esta fallando porque cuando carga el valor al TMR0 de 50, lo veo en los registros que carga a "50" y luego empieza a incrementarse hasta que se desborda y regresa a la rutina de interrupcion pero esto no ocurre, simplemente sigue y sigue

254, 255, 0, 1, 2, 3 .... hasta llega un momento donde cambia de signo , 
estoy censando cuando se mete en la rutina de interrupcion, verificando las intrucciones que se estan ejecutando.

estoy usando el PBP, y lo estoy depurando en PROTEUS


```
;CONFIGURACION DEL LCD
DEFINE LCD_DREG PORTD 
DEFINE LCD_BITS 4 
DEFINE LCD_DBIT 4
DEFINE LCD_RSREG PORTC 
DEFINE LCD_RSBIT 0 
DEFINE LCD_EREG PORTC 
DEFINE LCD_EBIT 1 
X VAR BYTE
CONT VAR BYTE
AUX VAR BYTE
A var byte
;CONFIGURACIONES DE LOS PUERTOS E/S
TRISB = %00000001  
TRISD = 0
TRISC = 0
;HABILITO LAS INTERRUPCIONES, POR RB0 Y POR TMR0
INTCON = %10110000
on interrupt goto INTERRUPCION
Symbol INTF = INTCON.1
SYMBOL GIE = INTCON.7
SYMBOL TMR0IF = INTCON.2
SYMBOL TOCS = OPTION_REG.5
SYMBOL INTEDG = OPTION_REG.6
X=0
;CONFIGURACION PARA CONVERSOR A/D
ADCON0 = %11000001
ADCON1 = %00001110
;RUTINA DEL LCD
lcdout $fe,1

BUCLE:
adcin 0, A
X = (((47)*A)-(175))/100 
LCDOUT $fe,2,"Disparo a "
lcdout $fe,$c0, "  ",dec X , "  "
goto BUCLE

;RUTINA DE INTERRUPCION
INTERRUPCION:
DISABLE
PORTB.3 = 1
if INTF = 1 THEN INT_EXT ;5 us
IF TMR0IF = 1 THEN INT_TIMER ; 5 us
;INTERRUPCION POR TEMPORIZADO
INT_TIMER:
TMR0IF = 0 ;1 us
IF PORTB.1 = 1 THEN ;10 us
	TOCS = 1
	PORTB.1 = 0 
endif
IF x-1=0 THEN PORTB.1 = 1 ;44us
TMR0 = 100 ; 2 us
GOTO SALIDA_INT ;5 us
;INTERRUPCION POR CRUCE POR CERO
INT_EXT:
INTF = 0 ; 1 us
TMR0 = 50 ; 2 us ; 23.132 ms
SELECT CASE INTEDG ; 0 us
CASE 0 ; 21 us 
INTEDG = 1 ; 3 us
CASE 1 ; 21 us
INTEDG = 0 ; 3 us
END SELECT
TOCS = 0 ; 3 us  23.157 ms 
CONT=X ; 2 us
;FIN DE LA RUTINA DE INTERRUPCION
SALIDA_INT:
GIE = 1 ; 1 us
ENABLE
RESUME
END
```


----------



## D@rkbytes (May 1, 2014)

marconikov dijo:
			
		

> Buenas a todos compañeros.
> Me encuentro realizando la depuración del siguiente código y me he encontrado con algo un tanto extraño, y es que la interrupción por medio del temporizador no está ocurriendo, he revisado el código y en cuanto a configuraciones todo esta bien realmente no lo entiendo.. puedo ver que esta fallando porque cuando carga el valor al TMR0 de 50, lo veo en los registros que carga a "50" y luego empieza a incrementarse hasta que se desborda y regresa a la rutina de interrupción pero esto no ocurre, simplemente sigue y sigue
> 
> 254, 255, 0, 1, 2, 3 .... Hasta llega un momento donde cambia de signo ,
> ...


No mencionas que tipo de PIC estás usando, pero al parecer es un PIC16F877/A 
Tampoco veo que estés definiendo la velocidad de reloj y por defecto serán 4MHz.

Por lo que no debe estar trabajando bien tu rutina de interrupción es porque no estás configurando el prescaler.
Por defecto el valor del prescaler para el TMR0 es de 1:256 si el bit PSA estuviera en 0, pero al estar en 1 queda asignado al Watch Dog Timer, o sea, el registro OPTION_REG se encuentra siempre en 0xFF.

Configura el registro OPTION_REG, por ejemplo con este valor: %10000000
Así tendrás el prescaler a 1:2 y asignado al TMR0.

Si necesitas otro tipo de valor en el prescaler, ve el registro OPTION_REG en la hoja de datos.

Nota:
Preferentemente también pon en 1 el bit 6 (PEIE: Peripheral Interrupt Enable bit) del registro INTCON.
Para depurar mejor el programa en proteus debes usar PBP3 para que te genere el archivo *.cof.

Suerte.


----------



## marconikov (May 3, 2014)

estoy consciente de lo del preescaler de hecho asi como esta funciona tal como necesito, con cada ciclo de instruccion este se incrementa en uno. por cierto tienes razon se me olvido decir el pic y lo demas, es tal como dijiste arriba compañero


----------



## D@rkbytes (May 5, 2014)

marconikov dijo:
			
		

> así como esta funciona tal como necesito


Entonces, ¿funciona o no funciona tu programa?


----------



## marconikov (May 5, 2014)

bueno en una parte lo que pasa es que esta sucediendo algo extraño.. en Picabasic pro esta la sentencia "ON INTERRUPT GOTO <LABEL>" que se supone es adonde tiene que ir SIEMPRE que ocurra una interrupcion no? el problema esta en que cuando cargo el tmr0 y este se desborda, NO va a esa LABEL (se cambia el bit y todo del intcon) sino que sigue en el programa :S es demasiado raro y en serio no se que hacer, ya verifique las configuraciones y lo corri con el mplab paso a paso y ocurre lo mismo


----------



## D@rkbytes (May 5, 2014)

marconikov dijo:
			
		

> bueno en una parte lo que pasa es que esta sucediendo algo extraño.. en Picabasic pro esta la sentencia "ON INTERRUPT GOTO <LABEL>" que se supone es adonde tiene que ir SIEMPRE que ocurra una interrupción no? el problema esta en que cuando cargo el tmr0 y este se desborda, NO va a esa LABEL (se cambia el bit y todo del intcon) sino que sigue en el programa :S es demasiado raro y en serio no se que hacer, ya verifique las configuraciones y lo corrí con el mplab paso a paso y ocurre lo mismo


Sip, cuando se desborda el TMR0 el programa debe entrar en la rutina de control de la interrupción.
La única forma que tengo para que veas que sucede con el programa es mostrándote un vídeo.
Mira las secuencias y ve viendo el valor de TMR0 para que notes como entra y sale de la interrupción.

El programa fue compilado usando PBP3 y usé el archivo *.cof generado para usarlo en proteus.

Nota:
Ve el vídeo con la pantalla maximizada para que notes mejor los detalles.


----------



## marconikov (May 5, 2014)

vaya hermano con ese programa se ve que es mas viable depurar el programa, ese pbp3 trate de descargarlo pero solo sonsigo la version de prueba de 15 dias, el programa deberia hacer lo siguiente:
Arranca el proteus
- detectar un cruce por cero por RB0, en ese instante ocurre una interrupcion mientras se ejecuta el programa.
- en la rutina de la interrupcion externa se carga por primera vez el tmr0 con ese valor, la idea es que el programa se interrumpa cada 100 us para verificar si RB1 esta activo
- cuando este activo rb1, se pone tocs = 1 con ese deberia detenerse el timer0, para ello la configuracion inicial del option reg es 11111111 

te adjunto el archivo de proteus

Estuve realizando la corrida paso a paso con el PBP3 y el proteus y si te das cuenta ocurre el problema que te mencione, si pones un breakpoint al inicio de la interrupcion este no entra cuando se desborda el timer0, es mas aun cuando el registro INTCON cambia sus bit GIE Y TOIF no entra en la rutina "INTERRUPCION" .. :S no entiendo..


----------



## D@rkbytes (May 6, 2014)

marconikov dijo:
			
		

> - en la rutina de la interrupción externa se carga por primera vez el tmr0 con ese valor.
> La idea es que el programa se interrumpa cada 100 us para verificar si RB1 esta activo


Deberías unicamente comprobar la interrupción por RB0 y posteriormente usar el TMR0.

Mira este programa _*Dimmer*_ (realizado por @dinoelectro)
Está escrito en C, pero lo podrás entender fácilmente.
Es muy parecido a lo que intentas realizar, únicamente tendrías que poner las rutinas para el LCD.


----------



## marconikov (May 11, 2014)

En realidad no manejor mucho (nada..) el C, aunque he pensando en cambiarme, pero quisiera intentar ver cual es el problema del codigo en basic de hecho he indagado en busca de la falla y mira lo que he conseguido, lo pongo segun la secuencia de imagenes:
1-inicio la corrida de programa
2-establezco la interrupcion externa mediante el stimulus y se me abre una pequeña ventana de instruccion en assembler referente a interrupciones
3-ejecuta las instrucciones de la rutina de interrupcion, y carga el timer0 haciendo que este empiece a correr.
4- mientras ejecuta las intrucciones veo que entra en ese ciclo de instrucciones que se refiere a unas instrucciones del programa principal, ya el timer0 esta apunto de desbordarse.
5- fijense que el timer0 se desborda y abre otra vez la ventana referente a interrupciones en assembler.
6- -.- se regresa al programa principal y se olvida de pasar por la rutina de interrupciones.

en lo personal CREO que el problema es las instrucciones de assembler de la interrupcion, pero la verdad es que no se que pueda hacer para solventar eso, si alguien pudiera echarme una mano se lo agradeceria


----------



## D@rkbytes (May 17, 2014)

marconikov dijo:


> 1-inicio la corrida de programa
> 2-establezco la interrupción externa mediante el stimulus y se me abre una pequeña ventana de instrucción en assembler referente a interrupciones
> 3-ejecuta las instrucciones de la rutina de interrupción, y carga el timer0 haciendo que este empiece a correr.
> 4- mientras ejecuta las instrucciones veo que entra en ese ciclo de instrucciones que se refiere a unas instrucciones del programa principal, ya el timer0 esta apunto de desbordarse.
> ...


Realicé un programa sencillo para poder comprobar que sucedía durante el bloque cuando se deben atender 2 o varias interrupciones en PICBasic Pro.

Sucede que, como únicamente se puede utilizar una etiqueta para atender las interrupciones,
si se colocan otras etiquetas dentro del bloque, cualquier otra interrupción que se ejecute podrá pasar por ellas.

Así que, para que se cumplan se deben ejecutar las rutinas dentro de una única sentencia IF
Se tiene que comprobar que flag se activó, limpiarlo y continuación realizar las rutinas correspondientes y cerrar ese bloque.
Así mismo para las otras rutinas del servicio de interrupciones.

Con esto se podrá realizar una cascada de verificación a las interrupciones que se ejecutan.
Si los tiempos de ejecución están coordinados y no se ejecutan al mismo tiempo, así debería funcionar.

Saludos.


----------



## marconikov (May 19, 2014)

ah.. poco a poco compañero ! te soy sincero no entendi a lo que te refieres, cuando dices que se puede utilizar una etiqueta para atender las interrupciones, te refieres a la instrucción en assembler ? y otra cuestión esa sentencias de if que dices tengo que hacerlo en los bloques assembler ?? realmente quisiera entender como solventar esto


----------



## D@rkbytes (May 19, 2014)

Me refiero al nombre de las subrutinas del programa. (Etiquetas)
Tu programa está escrito en PICBasic Pro y también lo que mencioné es válido para lenguaje ensamblador.
Sin embargo no es necesario que escribas bloques en ensamblador.

Lo que debes hacer, es generar las subrutinas de cada interrupción dentro de bloques IF y cerrarlos.

Por ejemplo, de esta forma:

```
Interrupts_ISR:
    Disable
    If INTCON.1 = 1 Then
        INTCON.1 = 0
        ; Código a ejecutar en interrupción por RB0
    EndIf
    
    If INTCON.2 = 1 Then
        INTCON.2 = 0
        ; Código a ejecutar en interrupción por TMR0
    EndIf
    
    Resume
    Enable
```

¿Ya comprendes como?


----------



## marconikov (May 19, 2014)

Ah ok ! si ya entiendo a lo que te refieres, voy a modificar eso y te cuento luego a ver que tal !



Hola compañero, ya hice las modificaciones pertinentes al codigo quedo asi:


```
'****************************************************************
'*  Name    : UNTITLED.BAS                                      *
'*  Author  : [select VIEW...EDITOR OPTIONS]                    *
'*  Notice  : Copyright (c) 2014 [select VIEW...EDITOR OPTIONS] *
'*          : All Rights Reserved                               *
'*  Date    : 5/6/2014                                          *
'*  Version : 1.0                                               *
'*  Notes   :                                                   *
'*          :                                                   *
'****************************************************************
DEFINE LCD_DREG PORTD 
DEFINE LCD_BITS 4 
DEFINE LCD_DBIT 4
DEFINE LCD_RSREG PORTC 
DEFINE LCD_RSBIT 0 
DEFINE LCD_EREG PORTC 
DEFINE LCD_EBIT 1 
X VAR BYTE
CONT VAR BYTE
AUX VAR BYTE
A var byte
;CONFIGURACIONES DE LOS PUERTOS E/S
TRISB = %00000001  
TRISD = 0
TRISC = 0
;HABILITO LAS INTERRUPCIONES, POR RB0 Y POR TMR0
INTCON = %10110000
OPTION_REG = %11110000
on interrupt goto INTERRUPCION
Symbol INTF = INTCON.1
SYMBOL GIE = INTCON.7
SYMBOL TMR0IF = INTCON.2
SYMBOL TOCS = OPTION_REG.5
SYMBOL INTEDG = OPTION_REG.6
X=0
PORTB = 0
;CONFIGURACION PARA CONVERSOR A/D
ADCON0 = %11000001
ADCON1 = %00001110
;RUTINA DEL LCD

lcdout $fe,1

BUCLE:

adcin 0, A

X = (((47)*A)-(175))/100 
LCDOUT $fe,2,"Disparo a "
lcdout $fe,$c0, "  ",dec X , "  "
goto BUCLE


DISABLE
;RUTINA DE INTERRUPCION 
INTERRUPCION:
PORTB.3 = 1 ;23.135ms

;INTERRUPCION POR CRUCE POR CERO
if INTF = 1 THEN  ;5 us
    INTF = 0 ; 1 us
    TMR0 = 230 ; 2 us ; 
    SELECT CASE INTEDG ; 0 us
    CASE 0 ; 21 us 
    INTEDG = 1 ; 3 us
    CASE 1 ; 21 us
    INTEDG = 0 ; 3 us
    END SELECT
    TOCS = 0 ; 3 us  23.157 ms 
    CONT=X ; 2 us
endif

;INTERRUPCION POR TEMPORIZADO
if TMR0IF = 1 THEN ; 5 us
    TMR0IF = 0 ;1 us
    if PORTB.1 = 1 THEN ;10 us
        TOCS = 1
        PORTB.1 = 0 
    endif
    IF x-1=0 THEN PORTB.1 = 1 ;44us
    TMR0 = 200 ; 2 us
endif

;FIN DE LA RUTINA DE INTERRUPCION
GIE = 1 ; 1 us
RESUME
ENABLE
END
```
Aún así, hice la corrida en frio con el mplab y sigue el problema compañero :/
Cuando se desborda no se para a la etiqueta y se regresa como te dije anteriormente.


----------



## D@rkbytes (May 20, 2014)

marconikov dijo:


> Aún así, hice la corrida en frio con el mplab y sigue el problema compañero :/
> Cuando se desborda no se para a la etiqueta y se regresa como te dije anteriormente.


Prueba con este programa, funciona físicamente pero tiene ligeros destellos que no pude corregir.
No utiliza LCD porque por los retardos que se usan en la escritura, se sale todo de control.
El programa utiliza la interrupción por RB0 para detectar los pulsos de 60Hz y también por desborde del Timer 1.

Está realizado como te mencioné anteriormente.

Nota:
Este mismo programa escrito en C funciona  muy bien.

Saludos.


----------



## Nestor2017 (May 26, 2014)

Estimado Marconikov,

En este link pueden encontrar un rectificador controlado en PIC16F876A y PIC18F2550 tienen LCD y comunicación MODBUS detectan el cruce por cero con interrupción además tienes la simulación en proteus.

http://nenriquez2017.blogspot.com/

Saludos
Nestor


----------

