Vumetro a Leds con PIC 16FXXX

El compañero tiene razón, puede que no todos usen el mismo visualizador de pdf o estén en el movil, desde KiCad exporte con trazar para que todo el texto del pdf sea seleccionable. aun así les comparto el hex para que lo tengan a la mano.

no compartí código y simulación porque mi intensión era que no lidien con el compilador o el simulador como en las respuestas anteriores y puedan simplemente armarlo. por las limitaciones del 628A no veo que mas se pueda mejorar a parte de variar el tiempo de peak o barra si es el caso. el 628A espacio tiene, pero pines ya no, a menos sino se quiere usar hardware adicional.

El programa lo desarrolle en MPLAB X actual, no uso CSS u PicPRO asi que estoy perdido en eso y no domino mucho C. mi entención inicial era compartir el codigo completo por eso esta comentado y dedicado al Foro como al autor a modo de agradecimiento por todo lo que aprendi pero asm no es muy común hoy en día, asi que se me ocurrio meter todo en el pdf, en fin.

respecto al uso del comparador y el mux interno tuve que leerme varias veces el manual ya que cada modificación en CMON debe esperar 10uS y seguir una secuencia o las 4 entradas se mezclaran con datos uno del otro, como pueden deducir se tiene 4 canales de ADC de 4 bits ya que la configuración del MUX interno te obliga a usar todas las entradas que ya no podrán ser salidas digitales, por eso esos pines en el PCB esta a gnd es mejor leer 0 a un valor aleatorio si llegase a suceder por error claro esta, asi como otras de cosas varias, como usar Power-up. el autor usa ISR eso ayuda a que el programa siga incrementandose es decir puedes implementar mas cosas y dejar el vumetro trabajar. podria explicar mas cosas pero temo se extienda mas la respuesta que de por si ya lleva codigo abajo.

un ejemplo usando las 4 entradas, el 595 superior son los teclados, el inferior las entrada con señal, cada uno cubre 4bits de los 16bits que suma ambos 595. mejor lo adjunto tambien para que puedan simularlo.

Ver el archivo adjunto 339436

pero bueno... servido esta, comparto el código completo en asm y simulación del VU12LD628AV2. disculpen el espanglish y la falta de mas comentarios en el código eso lo deje a medias.
Código:
;--------------------------------------------------------;
;    VU meter estéreo - 2x12 LED (multiplexado)     ;
;           con el PIC16F628A             ;
;--------------------------------------------------------;
; Datos ajustables:                     ;
; - Seleccionable entre Punto/barra con o sin peak.     ;
; - guarda el modo seleccionado en la EEPROM.         ;
;--------------------------------------------------------;
;    Basado en el algoritmo de s-o.webnode.cz     ;
;        para fines no comerciales.         ;
;        www.Forosdelectronia.com         ;
;--------------------------------------------------------;
;   Versión : 1.1A2                 KSST 07/25     ;
;--------------------------------------------------------;

PROCESSOR 16F628A
#include <xc.inc>

CONFIG  FOSC = INTOSCIO       ; Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
CONFIG  WDTE = ON             ; Watchdog Timer Enable bit (WDT enabled)
CONFIG  PWRTE = ON          ; Power-up Timer Enable bit (PWRT enabled)
CONFIG  MCLRE = OFF           ; RA5/MCLR/VPP PinS Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
CONFIG  BOREN = OFF           ; Brown-out Detect Enable bit (BOD disabled)
CONFIG  LVP = OFF             ; Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
CONFIG  CPD = OFF             ; Data EE Memory Code Protection bit (Data memory code protection off)
CONFIG  CP = OFF              ; Flash Program Memory Code Protection bit (Code protection off)

C   equ STATUS_C_POSITION
Z   equ STATUS_Z_POSITION

PSECT udata_bank0
Position:   DS    1   ; Position Multiplex (anodos PORTA)
LLSB:        DS    1   ; LSB 8 LED L
LMSB:        DS    1   ; MSB 4 LED L
RLSB:        DS    1   ; LSB 8 LED R
RMSB:        DS    1   ; MSB 4 LED R
PNT1:        DS    1   ; nivel general de point para L y R
PNT2:        DS    1   ;
BAR1:        DS    1   ; nivel general de bar para L y R
BAR2:        DS    1   ;
LPNT1:        DS    1   ; sobreescribe RAM (descenso artificial de L)
LPNT2:        DS    1   ;
LBAR1:        DS    1   ; dato a mostrar del cátodo L
LBAR2:        DS    1   ;
LRAM1:        DS    1   ; RAM peak L
LRAM2:        DS    1   ;
RPNT1:        DS    1   ; sobreescribe RAM (descenso artificial de R)
RPNT2:        DS    1   ;
RBAR1:        DS    1   ; dato a mostrar del cátodo R
RBAR2:        DS    1   ;
RRAM1:        DS    1   ; RAM peak R
RRAM2:        DS    1   ;
LPRM1:        DS    1   ; RAM point L
LPRM2:        DS    1   ;
RPRM1:        DS    1   ; RAM point R
RPRM2:        DS    1   ;
LBRM1:        DS    1   ; RAM bar L
LBRM2:        DS    1   ;
RBRM1:        DS    1   ; RAM bar R
RBRM2:        DS    1   ;
LPSV1:        DS    1   ; dato a mostrar para punto L
LPSV2:        DS    1   ;
RPSV1:        DS    1   ; dato a mostrar para punto R
RPSV2:        DS    1   ;
LTML:        DS    1   ; timer PAM L (la primera vez con 500ms)
LTMH:        DS    1   ;
RTML:        DS    1   ; timer PAM R (LTMx x2)
RTMH:        DS    1   ;  
LPTM:        DS    1   ; point time
RPTM:        DS    1   ;
LBRM:        DS    1   ; bar time
RBRM:        DS    1   ;    
DTMODE:        DS    1   ; Mode dato de 2bits
SWPPCB:        DS    1   ; SWAP de bits (cátodos) para el PCB V12LD628AV2
   
