Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 11:53 11 May 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : [Micromite]Rotary Encoder

Author Message
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 08:25am 31 May 2014
Copy link to clipboard 
Print this post

Hi

MMBasic makes life so much easier on MCUs ! I had a rotary encoder working within 20 minutes of getting the encoder out of my junk-box following the instructions on Page 22 of the "Micromite User Manual".

However as it says, the code snippet is only sufficient for a basic demonstration of the principle.

I'm using the rotary encoder with the Micromite to drive a DDS based VFO and so dropped/skipped values would be a real pain, hence the code below. The key benefit is that the main value is incremented/decremented at the rate at which the MAIN program loop can react to. If one uses the VAR Value directly you will see many skips in the value displayed/printed out from the Main loop, whereas the method used below should near enough eliminate such skips.

I'd be very interested in other people's experiences/code for handling Rotary Encoders.

73

Peter (GM8JCF)


'***********************************************
'Rotary Encoder Test (c) Peter Carnegie 2014
'Wiring as per Page 22 Micromite User Manual
'Use LCD wired as follows (see Page 19)
'26=D7, 25=D6, 24=d5, 23=d4
'22=RS, 21=EN
'If NO LCD, then REM out lines starting with "LCD"
'
'This software improves on the snippet listed
'in the Micromite User Manual in that the count
'increases/decreases more accurately
'***********************************************


'Declare all Global Variables here

'Rotary Encoder Input pins - see page 22
Dim RA,RB
RA=2
RB=3

SetPin RB, Din
SetPin RA, INTH, RInt

'Variable incremented/decremented by the Interrupt handling
'routine for the Rotary Encoder
Dim Value

'Go run the Program
Main

End

Sub Main

Local LastValue
Local DispValue, LastDispValue

Local DispLen

Local A$, B$

'Initialise the LCD Display
DispLen=16
'26=D7, 25=D6, 24=d5, 23=d4
'22=RS, 21=EN
lcd init 26,25,24,23,22,21

A$="Rotary Enc Test"
LCD 1, (dispLen-Len(A$) )/2, A$

A$="Rotate Encoder"
LCD 2, (dispLen-Len(A$) )/2, A$

'The Main Program Loop
Do

'If encoder is turning ANTI-clockwise, Decrement
If Value < LastValue then
DispValue=DispValue-1
Endif

'If encoder is turning CLOCKwise, Increment
If Value > LastValue then
DispValue=DispValue+1
Endif

'Was there a Change in DispValue ?
If LastDispValue <> DispValue then

LastValue=Value

A$=Str$(DispValue)

'Find out how much space padding is required
'Before and After the digits
B$=String$((Displen-Len(A$))/2," ")

'Make the Display String
A$=B$ + A$ + B$

'Send to the Console
print A$

'Display on the LCD
LCD 2, 1, A$

LastDispValue=DispValue

Else
'Nothing to do so wait
Pause 100
endif

Loop

End Sub

'Here when the Rotary encoder moves
RInt:

If Pin(RB)=1 then
'Clockwise rotation
Value=Value+1
Else
'Anti-Clockwise rotation
Value=Value-1
Endif

IReturn

The only Konstant is Change
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 09:47am 31 May 2014
Copy link to clipboard 
Print this post

Nice way of smoothing out those values!

Just one remark for your use of the LCD command.
You can use a C16 (or C8, C20, C40 depending which lcd you have) as the second argument for the LCD command to center a tekst.

Microblocks. Build with logic.
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 10:02am 31 May 2014
Copy link to clipboard 
Print this post

Hi TZ

Indeed, but when I did that I had remnants left on the display as the number went from say 100 to 99, the 1 would remain on the LCD, or from -1 to 1, that's why I send an entire 16 char string to the LCD so that every char position is rewritten every time

Reading through Page 22 again, I notice that Geoff credits you with the code snippet on P22 - I feel a little abashed now !

73

Peter - GM8JCF

The only Konstant is Change
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 10:31am 31 May 2014
Copy link to clipboard 
Print this post

:)

Read this thread to see how it all started.
http://www.thebackshed.com/forum/forum_posts.asp?TID=6342&KW =rotary+encoder&PN=0&TPN=1

My preference is to use a small cap to debounce the signal, especially with cheaper encoders this can become necessary.
A small test in the interrupt routine to check the time between the last and current interrupt can also be used to debounce and you can use it also to determine how fast someone turns the encoder. Faster = bigger steps, slower is higher precision.

I mostly need to up/down count in the interrupt routine to capture rapid turns.
Works best when you need to select from a wide range. It allows the user to quickly go through the values. It all depends on what you need.

Microblocks. Build with logic.
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6220
Posted: 02:42pm 31 May 2014
Copy link to clipboard 
Print this post

Peter,
What DDS are you using?
I have a AD9850 DDS in the to-do pile but need time to play with it.

