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 StatesPosts: 71 |
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 ZealandPosts: 2350 |
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. |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9308 |
...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) Smoke makes things work. When the smoke gets out, it stops! |
||||
MicroBlocks Guru Joined: 12/05/2012 Location: ThailandPosts: 2209 |
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] Microblocks. Build with logic. |
||||
atmega8 Guru Joined: 19/11/2013 Location: GermanyPosts: 722 |
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 [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] |
||||
vegipete Guru Joined: 29/01/2013 Location: CanadaPosts: 1110 |
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: AustraliaPosts: 4406 |
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 ZealandPosts: 2350 |
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: AustraliaPosts: 3196 |
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. Geoff Graham - http://geoffg.net |
||||
robert.rozee Guru Joined: 31/12/2012 Location: New ZealandPosts: 2350 |
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 |
||||
MicroBlocks Guru Joined: 12/05/2012 Location: ThailandPosts: 2209 |
@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. Microblocks. Build with logic. |
||||
robert.rozee Guru Joined: 31/12/2012 Location: New ZealandPosts: 2350 |
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: ThailandPosts: 2209 |
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 ZealandPosts: 2350 |
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. |
||||
atmega8 Guru Joined: 19/11/2013 Location: GermanyPosts: 722 |
"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: AustraliaPosts: 4406 |
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 ZealandPosts: 2350 |
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. |
||||
Warpspeed Guru Joined: 09/08/2007 Location: AustraliaPosts: 4406 |
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. Cheers, Tony. |
||||
jman Guru Joined: 12/06/2011 Location: New ZealandPosts: 711 |
[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: AustraliaPosts: 1329 |
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 |