PSECT udata_shr
MemSTATUS:  DS    1   ; Guarda STATUS temporal
MemPCLATH:  DS    1   ; Guarda PCLATH temporal
EEADRp:        DS    1   ; EEPROM Auxiliary address
MemW:        DS    1   ; REG W data memory saved
SVData:        DS    1   ; EEPROM data to be saved
JMPSL:        DS    1   ; Selector de Modo
TEMP:        DS    1   ; Valor de AN1
ANNDRL:        DS    1   ; Valor de AN0
ANNDRR:        DS    1   ; Valor de AN0
CTCOMP:     DS    1   ; contador de VRCON 0-F
TPCM:        DS    1   ; Valor Temporal de CMCON

;*************************************************
;  EEPROM Address = 0x0E | default = bar + peak
; |-------------------------------------------|
; |    bar   |   point  |  peak+pt | peak+bar |
; |----------|----------|----------|----------|
; | xxxxxx00 | xxxxxx01 | xxxxxx10 | xxxxxx11 |
; |-------------------------------------------|
;*************************************************
   
PSECT PM1, class=code,delta=2,abs ; PIC10/12/16
ORG 0x0000
    GOTO    PM1
PSECT ISR, class=code,delta=2,abs,reloc=4
ORG 0x0004
;-------------------------------------------;
;        Guarda PCL            ;
;-------------------------------------------;
     MOVWF    MemW
    SWAPF    STATUS,W
    CLRF    STATUS
    MOVWF    MemSTATUS
    MOVF    PCLATH,W
    MOVWF    MemPCLATH
;-------------------------------------------;
    BTFSC    INTCON,2    ;TMR0=1?
    GOTO    ITMR0        ;si
    GOTO    EINT

ITMR0:    BCF    INTCON,2    ;off TMR0IF
;    SWAPF    LMSB,F        ;intercambia bytes LSB a MSB
                ;(solo aplica para el PCB V12LD628A)
;-------------------------------------------;
;  solo aplica para el orden de cátodos en  ;
;     anodo RA4 para el PCB V12LD628AV2        ;
;-------------------------------------------;
    MOVF    LMSB,W
    MOVWF    SWPPCB
   
    RLF    SWPPCB,F
    RRF    LMSB,F
    RLF    SWPPCB,F
    RRF    LMSB,F
    RLF    SWPPCB,F
    RRF    LMSB,F
    RLF    SWPPCB,F
    RRF    LMSB,F
    RLF    SWPPCB,F
    RRF    LMSB,F
    RLF    SWPPCB,F
    RRF    LMSB,F
    RLF    SWPPCB,F
    RRF    LMSB,F
    RLF    SWPPCB,F
    RRF    LMSB,F
   
    SWAPF    RMSB,F
    MOVF    RMSB,W
    MOVWF    SWPPCB
   
    RLF    SWPPCB,F
    RRF    RMSB,F
    RLF    SWPPCB,F
    RRF    RMSB,F
    RLF    SWPPCB,F
    RRF    RMSB,F
    RLF    SWPPCB,F
    RRF    RMSB,F
    RLF    SWPPCB,F
    RRF    RMSB,F
    RLF    SWPPCB,F
    RRF    RMSB,F
    RLF    SWPPCB,F
    RRF    RMSB,F
    RLF    SWPPCB,F
    RRF    RMSB,F

;-------------------------------------------;
   
;Memory Peak L
    DECFSZ    LTML,F        ;LTML=0?
    GOTO    NXT1        ;no
    DECFSZ    LTMH,F        ;LTMH=0?
    GOTO    NXT1        ;no
    BSF    STATUS,C
    RRF    LRAM2,F        ;rotar derecha L MSB
    RRF    LRAM1,F        ;rotar derecha L LSB(deciende peak)
    MOVLW    45        ;timeL
    MOVWF    LTML        ;(40ms)
    MOVLW    1        ;timeH
    MOVWF    LTMH        ;(xms)
   
;Memory Peak R
NXT1:    DECFSZ    RTML,F        ;RTML=0?
    GOTO    NXT2        ;no  
    DECFSZ    RTMH,F        ;RTMH=0?
    GOTO    NXT2        ;no
    BSF    STATUS,C
    RRF    RRAM2,F        ;rotar derecha R MSB
    RRF    RRAM1,F        ;rotar derecha R LSB(deciende peak)
    MOVLW    45        ;timeL
    MOVWF    RTML        ;(40ms)
    MOVLW    1        ;timeH
    MOVWF    RTMH        ;(xms)
   
;Memory point L
NXT2:    DECFSZ    LPTM,F        ;LPTM=0?
    GOTO    NXT3        ;no  
    BSF    STATUS,C
    RRF    LPRM2,F        ;rotar derecha R LSB
    RRF    LPRM1,F        ;rotar derecha R MSB
    MOVLW    40        ;timeL
    MOVWF    LPTM        ;(40ms)
   
;Memory point R
NXT3:    DECFSZ    RPTM,F        ;RPTM=0?
    GOTO    NXT4        ;no  
    BSF    STATUS,C
    RRF    RPRM2,F        ;rotar derecha R LSB
    RRF    RPRM1,F        ;rotar derecha R MSB
    MOVLW    40        ;timeL
    MOVWF    RPTM        ;(40ms)  
   
