; DEVICE = 16F628A ; Mains grid frequency indicator, 24 LEDs indicate the line frequency in 10 mHz increments from 49.89 to 50.12 Hz ; using 24 LEDs and three HEF4094B shift registers reused from LED PPM project. ; To reduce jitter a 50 Hz bandpass filter is recommended. ; US 60 Hz version should be trivial ; Filename: super_netzlupe.asm ; v0.1 220407 Copied from netzlupe.asm ; v0.2 220407 Fixed lamp test ; v0.3 220408 Display measured averaged value MA ; v0.4 220408 Calibrated display again OK ; v0.5 230115 Backlight ; v1.0 230115 Release LIST P=16F628A, F=INHX8M #include <p16f628a.inc> __CONFIG _XT_OSC & _WDT_OFF & _LVP_OFF & _CP_OFF ERRORLEVEL -302 ; sod message about using proper bank ; Equates RESET_V EQU 0x00 ; Address of RESET Vector OSC_FREQ EQU D'4000000' ; Oscillator Frequency is 4.0 MHz ; Registers FLAGS EQU 0x20 ; Only used for lamp test MAN EQU 0x21 ; Moving Average * N MA EQU 0x22 ; Moving Average which gets displayed MAPREV EQU 0x23 ; Previous Moving Average MAINT EQU 0x24 ; Intermediate value for moving average calculation (SUBWF) XI EQU 0x25 ; Measurement to be averaged SKIP EQU 0x26 ; Skip display counter to make readout less jittery DISP EQU 0x27 ; Value to be displayed from MA including GLIDE BLCTR EQU 0x28 ; Backlight Counter HEF1 EQU 0x2B ; First shift register HEF2 EQU 0x2C ; Second shift register HEF3 EQU 0x2D ; Third shift register ; Flags #define LAMPTST FLAGS,0 #define LTWAIT FLAGS,1 ; Slow down lamp test (1 second) ; Ports #define SDI PORTB,7 ; Serial Data line of HEF4094 #define CLK PORTB,6 ; Clock for HEF4094 (high pulse) #define OE PORTB,4 ; Output Enable for HEF4094 (active high) #define STROE PORTB,3 ; STRObE for HEF4094 (high pulse) ; Port RB0 is INT for 50 Hz input with INTF as flag for interrupt ;LEDs #define LED1 HEF1,0 ; Q5 output of HEF1, 50.12 Hz and up (RED, extragratis LED) #define LED2 HEF1,1 ; Q6 output of HEF1, 50.11 Hz (RED) #define LED3 HEF1,2 ; Q7 output of HEF1, 50.10 Hz (RED) #define LED4 HEF1,3 ; Q8 output of HEF1, 50.09 Hz (RED) #define LED5 HEF1,4 ; Q1 output of HEF1, 50.08 Hz (RED) #define LED6 HEF1,5 ; Q2 output of HEF1, 50.07 Hz (YEL) #define LED7 HEF1,6 ; Q3 output of HEF1, 50.06 Hz (YEL) #define LED8 HEF1,7 ; Q4 output of HEF1, 50.05 Hz (YEL) #define LED9 HEF2,0 ; Q5 output of HEF2, 50.04 Hz (YEL) #define LED10 HEF2,1 ; Q6 output of HEF2, 50.03 Hz (GRN) #define LED11 HEF2,2 ; Q7 output of HEF2, 50.02 Hz (GRN) #define LED12 HEF2,3 ; Q8 output of HEF2, 50.01 Hz (GRN) #define LED13 HEF2,4 ; Q1 output of HEF2, 50.00 Hz (BLU) #define LED14 HEF2,5 ; Q2 output of HEF2, 49.99 Hz (GRN) #define LED15 HEF2,6 ; Q3 output of HEF2, 49.98 Hz (GRN) #define LED16 HEF2,7 ; Q4 output of HEF2, 49.97 Hz (GRN) #define LED17 HEF3,0 ; Q5 output of HEF3, 49.96 Hz (YEL) #define LED18 HEF3,1 ; Q6 output of HEF3, 49.95 Hz (YEL) #define LED19 HEF3,2 ; Q7 output of HEF3, 49.94 Hz (YEL) #define LED20 HEF3,3 ; Q8 output of HEF3, 49.93 Hz (YEL) #define LED21 HEF3,4 ; Q1 output of HEF3, 49.92 Hz (RED) #define LED22 HEF3,5 ; Q2 output of HEF3, 49.91 Hz (RED) #define LED23 HEF3,6 ; Q3 output of HEF3, 49.90 Hz (RED) #define LED24 HEF3,7 ; Q4 output of HEF3, 49.89 Hz and down (RED) ORG 0x00 GOTO START ORG 0x04 ; Interrupt handlers BCF INTCON,INTF ; Clear the interrupt caused by RB0 INT (there are no others) GOTO UPDATE RETFIE ; Just in case UPDATE ; Calculate moving average: MA*[i]=MA*[i-1]+X[i]-MA*[i-1]/N (MA*=MA*N, N=4) MOVFW TMR1L ; Get timer1 LSB, 0x4E20 is 20,000 us ADDLW 0x27 ; Offset and correction -> 0x40 MOVWF XI ; Store into measurement register CLRF TMR1L ; Need to clear Timer1 as soon as possible CLRF TMR1H CALL Backlight CALL Show ; Put here to make sure the display is updated BCF STATUS,C ; Clear carry RRF XI,1 ; divide by two (->0x20) MOVFW MAN ; Get previous moving average*N MOVWF MAPREV ; Store previous moving average*N ADDWF XI,0 ; Add X[i] MOVWF MAINT ; Intermediate calculation MA BCF STATUS,C ; Clear carry RRF MAPREV,1 ; Calculate previous moving average/N BCF STATUS,C ; Clear carry RRF MAPREV,0 ; Divide by 4 and store in W SUBWF MAINT,0 ; and subtract MA MOVWF MAN ; Store new moving average *N MOVWF MA ; and store in MA (temp) BCF STATUS,C ; Clear carry RRF MA,1 ; Calculate moving average (MA*/N) BCF STATUS,C ; Clear carry RRF MA,1 ; Divide by 4 and keep in MA BTFSC LAMPTST GOTO LAMPTEST DISPLAY ; The final value gets decoded and displayed DECFSZ SKIP RETFIE MOVLW 0x19 ; Every 500 ms (25*20ms) update display MOVWF SKIP MOVFW MA MOVWF DISP ; Get display value CLRF HEF1 CLRF HEF2 CLRF HEF3 ; Test for LED1, <0x0E MOVFW DISP SUBLW 0x09 BTFSS STATUS,C GOTO $+3 BSF LED1 RETFIE ; Test for LED1+2 MOVFW DISP SUBLW 0x0A BTFSS STATUS,C GOTO $+4 BSF LED1 BSF LED2 RETFIE ; Test for LED2 MOVFW DISP SUBLW 0x0B BTFSS STATUS,C GOTO $+3 BSF LED2 RETFIE ; Test for LED2+3 MOVFW DISP SUBLW 0x0C BTFSS STATUS,C GOTO $+4 BSF LED2 BSF LED3 RETFIE ; Test for LED3 MOVFW DISP SUBLW 0x0D BTFSS STATUS,C GOTO $+3 BSF LED3 RETFIE ; Test for LED3+4 MOVFW DISP SUBLW 0x0E BTFSS STATUS,C GOTO $+4 BSF LED3 BSF LED4 RETFIE ; Test for LED4 MOVFW DISP SUBLW 0x0F BTFSS STATUS,C GOTO $+3 BSF LED4 RETFIE ; Test for LED4+5 MOVFW DISP SUBLW 0x10 BTFSS STATUS,C GOTO $+4 BSF LED4 BSF LED5 RETFIE ; Test for LED5 MOVFW DISP SUBLW 0x11 BTFSS STATUS,C GOTO $+3 BSF LED5 RETFIE ; Test for LED5+6 MOVFW DISP SUBLW 0x12 BTFSS STATUS,C GOTO $+4 BSF LED5 BSF LED6 RETFIE ; Test for LED6 MOVFW DISP SUBLW 0x13 BTFSS STATUS,C GOTO $+3 BSF LED6 RETFIE ; Test for LED6+7 MOVFW DISP SUBLW 0x14 BTFSS STATUS,C GOTO $+4 BSF LED6 BSF LED7 RETFIE ; Test for LED7 MOVFW DISP SUBLW 0x15 BTFSS STATUS,C GOTO $+3 BSF LED7 RETFIE ; Test for LED7+8 MOVFW DISP SUBLW 0x16 BTFSS STATUS,C GOTO $+4 BSF LED7 BSF LED8 RETFIE ; Test for LED8 MOVFW DISP SUBLW 0x17 BTFSS STATUS,C GOTO $+3 BSF LED8 RETFIE ; Test for LED8+9 MOVFW DISP SUBLW 0x18 BTFSS STATUS,C GOTO $+4 BSF LED8 BSF LED9 RETFIE ; Test for LED9 MOVFW DISP SUBLW 0x19 BTFSS STATUS,C GOTO $+3 BSF LED9 RETFIE ; Test for LED9+10 MOVFW DISP SUBLW 0x1A BTFSS STATUS,C GOTO $+4 BSF LED9 BSF LED10 RETFIE ; Test for LED10 MOVFW DISP SUBLW 0x1B BTFSS STATUS,C GOTO $+3 BSF LED10 RETFIE ; Test for LED10+11 MOVFW DISP SUBLW 0x1C BTFSS STATUS,C GOTO $+4 BSF LED10 BSF LED11 RETFIE ; Test for LED11 MOVFW DISP SUBLW 0x1D BTFSS STATUS,C GOTO $+3 BSF LED11 RETFIE ; Test for LED11+12 MOVFW DISP SUBLW 0x1E BTFSS STATUS,C GOTO $+4 BSF LED11 BSF LED12 RETFIE ; Test for LED12 MOVFW DISP SUBLW 0x1F BTFSS STATUS,C GOTO $+3 BSF LED12 RETFIE ; Test for LED12+13 MOVFW DISP SUBLW 0x20 BTFSS STATUS,C GOTO $+4 BSF LED12 BSF LED13 RETFIE ; Test for LED13 MOVFW DISP SUBLW 0x21 BTFSS STATUS,C GOTO $+3 BSF LED13 RETFIE ; Test for LED13+14 MOVFW DISP SUBLW 0x22 BTFSS STATUS,C GOTO $+4 BSF LED13 BSF LED14 RETFIE ; Test for LED14 MOVFW DISP SUBLW 0x23 BTFSS STATUS,C GOTO $+3 BSF LED14 RETFIE ; Test for LED14+15 MOVFW DISP SUBLW 0x24 BTFSS STATUS,C GOTO $+4 BSF LED14 BSF LED15 RETFIE ; Test for LED15 MOVFW DISP SUBLW 0x25 BTFSS STATUS,C GOTO $+3 BSF LED15 RETFIE ; Test for LED15+16 MOVFW DISP SUBLW 0x26 BTFSS STATUS,C GOTO $+4 BSF LED15 BSF LED16 RETFIE ; Test for LED16 MOVFW DISP SUBLW 0x27 BTFSS STATUS,C GOTO $+3 BSF LED16 RETFIE ; Test for LED16+17 MOVFW DISP SUBLW 0x28 BTFSS STATUS,C GOTO $+4 BSF LED16 BSF LED17 RETFIE ; Test for LED17 MOVFW DISP SUBLW 0x29 BTFSS STATUS,C GOTO $+3 BSF LED17 RETFIE ; Test for LED17+18 MOVFW DISP SUBLW 0x2A BTFSS STATUS,C GOTO $+4 BSF LED17 BSF LED18 RETFIE ; Test for LED18 MOVFW DISP SUBLW 0x2B BTFSS STATUS,C GOTO $+3 BSF LED18 RETFIE ; Test for LED18+19 MOVFW DISP SUBLW 0x2C BTFSS STATUS,C GOTO $+4 BSF LED18 BSF LED19 RETFIE ; Test for LED19 MOVFW DISP SUBLW 0x2D BTFSS STATUS,C GOTO $+3 BSF LED19 RETFIE ; Test for LED19+20 MOVFW DISP SUBLW 0x2E BTFSS STATUS,C GOTO $+4 BSF LED19 BSF LED20 RETFIE ; Test for LED20 MOVFW DISP SUBLW 0x2F BTFSS STATUS,C GOTO $+3 BSF LED20 RETFIE ; Test for LED20+21 MOVFW DISP SUBLW 0x30 BTFSS STATUS,C GOTO $+4 BSF LED20 BSF LED21 RETFIE ; Test for LED21 MOVFW DISP SUBLW 0x31 BTFSS STATUS,C GOTO $+3 BSF LED21 RETFIE ; Test for LED21+22 MOVFW DISP SUBLW 0x32 BTFSS STATUS,C GOTO $+4 BSF LED21 BSF LED22 RETFIE ; Test for LED22 MOVFW DISP SUBLW 0x33 BTFSS STATUS,C GOTO $+3 BSF LED22 RETFIE ; Test for LED22+23 MOVFW DISP SUBLW 0x34 BTFSS STATUS,C GOTO $+4 BSF LED22 BSF LED23 RETFIE ; Test for LED23 MOVFW DISP SUBLW 0x35 BTFSS STATUS,C GOTO $+3 BSF LED23 RETFIE ; Test for LED23+24 MOVFW DISP SUBLW 0x36 BTFSS STATUS,C GOTO $+4 BSF LED23 BSF LED24 RETFIE ; No test for LED24 necessary, >=0x36 BSF LED24 RETFIE ; End interrupt handlers START CLRF STATUS ; Do initialization, Select bank 0 CLRF INTCON ; Clear int-flags, Disable interrupts CLRF PCLATH ; Keep in lower 2KByte MOVLW B'00000111' ; Disable comparators (damn you Microchip! Should have been 0x00!) MOVWF CMCON BSF STATUS, RP0 ; Select bank 1 CLRF TRISA ; RA7-0 Outputs CLRF TRISB ; RB7-0 Outputs BSF TRISB,0 ; Except RB0 (INT) MOVLW B'11000000' ; Disable weak pullups, INT rising edge MOVWF OPTION_REG BCF STATUS, RP0 ; Select bank 0 MOVLW 0xFF MOVWF PORTA ; Make all PORT A outputs high (LEDs OFF) MOVWF PORTB ; Make all PORT B outputs high ; Clear/init registers CLRF FLAGS MOVLW 0x01 ; To make sure the first readout gets displayed after lamp test MOVWF SKIP CLRF HEF1 CLRF HEF2 CLRF HEF3 ; Set up interrupts CLRF PIR1 ; Clear peripheral stuff BSF STATUS,RP0 ; Go to bank 1 (BANKSEL PIE1) CLRF PIE1 ; Clear more peripheral stuff BCF STATUS,RP0 ; Go to bank 0 BSF INTCON,INTE ; Enable external interrupt on RB0 ; Setup Timer1 BCF T1CON,T1CKPS1 ; These set the TIMER1 prescaler. Values: BCF T1CON,T1CKPS0 ; 00=1:1 01=1:2 10=1:4 11=1:8 BCF T1CON,T1OSCEN ; Turn off the TIMER1 oscillator (we don't need it because we're using the internal oscillator) BCF T1CON,TMR1CS ; Select the internal oscillator for TIMER1 BSF T1CON,TMR1ON ; Enable TIMER1 CLRF TMR1H CLRF TMR1L BSF LAMPTST BSF LED24 ; Switch on leftmost LED BSF INTCON,GIE ; Enable global interrupts MAIN NOP GOTO MAIN ; Loop forever ; Subroutines Backlight BTFSC LAMPTST ; Lamp Test ongoing? RETURN ; Yes BCF OE ; Disable (Hi-Z) outputs HEF chips to prevent ghosting BSF SDI MOVLW 0x18 ; Preload backlight counter for 24 clock pulses MOVWF BLCTR BSF CLK BCF CLK DECFSZ BLCTR,F GOTO $-3 ; Clock out ones for backlight BCF SDI BSF STROE BCF STROE ; STROEobe latch BSF OE ; Re-enable (Hi-Z) outputs HEF chips MOVLW 0x3F MOVWF BLCTR ; Preload counter for 0.2 ms DECFSZ BLCTR,F GOTO $-1 ; Ugly delay loop RETURN ; Clock out HEF data. Takes 148 µs. Fucked up interleaving because of layout. Show BCF OE ; Disable (Hi-Z) outputs HEF chips to prevent ghosting BTFSC LED20 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED20 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED19 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED19 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED18 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED18 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED17 ; Bit clear? BSF SDI ; Clear Data Line BTFSS LED17 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED24 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED24 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED23 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED23 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED22 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED22 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED21 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED21 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED12 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED12 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED11 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED11 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED10 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED10 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED9 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED9 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED16 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED16 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED15 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED15 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED14 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED14 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED13 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED13 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED4 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED4 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED3 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED3 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED2 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED2 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED1 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED1 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED8 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED8 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED7 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED7 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED6 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED6 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BTFSC LED5 ; Bit clear? BSF SDI ; No, set Serial Data Line BTFSS LED5 ; Bit set? BCF SDI ; No, clear Serial Data Line BSF CLK BCF CLK ; Output bit BSF STROE BCF STROE ; STROEobe latch BCF SDI ; Clear Data Line BSF OE ; Done shift register, enable outputs RETURN LAMPTEST ; Lamp Test! Yeah! BTFSS LTWAIT ; Skip next LED increment? GOTO $+3 ; No BCF LTWAIT RETFIE BSF LTWAIT BTFSS LED24 ; LED24 ON? GOTO $+4 ; No BCF LED24 BSF LED23 RETFIE BTFSS LED23 ; LED23 ON? GOTO $+4 ; No BCF LED23 BSF LED22 RETFIE BTFSS LED22 ; LED22 ON? GOTO $+4 ; No BCF LED22 BSF LED21 RETFIE BTFSS LED21 ; LED21 ON? GOTO $+4 ; No BCF LED21 BSF LED20 RETFIE BTFSS LED20 ; LED20 ON? GOTO $+4 ; No BCF LED20 BSF LED19 RETFIE BTFSS LED19 ; LED19 ON? GOTO $+4 ; No BCF LED19 BSF LED18 RETFIE BTFSS LED18 ; LED18 ON? GOTO $+4 ; No BCF LED18 BSF LED17 RETFIE BTFSS LED17 ; LED17 ON? GOTO $+4 ; No BCF LED17 BSF LED16 RETFIE BTFSS LED16 ; LED16 ON? GOTO $+4 ; No BCF LED16 BSF LED15 RETFIE BTFSS LED15 ; LED15 ON? GOTO $+4 ; No BCF LED15 BSF LED14 RETFIE BTFSS LED14 ; LED14 ON? GOTO $+4 ; No BCF LED14 BSF LED13 RETFIE BTFSS LED13 ; LED13 ON? GOTO $+4 ; No BCF LED13 BSF LED12 RETFIE BTFSS LED12 ; LED12 ON? GOTO $+4 ; No BCF LED12 BSF LED11 RETFIE BTFSS LED11 ; LED11 ON? GOTO $+4 ; No BCF LED11 BSF LED10 RETFIE BTFSS LED10 ; LED10 ON? GOTO $+4 ; No BCF LED10 BSF LED9 RETFIE BTFSS LED9 ; LED9 ON? GOTO $+4 ; No BCF LED9 BSF LED8 RETFIE BTFSS LED8 ; LED8 ON? GOTO $+4 ; No BCF LED8 BSF LED7 RETFIE BTFSS LED7 ; LED7 ON? GOTO $+4 ; No BCF LED7 BSF LED6 RETFIE BTFSS LED6 ; LED6 ON? GOTO $+4 ; No BCF LED6 BSF LED5 RETFIE BTFSS LED5 ; LED5 ON? GOTO $+4 ; No BCF LED5 BSF LED4 RETFIE BTFSS LED4 ; LED4 ON? GOTO $+4 ; No BCF LED4 BSF LED3 RETFIE BTFSS LED3 ; LED3 ON? GOTO $+4 ; No BCF LED3 BSF LED2 RETFIE BTFSS LED2 ; LED2 ON? GOTO $+4 ; No BCF LED2 BSF LED1 RETFIE BCF LED1 ; Switch off LED1 BCF LAMPTST ; End Lamp Test RETFIE END