Już nie pamiętam jak długo walczę z tym ustrojstwem ilość rejestrów do ustawienia troszkę mnie przerosła i musiałem szukać pomocy w sieci .
Znalazłem program napisany pod procka Tiny85 a że takiego na składzie nie mam zacząłem go adoptować dla Atmegi8 .
poniżej kod oryginalny bez mojego dłubania .
- '------------------------------------------------------------------
- ' si5351a DDS Oscillator with I2C LCD display
- ' Author: Andrew Woodfield ZL2PD
- ' Date: March 2016
- ' File Name: si85vfoxx.bas (where xx is version number)
- '
- ' Released under the terms and conditions of the
- ' Creative Commons Public License ("CCPL")
- ' See creativecommons.org for details
- '
- ' Commercial use is prohibited without written permission
- ' from the author
- '
- '------------------------------------------------------------------
- ' Adapted from boardtest11.bas:
- '
- ' V01: initial code
- '
- '------------------------------------------------------------------
- ' Credits:
- '
- ' I2C LCD code adapted from www.ne.jp/asahi/shared/o-family/ElecRoom/ElecMAIN.htm
- ' si5351 code is adapted from OE1CGS and Jason Milldrum C code
- '
- ' Rotary encoder software is adapted from:
- ' http://dl6gl.de/software/drehencoder-mit-bascom
- '
- '------------------------------------------------------------------
- ' Program Description:
- ' An ATtiny85 is used to control a Silicon Labs si5351a 3-output
- ' PLL/divider oscillator and I2C 16x2 alphanumeric LCD display with
- ' rotary encoder and some pushbuttons.
- '
- '------------------------------------------------------------------
- ' Fuse settings
- '
- ' LOCK Byte: 0ffh (No locks)
- ' EXTd Byte: 0ffh (BOD disabled)
- '
- ' HIGH Byte: 05fh
- ' RSTDISBL 0 DISABLED
- ' DWEN 1 DW not enabled
- ' SPIEN 0 SPI programming enabled
- ' WDTON 1 Watchdog timer off
- ' EESAVE 1 EEPROM not preserved in erase
- ' BODLEVEL2 1 Boot ROM size
- ' BODLEVEL1 1
- ' BODLEVEL0 1 No boot vector at startup
- '
- ' LOW Byte: 0e2h
- ' CKDIV8 1 NOT divided by 8
- ' CKOUT 1 Not enabled
- ' SUT1 1 Slow rising power
- ' SUT0 0
- ' CKSEL3 0 8 MHz internal RC clock
- ' CKSEL2 0
- ' CKSEL1 1
- ' CKSEL0 0
- '
- '------------------------------------------------------------------
- ' Compiler Directives (some fundamental hardware issues)
- $regfile = "attiny85.dat"
- $crystal = 8000000 '8MHz internal RC clock
- $hwstack = 128
- $swstack = 64
- $framesize = 128
- '-------------------------------------------------------------------------------
- ' Declare Variables
- Dim MHz As String * 2 'display subroutine variables
- Dim kHz as string * 3
- Dim Hz as string * 3
- dim lastftext as string * 6 'for display of freqb khz & Hz digits
- dim freqtxt as string * 8
- dim fcnt as Byte
- dim temp as byte 'temporary variable used in sendfreq and sbarplot routines
- Dim Frequency As Dword 'four byte unsigned variable
- dim gfreq as dword 'calculates si5351 VFO output frequency
- Dim Stepsize As Byte
- Dim spin As Byte 'Encoder rotation (encoder incr = 2, decr = 1, no change = 0)
- Dim Delta As Dword
- Dim Encval As Byte 'current rotary encoder value
- Dim Lastencoder As Byte 'previous rotary encoder value
- Dim Update As Bit 'bit is set (1) if a switch or encoder has changed
- dim upwards as bit 'direction of band change
- dim bandup as bit , banddown as bit , modekey as bit 'key flags (0=pressed and 1=not pressed)
- Dim Vadc As Word 'for adc read routine
- Dim Vadcl As Byte At Vadc Overlay
- Dim Vadch As Byte At Vadc + 1 Overlay
- dim bandpointer as byte 'identifies currently selected amateur band
- dim modetype as byte 'holds mode (1=LSB, 2=USB, 3=CW)
- dim ptt as bit 'set by adc routine
- dim fvco as dword 'si5351 vco frequency
- dim outdivider as dword '4,6,8-900
- dim rdivider as byte 'Normally 1 unless freqeuncy<1MHz then 1,2,4,8,16,32,64 or 128 only
- dim rbyte as byte 'used as temp store before final data load to si5351
- dim afactor as dword
- dim bfactor as Dword
- dim fvalue as single 'used to determine accuracy of fractional calculation
- dim finteger as Dword
- dim ms0p1 as Dword '18-bit MS0_P1 si5351 parameters for Output 0
- dim m0p11 as byte at ms0p1 overlay 'mirrored variables for dds calculation
- dim m0p12 as byte at ms0p1 + 1 overlay
- dim m0p13 as byte at ms0p1 + 2 overlay
- dim m0p14 as byte at ms0p1 + 3 overlay 'most significant byte for ms0p1
- 'Note: MS0_P2 and MS0_P3 are hard-coded as 0 and 1 respectively so ignored during dimensioning
- 'si5351 parameters for PLLA
- dim msnap1 as Dword '18-bit variable for MSNA_P1
- dim ms11 as byte at msnap1 overlay 'mirrored variables for dds calculation
- dim ms12 as byte at msnap1 + 1 overlay
- dim ms13 as byte at msnap1 + 2 overlay
- dim ms14 as byte at msnap1 + 3 overlay 'most significant byte
- dim msnap2 as Dword '20-bit variable for MSNA_P2
- dim ms21 as byte at msnap2 overlay 'mirrored variables for dds calculation
- dim ms22 as byte at msnap2 + 1 overlay
- dim ms23 as byte at msnap2 + 2 overlay
- dim ms24 as byte at msnap2 + 3 overlay 'most significant byte
- dim msnap3 as Dword '20-bit variable for MSNA_P3
- dim ms31 as byte at msnap3 overlay 'mirrored variables for dds calculation
- dim ms32 as byte at msnap3 + 1 overlay
- dim ms33 as byte at msnap3 + 2 overlay
- dim ms34 as byte at msnap3 + 3 overlay 'most significant byte
- dim regaddr as byte , regdata as byte 'for i2c calls
- dim siaddr1 as byte , siaddr2 as byte , siaddr3 as byte 'for writing to si5351 CLK0 and CLK1
- ' Declare Constants
- const startfreq = 7100000 '40m starting frequency
- const xtal = 25002900 '**NOTE: Value may be adjusted during alignment ***
- const cfactor = 1048575
- const ifoffset = 8867000 'ifoffset=0 if no offset e.g. VFO used in SDR or DC receiver
- const bfofreq = 8870000 'bfo/cio frequencies but not currently supported in this version
- Const Midas_vdd = 3 'LCD display is powered from 3V rail
- ' Declare Subroutines
- declare sub si5351init 'initialises si5351
- Declare Sub Displaylcd 'displays current oscillator frequency
- Declare Sub Calculate 'converts current VFO or BFO freq to data for si5351
- Declare Sub Sendfreq 'sends VFO or BFO/CIO freq data to si5351 CLK0 or CLK1 respectively
- declare sub siout(sireg as byte , sidata as byte) 'for i2c write to si5351
- declare sub barplot 'plots current s-meter input voltage
- '------------------------------------------------------------------------------------
- ' Hardware Setup
- '
- ' See schematic for details
- '
- ' Hardware Aliases:
- StepKey alias pinb.0 'step key on encoder
- EncA alias pinb.3 'rotary encoder input A
- EncB alias pinb.4 'rotary encoder input B
- ' Initialise I/O (LCD already done above)
- config portb = OUTPUT 'used for filter selection and i2c
- config sda = PORTb.1
- config scl = PORTb.2
- Config Pinb.0 = Input
- config PinB.3 = input
- config PinB.4 = input
- config pinb.5 = input 'adc
- set portb.0 'set pullups
- set portb.3
- set portb.4
- '***************************** Program *****************************************
- 'initialise adc
- config adc = single , prescaler = auto , reference = avcc 'starts automatically
- admux = &b00100000 'left adjust result
- 'initialise i2c here...
- i2cinit
- waitms 50 'for i2c to settle and for lcd RC reset time
- Config Lcd = 16 * 2 'LCD has standard 2 x 16 display
- $lib "Lcd_Midas.lib" 'LCD library for serial LCD
- Initlcd 'so now initialise the LCD
- Cursor Off 'LCD cursor off
- 'brief splash message to the LCD...
- Locate 1 , 1 'Show program version
- Lcd "ZL2PD Tiny85 VFO"
- Locate 2 , 1
- Lcd "Version 1.0 2016"
- Wait 2
- Deflcdchar 1 , 32 , 32 , 16 , 16 , 16 , 16 , 32 , 32 'define the bargraph characters
- Deflcdchar 2 , 32 , 32 , 24 , 24 , 24 , 24 , 32 , 32
- Deflcdchar 3 , 32 , 32 , 28 , 28 , 28 , 28 , 32 , 32
- Deflcdchar 4 , 32 , 32 , 30 , 30 , 30 , 30 , 32 , 32
- Deflcdchar 5 , 32 , 32 , 31 , 31 , 31 , 31 , 32 , 32
- Cls
- 'initialise some variables
- Frequency = startfreq 'initialise frequency (20m for now)
- stepsize = 1
- delta = 5
- spin = 0
- reset update 'clear the flags
- si5351init 'initialises si5351
- gfreq = frequency 'gfreq holds value used for si5351
- 'frequency offset routine
- gfreq = gfreq + ifoffset 'high side injection
- 'gfreq = gfreq - ifoffset 'low-side injection required
- Calculate 'calculate the startup VFO value
- siaddr1 = 26 'point to CLK0 base register addresses
- siaddr2 = 42
- siaddr3 = 44
- Sendfreq 'and send it to the si5351 CLK0
- regaddr = 16
- regdata = 79
- call siout(regaddr , regdata) 'enable CLK0, source=crystal, PLLA=integer mode, power level=8mA i.e. 0dB
- gfreq = bfofreq 'now load bfo frequency
- Calculate 'calculate startup bfo/cio
- siaddr1 = 34 'point to CLK1 base register addresses
- siaddr2 = 50
- siaddr3 = 52
- sendfreq 'and send data to si5351 CLK1
- regaddr = 17
- regdata = 111
- call siout(regaddr , regdata) 'enable CLK1, source=crystal, PLLB=integer mode, power level=8mA i.e. 0dB
- Displaylcd 'then display frequency and status on lcd
- 'Configure the 8-bit Timer0 interrupt for encoder
- 'Overflow time = overflow counts * prescale / uP clock frequency
- '= 128 * 256 / 8,000,000 = 4mS = 244 Hz (8 MHz RC clock)
- 'Here prescale = 256 (Possible prescale factors: 8, 64, 256, 1024)
- Config Timer0 = Timer , Prescale = 256
- Const PresetTimer0 = 192 'Timer preset value to initialize Timer0 i.e. 2mS)
- On Timer0 Timer0_isr 'Timer0 interrupt service routine on overflow
- Enable Timer0 'interrupt encoder
- Enable Interrupts 'enable all interrupts
- Do 'Start of main program
- Vadc = getadc(0) 'get current s-meter value
- barplot 'and plot result
- 'STEP
- If Stepkey = 0 Then
- Incr Stepsize
- If Stepsize = 5 Then Stepsize = 1
- If Stepsize = 1 Then Delta = 5 'Delta value sets tuning rates of 5, 100, 1000 and 10000 Hz/step
- If Stepsize = 2 Then Delta = 100 '24 steps/turn encoder gives about 120Hz, 2.4, 24 and 240kHz/turn
- If Stepsize = 3 Then Delta = 1000
- If Stepsize = 4 Then Delta = 10000
- set update 'to flag this change
- end if
- Keyup1:
- If Stepkey = 0 Then Goto Keyup1 'and wait for button to be released
- 'Processing of rotary encoder
- Disable Timer0 'Stop Timer0 interrupts
- Select Case spin
- Case 1 : Frequency = Frequency - Delta
- Case 2 : Frequency = Frequency + Delta
- End Select
- If spin > 0 or update = 1 Then 'encoder or buttons changed so update display and si5351
- displaylcd 'show new frequency and status
- gfreq = frequency 'gfreq holds value used for si5351
- 'frequency offset routine
- gfreq = gfreq + ifoffset 'high side injection
- 'gfreq = gfreq - ifoffset 'if low-side injection required
- Calculate 'calculate new VFO data
- siaddr1 = 26 'point to CLK0 base register addresses
- siaddr2 = 42
- siaddr3 = 44
- Sendfreq 'and send it to the si5351
- regaddr = 16
- regdata = 79
- call siout(regaddr , regdata) 'enable CLK0, source=crystal, PLLA=integer mode, power level=8mA i.e. 0dB
- spin = 0 'Reset spin after processing
- reset update 'and update flag
- End If
- Enable Timer0 'Restart Timer0
- Loop 'End of main program
- '**********************************************************************
- 'Subroutines...
- '**********************************************************************
- 'Interrupt service routine for Timer0 (encoder)
- 'Encoder interrupt on timer0 overflow
- 'Timer0 should be stopped in main program while data is being displayed
- 'Output: spin = 2: increment or
- ' = 1: decrement if encoder has changed
- 'if no change then spin = 0
- '
- '**********************************************************************
- Timer0_isr:
- Timer0 = PresetTimer0 'Initialize Timer0
- encval = 0 'clear variable
- encval.0 = enca 'input current encoder levels
- encval.1 = encb 'so encval now holds current encoder state
- 'Check if encoder encoder pattern is changed
- 'spin = 1: decremented (turned counter clockwise)
- 'spin = 2: incremented (turned clockwise)
- If encval <> Lastencoder Then 'encoder is changed
- If encval = &B00000011 And Lastencoder = &B00000010 Then spin = 2
- If encval = &B00000011 And Lastencoder = &B00000001 Then spin = 1
- 'the following lines may be required to be ADDED to those above with some encoders
- 'which give an additional step between mechanical detent positions
- ' If encval = &B00000000 And Lastencoder = &B00000001 Then spin = 2
- ' If encval = &B00000000 And Lastencoder = &B00000010 Then spin = 1
- Lastencoder = encval 'update for next time
- End If
- Return
- '**********************************************************************
- '**********************************************************************
- ' Displays frequency on upper line of the 16*2 LCD to 1 Hz resolution
- ' and step size, band, PTT status and mode on the lower line
- ' *************************REDO SOFTWARE***********************
- '**********************************************************************
- Sub Displaylcd
- 'parse Frequency for display
- freqtxt = str(frequency) 'convert frequency to text
- Hz = right(freqtxt , 3) 'extract Hz text
- freqtxt = str(frequency) 'do it again because for some reason !! freqtxt gets blown away by right()
- fcnt = len(freqtxt) - 3 'nbr of remaining digits (assumes lowest freq is 1000 Hz)
- while fcnt < 5
- insertchar freqtxt , 1 , " " 'add spaces to start of text for formatting
- fcnt = fcnt + 1
- wend
- MHz = left(freqtxt , 2) 'now grab first two chars
- kHz = mid(freqtxt , 3 , 3) 'and mid three chars
- Locate 1 , 1 'point to start of top line
- lcd " " ; MHz ; "," ; kHz ; "." ; Hz ; " MHz " 'Format: _MM.kkk.hhh MHz_
- Locate 2 , 1 'second line
- 'Format: SSSSS_xxxxxxxxxx where SSS=step size, x..x=S-meter bargraph (50 dots wide)
- select case stepsize
- case 1 : Lcd " 5Hz "
- case 2 : Lcd "100Hz"
- case 3 : Lcd " 1kHz"
- case 4 : Lcd "10kHz"
- end select
- End Sub
- '**********************************************************************
- ' subroutine to initialise the si5351 chip via I2C
- '**********************************************************************
- Sub si5351init
- regaddr = 183
- regdata = 192
- call siout(regaddr , regdata) 'set xtal load cap to 10pF
- regaddr = 3
- regdata = 0
- call siout(regaddr , regdata) 'enable all outputs
- regaddr = 15
- regdata = 0
- call siout(regaddr , regdata) 'select xtal as PLL input source
- regaddr = 16
- regdata = 15 'PLLA is source, 8mA output
- call siout(regaddr , regdata) 'configure clock 0 control register
- regaddr = 17
- regdata = 47 'PLLB is source, 8mA output
- call siout(regaddr , regdata) 'configure clock 1 control register
- regaddr = 18
- regdata = 47 'PLLB is source, 8mA output
- call siout(regaddr , regdata) 'configure clock 2 control register
- regaddr = 177
- waitms 10 'wait 10ms just in case
- End Sub
- '********************************************************************************
- ' calculate data bytes for current VFO or BFO frequency to send to si5351a CLK0/1
- '********************************************************************************
- sub calculate
- rdivider = 1 'initialise r
- outdivider = 900000000 \ gfreq 'and outdivider
- while outdivider > 900
- rdivider = 2 * rdivider
- outdivider = outdivider \ 2
- wend
- fvco = outdivider mod 2 'check outdivider is an even number
- if fvco <> 0 then outdivider = outdivider - 1 'using fvco as a temporary register
- fvco = outdivider * rdivider
- fvco = fvco * gfreq 'determine PLL frequency
- select case rdivider 'determine value of R44 bits [6:4]
- case 1 : rbyte = 0 '000 0000
- case 2 : rbyte = 16 '001 0000
- case 4 : rbyte = 32 '010 0000
- case 8 : rbyte = 48 '011 0000
- case 16 : rbyte = 64 '100 0000
- case 32 : rbyte = 80 '101 0000
- case 64 : rbyte = 96 '110 0000
- case 128 : rbyte = 112 '111 0000
- end select
- afactor = fvco \ xtal
- fvalue = afactor * xtal 'fvalue = fvco -afactor * xtal
- fvalue = fvco - fvalue 'a+b/c
- fvalue = fvalue * cfactor
- fvalue = fvalue \ xtal
- bfactor = fvalue
- ms0p1 = 128 * outdivider
- ms0p1 = ms0p1 - 512
- fvalue = 128 * bfactor
- fvalue = fvalue \ cfactor
- finteger = fvalue
- msnap1 = 128 * afactor
- msnap1 = msnap1 + finteger 'finteger used instead of fvalue for variable matching
- msnap1 = msnap1 - 512
- msnap3 = finteger * cfactor 'using msnap3 as temp result buffer
- msnap2 = 128 * bfactor
- msnap2 = msnap2 - msnap3
- msnap3 = cfactor
- 'calculations are complete so now build and send the required output data bytes by calling sendfreq (About 20 bytes sent per frequency)
- end sub
- '**********************************************************************
- ' send converted freq data to si5351 for CLK0 output
- '**********************************************************************
- sub sendfreq
- regaddr = siaddr1
- call siout(regaddr , ms32) 'R26=msnap3[15:8]
- incr regaddr
- call siout(regaddr , ms31) 'R27=msnap3[7:0]
- incr regaddr
- call siout(regaddr , ms13) 'R28=msnap1[17:16] in R28[1:0] with R28[7:2]=0
- incr regaddr
- call siout(regaddr , ms12) 'R29=msnap1[15:8]
- incr regaddr
- call siout(regaddr , ms11) 'R30=msnap1[7:0]
- temp = ms33 'temp[3:0]=msnap3[19:16]
- swap temp 'temp[7:4]=msnap3[19:16]
- temp = temp or ms23 'temp[7:4]=msnap3[19:16] and temp[3:0]=msnap2[19:16]
- incr regaddr
- call siout(regaddr , temp) 'R31=(msnap3[19:16],msnap2[19:16])
- incr regaddr
- call siout(regaddr , ms22) 'R32=msnap2[15:8]
- incr regaddr
- call siout(regaddr , ms21) 'R33=msnap2[7:0]
- regaddr = siaddr2
- regdata = 0
- call siout(regaddr , regdata) 'R42=MS0_P3[15:8]
- incr regaddr
- regdata = 1
- call siout(regaddr , regdata) 'R43=MS0_P3[7:0]
- temp = rbyte
- temp = temp or m0p13
- incr regaddr
- call siout(regaddr , temp) 'R44=(0,R[7:4],MS0_P1[17:16])
- incr regaddr
- call siout(regaddr , m0p12) 'R45=MS0_P1[15:8]
- incr regaddr
- call siout(regaddr , m0p11) 'R46=MS0_P1[7:0]
- incr regaddr
- regdata = 0
- call siout(regaddr , regdata) 'R47=(MS0_P3[19:16],MS0_P2[19:16]) and both are always 0
- incr regaddr
- regdata = 0
- call siout(regaddr , regdata) 'R48=MS0_P2[15:8]=0 always
- incr regaddr
- regdata = 0
- call siout(regaddr , regdata) 'R49=MS0_P2[7:0]=0 always
- if outdivider = 4 then 'for output frequencies greater than 150MHz and less than 200MHz
- regaddr = siaddr3
- regdata = 12
- call siout(regaddr , regdata)
- incr regaddr
- regdata = 0
- call siout(regaddr , regdata)
- incr regaddr
- regdata = 0
- call siout(regaddr , regdata)
- end if
- regaddr = 3
- regdata = 4
- call siout(regaddr , regdata) 'enable all outputs except CLK2
- end sub
- '**********************************************************************
- ' i2c transmission to si5351
- '**********************************************************************
- sub siout(sireg as byte , sidata as byte)
- 'subroutine sends databyte to register_nbr at i2c address 192 (si5351 register read is from address 194)
- 'Write a single byte (slave address 192, register sireg, value sibyte)
- I2cstart
- I2cwbyte 192 'i2c address of si5351a
- waitus 1 'suggested delay from forum
- I2cwbyte sireg
- waitus 1
- I2cwbyte sidata
- waitus 1
- I2cstop
- end sub
- '**********************************************************************
- ' s-meter display shows current adc value Vadc plotted on a 50 dot
- ' bargraph on lower line of LCD from (2,7) to end of the line
- '**********************************************************************
- sub barplot
- Local Col As Byte
- Local Bar5 As Byte
- Local Bar1 As Byte
- Bar5 = Vadch \ 25 'nbr of full bargraph blocks
- Bar1 = Vadch Mod 25 'nbr of dots in remaining block
- bar1 = bar1 \ 5
- Locate 2 , 7 'point cursor to start of graph
- For Col = 1 To Bar5 'plot the full blocks
- Lcd Chr(5)
- Next Col
- Select Case Bar1 'and last sub-block
- case 0 : lcd " "
- Case 1 : Lcd Chr(1)
- Case 2 : Lcd Chr(2)
- Case 3 : Lcd Chr(3)
- Case 4 : Lcd Chr(4)
- End Select
- bar5 = bar5 + 2 'point to next location
- if bar5 < 11 then 'blank any previous dots
- for col = bar5 to 10
- lcd " "
- next col
- end if
- end sub
- '**********************************************************************
- end
Jeszcze wprowadzę kilka zmian by dostosować do moich potrzeb w radyjku .
- '------------------------------------------------------------------
- ' si5351a DDS Oscillator with I2C LCD display
- ' Author: Andrew Woodfield ZL2PD
- ' Date: March 2016
- ' File Name: si85vfoxx.bas (where xx is version number)
- '
- ' Released under the terms and conditions of the
- ' Creative Commons Public License ("CCPL")
- ' See creativecommons.org for details
- '
- ' Commercial use is prohibited without written permission
- ' from the author
- '
- '------------------------------------------------------------------
- ' Adapted from boardtest11.bas:
- '
- ' V01: initial code
- '
- '------------------------------------------------------------------
- ' Credits:
- '
- ' I2C LCD code adapted from www.ne.jp/asahi/shared/o-family/ElecRoom/ElecMAIN.htm
- ' si5351 code is adapted from OE1CGS and Jason Milldrum C code
- '
- ' Rotary encoder software is adapted from:
- ' http://dl6gl.de/software/drehencoder-mit-bascom
- '
- '------------------------------------------------------------------
- ' Program Description:
- ' An ATtiny85 is used to control a Silicon Labs si5351a 3-output
- ' PLL/divider oscillator and I2C 16x2 alphanumeric LCD display with
- ' rotary encoder and some pushbuttons.
- '
- '------------------------------------------------------------------
- ' Fuse settings
- '
- ' LOCK Byte: 0ffh (No locks)
- ' EXTd Byte: 0ffh (BOD disabled)
- '
- ' HIGH Byte: 05fh
- ' RSTDISBL 0 DISABLED
- ' DWEN 1 DW not enabled
- ' SPIEN 0 SPI programming enabled
- ' WDTON 1 Watchdog timer off
- ' EESAVE 1 EEPROM not preserved in erase
- ' BODLEVEL2 1 Boot ROM size
- ' BODLEVEL1 1
- ' BODLEVEL0 1 No boot vector at startup
- '
- ' LOW Byte: 0e2h
- ' CKDIV8 1 NOT divided by 8
- ' CKOUT 1 Not enabled
- ' SUT1 1 Slow rising power
- ' SUT0 0
- ' CKSEL3 0 8 MHz internal RC clock
- ' CKSEL2 0
- ' CKSEL1 1
- ' CKSEL0 0
- '
- '------------------------------------------------------------------
- ' Compiler Directives (some fundamental hardware issues)
- '$sim
- $regfile = "m8def.dat"
- $crystal = 8000000 '8MHz internal RC clock
- $hwstack = 128
- $swstack = 64
- $framesize = 128
- '-------------------------------------------------------------------------------
- Config Lcdpin = Pin , Db4 = Pinc.2 , Db5 = Pinc.3 , Db6 = Pinc.4 , Db7 = Pinc.5 , E = Pinc.1 , Rs = Pinc.0
- Config Lcd = 20 * 2
- Config Portb.1 = Output 'dds
- Config Portb.2 = Output 'dds
- Config Sda = Portb.1
- Config Scl = Portb.2
- Config Pinb.0 = Input
- Config Pinb.3 = Input
- Config Pinb.4 = Input
- Set Portb.0 'set pullups
- Set Portb.1
- Set Portb.2
- Set Portb.3
- Set Portb.4
- Stepkey Alias Pinb.0 'step key on encoder
- Enca Alias Pinb.3 'rotary encoder input A
- Encb Alias Pinb.4 'rotary encoder input B
- ' Declare Variables
- Dim Mhz As String * 2 'display subroutine variables
- Dim Khz As String * 3
- Dim Hz As String * 3
- Dim Lastftext As String * 6 'for display of freqb khz & Hz digits
- Dim Freqtxt As String * 9
- Dim Tekst1 As String * 9
- Dim Fcnt As Byte
- Dim Temp As Byte 'temporary variable used in sendfreq and sbarplot routines
- Dim Frequency As Dword 'four byte unsigned variable
- Dim Gfreq As Dword 'calculates si5351 VFO output frequency
- Dim Stepsize As Byte
- Dim Delta As Dword
- Dim Update As Bit 'bit is set (1) if a switch or encoder has changed
- Dim Fvco As Dword 'si5351 vco frequency
- Dim Outdivider As Dword '4,6,8-900
- Dim Rdivider As Byte 'Normally 1 unless freqeuncy<1MHz then 1,2,4,8,16,32,64 or 128 only
- Dim Rbyte As Byte 'used as temp store before final data load to si5351
- Dim Afactor As Dword
- Dim Bfactor As Dword
- Dim Fvalue As Single 'used to determine accuracy of fractional calculation
- Dim Finteger As Dword
- Dim Ms0p1 As Dword '18-bit MS0_P1 si5351 parameters for Output 0
- Dim M0p11 As Byte At Ms0p1 Overlay 'mirrored variables for dds calculation
- Dim M0p12 As Byte At Ms0p1 + 1 Overlay
- Dim M0p13 As Byte At Ms0p1 + 2 Overlay
- Dim M0p14 As Byte At Ms0p1 + 3 Overlay 'most significant byte for ms0p1
- 'Note: MS0_P2 and MS0_P3 are hard-coded as 0 and 1 respectively so ignored during dimensioning
- 'si5351 parameters for PLLA
- Dim Msnap1 As Dword '18-bit variable for MSNA_P1
- Dim Ms11 As Byte At Msnap1 Overlay 'mirrored variables for dds calculation
- Dim Ms12 As Byte At Msnap1 + 1 Overlay
- Dim Ms13 As Byte At Msnap1 + 2 Overlay
- Dim Ms14 As Byte At Msnap1 + 3 Overlay 'most significant byte
- Dim Msnap2 As Dword '20-bit variable for MSNA_P2
- Dim Ms21 As Byte At Msnap2 Overlay 'mirrored variables for dds calculation
- Dim Ms22 As Byte At Msnap2 + 1 Overlay
- Dim Ms23 As Byte At Msnap2 + 2 Overlay
- Dim Ms24 As Byte At Msnap2 + 3 Overlay 'most significant byte
- Dim Msnap3 As Dword '20-bit variable for MSNA_P3
- Dim Ms31 As Byte At Msnap3 Overlay 'mirrored variables for dds calculation
- Dim Ms32 As Byte At Msnap3 + 1 Overlay
- Dim Ms33 As Byte At Msnap3 + 2 Overlay
- Dim Ms34 As Byte At Msnap3 + 3 Overlay 'most significant byte
- Dim Regaddr As Byte , Regdata As Byte 'for i2c calls
- Dim Siaddr1 As Byte , Siaddr2 As Byte 'for writing to si5351 CLK0 and CLK1
- ' Declare Constants
- Const Startfreq = 10000 'xxx '40m starting frequency
- Const Xtal = 25001000 ' xxx 25000000 '**NOTE: Value may be adjusted during alignment ***
- Const Cfactor = 10000 'xxx 1048575
- Frequency = Startfreq 'initialise frequency (20m for now)
- Stepsize = 1
- Delta = 5
- ' Declare Subroutines
- Declare Sub Si5351init 'initialises si5351
- Declare Sub Displaylcd 'displays current oscillator frequency
- Declare Sub Calculate 'converts current VFO or BFO freq to data for si5351
- Declare Sub Sendfreq 'sends VFO or BFO/CIO freq data to si5351 CLK0 or CLK1 respectively
- Declare Sub Siout(sireg As Byte , Sidata As Byte) 'for i2c write to si5351
- Declare Sub Plus
- Declare Sub Minus
- '***************************** Program *****************************************
- ' initialise i2c here...
- I2cinit
- Waitms 50 'for i2c to settle and for lcd RC reset time
- Cursor Off 'LCD cursor of
- Cls
- Update = 0 'clear the flags
- Si5351init 'initialises si5351
- Gfreq = Frequency 'gfreq holds value used for si5351
- Calculate 'calculate the startup VFO value
- Siaddr1 = 26 'point to CLK0 base register addresses
- Siaddr2 = 42
- Sendfreq 'and send it to the si5351 CLK0
- Regaddr = 16
- Regdata = 79
- Call Siout(regaddr , Regdata) 'enable CLK0, source=crystal, PLLA=integer mode, power level=8mA i.e. 0dB
- Displaylcd 'then display frequency and status on lcd
- Do 'Start of main program
- If Stepkey = 0 Then
- Incr Stepsize
- Waitms 500 ' xxx
- If Stepsize = 8 Then 'xxx
- Stepsize = 1
- End If
- If Stepsize = 1 Then Delta = 5 'Delta value sets tuning rates of 5, 100, 1000 and 10000 Hz/step
- If Stepsize = 2 Then Delta = 100 '24 steps/turn encoder gives about 120Hz, 2.4, 24 and 240kHz/turn
- If Stepsize = 3 Then Delta = 1000
- If Stepsize = 4 Then Delta = 10000
- If Stepsize = 5 Then Delta = 100000 'xxx
- If Stepsize = 6 Then Delta = 1000000 ' xxx
- If Stepsize = 7 Then Delta = 10000000 ' xxx
- Update = 1
- Displaylcd 'to flag this change
- End If
- Debounce Pinb.3 , 0 , Plus , Sub
- Debounce Pinb.4 , 0 , Minus , Sub
- If Update = 1 Then 'encoder or buttons changed so update display and si5351
- 'show new frequency and status
- Gfreq = Frequency 'gfreq holds value used for si5351
- Calculate 'calculate new VFO data
- Siaddr1 = 26 'point to CLK0 base register addresses
- Siaddr2 = 42
- Sendfreq 'and send it to the si5351
- Regaddr = 16
- Regdata = 79
- Call Siout(regaddr , Regdata) 'enable CLK0, source=crystal, PLLA=integer mode, power level=8mA i.e. 0dB
- Update = 0
- 'and update flag
- End If
- Loop 'End of main program
- End
- '**********************************************************************
- 'Subroutines...
- '=====================================================================
- Sub Plus
- Frequency = Frequency + Delta
- If Frequency > 150000000 Then
- Frequency = 150000000
- End If
- Update = 1
- Displaylcd
- End Sub
- Sub Minus
- Frequency = Frequency - Delta
- If Frequency < 10000 Then
- Frequency = 10000
- End If
- If Frequency > 150000000 Then
- Frequency = 10000
- End If
- Update = 1
- Displaylcd
- End Sub
- '========================================================================
- '========================================================================
- Sub Displaylcd
- Tekst1 = "000000000"
- Freqtxt = Str(frequency)
- Fcnt = Len(freqtxt)
- If Fcnt = 1 Then
- Mid(tekst1 , 9 , Fcnt) = Freqtxt '9
- Elseif Fcnt = 2 Then
- Mid(tekst1 , 8 , Fcnt) = Freqtxt '8
- Elseif Fcnt = 3 Then
- Mid(tekst1 , 7 , Fcnt) = Freqtxt '7
- Elseif Fcnt = 4 Then
- Mid(tekst1 , 6 , Fcnt) = Freqtxt '6
- Elseif Fcnt = 5 Then
- Mid(tekst1 , 5 , Fcnt) = Freqtxt '5
- Elseif Fcnt = 6 Then
- Mid(tekst1 , 4 , Fcnt) = Freqtxt '5
- Elseif Fcnt = 7 Then
- Mid(tekst1 , 3 , Fcnt) = Freqtxt '3
- Elseif Fcnt = 8 Then
- Mid(tekst1 , 2 , Fcnt) = Freqtxt '2
- Elseif Fcnt = 9 Then
- Mid(tekst1 , 1 , Fcnt) = Freqtxt '1
- End If
- If Frequency < 1000000 Then
- Locate 1 , 1
- Lcd " "
- Lcd Mid(tekst1 , 4 , 3)
- Lcd "."
- Lcd Mid(tekst1 , 7 , 3)
- Lcd " kHz"
- End If
- If Frequency => 1000000 Then
- Locate 1 , 2
- Lcd Mid(tekst1 , 1 , 3)
- Lcd "."
- Lcd Mid(tekst1 , 4 , 3)
- Lcd "."
- Lcd Mid(tekst1 , 7 , 3)
- Lcd " MHz"
- End If
- Locate 2 , 1 'second line
- Select Case Stepsize
- Case 1 : Lcd " 5 Hz "
- Case 2 : Lcd " 100 Hz"
- Case 3 : Lcd " 1 kHz "
- Case 4 : Lcd " 10 kHz"
- Case 5 : Lcd " 100kHz "
- Case 6 : Lcd " 1 MHz "
- Case 7 : Lcd " 10 MHz "
- End Select
- End Sub
- '**********************************************************************
- ' subroutine to initialise the si5351 chip via I2C
- '**********************************************************************
- Sub Si5351init
- Regaddr = 183
- Regdata = 192
- Call Siout(regaddr , Regdata) 'set xtal load cap to 10pF
- Regaddr = 3
- Regdata = 0
- Call Siout(regaddr , Regdata) 'enable all outputs
- Regaddr = 15
- Regdata = 0
- Call Siout(regaddr , Regdata) 'select xtal as PLL input source
- Regaddr = 16
- Regdata = 15 'PLLA is source, 8mA output
- Call Siout(regaddr , Regdata) 'configure clock 0 control register
- Waitms 10 'wait 10ms just in case
- End Sub
- '********************************************************************************
- ' calculate data bytes for current VFO or BFO frequency to send to si5351a CLK0/1
- '********************************************************************************
- Sub Calculate
- Rdivider = 1 'initialise r
- Outdivider = 900000000 \ Gfreq 'and outdivider
- While Outdivider > 900 '900
- Rdivider = 2 * Rdivider
- Outdivider = Outdivider \ 2
- Wend
- Fvco = Outdivider Mod 2 'check outdivider is an even number
- If Fvco <> 0 Then Outdivider = Outdivider - 1 'using fvco as a temporary register
- Fvco = Outdivider * Rdivider
- Fvco = Fvco * Gfreq 'determine PLL frequency
- Select Case Rdivider 'determine value of R44 bits [6:4]
- Case 1 : Rbyte = 0 '000 0000
- Case 2 : Rbyte = 16 '001 0000
- Case 4 : Rbyte = 32 '010 0000
- Case 8 : Rbyte = 48 '011 0000
- Case 16 : Rbyte = 64 '100 0000
- Case 32 : Rbyte = 80 '101 0000
- Case 64 : Rbyte = 96 '110 0000
- Case 128 : Rbyte = 112 '111 0000
- End Select
- Afactor = Fvco \ Xtal
- Fvalue = Afactor * Xtal 'fvalue = fvco -afactor * xtal
- Fvalue = Fvco - Fvalue 'a+b/c
- Fvalue = Fvalue * Cfactor
- Fvalue = Fvalue \ Xtal
- Bfactor = Fvalue
- Ms0p1 = 128 * Outdivider
- Ms0p1 = Ms0p1 - 512
- Fvalue = 128 * Bfactor
- Fvalue = Fvalue \ Cfactor
- Finteger = Fvalue
- Msnap1 = 128 * Afactor
- Msnap1 = Msnap1 + Finteger 'finteger used instead of fvalue for variable matching
- Msnap1 = Msnap1 - 512
- Msnap3 = Finteger * Cfactor 'using msnap3 as temp result buffer
- Msnap2 = 128 * Bfactor
- Msnap2 = Msnap2 - Msnap3
- Msnap3 = Cfactor
- 'calculations are complete so now build and send the required output data bytes by calling sendfreq (About 20 bytes sent per frequency)
- End Sub
- '**********************************************************************
- ' send converted freq data to si5351 for CLK0 output
- '**********************************************************************
- Sub Sendfreq
- Regaddr = Siaddr1
- Call Siout(regaddr , Ms32) 'R26=msnap3[15:8]
- Incr Regaddr
- Call Siout(regaddr , Ms31) 'R27=msnap3[7:0]
- Incr Regaddr
- Call Siout(regaddr , Ms13) 'R28=msnap1[17:16] in R28[1:0] with R28[7:2]=0
- Incr Regaddr
- Call Siout(regaddr , Ms12) 'R29=msnap1[15:8]
- Incr Regaddr
- Call Siout(regaddr , Ms11) 'R30=msnap1[7:0]
- Temp = Ms33 'temp[3:0]=msnap3[19:16]
- Swap Temp 'temp[7:4]=msnap3[19:16]
- Temp = Temp Or Ms23 'temp[7:4]=msnap3[19:16] and temp[3:0]=msnap2[19:16]
- Incr Regaddr
- Call Siout(regaddr , Temp) 'R31=(msnap3[19:16],msnap2[19:16])
- Incr Regaddr
- Call Siout(regaddr , Ms22) 'R32=msnap2[15:8]
- Incr Regaddr
- Call Siout(regaddr , Ms21) 'R33=msnap2[7:0]
- Regaddr = Siaddr2
- Regdata = 0
- Call Siout(regaddr , Regdata) 'R42=MS0_P3[15:8]
- Incr Regaddr
- Regdata = 1
- Call Siout(regaddr , Regdata) 'R43=MS0_P3[7:0]
- Temp = Rbyte
- Temp = Temp Or M0p13
- Incr Regaddr
- Call Siout(regaddr , Temp) 'R44=(0,R[7:4],MS0_P1[17:16])
- Incr Regaddr
- Call Siout(regaddr , M0p12) 'R45=MS0_P1[15:8]
- Incr Regaddr
- Call Siout(regaddr , M0p11) 'R46=MS0_P1[7:0]
- Incr Regaddr
- Regdata = 0
- Call Siout(regaddr , Regdata) 'R47=(MS0_P3[19:16],MS0_P2[19:16]) and both are always 0
- Incr Regaddr
- Regdata = 0
- Call Siout(regaddr , Regdata) 'R48=MS0_P2[15:8]=0 always
- Incr Regaddr
- Regdata = 0
- Call Siout(regaddr , Regdata) 'R49=MS0_P2[7:0]=0 always
- End Sub
- '**********************************************************************
- ' i2c transmission to si5351
- '**********************************************************************
- Sub Siout(sireg As Byte , Sidata As Byte)
- 'subroutine sends databyte to register_nbr at i2c address 192 (si5351 register read is from address 194)
- 'Write a single byte (slave address 192, register sireg, value sibyte)
- I2cstart
- I2cwbyte 192 'i2c address of si5351a
- Waitus 1 'suggested delay from forum
- I2cwbyte Sireg
- Waitus 1
- I2cwbyte Sidata
- Waitus 1
- I2cstop
- End Sub
Chciał bym mieć możliwość sterowania osobno każdym wyjściem
Pozdrawiam Henryk .