Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Rotary Encoder

Status
Not open for further replies.

SwingeyP

Member
Hello again. I now have a new project which will be a a Digital VFO using a 16f876a

I plan to use a rotary encoder to act as the 'user input' with an LCD showing the frequency and probably the AD9850 module.
As a newbie this is going to be a task and a half.

I have code for the LCD showing bar graphs and frequency readout etc.
I have just been playing with interupts to see how those works and with thanks to what Eric posted and some data sheet reading i'm fairly up on that. Well my code worked anyway :)

The next bit I have undertaken is the reading the rotary encoder. I have read the data sheet, understand what's going on to some extent but I need to know how to read just the two pins I have the encoder connected to.

The data sheet sets encoder = ra and then does a mov old, encoder. Which as I understand it loads what is currently on port A and places it in a variable called old.

How can I do this in OSHON but just addressing the two pins the encoder is connected to. I don't want to use a whole port just for two pins. I might use other pins of porta for something else .....

Also does anyone have a rotary encoder plugin for the OSHON simulator? - If not what clever ways can I simulate the encoder.

Thanks for any help.

Regards - Paul
 
Hello Swingey,

I'm also interested in this sort of thing, and have done stuff before, but I'm not qualified to help you, unless no one replies.

Are you using Quadrature encoding?

Cheers, Camerart.
 
The simplest way is to generate an interrupt with one signal and read the other, if high increment the variable, if low then decrement. Note the interrupt must be edge triggered (RB0). Can't help with OSHON but Eric might be able to help there.

I should mention that this technique is not suitable for precise position measurement but good enough for this application.

Mike.
 
I've only triggered interrupts from TIMER1 so far as per Eric's code. I'm not sure how to trigger the interrupt as you say. Something to do with peripheral register?

Brain Dump:

read initial value from encoder

Loop
calculate frequency from encoder variable
Some code displaying the frequency looping around and sending data to the AD9850.
end loop

interupt --> triggered by turning the encoder
get new value from encoder
update some variable to send back to freq
resume

I guess something like this should work but how to trigger that interrupt?

Any comments?

Regards - Paul
 
I have done exactly what you are trying to do, count a rotary encoder with a PIC to drive an AD9850.

But I did it in assembler and I know nothing about OSHON.

JimB
 
hi Paul,
The link that 'Camerart' posted looks helpful.
If you post your 'Oshonsoft' code , I will give it a run thru.
Do you have an Encoder d/s you could post.?
Eric
OT: did you finish your GPS project.?
 
Hi Eric. The GPS drove me nuts. I have it almost complete but the conversion routines from DDMMSS dd.mm.sss etc etc have a bug somewhere. It's nearly there i'll come back to it later :)

I read through the stuff from camerart - thank you. I like the trigger idea for the interupt I think i'll give that a try.

I'll work on some code this evening and see what happens.

Thanks for the help

Regards - Paul
 
Ok, So much work to do but it's taking shape I think.

I need to know how to setup the interrupt to be triggered externally on RBO?

The following code will take forever to run in simulation so I suggest you remove the counter for 4 times and just go with 1/4 second.
Of course if anyone can tell me who to trigger externally then this won't be an issue. I plan to use the trigger with the 4030 xor chip as described above.

Some code. It seems to work of a fashion.

Code:
Define SIMULATION_WAITMS_VALUE = 1

'---------------------------------------------------------------
'DEFININTIONS
'---------------------------------------------------------------


Define CONF_WORD = 0x3f50  'Internal Oscillator'
Define CLOCK_FREQUENCY = 8
AllDigital

'--------------------------------------------------------------
'LCD SETUP
'--------------------------------------------------------------
Define LCD_LINES = 4
Define LCD_CHARS = 20
Define LCD_BITS = 4
Define LCD_DREG = PORTB
Define LCD_DBIT = 4  'Data RB7 - RB4
Define LCD_RSREG = PORTB
Define LCD_RSBIT = 3
Define LCD_EREG = PORTB
Define LCD_EBIT = 2
Define LCD_RWREG = PORTB
Define LCD_RWBIT = 1
Define LCD_READ_BUSY_FLAG = 1

'NOTE RB0 IS USED FOR INTERUPT!!!