Jim
VK7JH
MMedit
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 12:53pm 01 Jun 2014
Copy link to clipboard 
Print this post

Hi Jim

I'm using an AD9850 - one of those Chinese cheap modules from eBay, and also NJQRP DDS30 module. BTW, that's why I need long precision arithmetic, as you know Fout=TuningWord x (CLKIn/ (2^32) or TuningWord=Fout * (2^32) / Clkin which in the case for the eBay modules is
TuningWord=Fout * (2^32)/125,000,000 = 34.359738368 in double precision. If I use MMBasic Single arithmetic, then I get significant errors when setting a specific frequency. So what I've done is scale everything up by 1E6, do the calcs in long precision integer arithmetic, and just before sending the TuningWord out to the DDS chip, scale the result back by 1E6.

If you like, I can directly email you a copy of my MMBasic source.

The only problem I'm having right now, is that the program randomly stops with "Error: Too many nested FOR loops" and I can assure you that I don't nest FOR loops more than 3 deep anywhere. I've got it less prone to crashing by moving variables from LOCAL to GLOBAL, but that's making the program more and more "mucky". BTW if I stub out the actual H/W lines, then I can run the code on MMBasic for DOS and there's no crashing out. I think this must have to do with there being a limit on the stack frame for subroutines/functions.

73

Peter - GM8JCF
The only Konstant is Change
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 3998
Posted: 08:33pm 01 Jun 2014
Copy link to clipboard 
Print this post

If you post the actual code that gives the error (so anyone can run it and see) there's a fair chance someone will explain why.

John
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 05:33am 03 Jun 2014
Copy link to clipboard 
Print this post

Hi JohnS

I've completed extensive tests, and since I've eliminated ALL "EXIT FOR" statements from my code, (800+ lines) I no longer get "Too Many Nested For Loops" Error.

What I did was replace each EXIT FOR statement by setting the loop variable to 1+ or -1 the loop termination value depending on the direction of the step.

EG

For I = 1 To Len(A$)
If Mid$(A$, I, 1) <> "0" Then
L = I
I=Len(A$)+1
'Exit For
EndIf
Next I

AND

For I = 11 To 0 Step -1
If A1(I) <> 0 Then
T = I
I=-1
'Exit For
EndIf
Next I



Perhaps I've spoken too soon, but I have done the same with another uMite program and that too no longer generates "Too Many Nested For Loops" Error now. So hopefully this is a good fix until something more permanent turns up.

Do you know how to send this kind of report to Geoff ?

Hope this info may help someone else.

73

Peter - GM8JCF
The only Konstant is Change
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3269
Posted: 12:16pm 03 Jun 2014
Copy link to clipboard 
Print this post

If you can post a short segment of code which demonstrates the error I will work on it when I get back from overseas (mid August).

BUT you must condense it down to a few lines - too many times people send me their whole program which makes it impossible to discover the alleged bug. The other thing that often happens when they try to demonstrate the error with a short code segment is that they discover that the problem was in their programming, not MMBasic.

Geoff
Geoff Graham - http://geoffg.net
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 12:57pm 03 Jun 2014
Copy link to clipboard 
Print this post

Hi Geoff

No worries. I'll try and write a test suite which demonstrates the problem on a consistent basis. As I reported, I never get this problem with MMBasic for DOS. And the "fix" seems to work for me thus far, so I can carry on programming on the uMite with minimal impact.

It could of course be my error, hence why a test suite will be required, and I shall do my best to write one.

Hopefully you're having a well earned rest.

Take care

Peter - GM8JCF


The only Konstant is Change
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 02:05pm 24 Jun 2014
Copy link to clipboard 
Print this post

Hi

The trick to avoiding the "Too Many Nested For Loops" Error seems to be to NOT use EXIT FUNCTION from inside a FOR Loop, having made that change I no longer get this error - see example below.

Previous, failing Code

'====================================
'
'Remove leading CHARacters from a string
'If char$ is ommitted or blank then trim ZEROES
'
Function TrimL$(A$, Char$)

Local I, CH$(1) Length 1

TrimL$ = A$

ch$(1) = Left$(Char$, 1)
If ch$(1) = "" Then ch$(1) = "0"

For I = 1 To Len(A$)

If Mid$(A$, I, 1) <> "0" Then
TrimL$ = Mid$(A$, I)
Exit Function
EndIf

Next I

End Function


Now, Working Code

'====================================
'
'Remove leading CHARacters from a string
'If char$ is ommitted or blank then trim ZEROES
'
Function TrimL$(A$, Char$)

Local I, CH$(1) Length 1

TrimL$ = A$

ch$(1) = Left$(Char$, 1)
If ch$(1) = "" Then ch$(1) = "0"

For I = 1 To Len(A$)

If Mid$(A$, I, 1) <> "0" Then
TrimL$ = Mid$(A$, I)
Exit For
EndIf

Next I

End Function


73

Peter
The only Konstant is Change
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3269
Posted: 05:00pm 24 Jun 2014
Copy link to clipboard 
Print this post

Ah, much appreciated Peter. Thanks to your great detective work I can see where the bug crept in.

I will add it to the todo list for the next release.

Geoff
Geoff Graham - http://geoffg.net
 
paceman
Guru

Joined: 07/10/2011
Location: Australia
Posts: 1329
Posted: 05:05pm 24 Jun 2014
Copy link to clipboard 
Print this post

Well I guess that's consistent with the Manual Peter, the EXIT is within a FOR first, or do you still find a problem with EXITs. Something for us to watch though isn't it - easy to miss.

Another simple method I use of lining up the LCD display and eliminating 'old' characters is to just be consistent with how you write the new display lines in the code and include any leading/trailing spaces into each new line. It's quick to code, runs fast, gives you instant feedback if it's too long and it's pretty obvious when things aren't displayed right.

Greg

Edit: Geoff got in ahead of me there - looks there is still a problem with EXIT FOR.Edited by paceman 2014-06-26
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 05:25pm 24 Jun 2014
Copy link to clipboard 
Print this post

@Geoff

Glad I can help. Thanks for such a great tool BTW.

@paceman

I had expected that an EXIT Function/Sub would clean up all of the local stackframe and hence why it shouldn't matter where an Exit Function/Sub is issued. But GeoffG has found a bug.

Anyway, as you say, if it's a For loop which is to be exited, then EXIT FOR is logically the correct thing to do, and from a structured programming perspective it is perhaps the right thing since control is being transferred from the current scope to the next outer level of scope rather than to a completely different scope entirely.

I think I've just been spoiled by VB !

73

Peter
The only Konstant is Change
 
paceman
Guru

Joined: 07/10/2011
Location: Australia
Posts: 1329
Posted: 06:01pm 24 Jun 2014
Copy link to clipboard 
Print this post

Yes but I don't think I've seen this actually spelled out in the Manual though so maybe it should be. Something like:"Using EXIT FUNCTION/SUB within a DO/FOR loop which is inside the FUNCTION/SUB, does/does not, automatically exit the program from the FUNCTION/SUB" I know I've 'done the wrong thing' with this too in the past and gotten away with it but maybe that was just dumb luck with the way the code went.

Greg
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 06:11pm 24 Jun 2014
Copy link to clipboard 
Print this post

Hi Greg

I think the key thing here is that one expects that when one exits a Sub/Function, all the local variables, local control structures, IF/ENDIFs etc would all be cleaned up. If Instead of doing Exit For, one was to do Goto FunctionEnd, eg


Function TrimL$(A$, Char$)

Local I, CH$(1) Length 1

TrimL$=A$

ch$(1) = Left$(Char$, 1)
If ch$(1) = "" Then ch$(1) = "0"

For I = 1 To Len(A$)

If Mid$(A$, I, 1) <> "0" Then
TrimL$ = Mid$(A$, I)
Goto FunctionEnd
EndIf

Next I

FunctionEnd:

End Function


would it not be unreasonable to expect that all the Local Vars disappear, and that the FOR loop and IF/ENDIF structure were all cleaned up ?

Anyway, Geoff is going to fix it in the next release which is great news and minimises the potential for days of head scratching !

73

Peter
The only Konstant is Change
 
paceman
Guru

Joined: 07/10/2011
Location: Australia
Posts: 1329
Posted: 07:46pm 24 Jun 2014
Copy link to clipboard 
Print this post

Interesting that you give that GOTO example because I think that's exactly the sort of thing I've done and found it was OK - mind you I may have only had a few loops so the "too many..." error might not have triggered. The local variables are released of course as is given in the Manual so guess it'll likely be just the EXIT FUNCTION/SUB where Geoff sees an issue.

As you say, I think we can safely lave it with him .

Greg
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 3998
Posted: 08:17pm 24 Jun 2014
Copy link to clipboard 
Print this post

Peter - in case you'd not noticed, your code's comment does not match what the code does. This line:
If Mid$(A$, I, 1) <> "0" Then
looks like it ought to be:
If Mid$(A$, I, 1) <> ch$(1) Then

John
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 08:34pm 24 Jun 2014
Copy link to clipboard 
Print this post

Thank you John, yes indeed, I've only been Trimming out leading Zeroes so I never got caught by that bug.

Once again, thanks

Peter
The only Konstant is Change
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 3998
Posted: 01:27am 25 Jun 2014
Copy link to clipboard 
Print this post

You're welcome.

Looks like you found a bug with Exit For, and that's a much more valuable find than my little suggestion to you.

John
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025