Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 08:50 29 Nov 2024 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 Feature Request Rotary Encoder

     Page 2 of 2    
Author Message
jwettroth

Regular Member

Joined: 02/08/2011
Location: United States
Posts: 71
Posted: 07:55pm 03 Mar 2014
Copy link to clipboard 
Print this post

you're right- I have implemented a lot of front panel controls with no debounce. The state machine that you go through is sort of a low pass filter of its own. I haven't had problems with "dither" or similar. It's nice having a fast background tick if it doesn't eat into the foreground too much.

Interesting discussion.
John Wettroth
 
robert.rozee
Guru

Joined: 31/12/2012
Location: New Zealand
Posts: 2350
Posted: 10:06pm 03 Mar 2014
Copy link to clipboard 
Print this post

  Geoffg said  
  robert.rozee said  would have been much cleaner to write if MMbasic had a MOD function

It does, it is called the MOD operator! You use it the same as the multiply or divide operators.
[...]
BUT Rob's code written in MMBasic is so elegant and simple that I am now wondering if I should bother adding this to the language in the first place.


awww... now you've made me blush!

and it was all written purely off my reading of the manual; i don't have actual hardware running here yet. i did miss seeing the mention of MOD, now the second two IF statements can be replaced thus:


:rotary
nxtv = (PIN(2) * 2) + PIN 3
IF ((last+nxtv) AND 1) = 1 THEN encoder = encoder - ((nxtv-last) MOD 4) + 2
last = nxtv
IRETURN


note: i also fixed my somewhat illegal use of 'next' as a variable name.Edited by robert.rozee 2014-03-05
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9308
Posted: 10:27pm 03 Mar 2014
Copy link to clipboard 
Print this post

...even more elegant, and even more simple now, with the addition of the MOD command.

Nice work, Rob.

Although, I expect that the colon is supposed to be at the right-hand side of the label?(rhetorical)Edited by Grogster 2014-03-05
Smoke makes things work. When the smoke gets out, it stops!
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 12:24am 04 Mar 2014
Copy link to clipboard 
Print this post

Can anyone test this code (Just a few more days and i can have some time to tinker again):
[code]
RotaryValue = 0
RotaryA = 2
RotaryB = 3
SETPIN RotaryA, INTH, RotaryInterrupt

DO
PRINT RotaryValue
'Add usefull stuff here
LOOP

SUB RotaryInterrupt
IF PIN(RotaryB) = 1 then
RotaryValue = RotaryValue + 1
ELSE
RotaryValue = RotaryValue - 1
ENDIF
END SUB
[/code]
Edited by TZAdvantage 2014-03-05
Microblocks. Build with logic.
 
atmega8

Guru

Joined: 19/11/2013
Location: Germany
Posts: 722
Posted: 09:03am 04 Mar 2014
Copy link to clipboard 
Print this post

Ok,

i tested it with an ALPS Encoder Type EC12E2424407.
Without Hardware debouncing no Chance.
I debounced it this way:




If you don't rotate to fast it is ok.
For clockwise Rotation with increasing counter you have to change Rotary value + against - in both lines.


But then a BUG ?????

If you slowly decrease until Rotary Value gets < 0, then the Micromite hangs, prints only zeroes to the Screen.
Only a reset helps!!!
When Value > 0, then it prints nice integer numbers like:
1
2
3

But if Value < 0 and mmmite doesnt Crash, then:

-10.9999

and if it hangs up:
-0000000
-0000000


UPDATE:

A Pause 100 in the do Loop, and mmite doesn't Crash.
Output ist then a funny:

0
-00.9999
-000.999
-0000.99
-00000.9
-000000
-0000000
-0000000
-0000000
-0000000
-0000000
-0000000
-0000000
-0000000
-1.99999
-1.99999
-1.9999







  TZAdvantage said   Can anyone test this code (Just a few more days and i can have some time to tinker again):
[code]
RotaryValue = 0
RotaryA = 2
RotaryB = 3
SETPIN RotaryA, INTH, RotaryInterrupt

DO
PRINT RotaryValue
'Add usefull stuff here
LOOP