Define LCD_COMMANDUS = 5000  'delay after LCDCMDOUT, default value is 5000
Define LCD_DATAUS = 100  'delay after LCDOUT, default value is 100
Define LCD_INITMS = 20


'--------------------------------------------------
'variables
'----------------------------------------------------
Symbol encodera = PORTA.0
Symbol encoderb = PORTA.1

Dim init_freg As Byte  'used to set the initial frequency to band centre
Dim freq_step As Byte  'used to set the tuning step 1khz/10khz etc
Dim init_anlg As Byte
Dim anlg As Byte
Dim init_digi_mhz As Byte
Dim init_digi_khz As Byte
Dim init_digi_hz As Byte
Dim i As Byte
Dim intrcnt As Byte  'number of times interupt is triggered
Dim direction As Bit  'which direction the encoder is turning.



startup:
'------------------------------------------------------
'Clear the LCD and give everyting time to initialise
'------------------------------------------------------
Lcdinit  'LcdCurBlink
Lcdcmdout LcdClear
WaitMs 10
'---------------------------------------------------------------------
'Define the analoug display
'---------------------------------------------------------------------
Lcddefchar 0, %00000, %00000, %00000, %11111, %11111, %00000, %00000, %00000
Lcddefchar 1, %11111, %11111, %11111, %11111, %11111, %11111, %11111, %11111

'--------------------------------------------------------
'Welcome message to LCD
'--------------------------------------------------------
Lcdcmdout LcdLine1Pos(4)
Lcdout "DIGITAL VFO"
Lcdcmdout LcdLine2Pos(7)
Lcdout "by M0TVU"
Lcdcmdout LcdLine4Pos(4)
Lcdout "Version 1.01"
WaitMs 1000  '1000
Lcdcmdout LcdClear

'---------------------------------------------------
'Set initial Values
'----------------------------------------------------
init_anlg = 9
anlg = init_anlg
init_digi_mhz = 7
init_digi_khz = 100
init_digi_hz = 0

'---------------------------------------------------
'Set interupt values
'----------------------------------------------------
TRISB = 0x00
'adcon1 = 0x84

T1CON = 0x30  '00110000 - set the prescaler 1:8
T1CON.T1OSCEN = 1  'oscillator enabled
T1CON.TMR1CS = 0  'Timer 1 clock source 0= internal clock
T1CON.TMR1ON = 1  'Enable TIMER 1
TMR1H = 0x0b  'Values for high bit ? Why these values?
TMR1L = 0xdc  'Valur for low bit ?

INTCON.GIE = 1  'enable all unmasked interupts - unmasked?
INTCON.PEIE = 1  'enable all unmasked peripheral inteupts

PIE1.TMR1IE = 1  'Enable overflow
PIR1.TMR1IF = 0  'clear overflow

Enable  'what does this do?

'----------------------------------------------------------------
'MAIN BODY
'----------------------------------------------------------------

'Read initial value from encoder

'loop
'calculate frequency from encoder variable
'some code displaying the frequency looping around And sending data To the ad9850.
'End loop

'interupt - -> triggered by turning the encoder
'get new value from encoder
'update some variable To send back To freq
'Resume


loop:
'Give the main code something to do.
'Call digidsp(init_digi_mhz, init_digi_khz, init_digi_hz)
Call anlgdsp(anlg)
Goto loop

End                                              

'----------------------------------------------------------------
'ON INTERRUPT
'----------------------------------------------------------------

On Interrupt
Save System
'interrupt triggers every 1/4 second approx so 4 times = 1 second.
'why aren't interupts disabled here?
PIR1.TMR1IF = 0  'clear the overflow

intrcnt = intrcnt + 1
If intrcnt = 4 Then  'interupted 4 times = 1 second?
    intrcnt = 0
    'this is where the interupt code would go.
    direction = encodera Xor encoderb
    If direction = 1 Then  'increment
        anlg = anlg + 1
    Else  'decrement
        anlg = anlg - 1
    Endif
Endif

TMR1H = 0x0b
TMR1L = 0xdc
Resume                                           


'----------------------------------------------------------------
'Functions
'----------------------------------------------------------------


