Program Zscan100 ' ' Device = 18F2620 Clock = 10 ' Config OSC = HS, LVP = OFF, DEBUG = OFF, PWRT = ON, WDT = OFF, PBADEN = OFF, 'for 18F4620 - makes port B digital XINST=OFF ' Include "usart", "EEPROM", "convert", "adc" Const CR = 13, 'carriage return LF = 10, 'line feed Tab = 9, 'tab feed WriteToMem = %0, ReadFromMem = %1, Step25Hz = %1, Step50Hz = %0, StoredFreq = %0, PotFreq = %1, LowStep = 25, 'frequency step in Hz HighStep = 50, AvgSize = 8 'number of freq readings to boxcar average // #Define SerialDebug 'if this is defined there are serial outputs for debugging Dim Freq As LongInt, AvgAry(AvgSize) As LongInt, 'holds individual frequency readings SumFreq As LongInt, Pass As Byte, 'for averaging pass LEDSel As Integer, CenterFreq As Integer, 'center frequency in Hz Fixed As PORTC.1, 'if 1 use current pot postion; if 0 use stored memory value SpanWidth As PORTA.5, 'if 1 step width = 25 Hz, if 0 then step width = 50 Hz SaveToMem As PORTC.0, 'if 1 recall from memory; if 0 then write to memory InPort As PORTC.5, 'input signal to this port Timer As TMR1L.AsWord, LEDBank0 As PORTC.2, 'LEDs are connected in 3 banks of 8 each LEDBank1 As PORTC.3, LEDBank2 As PORTC.4 '------------------ Sub InitializeADC() '------------------ // initialise ADC... ADC.SetConvTime(FOSC_64) ADC.SetAcqTime(5) 'PIC defaults on power up to all as inputs, but still good idea to explicit 'assign the pins to input TRISA.0 = %1 // configure AN0 as an input 'for 18F2420, follow setup in data sheet, section 19 VCFG1 = %0 'negative reference to ground VCFG0 = %0 'positive reference to Vdd PCFG3 = %1 ' The configuration nibble is %1110 PCFG2 = %1 ' - voltage reference is to Vss PCFG1 = %1 ' + voltage reference is to Vdd PCFG0 = %0 ' AN0 is analog input, all other PortA pins are DIGITAL End Sub 'turns LED p on. LEDs are numbered from 0 to 23 'for 0, the center LED is on, - goes left, + goes right '------------------------- Sub TurnOn(pID As Integer) '------------------------- Const PortVal(8) As Byte = (%11111110,%11111101,%11111011,%11110111,%11101111,%11011111,%10111111,%01111111) Dim BankNo As Byte 'to avoid ghosting, follow this order Low(LEDBank0) 'first turn off all LEDs Low(LEDBank1) 'then turn on the one that should be illuminated Low(LEDBank2) pID = pID + 12 If pID < 0 Then pID = 0 EndIf 'bound the leds If pID > 23 Then pID = 23 EndIf 'stick high LED on BankNo = pId / 8 'LEDs connected in 3 banks of 8 each PORTB = PortVal(pID Mod 8) 'to illuminate LED, Port B pin taken low to select 1 of 8 Select BankNo 'then to select bank, take one of the three PortC pins high Case 0 High(LEDBank0) Case 1 High(LEDBank1) Case 2 High(LEDBank2) EndSelect End Sub 'Read DIP switches '------------------------- Function ReadDip() As Byte '------------------------- Result = (PORTA And %00011110) 'grab all of port A, mask off parts not wanted Result = Result >> 1 'shift right 1 to get 0...$F result, as switches are on A4...A1 End Function 'Initialization code here '--------------- Sub Initialize() '--------------- Dim i As Integer TRISB = $00 ADCON1 = %00001111 TRISA = $00 PORTB = $FF 'turn all off PORTA.4 = %1 PORTA.5 = %1 Input(InPort) 'has slicer connected to it Input(PORTA.1) 'frequency memory selection ports Input(PORTA.2) Input(PORTA.3) Input(PORTA.4) Output(LEDBank0) Output(LEDBank1) Output(LEDBank2) #IfDef SerialDebug USART.SetBaudrate(br9600) USART.Write("Good to go and ready to launch!",CR,LF) DelayMS(500) #EndIf Pass = 0 //set up for averaging SumFreq = 0 For i = 0 To AvgSize-1 AvgAry(i) = 0 Next //i End Sub 'boxcar average routine Function ComputeAvg(pFreq As LongInt) As LongInt '----------------------------------------------- Dim temp As Byte temp = Pass Mod AvgSize SumFreq = SumFreq + pFreq -AvgAry(temp) Result = SumFreq / AvgSize AvgAry(temp) = pFreq Inc(Pass) End Function 'test LEDs at startup '---------------------- Sub TestLEDs() '---------------------- Dim i As ShortInt For i = -12 To 11 TurnOn(i) DelayMS(150) Next Low(LEDBank0) 'turn all LEDs off Low(LEDBank1) Low(LEDBank2) End Sub '================= 'Main code here '================= Initialize InitializeADC TestLEDs Repeat #IfDef SerialDebug USART.Write(BinToStr(Fixed),CR,LF) #EndIf 'option here is to read the pot If Fixed = PotFreq Then CenterFreq = 3* ADC.Read(0) 'read the pot to get the low frequency edge 'range is thus approx 200 - 3200 Hz End If 'recall stored frequency from memory If Fixed = StoredFreq Then CenterFreq = EE.ReadWord(2*ReadDip) EndIf Repeat Until InPort = %1 'following code ensures that a full half cycle is read Repeat Until InPort = %0 'delay one 0 level after the first high level 'this ensures a full half cycle is read Timer = 0 'use timer 1 to measure it PIE1.0 = 1 'counter is Fosc/4, so 400 ns/tick T1CON.0 = 1 'start the counter Repeat 'now count until the next high level Until InPort = %1 ' T1CON.0 = 0 'stop the timer #IfDef SerialDebug USART.Write(DecToStr(Timer),CR,LF) #EndIf 'counter is reading half the interval and the ticks are Freq = 1250000 / Timer '2500000/sec so for half interval, 1250000 is the number to use 'timer granularity (400ns) gives ~ 7 Hz error at 3KHz. At more normal frequencies 'error is less. At 1 KHz ~ 0.8 Hz error results from +/- 400 ns. 'Delayms(10) 'selection is 25 or 50 Hz steps If SpanWidth = Step25Hz Then LEDSel = (ComputeAvg(Freq) - CenterFreq) / LowStep Else LEDSel = (ComputeAvg(Freq) - CenterFreq) / HighStep End If TurnOn(LEDSel) 'light the appropriate LED If SaveToMem = WriteToMem Then 'in mode to read ADC and write to memory EE.WriteWord(2*ReadDip,3* ADC.Read(0)) 'read the POT and save the value to EEPROM EndIf Until False End