SUB RotaryInterrupt
IF PIN(RotaryB) = 1 then
RotaryValue = RotaryValue + 1
ELSE
RotaryValue = RotaryValue - 1
ENDIF
END SUB
[/code]
Edited by atmega8 2014-03-05
 
vegipete

Guru

Joined: 29/01/2013
Location: Canada
Posts: 1110
Posted: 10:41am 04 Mar 2014
Copy link to clipboard 
Print this post

I've played with encoders a fair amount also and I have a tough time believing that the encoder routines could be reliably implemented in MMBasic as opposed to lower level routines.

Years ago I picked up a JControl device - an embedded Java processor with a built in 128x64 LCD screen. It was easy enough to write an encoder reader in Java but response was poor. Spin the knob fast with the edge of your finger and nothing registered. Sloppy code written for PIC18 and PIC24 has similar problems. Debounce settings can really effect how well the encoder is read at speed or near stopped. And interrupting on one channel and reading the other for direction is an invitation to disaster.

The routines I've had most success with have some form of 2 bit debounce on the input side, giving the new encoder bit pattern. This is combined with the previous 2 bit reading, resulting in a 4 bit number. This 4 bit number is used as an index into a 16 element table which has the values +1, -1 and 0.
Visit Vegipete's *Mite Library for cool programs.
 
Warpspeed
Guru

Joined: 09/08/2007
Location: Australia
Posts: 4406
Posted: 12:25pm 04 Mar 2014
Copy link to clipboard 
Print this post

If you want super fast response without any missing counts, and less software overhead, best way is to feed your encoder into a hardware digital up/down counter and read the counter output into a parallel port.
As many bits as may be required.

One encoder output goes to the up/down control pin on the counter.
Other encoder output goes to the clock pin on the counter.
Its very very fast and totally fool proof.
You just read the counter contents.
Its either the same as it was last read.
Or its gone up (or down) by maybe three counts,or three hundred counts since last read.

While that is going on, your processor can be away doing something else, and miss nothing.

Cheers,  Tony.
 
robert.rozee
Guru

Joined: 31/12/2012
Location: New Zealand
Posts: 2350
Posted: 12:46pm 04 Mar 2014
Copy link to clipboard 
Print this post


has anyone tried this code yet:


encoder = 1000
last = 0
SETPIN 2, INTB, rotary
SETPIN 3, INTB, rotary

DO
LOOP

rotary:
nxtv = (PIN(2) * 2) + PIN 3
IF ((last+nxtv) AND 1) = 1 THEN encoder = encoder - ((nxtv-last) MOD 4) + 2
last = nxtv
PRINT encoder
IRETURN


note the 1000 offset to get away from issues with printing negative numbers

rob :-)
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3196
Posted: 02:42pm 04 Mar 2014
Copy link to clipboard 
Print this post

Sorry Rob but your code does not work. There is one bug, line 10 should read:
nxtv = (PIN(2) * 2) + PIN(3)

but even with this fixed, all the program does is count up regardless of the direction of rotation.

TZAdvantage's code works fine with a panel mounting encoder and a knob.

If it takes so little effort to implement a rotary encoder in BASIC I am wondering as to the worth of implementing a dedicated function in MMBasic. As I see it most constructors would like to mount an encoder on the front panel of their gadget and use it to adjust some setting in MMBasic. In that case a few lines of BASIC are all that is needed.

There seems to be another group that would like to use encoders to track mechanical movement on robots, milling machines, etc and I am not sure that the Micromite is the right processor for that. It just does not have the performance to track multiple high speed encoders and drive multiple high speed servos.

Regardless this debate is quite educational.

Geoff

EDIT: There is a serious bug in beta 8 regarding printing numbers. I hope to have a new release that fixes that out soon.Edited by Geoffg 2014-03-06
Geoff Graham - http://geoffg.net
 
robert.rozee
Guru

Joined: 31/12/2012
Location: New Zealand
Posts: 2350
Posted: 06:12pm 04 Mar 2014
Copy link to clipboard 
Print this post

interesting - could well be i was trying to be a bit too clever!