Function anlgdsp(arg1 As Byte) As Byte  'this should be a procedure!!
Lcdcmdout LcdLine3Home
Select Case arg1
    Case 0
        Lcdout 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    Case 1
        Lcdout 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    Case 2
        Lcdout 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    Case 3
        Lcdout 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    Case 4
        Lcdout 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    Case 5
        Lcdout 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    Case 6
        Lcdout 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    Case 7
        Lcdout 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    Case 8
        Lcdout 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    Case 9
        Lcdout 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    Case 10
        Lcdout 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
    Case 11
        Lcdout 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0
    Case 12
        Lcdout 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0
    Case 13
        Lcdout 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0
    Case 14
        Lcdout 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0
    Case 15
        Lcdout 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0
    Case 16
        Lcdout 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0
    Case 17
        Lcdout 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0
    Case 18
        Lcdout 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0
    Case 19
        Lcdout 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
EndSelect
End Function                                     

'----------------------------------------------------------------
'Procedures
'----------------------------------------------------------------

Is there a better way of doing that nasty LCDOUT group and how do I trigger the interrupt externally?

Cheers - Paul
 
hi Paul,
Downloaded your code, get back to you later.
E.

EDIT
This edit covers the Interrupt query.
Code:
'---------------------------------------------------
'Set interupt values
'----------------------------------------------------

T1CON = 0x30  '00110000 - set the prescaler 1:8
T1CON.T1OSCEN = 1  'oscillator enabled
T1CON.TMR1CS = 0  'Timer 1 clock source 0= internal clock
T1CON.TMR1ON = 1  'Enable TIMER 1

''TRISB = 0x00  'if RB.0 is for intr then
TRISB = 0x01
'adcon1 = 0x84

'Timer1 is a 16 bit UP counter, so it would count from 0000h thru FFFFh
'as it rolls over to 0000h it will generate a TMR1 Interrupt
'To get the required interrupt interval we preload the Timer1 counter with
'a value.
'if the xtal is say 4MHz, this would mean the PIC internal cycle will be
'4MHZ/4 ie: 1MHZ == 1uSec
'we first divide this 1MHZ by 8 in the TMR1 prescaler to give 125KHz
'I prefer to use the Period rather than the Freq, so thats a 8uSec Period.

'If we want an TMR1 intr every 0.5Sec we need to calculate TMR1 Period as
'0.5sec/8uSec = 0.5/0.000008 = 62500uS, BUT as its a UP counter we must preload the
'TMR1 with its maximum possible count of 65536 - 62500 = 3036 decimal
'convert to Hex 0BDCh... So load TMR1H with 0Bh and TMR1L with DCh

'NOTE: you MUST reload this TMR1 count value every time you EXIT the Interrupt Subr
' as well as clearing the TMR1IF

TMR1H = 0x0b  'Values for high BYTE ? Why these values?
TMR1L = 0xdc  'Valur for low BYTE ?

INTCON.GIE = 1  'enable all unmasked interrupts - unmasked?
INTCON.PEIE = 1  'enable all unmasked peripheral interrupts

PIE1.TMR1IE = 1  'Enable overflow
PIR1.TMR1IF = 0  'clear overflow

Enable  'what does this do?
'BASIC should Enable the required Interrupts
'I prefer to control the Interrupts individually, as above.

'----------------------------------------------------------------
 
Last edited:
hi Paul,
This code will run with Intr in Oshonsoft.
NOTE: I have shortened the TMR1 Interrupt preload Count in order to make it run faster in simulation.

Will look at the rest later.

Eric
 

Attachments

  • PaulEncode1a.bas
    6.7 KB · Views: 454
Aha! - After reading the data sheets I can see this INTCON.INTE = 1. This triggers the interrupt but now it just keeps triggering. Which flag must I clear in the interrupt routine to stop this.

Code:
Define SIMULATION_WAITMS_VALUE = 1

'---------------------------------------------------------------
'DEFININTIONS
'---------------------------------------------------------------


Define CONF_WORD = 0x3f50  'Internal Oscillator'
Define CLOCK_FREQUENCY = 8
AllDigital