;Memory bar L
NXT4:    DECFSZ    LBRM,F        ;LBRM=0?
    GOTO    NXT5        ;no  
    BSF    STATUS,C
    RRF    LBRM2,F        ;rotar derecha R LSB
    RRF    LBRM1,F        ;rotar derecha R MSB
    MOVLW    20        ;timeL
    MOVWF    LBRM        ;(40ms)
   
;Memory bar R
NXT5:    DECFSZ    RBRM,F        ;RBRM=0?
    GOTO    NXT6        ;no  
    BSF    STATUS,C
    RRF    RBRM2,F        ;rotar derecha R LSB
    RRF    RBRM1,F        ;rotar derecha R MSB
    MOVLW    20        ;timeL
    MOVWF    RBRM        ;(40ms)      
   
NXT6:      MOVLW    0b00001111
    MOVWF    PORTA        ;turn off all Anode
    MOVLW    LLSB        ;Dirección de FSR (LLSB es 0x23 FSR).
      MOVWF    FSR        ;FSR apunta a valor inicial de Position.
    MOVF    Position,W  ;guarda valor incial.
      ADDWF    FSR,F        ;actualiza Position.
    MOVF    INDF,W        ;Lee FSR.
    MOVWF    PORTB        ;carga el valor de 8bit o 4bit del VU (cátodos).  
    CALL    Anode        ;Carga el nuevo valor de Anode
    MOVWF    PORTA        ;al PORTA (anodos).
    INCF    Position,F  ;incremeta Position.
      MOVLW    0x03        ;limitador de 2 bits (0-3)
    ANDWF    Position,F  ;recorta bits 4-7 en Position.
   
;-------------------------------------------;
;        Restauración de PCL            ;
;-------------------------------------------;  
EINT:    MOVF    MemPCLATH,W
    MOVWF    PCLATH
    SWAPF    MemSTATUS,W
    MOVWF    STATUS
    SWAPF    MemW,F
    SWAPF    MemW,W
    RETFIE  
;-------------------------------------------;  

;-------------------------------------------;
; //////////////   Rutinas    /////////////
;-------------------------------------------;
;position tabla (Anodos)
Anode:    MOVF    Position,W
      ANDLW    0x03
      ADDWF    PCL,F
      RETLW    0b10000000  ;Anode0 = L LSB
      RETLW    0b00010000  ;Anode1 = L MSB
      RETLW    0b01000000  ;Anode2 = R LSB
      RETLW    0b00010000  ;Anode3 = R MSB
;    PORTx     76543210
;-------------------------------------------;
;Leer EEPROM
ERead:    CLRWDT
    BANKSEL EEADR
    MOVF    EEADRp,W  
    MOVWF    EEADR
    BANKSEL EECON1
    BSF    EECON1,0
    BTFSC    EECON1,0
    GOTO    $-1
    BANKSEL    EEDATA
    MOVF    EEDATA,W
    BANKSEL EEADRp
    RETURN
   
;-------------------------------------------;
;Escribir EEPROM
EWrite:    CLRWDT
    BANKSEL EEADR
    MOVLW    0x0E
    MOVWF    EEADR
    BANKSEL    SVData
    MOVF    SVData,W
    BANKSEL    EEDATA
    MOVWF    EEDATA
    BANKSEL    EECON1
    BSF    EECON1,2
    MOVLW    0x55
    MOVWF    EECON2
    MOVLW    0xAA
    MOVWF    EECON2
    BSF    EECON1,1
    BTFSC    EECON1,1
    GOTO    $-1
    BCF    EECON1,2
    BCF    EECON1,7
    BANKSEL    EEADRp
    RETURN
   