how about with the original two IF statements reinstated:

rotary:
next = (PIN(2) * 2) + PIN(3)
IF ((last+nxtv) AND 1) = 1 THEN ' two-step change is an error
IF ((nxtv-last)=1) OR ((last-nxtv)=3) THEN encoder = encoder + 1
IF ((last-nxtv)=1) OR ((nxtv-last)=3) THEN encoder = encoder - 1
ENDIF
last = nxtv
IRETURN


and what does MMbasic produce as the result of "(-1) MOD 4"? the result of MOD on negative numbers should be as follows:

(-1) mod 4 = 3
(-3) mod 4 = 1
Edited by robert.rozee 2014-03-06
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 06:41pm 04 Mar 2014
Copy link to clipboard 
Print this post

@Geoff,

The way i coded it will work when interrupts are handled quick enough.
A PIN is read in the interrupt routine and that PIN could have changed state.
If MMAsic is in a blocking statement then it will give wrong results.
Implementing the same code on a lower level would increase accuracy and devices with very short pulses will still work.
You might even be able to count up until a few hundred RPM. That opens up another range of uses.
Still for a knob that is hand operated it would be overkill.

Edited by TZAdvantage 2014-03-06
Microblocks. Build with logic.
 
robert.rozee
Guru

Joined: 31/12/2012
Location: New Zealand
Posts: 2350
Posted: 07:12pm 04 Mar 2014
Copy link to clipboard 
Print this post

btw, the logic i used was based upon the following map:



green and yellow represent the two different directions of rotation, while white cells are the 'illegal' states where a transition has been skipped.
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 08:33pm 04 Mar 2014
Copy link to clipboard 
Print this post

the problem with 'illegal states' is what you are going to do with them.
From that moment the counter is wrong and there is no way to fix it.
In software you can not fix illegal states caused by contact bounce or any other reasons.
The solution is in hardware like better encoders and debouncing, optical would be great.
It is the reason why i ignored the Gray encoding.
It makes things slower and more complicated.

Microblocks. Build with logic.
 
robert.rozee
Guru

Joined: 31/12/2012
Location: New Zealand
Posts: 2350
Posted: 01:51am 05 Mar 2014
Copy link to clipboard 
Print this post

when you encounter an 'illegal state' you do nothing - just assume a new safe starting position, and wait for a new transition to come along. provided this doesn't happen too often it is not a big issue for most applications.

consider a volume control or a knob that takes you up and down through a menu; if there are, say, 8 or 16 events per turn, the user is hardly likely to notice if the odd one is skipped. compare this to the mouse pointer occasionally jumping on your computer screen, or the indicators on your car self-cancelling now and then when you're halfway round a corner. both are everyday common occurrences that happen all the time and that nobody loses any sleep over.

in critical applications, you take more care. you add a few cents worth of extra components to ensure closer to 100% reliability. in the case of counting turns of a shaft, i'd probably use two optical sensors on two holes through the shaft (90 degrees apart), along with a third sensor on a pair of 'x' holes 45 degrees out from the above to generate a clock. these would feed a couple of latches, which would then be gated into an up/down counter. and even that would not be totally foolproof if the shaft changed direction of rotation at just the right instant.

the reality is that the physical world is unreliable. one has to learn to live with it.Edited by robert.rozee 2014-03-06
 
atmega8

Guru

Joined: 19/11/2013
Location: Germany
Posts: 722
Posted: 08:57am 05 Mar 2014
Copy link to clipboard 
Print this post

"the reality is that the physical world is unreliable. one has to learn to live with it."


And the answer is to code intelligent Software that eliminates the unreliable physical world ;-)

Reagrding to the Encoders, there are enough code examples in the web, which do the Job.

I posted some links.....


 
Warpspeed
Guru

Joined: 09/08/2007
Location: Australia
Posts: 4406
Posted: 11:16am 05 Mar 2014
Copy link to clipboard 
Print this post

  robert.rozee said   And even that would not be totally foolproof if the shaft changed direction of rotation at just the right instant.