'--------------------------------------------------------------
'LCD SETUP
'--------------------------------------------------------------
Define LCD_LINES = 4
Define LCD_CHARS = 20
Define LCD_BITS = 4
Define LCD_DREG = PORTB
Define LCD_DBIT = 4  'Data RB7 - RB4
Define LCD_RSREG = PORTB
Define LCD_RSBIT = 3
Define LCD_EREG = PORTB
Define LCD_EBIT = 2
Define LCD_RWREG = PORTB
Define LCD_RWBIT = 1
Define LCD_READ_BUSY_FLAG = 1

'NOTE RB0 IS USED FOR INTERUPT!!!

Define LCD_COMMANDUS = 5000  'delay after LCDCMDOUT, default value is 5000
Define LCD_DATAUS = 100  'delay after LCDOUT, default value is 100
Define LCD_INITMS = 20


'--------------------------------------------------
'variables
'----------------------------------------------------
Symbol encodera = PORTA.0
Symbol encoderb = PORTA.1

Dim bandwidth_upper As Byte
Dim bandwidth_lower As Byte
Dim freq_step As Byte  'used to set the tuning step 1khz/10khz etc
Dim init_anlg As Byte
Dim anlg As Byte
Dim init_digi_mhz As Byte
Dim init_digi_khz As Byte
Dim init_digi_hz As Byte
Dim intrcnt As Byte  'number of times interupt is triggered
Dim direction As Bit  'which direction the encoder is turning.



startup:
'------------------------------------------------------
'Clear the LCD and give everyting time to initialise
'------------------------------------------------------
Lcdinit  'LcdCurBlink
Lcdcmdout LcdClear
WaitMs 10
'---------------------------------------------------------------------
'Define the analoug display
'---------------------------------------------------------------------
Lcddefchar 0, %00000, %00000, %00000, %11111, %11111, %00000, %00000, %00000
Lcddefchar 1, %11111, %11111, %11111, %11111, %11111, %11111, %11111, %11111
Lcddefchar 2, %10000, %10000, %10000, %11111, %11111, %10000, %10000, %10000
Lcddefchar 3, %00001, %00001, %00001, %11111, %11111, %00001, %00001, %00001

'--------------------------------------------------------
'Welcome message to LCD
'--------------------------------------------------------
Lcdcmdout LcdLine1Pos(4)
Lcdout "DIGITAL VFO"
Lcdcmdout LcdLine2Pos(7)
Lcdout "by M0TVU"
Lcdcmdout LcdLine4Pos(4)
Lcdout "Version 1.01"
WaitMs 1000  '1000
Lcdcmdout LcdClear

'---------------------------------------------------
'Set initial Values
'----------------------------------------------------
bandwidth_upper = 200
bandwidth_lower = 0
freq_step = 10
init_anlg = 9
anlg = init_anlg
init_digi_mhz = 7
init_digi_khz = 100
init_digi_hz = 0

'---------------------------------------------------
'Set interupt values
'----------------------------------------------------
TRISB = 0x00
'adcon1 = 0x84

'T1CON = 0x30  '00110000 - set the prescaler 1:8
'T1CON.T1OSCEN = 1  'oscillator enabled
'T1CON.TMR1CS = 0  'Timer 1 clock source 0= internal clock
'T1CON.TMR1ON = 1  'Enable TIMER 1
'TMR1H = 0x0b  'Values for high bit ? Why these values?
'TMR1L = 0xdc  'Valur for low bit ?

INTCON.GIE = 1  'enable all unmasked interupts - unmasked?
INTCON.PEIE = 1  'enable all unmasked peripheral inteupts
INTCON.INTE = 1  'external interrupt on RB0.


PIE1.TMR1IE = 1  'Enable overflow
PIR1.TMR1IF = 0  'clear overflow

Enable  'what does this do?

'----------------------------------------------------------------
'MAIN BODY
'----------------------------------------------------------------

'Read initial value from encoder

'loop
'calculate frequency from encoder variable
'some code displaying the frequency looping around And sending data To the ad9850.
'End loop

'interupt - -> triggered by turning the encoder
'get new value from encoder
'update some variable To send back To freq
'Resume


loop:
'Give the main code something to do.
'Call digidsp(init_digi_mhz, init_digi_khz, init_digi_hz)
Call anlgdsp(anlg)
Goto loop

End                                              

'----------------------------------------------------------------
'ON INTERRUPT
'----------------------------------------------------------------