;------------------------------------  
;Logaritmo conversor de adc a nivel
LOG:    CLRWDT
    MOVLW    0xFF        ;todo en OFF
    MOVWF    PNT1        ;
    MOVWF    PNT2        ;
    CLRF    BAR1        ;00000000, Todo en ON
    MOVLW    0xF0        ;mascara de 1111 al MSB (4 bit)
    MOVWF    BAR2        ;11110000, solo se usan 12bits
   
    MOVLW    0x0E        ;
    SUBWF    TEMP,W        ;TEMP - constante
    BTFSS    STATUS,C    ;positivo?
    GOTO    $+3        ;no carry
    BCF    PNT2,3        ;ON
    RETURN

    BSF    BAR2,3        ;OFF
    MOVLW    0x0D
    SUBWF    TEMP,W        ;TEMP - constante
    BTFSS    STATUS,C    ;positivo?
    GOTO    $+3        ;no carry
    BCF    PNT2,3        ;ON
    RETURN

    BSF    BAR2,3        ;OFF
    MOVLW    0x0C
    SUBWF    TEMP,W        ;TEMP - constante
    BTFSS    STATUS,C    ;positivo?
    GOTO    $+3        ;no carry
    BCF    PNT2,2        ;ON
    RETURN

    BSF    BAR2,2        ;OFF
    MOVLW    0x0B
    SUBWF    TEMP,W        ;TEMP - constante
    BTFSS    STATUS,C    ;positivo?
    GOTO    $+3        ;no carry
    BCF    PNT2,2        ;ON
    RETURN

    BSF    BAR2,2        ;OFF
    MOVLW    0x0A
    SUBWF    TEMP,W        ;TEMP - constante
    BTFSS    STATUS,C    ;positivo?
    GOTO    $+3        ;no carry
    BCF    PNT2,1        ;ON
    RETURN

    BSF    BAR2,1        ;OFF
    MOVLW    0x09
    SUBWF    TEMP,W        ;TEMP - constante
    BTFSS    STATUS,C    ;positivo?
    GOTO    $+3        ;no carry
    BCF    PNT2,0        ;ON
    RETURN
   
    BSF    BAR2,0        ;OFF
    MOVLW    0x08
    SUBWF    TEMP,W        ;TEMP - constante
    BTFSS    STATUS,C    ;positivo?
    GOTO    $+3        ;no carry
    BCF    PNT1,7        ;ON
    RETURN
 
    BSF    BAR1,7        ;OFF
    MOVLW    0x07
    SUBWF    TEMP,W        ;TEMP - constante
    BTFSS    STATUS,C    ;positivo?
    GOTO    $+3        ;no carry
    BCF    PNT1,6        ;ON
    RETURN

    BSF    BAR1,6        ;OFF
    MOVLW    0x06
    SUBWF    TEMP,W        ;TEMP - constante
    BTFSS    STATUS,C    ;positivo?
    GOTO    $+3        ;no carry
    BCF    PNT1,5        ;ON
    RETURN
 
    BSF    BAR1,5        ;OFF
    MOVLW    0x05
    SUBWF    TEMP,W        ;TEMP - constante
    BTFSS    STATUS,C    ;positive?
    GOTO    $+3        ;no carry
    BCF    PNT1,4        ;ON
    RETURN
 
    BSF    BAR1,4        ;OFF
    MOVLW    0x04
    SUBWF    TEMP,W        ;TEMP - constante
    BTFSS    STATUS,C    ;positivo?
    GOTO    $+3        ;no carry
    BCF    PNT1,3        ;ON
    RETURN

    BSF    BAR1,3        ;OFF
    MOVLW    0x03
    SUBWF    TEMP,W        ;TEMP - constante
    BTFSS    STATUS,C    ;positivo?
    GOTO    $+3        ;no carrys
    BCF    PNT1,2        ;ON
    RETURN

    BSF    BAR1,2        ;OFF
    MOVLW    0x02
    SUBWF    TEMP,W        ;TEMP - constante
    BTFSS    STATUS,C    ;positivo?
    GOTO    $+3        ;no carry
    BCF    PNT1,1        ;ON
    RETURN
 
    BSF    BAR1,1        ;OFF
    MOVLW    0x02
    SUBWF    TEMP,W        ;TEMP - constante
    BTFSS    STATUS,C    ;positivo?
    GOTO    $+3        ;no carry
    BCF    PNT1,0        ;ON
    RETURN
   
    BSF    BAR1,0        ;OFF
    RETURN
;-------------------------------------------;
; //////////  Fin de Rutinas   /////////////
;-------------------------------------------;

;-------------------------------------------;
; Configuraciones de Puertos y Flags        ;
;-------------------------------------------;
PM1:    BANKSEL TRISA
    CLRF    INTCON
    MOVLW    0b00001011  ; Configuración de OSC
    MOVWF    PCON        ; Interno 4MHz
    BSF    TRISA,0        ; AN0/RA0=Input L
    BSF    TRISA,1        ; AN1/RA1=Input R
    BSF    TRISA,2        ; sin uso
    BSF    TRISA,3        ; sin uso
    BCF    TRISA,4        ; Anodo 2,3 compartido (MSB de L y R 4bits)
    BSF    TRISA,5        ; Selector de modo -> Peak/bar/Point (pulsador)
    BCF    TRISA,6        ; Anodo 0 (LSB=L 8bts)
    BCF    TRISA,7        ; Anodo 1 (LSB=R 8bts)
    MOVLW    0b00000000  ; 0=Output/1=Input
    MOVWF    TRISB        ; PORTB=Output 8bits
    MOVLW    0b10000001  ; prescaler 1:4 TMR0 / pull-ups off
    MOVWF    OPTION_REG  ; (1ms) TMR0 @ 4Mhz internal OSC
    MOVLW    0b00000000  ; (EEW,CCP1,USART,TMR1,TMR2...)
    MOVWF    PIE1        ; interrupciones de PIE1=off
   
    BANKSEL PORTA  
    BCF    PORTA,4        ;
    BCF    PORTA,6        ; Apagamos anodos
    BCF    PORTA,7        ;
    MOVLW    0b00000101  ; prescaler 1:1 (TMR1 sin uso)
    MOVWF    T1CON  
    MOVLW    0b10100000  ; Enable INT TMR0
    MOVWF    INTCON
    MOVLW    0xFF        ; Apagamos cátodos (logica inversa)
    MOVWF    LRAM1
    MOVWF    LRAM2
    MOVWF    RRAM1
    MOVWF    RRAM2
    MOVWF    LPRM1
    MOVWF    LPRM2
    MOVWF    RPRM1
    MOVWF    RPRM2
    MOVWF    LBRM1
    MOVWF    LBRM2
    MOVWF    RBRM1
    MOVWF    RBRM2
    MOVWF    PORTB
    CLRF    Position
   
    MOVLW    0x0E        ; Dirección de EEPROM donde guarda el modo
    MOVWF    EEADRp        ; por defecto lee 0xFF (memoria vacia).
    CALL    ERead        ; rutina que Lee EEPROM.
    MOVWF    DTMODE        ; valor fijo del modo.
    MOVWF    JMPSL        ; valor variable del modo a usar.
    BSF    JMPSL,2        ; bit de enclavamiento.
   
;-------------------------------------------;
;    Programa Principal - Loop        ;
;(ISR interrumpe el loop cada 1ms y regresa);
;-------------------------------------------;
   