Yes it would still be foolproof, because the hardware up down counter will be edge triggered and not level triggered.
A clock edge cannot suddenly be moving simultaneously in both directions, and when one edge (the clock edge) does suddenly jump the correct way, and is recognised as a valid clock edge, the other encoder output will always be stable.

If you have high frequency noise, shonky logic levels, or contact bounce problems with your encoder, NOTHING in software is going to work reliably.

As with interfacing any type of analog sensor to a digital system, the signal often needs to be processed in some way before it is fit to be used as a reliable input to a digital or software system.

That might be an amplitude related problem where uncertain logic levels, noise, or contact bounce can be an issue.
Or it could be a "time coincidence related" problem, with high frequencies or very short pulses, where latching or counting has to be done externally in hardware as part of the signal processing, before software gets to work with it.

Trying to fix problem plagued erratic external hardware, with some clever software algorithm is a total waste of time.
Much more productive to fix the problems at the source than trying to band aid it.


Cheers,  Tony.
 
robert.rozee
Guru

Joined: 31/12/2012
Location: New Zealand
Posts: 2350
Posted: 11:48am 05 Mar 2014
Copy link to clipboard 
Print this post

  Warpspeed said  
  robert.rozee said   And even that would not be totally foolproof if the shaft changed direction of rotation at just the right instant.

Trying to fix problem plagued erratic external hardware, with some clever software algorithm is a total waste of time.


agreed. but when the rotation direction changes at just the instant a clock pulse is being generated, there is always the chance (albeit diminishingly remote) of not one, but two, three, or more clock pulses being produced. the only solution (at high speed) is to impose some sort of a time-window (stretch the pulse), which others have dismissed as being unacceptable as it imposes a maximum rotation speed. and then there is the problem of what happens at low speed.

i have seen "fool-proof" designs for all sorts of things before, and with enough persistence they can always be fooled. so one builds in redundancy, zeros the measuring device against an endstop periodically, etc.Edited by robert.rozee 2014-03-06
 
Warpspeed
Guru

Joined: 09/08/2007
Location: Australia
Posts: 4406
Posted: 12:06pm 05 Mar 2014
Copy link to clipboard 
Print this post

That means the clock must have several real edges in very fast succession.
Most likely mechanical vibration or torsional jitter, assuming everything else is electrically sound.
Quite possible with fast high power stepper motors, gearboxes with backlash, flapping drive belts etc....

If the whole mechanical mess is jumping up and down and flopping around, a shaft encoder with very fine resolution is going to be a complete waste of time anyway.
Fix the (mechanical) problem at the source.

Edited by Warpspeed 2014-03-06
Cheers,  Tony.
 
jman

Guru

Joined: 12/06/2011
Location: New Zealand
Posts: 711
Posted: 06:29pm 28 Mar 2014
Copy link to clipboard 
Print this post

  TZAdvantage said   Can anyone test this code (Just a few more days and i can have some time to tinker again):
[code]
RotaryValue = 0
RotaryA = 2
RotaryB = 3
SETPIN RotaryA, INTH, RotaryInterrupt

DO
PRINT RotaryValue
'Add usefull stuff here
LOOP

SUB RotaryInterrupt
IF PIN(RotaryB) = 1 then
RotaryValue = RotaryValue + 1
ELSE
RotaryValue = RotaryValue - 1
ENDIF
END SUB
[/code]


Hi Rob

Your code works perfectly with the addition for 2 x pull-up resistors
on pins 2 and 3

I had to add the line below to stop the error below

[14] If Pin(RotaryB) = 1 Then
Error: Pin is not an input


SetPin RotaryB, Din


Thank you the code it is a great fit for a project that I am
currently working on

Regards
Jman
 
paceman
Guru

Joined: 07/10/2011
Location: Australia
Posts: 1329
Posted: 12:35am 29 Mar 2014
Copy link to clipboard 
Print this post

That's a bit odd John. The code I've got copied in my 'useful stuff' file from the earlier discussion has got your extra line in it. Looks like it's been lost in translation somewhere.

Greg
 
     Page 2 of 2    
Print this page


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

© JAQ Software 2024