On Interrupt
Save System
'interrupt triggers every 1/4 second approx so 4 times = 1 second.
'why aren't interupts disabled here?
PIR1.TMR1IF = 0  'clear the overflow

intrcnt = intrcnt + 1
'If intrcnt = 4 Then  'interupted 4 times = 1 second?
    'intrcnt = 0
    'this is where the interupt code would go.
    direction = encodera Xor encoderb
    If direction = 1 Then  'increment
        anlg = anlg + 1
    Else  'decrement
        anlg = anlg - 1
    Endif
'Endif

TMR1H = 0x0b
TMR1L = 0xdc
Resume                                           


'----------------------------------------------------------------
'Functions
'----------------------------------------------------------------


Function anlgdsp(arg1 As Byte) As Byte  'this should be a procedure!!
Lcdcmdout LcdLine3Home
Select Case arg1
    Case 0
        Lcdout 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 1
        Lcdout 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 2
        Lcdout 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 3
        Lcdout 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 4
        Lcdout 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 5
        Lcdout 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 6
        Lcdout 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 7
        Lcdout 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 8
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 9
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 10
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 11
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3
    Case 12
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3
    Case 13
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3
    Case 14
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 3
    Case 15
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3
    Case 16
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 3
    Case 17
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 3
    Case 18
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3
    Case 19
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
EndSelect
End Function                                     

'----------------------------------------------------------------
'Procedures
'----------------------------------------------------------------
 
Aha! - After reading the data sheets I can see this INTCON.INTE = 1. This triggers the interrupt but now it just keeps triggering. Which flag must I clear in the interrupt routine to stop this.

hi Paul,
This PIE1.TMR1IE = 1 does not trigger the Interrupt it Enables the TMR1 interrupt,,, PIE1.TMR1IE =0 will Disable TMR1 interrupt

Its when the TMR1 count rolls over ffom 65535 [FFFFh] to 0000 that creates a TMR1 interrupt.
E

EDIT:
Code:
INTCON.GIE = 1  'enable all unmasked GENERAL interrupts - unmasked= enabled
INTCON.PEIE = 1  'enable all unmasked PERIPHERAL interrupts
 
Last edited:
hi Paul,
For your Bar graph you could develop this idea.
I have reduced the program to show only the bar, download and give it a run. [hijacked your Func:]
Eric

Code:
up = 1
dwn = 20
loop:
Call anlgdsp(anlg)
Goto loop
End  
Function anlgdsp(arg1 As Byte) As Byte  'this should be a procedure!!
If dir = 0 Then
Lcdcmdout LcdLine3Pos(up)
Lcdout "-", 0x7e
up = up + 1
If up > 19 Then
up = 1
dir = 1
dwn = 20
Endif
Endif
If dir = 1 Then
Lcdcmdout LcdLine3Pos(dwn)
Lcdout 0x7f, "  "
dwn = dwn - 1
If dwn < 1 Then
dwn = 1
dir = 0
up = 1
Endif
Endif
End Function
 

Attachments

  • PaulEncode1b.bas
    1.5 KB · Views: 411
Hi Eric, I should have said that I only used the timer interrupt because I didn't know how to trigger external interrupts and I used your timer code as a starter. I can now see the INTE and the INTF and think I know what these do as if I pulse RBO in the simulator it does as expected. There is still a lot of work to do t ensure boundaries and counts are correct etc (i'll give your bar graph a twirl in a minute) but this is what I have now.

Code:
Define SIMULATION_WAITMS_VALUE = 1

'---------------------------------------------------------------
'DEFININTIONS
'---------------------------------------------------------------


Define CONF_WORD = 0x3f50  'Internal Oscillator'
Define CLOCK_FREQUENCY = 8
AllDigital

'--------------------------------------------------------------
'LCD SETUP
'--------------------------------------------------------------
Define LCD_LINES = 4
Define LCD_CHARS = 20
Define LCD_BITS = 4
Define LCD_DREG = PORTB
Define LCD_DBIT = 4  'Data RB7 - RB4
Define LCD_RSREG = PORTB
Define LCD_RSBIT = 3
Define LCD_EREG = PORTB
Define LCD_EBIT = 2
Define LCD_RWREG = PORTB
Define LCD_RWBIT = 1
Define LCD_READ_BUSY_FLAG = 1

