Hola a todos,
Encontré este código en Internet, pero esto funciona solo para LED, no para LCD, entonces, ¿cómo podemos convertirlo para que funcione en LCD VU Meter?
Esperando la respuesta de tu maestro.
Lahmun,
Encontré este código en Internet, pero esto funciona solo para LED, no para LCD, entonces, ¿cómo podemos convertirlo para que funcione en LCD VU Meter?
Esperando la respuesta de tu maestro.
Lahmun,
Código:
' Stereo peak-hold/decay VU meter (2x10 or 2x16 LEDs), version 2.0
' on-the-fly switchable mode (style) jumper
' Filename: VU_2x16_BarJp.bas
' Written for the Proton BASIC compiler v3.6.0.3, © Istvan K, 2017
'$define WIDTH 10 ' 2x10-led
$define WIDTH 16 ' 2x16-led
' peak hold time (also see below):
$define PHOLDTIME 500 ' ms, max 255*4=1020 ms (phold is a 8-bit counter)
'-----------
Device = 16F88 ' a 18-pin PIC
Declare Xtal = 8 ' int osc
' not HS_OSC but INTRC_IO, config word: 0x3F10
Config INTRC_IO, WDT_OFF, MCLR_OFF, LVP_OFF, _
PWRTE_ON, BODEN_OFF, CP_OFF, DEBUG_OFF
' intosc (8 Mhz), RA6 and RA7 (ext osc pins) are IOs, MCLR disabled (input)
' Define ADC parameters:
$if WIDTH = 10
Declare Adin_Res = 8 ' 8-bit result
$else
Declare Adin_Res = 10 ' have to set right justify (ADFM_bit = 1)
$endif
Declare Adin_Tad = FRC ' RC OSC
Declare Adin_Stime = 50 ' 50us sample time
Declare Dead_Code_Remove On
Declare Reminders OFF
Declare Optimiser_Level 2
On_Hardware_Interrupt TMR2_IT ' 1 ms for exact mux timing
' IT timed led multiplexing, using four 5-led groups ('quintets')
' If WIDTH = 16 then four 8-led groups are used (4 'octets')
' Circuit: VU_2x16_BarJp.DSN, input is a real stereo wav file.
' RA0, RA1, RA6, RA7 = mux outputs (ON = 0)
' RA2, RA4 = AN_R, AN_L (AN2 and AN4)
' RA3 = REF (VREF+), set by a pot, sensitivity (level)
' RA5 = MODE jumper: 0 = POINTER, 1 = BAR (standard mode)
' RB3..RB7 = L0...L4 = common 5-bit Led port (5 anodes of all quintets)
' if WIDTH = 16 then the full 8-bit PORTB is used (RB0..7 = L0..7)
' Four pins to drive the common cathodes of the 4 groups (quintets/octets):
' RcH 'R'ight 'c'athodes 'H'igh (group drive pin, active 0)
' RcL 'L'ow
' LcH 'L'eft
' LcL
$define RcH PORTA.0
$define RcL PORTA.7
$define LcH PORTA.1
$define LcL PORTA.6
$define LED_Port PORTB
' on-the-fly switchable mode (style) jumper (BAR_JP, open = 1: BAR mode)
' jumper closed: running led pointer, not bar (plus the lastpeak if any)
' open: a standard VU meter will be displayed (filled bar)
' ie all the LEDs on the left side of the mpeak will also turn on
$define BAR_JP PORTA.5
' different (own) variables for R and L channels:
Dim R_peak As Byte
Dim R_phold As Byte
Dim R_dhold As Byte
Dim L_peak As Byte
Dim L_phold As Byte
Dim L_dhold As Byte
' common variables:
Dim mpeak As Byte ' momentary peak position
Dim lastpeak As Byte
Dim pos As Byte
Dim barbits As Word ' 10 bar positions > 16-bit var, leftmost pos. > bit 6
' 16 bar positions > 16-bit var, leftmost pos. > bit 0
$if WIDTH = 10
Dim adval As Byte
Dim LogTable[10] As Byte ' array in RAM, for speed
$else ' width = 16
Dim adval As Word
Dim LogTable[16] As Word
$endif
Symbol TMR2_ON T2CON.2
'GoTo main
' CMCON = 7 (comparators OFF, automatically placed by the compiler)
'main:
' HW init
OSCCON = %01110000 ' Internal clock at 8 MHz
ANSEL = %00011100 ' set RA2, RA3 (VREF+) and RA4 as analog input
Repeat Until OSCCON.2 = 1 ' IOFS bit, wait until INTOSC frequency stable
TRISA = %00111100 ' mux pins are outputs
TRISB = 0 ' tris reg of LED_Port (PORTB), all outputs
' leds off
PORTA = 0xFF ' all mux pins are off (1)
LED_Port = 0
ADCON1.5 = 1 ' VCFG1 = 1 (use RA3 as VREF+), it remains 1
$if WIDTH = 16' only for 10-bit AD:
ADCON1.7 = 1 ' ADFM = 1: right justified (missing in Proton ADin)
$endif
' init timer2 for mux timing: period = 1 ms
' a channel calculation is max 300 us (without timer2 waiting)
' Prescaler=1:1, PostScaler=1:8, Period = 1 ms (8 MHz clock)
' 1 ms/group, the whole loop is 4 ms (250 Hz refresh rate)
PR2 = 250 ' Timer2 Match value
T2CON = %00111100 ' enable Timer2 with 1:8 postscaler, 1:1 prescaler
PIR1.1 = 0 ' clear TMR2IF
PIE1 = %10 ' only TMR2IE = 1 (enable Timer2 IT)
INTCON = 0xC0 ' Enable global (GIE) and periferial (PEIE) ITs
'init variables:
R_peak = 0
R_phold = 0
R_dhold = 0
L_peak = 0
L_phold = 0
L_dhold = 0
$if WIDTH = 10
' 10-stage log table in RAM, 6 then 3 dB/step, can be modified :-)
' 2, 4, 8, 16, 32, 64, 90, 128, 180, 255
' -36 -30 -24 -18 -12 -6 -3 0 +3 +6 dB
' fill the table:
LogTable[0] = 2
LogTable[1] = 4
LogTable[2] = 8
LogTable[3] = 16
LogTable[4] = 32
LogTable[5] = 64
LogTable[6] = 90
LogTable[7] = 128
LogTable[8] = 180
LogTable[9] = 255
$else
' 16-stage WORD log table in RAM, 3 dB/step
' 6, 8, 11, 16, 23, 32, 45, 64, 90, 127, 180, 255, 361, 510, 721, 1020
'-39 -36 -33 -30 -27 -24 -21 -18 -15 -12 -9 -6 -3 0 +3 +6 dB
' fill the table:
LogTable[0] = 6
LogTable[1] = 8
LogTable[2] = 11
LogTable[3] = 16
LogTable[4] = 23
LogTable[5] = 32
LogTable[6] = 45
LogTable[7] = 64
LogTable[8] = 90
LogTable[9] = 127
LogTable[10] = 180
LogTable[11] = 255
LogTable[12] = 361
LogTable[13] = 510
LogTable[14] = 721
LogTable[15] = 1020
$endif
$define LOOPTIME 4 ' 4 ms repeating (loop) time (used below)
' 4 mS/loop (using 1 ms timer2 IT) = 250 Hz refresh rate at 8 MHz clock
While 1=1 ' infinite loop
adval = ADIn 2 ' sample AN2 (channel R)
GoSub R_PosCalc ' calculate the momentary mpeak and lastpeak
GoSub Set_BarBits ' update barbits using mpeak and lastpeak
' Execution time of the above three routines varies (depends on audio level)
' but this is compensated by the timer2 waiting, so every mux step will be
' exactly 1 ms (to get same brightness for the four led-groups).
' The mux order is: RcH RcL LcH LcL
Repeat Until TMR2_ON = 0 ' wait for timer2 IT (max 1 ms to timer2 off)
TMR2_ON = 1 ' restart timer2
LcL = 1 ' mux off (switch off the lastly switched mux pin)
LED_Port = barbitsH ' R higher quintet/octet
RcH = 0 ' actual (here: the first) mux pin ON
$if WIDTH = 10 ' ie not 16
barbits = barbits >> 3 ' calculate the R lower quintet (see below)
$endif
Repeat Until TMR2_ON = 0
TMR2_ON = 1
RcH = 1
LED_Port = barbits ' R lower quintet/octet
RcL = 0
' calculate mpeak, lastpeak and barbits (for channel L)
adval = ADIn 4 ' appr 107 us
GoSub L_PosCalc ' max 82 us
GoSub Set_BarBits ' 87-90 us
Repeat Until TMR2_ON = 0
TMR2_ON = 1
RcL = 1
LED_Port = barbitsH ' L higher quintet/octet
LcH = 0
$if WIDTH = 10
barbits = barbits >> 3
$endif
Repeat Until TMR2_ON = 0
TMR2_ON = 1
LcH = 1
LED_Port = barbits ' L lower quintet/octet
LcL = 0
Wend ' infinite loop
' --------------------- end of main
' subroutines:
TMR2_IT:
Context Save ' how to disable it (in this case nothing to save) ????
PIR1.1 = 0 ' clear TMR2IF (IT flag)
TMR2_ON = 0 ' stop TMR2, examined (and set) in the main loop
Context Restore
' peak hold/decay timings (in reality other values may be needed, try it!)
' starting value of the counters, decremented once per each main loop:
$define PHOLDCNT PHOLDTIME/LOOPTIME ' countdown before the first decay
' = 125, ie the peak bit stays for 125*4=500 ms before decay begins
$define DHOLDCNT PHOLDCNT/13 ' countdown before the next decay
' = 9, ie the decay repeating time is 9*4=36 ms (for my Proteus !!)
' the above values depend on the speed of the PC so you have to try
R_PosCalc: ' input: adval, output: mpeak and lastpeak variables
mpeak = WIDTH - 1 ' position loop in reversed order, to find mpeak
Do
' comparing adc value to the actual table value
If adval >= LogTable[mpeak] Then
' momentary max position (mpeak) found
If mpeak > R_peak Then ' new, greater peak (pos 0 is excluded)
R_peak = mpeak ' preserve it for the next call
' now lastpeak will be peak, so clear prev. lastpeak if any:
lastpeak.7 = 1 ' invalid (too large) value
' prepare peak hold/decay counters:
R_phold = PHOLDCNT ' (re)start peak hold time (also preserved)
R_dhold = 0 ' if phold is expired, this will be DHOLDCNT
Return ' end of function
EndIf ' end new peak
Break ' exit loop
EndIf ' end of compare
Dec mpeak
Loop While mpeak.7 = 0
' If the loop ran through, mpeak will be 0xFF (invalid value: not found)
' calculate peak hold and decay
If R_phold != 0 Then
Dec R_phold ' previous (last) peak bit (led) remains
Else
' phold time is expired, repeating peak decay begins
If R_dhold != 0 Then
Dec R_dhold
ElseIf R_peak != 0 Then
' Repeat peak decay until zero (or a new, greater peak)
Dec R_peak ' zero peak: end of repeating decay
R_dhold = DHOLDCNT ' re)start decay time
EndIf
EndIf
' lastpeak displayed if it is greater than mpeak (the momentary max)
lastpeak = R_peak
If lastpeak = 0 Then ' zero lastpeak is invalid (excluded)
lastpeak.7 = 1 ' surely too large value
EndIf
Return ' end of R_PosCalc
L_PosCalc: ' same as R_PosCalc but with L_ prefixes
mpeak = WIDTH - 1
Do
If adval >= LogTable[mpeak] Then
If mpeak > L_peak Then
L_peak = mpeak
lastpeak.7 = 1
L_phold = PHOLDCNT
L_dhold = 0
Return
EndIf
Break
EndIf
Dec mpeak
Loop While mpeak.7 = 0
If L_phold != 0 Then
Dec L_phold
Else
If L_dhold != 0 Then
Dec L_dhold
ElseIf L_peak != 0 Then
Dec L_peak
L_dhold = DHOLDCNT
EndIf
EndIf
lastpeak = L_peak
If lastpeak = 0 Then
lastpeak.7 = 1
EndIf
Return ' end of L_PosCalc
' Set_BarBits:
' as the name shows, it only sets the "barbits" variable, that you
' have to send to the appropriate PIC ports to drive the LEDs.
' Its result:
' ****** If WIDTH = 10:
'< barbitsH > < barbits >
'7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 bit numbers (x = undetermined, not used)
'H H H H H L L L L L x x x x x x H = higher quintet, L = lower quintet
' the higher quintet is ready in barbitsH (bit7-3, PORTB.2..0 are not used)
'*** after three right-shifts (barbits >> 3):
'< barbitsH > < barbits >
'7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
'0 0 0 H H H H H L L L L L x x x
' the lower quintet = barbits.7-3 (bit2..0 are not used, too)
' ****** If WIDTH = 16:
'< barbitsH > < barbits >
'7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 bit numbers
'H H H H H H H H L L L L L L L L H = higher octet, L = lower octet
' both octets are ready in barbits (barbitsH, barbits)
Set_BarBits: ' input: mpeak and lastpeak, output: barbits
pos = 0 ' position of the leftmost bar LED
' after 10 rshifts it will be the barbits.6
Do ' pos loop 0..(WIDTH-1)
' rshifted and barbitsH.7 = 0 which means that bit (led) is off:
barbits = barbits >> 1
' compare position with the actual (valid) mpeak and lastpeak:
If BAR_JP = 0 Then ' pointer mode (running led)
If pos = mpeak Then set_led
ElseIf mpeak.7 = 0 Then ' valid mpeak
' filled bar (standard display)
If pos <= mpeak Then set_led
EndIf
If pos = lastpeak Then
set_led:
barbitsH.7 = 1 ' bit (led) is on
EndIf
Inc pos
Loop While pos < WIDTH
Return ' end of Set_BarBits
'----------- end of program, 357 rom, 59 ram (optimiser = 2)