; para CMCOM=0x02 se tiene del manual:        ;
; 0 = C2INV: VREF menor que AN1 (VIN-) **
; 0 = C1INV: VREF menor que AN0 (VIN-) **
; 0 = C2: Output not inverted
; 0 = C1: Output not inverted
; 0 = CIS: Comparator Input Switch bit
;    C1: VIN- connects to RA0
;    C2: VIN- connects to RA1
; 010 = CM<2:0>
;    Four Inputs Multiplexed
;    to Two Comparators.
;  
; (**) para menor sensibilidad CMCOM = 0xC2
;-------------------------------------------;
   
START:    CLRWDT
    BTFSS    JMPSL,0        ; selector de modo bar/point
    GOTO    Point
   
;Carga datos del modo Bar de L y R.
Barh:    MOVF    LBAR1,W    ; cátodo L LSB 8bits
    MOVWF    LLSB       ;
    MOVF    LBAR2,W    ; cátodo L MSB 4bits
    MOVWF    LMSB       ;
    MOVF    RBAR1,W    ; cátodo R LSB 8bits
    MOVWF    RLSB
    MOVF    RBAR2,W    ; cátodo R MSB 4bits
    MOVWF    RMSB
    GOTO    Mode
   
;Carga datos del modo punto de L y R.
Point:    MOVF    LPSV1,W   ; cátodo L LSB 8bits
    MOVWF    LLSB      ;
    MOVF    LPSV2,W   ; cátodo L MSB 4bits
    MOVWF    LMSB      ;
    MOVF    RPSV1,W   ; cátodo R LSB 8bits
    MOVWF    RLSB
    MOVF    RPSV2,W   ; cátodo R MSB 4bits
    MOVWF    RMSB

;Lee RA5 Selector de modos.
Mode:    BTFSS    JMPSL,2        ; JMPSL,2= 0? -> JMPSL,2 inicia en 1.
    GOTO    SAFE        ; ;bit de enclavamiento.
    BTFSC    PORTA,5        ; selector de modo.
    GOTO    NXT0        ; continua por defecto.
    DECF    DTMODE,F    ; si se presiona RA5 continua aqui.
    MOVLW    0x03        ; selecciona filtrando de 0xFF de DTMODE
    ANDWF    DTMODE,F    ; mascara entre 3 - 0 y lo carga en JMPSL.
    MOVF    DTMODE,W    ;
    MOVWF    JMPSL        ;
    MOVWF    SVData        ; Guarda el valor de modo en EEPROM.
    CALL    EWrite        ; rutina escribir EEPROM 6ms aprox.
    BCF    JMPSL,2        ; activa el bit de enclavamiento.
SAFE:    BTFSS    PORTA,5        ; logica invertida si se sigue presionado RA5.
    GOTO    NXT0        ; sigue.
    BSF    JMPSL,2        ; desactiva el bit de enclavamiento.
   
NXT0:    NOP            ; Tiempo de compensación al  
        NOP            ; guardar en la EEPROM dentro de Mode.
        NOP            ; (no incluye CALL EWrite)
        NOP
        NOP
    NOP
    NOP
    NOP
    NOP
    NOP
   
;--------------------------------
;Lectura del Comparador AN0  
COMRead:
    MOVLW    0x02        ; Comparador modo Mux interno (Vref=0x02).
    MOVWF    TPCM        ;
    MOVWF    CMCON        ; carga el modo Mux en CMCON.
    BANKSEL    VRCON        ;
    MOVLW    0xA0        ; (VREN=ON,VROE=OFF,VRR=ON,U-0=Unimplemented bit)
    MOVWF    VRCON        ; Configura VRCON (ver figura 11-1 del manual).
    BANKSEL    CMCON
   
    MOVLW    0x0F        ; 0 to F -> 4bits (resolución del comparador).
    MOVWF    CTCOMP        ;
   
LOOP2:    MOVF    TPCM,W        ;
    MOVWF    CMCON        ; Configuración de CMCOM
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    BTFSC    CMCON,6        ; C1OUT=1? AN0
    GOTO    AN0        ; yup
    BANKSEL    VRCON        ; nop
    INCF    VRCON,F     ; ADC 4bits
    BANKSEL    CMCON
    CLRF    CMCON        ; Limpia C1 y C2.
    DECFSZ    CTCOMP,F    ; limitador a 4bits.
    GOTO    LOOP2
   
AN0:    BANKSEL    VRCON
    MOVF    VRCON,W        ; se obtiene lectura
    ANDLW    0x0F        ;
    MOVWF    ANNDRL        ; 4bits ADC de VRCON
    BANKSEL    CMCON
   
LOUT:    MOVF    ANNDRL,W
    MOVWF    TEMP
    CALL    LOG
;--------------------------------

    MOVF    BAR1,W        ; nuevo nivel de Bar LSB
    MOVWF    LBAR1        ;
    MOVF    BAR2,W        ; nuevo nivel de Bar MSB
    MOVWF    LBAR2        ;
    MOVF    PNT1,W        ; nuevo nivel de Punto LSB
    MOVWF    LPNT1        ;
    MOVWF    LPSV1        ;
    MOVF    PNT2,W        ; nuevo nivel de Punto MSB
    MOVWF    LPNT2        ;
    MOVWF    LPSV2

;------------------------------------
; logica de tiempo para peak    
;------------------------------------
    MOVF    LRAM2,W        ; nivel MSB guardada (peak)
    SUBWF    LPNT2,W        ; nivel MSB actual
    BTFSS    STATUS,C    ; positivo? C=1 LPNT2-LRAM2
    GOTO    LCHANGEDT   ; nivel actual es menor que nivel guardado en MSB
    BTFSS    STATUS,Z    ; igual? Z=1 salta uno instrucción.
    GOTO    LJOINDT        ; nivel actual es mayor que nivel guardado
    MOVF    LPNT1,W        ; nivel LSB actual
    SUBWF    LRAM1,W        ; nivel LSB guardada LRAM1-LPNT1
    BTFSC    STATUS,C    ; negativo? C=0 salta uno instrucción.
    GOTO    LCHANGEDT   ; nivel actual es menor que nivel guardado en LSB
   