'NOTE RB0 IS USED FOR INTERUPT!!!

Define LCD_COMMANDUS = 5000  'delay after LCDCMDOUT, default value is 5000
Define LCD_DATAUS = 100  'delay after LCDOUT, default value is 100
Define LCD_INITMS = 20


'--------------------------------------------------
'variables
'----------------------------------------------------
Symbol encodera = PORTA.0
Symbol encoderb = PORTA.1

Dim bandwidth_upper As Byte
Dim bandwidth_lower As Byte
Dim freq_step As Byte  'used to set the tuning step 1khz/10khz etc
Dim init_anlg As Byte
Dim anlg As Byte
Dim init_digi_mhz As Byte
Dim init_digi_khz As Byte
Dim init_digi_hz As Byte
Dim digi_mhz As Byte
Dim digi_khz As Byte
Dim digi_hz As Byte

Dim intrcnt As Byte  'number of times interupt is triggered
Dim direction As Bit  'which direction the encoder is turning.

startup:
'------------------------------------------------------
'Clear the LCD and give everyting time to initialise
'------------------------------------------------------
Lcdinit  'LcdCurBlink
Lcdcmdout LcdClear
WaitMs 10
'---------------------------------------------------------------------
'Define the analoug display
'---------------------------------------------------------------------
Lcddefchar 0, %00000, %00000, %00000, %11111, %11111, %00000, %00000, %00000
Lcddefchar 1, %11111, %11111, %11111, %11111, %11111, %11111, %11111, %11111
Lcddefchar 2, %10000, %10000, %10000, %11111, %11111, %10000, %10000, %10000
Lcddefchar 3, %00001, %00001, %00001, %11111, %11111, %00001, %00001, %00001

'--------------------------------------------------------
'Welcome message to LCD
'--------------------------------------------------------
Lcdcmdout LcdLine1Pos(5)
Lcdout "DIGITAL VFO"
Lcdcmdout LcdLine2Pos(7)
Lcdout "by M0TVU"
Lcdcmdout LcdLine4Pos(4)
Lcdout "Version 1.01"
WaitMs 1000  '1000
Lcdcmdout LcdClear

'---------------------------------------------------
'Set initial Values
'----------------------------------------------------
bandwidth_upper = 200
bandwidth_lower = 0
freq_step = 10
init_anlg = 9
anlg = init_anlg
init_digi_mhz = 7
init_digi_khz = 100
init_digi_hz = 0

digi_mhz = init_digi_mhz
digi_khz = init_digi_khz
digi_hz = init_digi_hz


'---------------------------------------------------
'Set interupt values
'----------------------------------------------------
TRISB = 0x00
'adcon1 = 0x84

'T1CON = 0x30  '00110000 - set the prescaler 1:8
'T1CON.T1OSCEN = 1  'oscillator enabled
'T1CON.TMR1CS = 0  'Timer 1 clock source 0= internal clock
'T1CON.TMR1ON = 1  'Enable TIMER 1
'TMR1H = 0xff  'Values for high bit ? Why these values?
'TMR1L = 0xfa  'Valur for low bit ?

INTCON.GIE = 1  'enable all unmasked interupts - unmasked?
INTCON.PEIE = 1  'enable all unmasked peripheral inteupts
INTCON.INTE = 1  'external interrupt on RB0.


'PIE1.TMR1IE = 1  'Enable overflow
'PIR1.TMR1IF = 0  'clear overflow

Enable  'what does this do?

'----------------------------------------------------------------
'MAIN BODY
'----------------------------------------------------------------

loop:
'Give the main code something to do.
Call digi_disp(digi_mhz, digi_khz, digi_hz)
Call anlg_disp(anlg)
Goto loop

End                                              

'----------------------------------------------------------------
'ON INTERRUPT
'----------------------------------------------------------------

On Interrupt
Save System
'interrupt triggers every 1/4 second approx so 4 times = 1 second.
'why aren't interupts disabled here?
PIR1.TMR1IF = 0  'clear the overflow
INTCON.INTF = 0  'clear interrupt on RB0.