LJOINDT:
    BTFSS    JMPSL,1        ; L peak on/off
    GOTO    LPTTM
   
; mantiene el valor de peak  
    MOVF    LRAM1,W        ; actualiza LSB de peak guardado
    MOVWF    LPNT1
    MOVF    LRAM2,W        ; actualiza MSB de peak guardado
    MOVWF    LPNT2
    GOTO    LPTTM
   
; actualiza nivel guardado (nivel guardado es menor que señal actual)
LCHANGEDT:
    MOVF    LPNT1,W        ; actualiza LSB de peak guardado
    MOVWF    LRAM1
    MOVF    LPNT2,W        ; actualiza MSB de peak guardado
    MOVWF    LRAM2
    MOVLW    244        ; inicia la primera vez con (500ms)
    MOVWF    LTML        ; memory timer L
    MOVLW    2
    MOVWF    LTMH        ; memory timer H  
   
;------------------------------------
; logica de tiempo para punto
;------------------------------------  
LPTTM:    MOVF    LPRM2,W
    SUBWF    LPSV2,W    ;LPSV2-LPRM2
    BTFSS    STATUS,C    ;positivo? C=1
    GOTO    LPTSWP
    BTFSS    STATUS,Z    ;igual? Z=1
    GOTO    LJNPT
    MOVF    LPSV1,W
    SUBWF    LPRM1,W        ;LPRM1-LPSV1
    BTFSC    STATUS,C    ;negativo? C=0
    GOTO    LPTSWP
   
LJNPT:    MOVF    LPRM1,W
    MOVWF    LPSV1
    MOVF    LPRM2,W
    MOVWF    LPSV2  
    GOTO    NXTPL

LPTSWP:    MOVF    LPSV1,W
    MOVWF    LPRM1
    MOVF    LPSV2,W
    MOVWF    LPRM2
    MOVLW    40
    MOVWF    LPTM        ;memory time  
   
NXTPL:    BTFSS    JMPSL,1        ;L peak on/off
    GOTO    LBRTM      
    MOVF    LRAM2,W
    ANDWF    LPSV2,F
    MOVF    LRAM1,W
    ANDWF    LPSV1,F

;------------------------------------
; logica de tiempo para barra
;------------------------------------  
LBRTM:    MOVF    LBRM2,W
    SUBWF    LBAR2,W    ;LBAR2-LBRM2
    BTFSS    STATUS,C    ;positivo? C=1
    GOTO    LBRSWP
    BTFSS    STATUS,Z    ;igual? Z=1
    GOTO    LJNBR
    MOVF    LBAR1,W
    SUBWF    LBRM1,W        ;LBRM1-LBAR1
    BTFSC    STATUS,C    ;negativo? C=0
    GOTO    LBRSWP
   
LJNBR:    MOVF    LBRM1,W
    MOVWF    LBAR1
    MOVF    LBRM2,W
    MOVWF    LBAR2
    GOTO    NXTBL

LBRSWP:    MOVF    LBAR1,W
    MOVWF    LBRM1
    MOVF    LBAR2,W
    MOVWF    LBRM2
    MOVLW    20
    MOVWF    LBRM  
   
NXTBL:    BTFSS    JMPSL,1        ;L peak on/off
    GOTO    ROUT
    MOVF    LRAM1,W
    ANDWF    LBAR1,F  
    MOVF    LRAM2,W
    ANDWF    LBAR2,F

;------------------------------------
;Lectura del Comparador AN1  
ROUT:    MOVLW    0x02        ; Comparador modo Mux interno (Vref=0x02).
    MOVWF    TPCM        ;
    MOVWF    CMCON        ; carga el modo Mux en CMCON.
    BANKSEL    VRCON        ;
    MOVLW    0xA0        ; (VREN=ON,VROE=OFF,VRR=ON,U-0=Unimplemented bit)
    MOVWF    VRCON        ; Configura VRCON (ver figura 11-1 del manual).
    BANKSEL    CMCON
   
    MOVLW    0x0F        ; 0 to F -> 4bits (resolución del comparador).
    MOVWF    CTCOMP        ;
   
LOOP1:    MOVF    TPCM,W        ;
    MOVWF    CMCON        ; Configuración de CMCOM
    NOP            ; 10uS según el manual (Example 11-1 pag. 70)
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    BTFSC    CMCON,7        ; C2OUT AN1
    GOTO    AN1        ; termina si VREF es menor que AN1 (CMCON=0x02)
    BANKSEL    VRCON
    INCF    VRCON,F     ; ADC 4bits incrementa de 0000 a 1111 en VR3-VR0.
    BANKSEL    CMCON
    CLRF    CMCON        ; Limpia C1 y C2.
    DECFSZ    CTCOMP,F    ; limitador a 4bits.
    GOTO    LOOP1
   
AN1:    BANKSEL    VRCON
    MOVF    VRCON,W        ; se extrae y filtra solo VR3-VR0.
    ANDLW    0x0F        ;
    MOVWF    ANNDRR        ; 4bits ADC del Comparador AN1
    BANKSEL    CMCON  
    MOVF    ANNDRR,W
    MOVWF    TEMP
    CALL    LOG
;------------------------------------
    MOVF    BAR1,W        ;new BAR
    MOVWF    RBAR1        ;
    MOVF    BAR2,W        ;
    MOVWF    RBAR2        ;
    MOVF    PNT1,W        ;new POINT
    MOVWF    RPNT1        ;
    MOVWF    RPSV1        ;
    MOVF    PNT2,W        ;
    MOVWF    RPNT2        ;
    MOVWF    RPSV2        ;

;------------------------------------
; logica de tiempo para peak
;------------------------------------      
    MOVF    RRAM2,W
    SUBWF    RPNT2,W        ;RPNT2-RRAM2
    BTFSS    STATUS,C    ;positivo?
    GOTO    RCHANGEDT
    BTFSS    STATUS,Z    ;igual? Z=1
    GOTO    RJOINDT
    MOVF    RPNT1,W
    SUBWF    RRAM1,W        ;RRAM1-RPNT1
    BTFSC    STATUS,C    ;negativo?
    GOTO    RCHANGEDT
   
RJOINDT:
    BTFSS    JMPSL,1        ;L peak on/off
    GOTO    RPTTM
   
    MOVF    RRAM1,W        ;sobreescribe RAM
    MOVWF    RPNT1        ;
    MOVF    RRAM2,W        ;
    MOVWF    RPNT2        ;
    GOTO    RPTTM

RCHANGEDT:
    MOVF    RPNT1,W        ;sobreescribe RAM
    MOVWF    RRAM1        ;
    MOVF    RPNT2,W        ;
    MOVWF    RRAM2        ;
    MOVLW    244        ;inicia con (500ms) la primera vez
    MOVWF    RTML        ; tiempo de retensión time L y H
    MOVLW    2
    MOVWF    RTMH
    GOTO    RPTTM

;------------------------------------
; logica de tiempo para punto
;------------------------------------  
RPTTM:    MOVF    RPRM2,W
    SUBWF    RPSV2,W    ;RPSV2-RPRM2
    BTFSS    STATUS,C    ;positivo? C=1
    GOTO    RPTSWP
    BTFSS    STATUS,Z    ;igual? Z=1
    GOTO    RJNPT
    MOVF    RPSV1,W
    SUBWF    RPRM1,W        ;RPRM1-RPSV1
    BTFSC    STATUS,C    ;negativo? C=0
    GOTO    RPTSWP
   
RJNPT:    MOVF    RPRM1,W  
    MOVWF    RPSV1
    MOVF    RPRM2,W
    MOVWF    RPSV2
    GOTO    NXTPR

RPTSWP:    MOVF    RPSV1,W
    MOVWF    RPRM1
    MOVF    RPSV2,W
    MOVWF    RPRM2
    MOVLW    40
    MOVWF    RPTM        ;memory time
   
NXTPR:    BTFSS    JMPSL,1        ;L peak on/off
    GOTO    RBRTM
    MOVF    RRAM1,W
    ANDWF    RPSV1,F
    MOVF    RRAM2,W
    ANDWF    RPSV2,F

;------------------------------------
; logica de tiempo para barra
;------------------------------------  
RBRTM:    MOVF    RBRM2,W
    SUBWF    RBAR2,W    ;RBAR2-RBRM2
    BTFSS    STATUS,C    ;positivo? C=1
    GOTO    RBRSWP
    BTFSS    STATUS,Z    ;igual? Z=1
    GOTO    RJNBR
    MOVF    RBAR1,W
    SUBWF    RBRM1,W        ;RBRM1-RBAR1
    BTFSC    STATUS,C    ;negativo? C=0
    GOTO    RBRSWP
   
RJNBR:    MOVF    RBRM1,W  
    MOVWF    RBAR1
    MOVF    RBRM2,W
    MOVWF    RBAR2
    GOTO    NXTBR

RBRSWP:    MOVF    RBAR1,W
    MOVWF    RBRM1
    MOVF    RBAR2,W
    MOVWF    RBRM2
    MOVLW    20
    MOVWF    RBRM        ;memory time
   
NXTBR:    BTFSS    JMPSL,1        ;L peak on/off
    GOTO    START
    MOVF    RRAM1,W
    ANDWF    RBAR1,F
    MOVF    RRAM2,W
    ANDWF    RBAR2,F
    GOTO    START
     END

lo que si me olvide era compartir la traducción a C del código original en asm que hice, que me parece necesario para que cualquiera pueda implementarlo donde desee. mi traducción trata de respetar el orden y logica que tiene el codigo asm original, para no tener problemas de la obtensión de datos en el tiempo asi como la multiplexión. los expertos lo sabran mejorar. temo aclarar que el autor envia tanto punto como barra directamente a la multiplexión eso genera mas de un punto o barras erraticas que en lo personal no me gusta, y el codigo del 628A lo corregía. pero bueno eso es a gusto de cada uno.

como me parecio un desperdicio usar un PIC DIP-40 como el 877A solo para un vumetro lo deje como ejemplo y no tiene implementado la opción guardar en la EEPROM el modo seleccionado y tiene pocos comentarios, sepan disculpar.

C:
// PIC16F877A Configuration Bit Settings

// CONFIG
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = ON         // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3/PGM pin has PGM function; low-voltage programming enabled)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

#include <xc.h>
#include <stdint.h>
#define _XTAL_FREQ 8000000

uint8_t registro[4];
#define LLSB registro[0]
#define LMSB registro[1]
#define RLSB registro[2]
#define RMSB registro[3]

uint16_t PeakR = 0xFFFF;
uint16_t PeakL = 0xFFFF;
uint8_t tiempoR = 244; // 500ms @ 8Mhz
uint8_t tiempoL = 244;
uint8_t pocision = 0;
uint8_t lectura_AN0;
uint8_t lectura_AN1;
uint8_t valor_adc;
uint16_t mezcla;
uint16_t punto;
uint16_t barra;
uint8_t Temp01,Temp02,Temp03,Temp04;