intrcnt = intrcnt + 1
'If intrcnt = 2 Then  'interupted 4 times = 1 second?
    'intrcnt = 0
    'this is where the interupt code would go.
    direction = encodera Xor encoderb
    If direction = 1 Then  'increment
        If freq_step = 10 Then
        digi_khz = digi_khz + 10
        Endif
        If freq_step = 1 Then
        digi_hz = digi_hz + 1
        Endif
        anlg = anlg + 1
    Else  'decrement
        If freq_step = 10 Then
        digi_khz = digi_khz - 10
        Endif
        If freq_step = 1 Then
        digi_hz = digi_hz - 1
        Endif
        anlg = anlg - 1
    Endif
'Endif

'TMR1H = 0xff
'TMR1L = 0xfa
Resume                                           


'----------------------------------------------------------------
'Functions
'----------------------------------------------------------------


Function anlg_disp(arg1 As Byte) As Byte  'this should be a procedure!!
Lcdcmdout LcdLine3Home
Select Case arg1
    Case 0
        Lcdout 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 1
        Lcdout 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 2
        Lcdout 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 3
        Lcdout 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 4
        Lcdout 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 5
        Lcdout 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 6
        Lcdout 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 7
        Lcdout 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 8
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 9
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 10
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3
    Case 11
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3
    Case 12
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3
    Case 13
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3
    Case 14
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 3
    Case 15
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3
    Case 16
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 3
    Case 17
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 3
    Case 18
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3
    Case 19
        Lcdout 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
EndSelect
End Function                                     

'----------------------------------------------------------------
'Procedures
'----------------------------------------------------------------
Proc digi_disp(arg1 As Byte, arg2 As Byte, arg3 As Byte,)
Lcdcmdout LcdLine1Pos(6)
Lcdout #arg1, "."
Lcdcmdout LcdLine1Pos(8)
Lcdout #arg2, "."
Lcdcmdout LcdLine1Pos(12)
Lcdout #arg3
End Proc
 
hi,
You have set PORTB.0 as an Output, it must an Input TRISB = 0x01

E
 
hi Paul,
Checking your program.
Clicking the PORTB.0 pin on the micro controller view creates an Interrupt and the Bar graph moves Up or Down as per PORTA,0,1 setting
The LCD display sometimes gets corrupted on the decimal points.
E
 
Hi Eric, It's very much in it's infancy at the moment. I noticed the decimal point error and also the counting error. I also have a problem where the analog and digital readouts get out of sync. I think this is because there are no boundaries for anlg at present. I'll post another version later as I have fixed a few problems. I am trying to get the analog display to be more linear. I have worked out that across 20 steps with 7.0 as the first step (important) each division comes in at 0.0953 (DISTANCE / (Number of steps +1) = 2/21 = 0.0953 ish. I'll have to do a greater than less than type of thing to ensure the analog display moves correctly.

I will be using the AD9850 and I have to figure out how that works too. There seems to be some discussion in google about controlling it with one wire comms. Not sure about this at present. I hope to get to a point where I can see the frequency on the display match it with the analog display and see the corresponding output from the AD9850 on a scope. LOTS TO DO :)

Next phase will be the step button so I can control a fine tune and then maybe a band switch with eeprom storing band upper and lower limits. MAYBE :)

It's not really about the finished product more the HOW DO YOU DO THAT but I would like to incorporate this into a low power CW transceiver. I have a friend doing it the traditional way and I just wanted to see if I could do the VFO with a PIC.
 
It's not really about the finished product more the HOW DO YOU DO THAT

hi Paul,
We are looking for projects like yours to become Articles for ETO, have you considered posting this project [ when finished, no pressure] to Article status.?:)
Eric
 
Er.... Wow. I don't think i'm anywhere near that status but whatever I have you're welcome to. What will you need from me?

Here's the code at the moment. I am trying to understand the AD9850 datasheet now to see what that needs. I'll maybe start building a prototype over the weekend if I can find a quad XOR 4030 in my junk box. I really need a better project board too. I still use the one you wired for me :)

Oooh just found the upload a file button instead of the cut & paste option (wood for the trees and all that)
 

Attachments

  • Rotary Encoder.bas
    7.4 KB · Views: 413
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top