uint8_t JMPSL = 0b00000100; // bit Enclavamiento bit2 = 1
uint8_t DTMODE = 0;         // registro temporal

const uint8_t Tabla_Log[16] = {
    0x02, 0x08, 0x0E, 0x13, 0x19, 0x1F, 0x26, 0x2D,
    0x36, 0x3E, 0x4A, 0x58, 0x6B, 0x89, 0xB4, 0xF8};

const uint8_t Anodos[4] = {0x01, 0x02, 0x04, 0x08};

void Logaritmo(uint8_t valor_adc) {
    punto = 0xFFFF;
    barra = 0x0000;

    for (int i = 15; i >= 0; i--) {
        if (valor_adc >= Tabla_Log[i]){
            punto &= ~(1U << i);
            break;          
        } else {
            barra |= (1U << i);
        }
    }
}

void __interrupt() ISR(void) {
    if (TMR0IF) {
        TMR0IF = 0;      
        PORTE = 0x00; // anodos en 0
       
        if (tiempoL > 0){          
            tiempoL--;
        }
        if (tiempoL == 0) {
            if (PeakL < 0xFFFF) {
                PeakL = (uint16_t)((PeakL >> 1) | 0x8000);
            }
            tiempoL = 20;
        }
       
        if (tiempoR > 0){          
            tiempoR--;
        }
        if (tiempoR == 0) {
            if (PeakR < 0xFFFF) {
                PeakR = (uint16_t)((PeakR >> 1) | 0x8000);
            }
            tiempoR = 20;
        }
       

        PORTD = registro[pocision]; // nuevo cátodo
        PORTE = Anodos[pocision];   // nuevo anodo
        pocision++;
        pocision &= 0x03;
   
        PORTB = Temp03;
        PORTC = Temp04;
    }
}

void main(void) {
   
    OPTION_REG = 0b01000011;
    ADCON0 = 0b01000011;
// | ADCS1 = 0| ADCS0 = 1 | CHS2-CHS1-CHS0 | GO/DONE = 1 | ? | ADON = 1 |
    ADCON1 = 0b01100101;
// | ADFM = 0 | ADCS2 = 1 |-U-|-U-| PCFG3-0 = xxDD-ADAA |
    TRISA  = 0b00001111; // 1=in 0=out
//  PORTX  = --76543210
    TRISB = 0x00;
    TRISC = 0x00;
    TRISD = 0x00;
    TRISE = 0x00;
    PORTB = 0x00;
    PORTC = 0x00;
    PORTD = 0x00;
    PORTE = 0x00;
   
    T1CON = 0b00000101;
    INTCON = 0b10100000;
   
    DTMODE = 0xFF;  // EEPROM por default lee 0xFF
    JMPSL = DTMODE;
    JMPSL |= 0x04;  // iniciamos con 1 el bit de enclavamiento
    PORTA = (PORTA & ~0x30)|(uint8_t)(JMPSL << 4); // arreglo de prueba
   
    while(1)
    {

        LLSB = Temp01;
        LMSB = Temp02;
        RLSB = Temp03;
        RMSB = Temp04;
       
       
        if ((JMPSL & 0x04) != 0) {      // bit de enclavamiento (inicia con 1)
            if ((PORTA & 0x04) == 0) {  // RA2 ( pueden aprovechar los PICs
                DTMODE--;               // con RA5/MCLR que son solo entrada)
                DTMODE &= 0x03;         // Mascara 0bxxxx-xx11
                JMPSL = DTMODE;         // intercambio de dato (sin uso)
                JMPSL &= ~0x04;         // bit de enclavamiento en 0
                PORTA = (PORTA & ~0x30)|(uint8_t)(JMPSL << 4);
            }                           // arreglo de prueba RA4,RA5
        }
        else {
            if ((PORTA & 0x04) != 0) {  // RA2 liberado? (dejo de presionar)
                JMPSL |= 0x04;          // restaura en 1 el bit
            }
        }
       
       
        ADCON0bits.CHS0 = 0;
        __delay_us(20);
        GO_nDONE = 1;
        while(GO_nDONE);
        lectura_AN0 = ADRESH;
       
        ADCON0bits.CHS0 = 1;
        __delay_us(20);
        GO_nDONE = 1;
        while(GO_nDONE);
        lectura_AN1 = ADRESH;
       
        Logaritmo(lectura_AN0);
        if (punto <= PeakL){
            PeakL = punto;
            tiempoL = 244;
        }
       
        switch(JMPSL&0x03)
        {
            case 0x00:  
            mezcla = punto;
            break;
            case 0x01:
            mezcla = barra;
            break;
            case 0x02:
            mezcla = punto & PeakL;
            break;
            case 0x03:
            mezcla = barra & PeakL;
            break;
        }
       
        Temp01 = (uint8_t)(mezcla & 0xFF);
        Temp02 = (uint8_t)((mezcla >> 8) & 0xFF);

       
        Logaritmo(lectura_AN1);
        if (punto <= PeakR){
            PeakR = punto;
            tiempoR = 244;
        }
       
        switch(JMPSL&0x03)
        {
            case 0x00:  
            mezcla = punto;
            break;
            case 0x01:
            mezcla = barra;
            break;
            case 0x02:
            mezcla = punto & PeakR;
            break;
            case 0x03:
            mezcla = barra & PeakR;
            break;
        }
       
        Temp03 = (uint8_t)(mezcla & 0xFF);
        Temp04 = (uint8_t)((mezcla >> 8) & 0xFF);
    }
}

Saludos.

Ahora si se esta poniendo lindo el tema 🤩
Llego a casa y lo miro con detenimiento
 
Atrás
Arriba