De-bouncing a (Gray) Rotary Encoder Switch in C
$begingroup$
I would like feedback on the correctness and performance of this code.
My priorities are also are readability, simplicity and self-documenting code - but I'm happy with those as they are.
I know I've used C pretty poorly as far as factoring out common code between the two input lines - but I'm brushing up my C and will do that.
RA2 and RA3 are the two digital input lines. My algorithm is not dissimilar to how debouncing would be done with a low pass capacitor and resistor followed by a schmitt trigger. This function is called by the ISR every 0.5ms, and the rotary switch produces transitions as short as 5-10ms.
I am curious how to deal with situations where the rotary switch is turned a bit faster than the algorithm can process. Can further information be deduced from the Gray encoding, even when a step is missed because of the low pass delay and limited sample rate? I suppose this could be taken as far as using neural networks?!
I'm mainly asking this question because I think the running time and the amount of code of the below can both be reduced by a factor of two at least. And I'd just prefer not to get out the logic analyzer and completely reinvent the wheel.
rotsw.h
#define ROTSW_AVG_SIZE 8
#define ROTSW_MAX 7
#define ROTSW_UPPER 5
#define ROTSW_LOWER 2
#define ROTSW_MIN 0
void rotsw_sample_avg_schmitt_count();
extern volatile int rotsw_count_steps;
rotsw.c
unsigned int rotsw_samples[ROTSW_AVG_SIZE];
unsigned char rotsw_write_idx = 0;
int rotsw_avg_ra2 = 0;
int rotsw_avg_ra3 = 0;
int ra2 = 0;
int ra3 = 0;
volatile int rotsw_count = 0;
void rotsw_sample_avg_schmitt_count()
{
int sample, old_sample, ra2_changed, ra3_changed, count = rotsw_count;
// Sample RA2 and RA3
old_sample = rotsw_samples[rotsw_write_idx];
rotsw_samples[rotsw_write_idx] = sample = PORTA & 0b00001100;
if (++rotsw_write_idx >= ROTSW_AVG_SIZE) rotsw_write_idx = 0;
// Moving average, turning digital sample to "analogue"
if (old_sample & 0x04) rotsw_avg_ra2--;
if (old_sample & 0x08) rotsw_avg_ra3--;
if (sample & 0x04) rotsw_avg_ra2++;
if (sample & 0x08) rotsw_avg_ra3++;
// 3. Do limit for Schmitt trigger
if (rotsw_avg_ra2 < ROTSW_MIN) rotsw_avg_ra2 = ROTSW_MIN;
else if (rotsw_avg_ra2 > ROTSW_MAX) rotsw_avg_ra2 = ROTSW_MAX;
if (rotsw_avg_ra3 < ROTSW_MIN) rotsw_avg_ra3 = ROTSW_MIN;
else if (rotsw_avg_ra3 > ROTSW_MAX) rotsw_avg_ra3 = ROTSW_MAX;
// Do Schmitt trigger
if (rotsw_avg_ra2 > ROTSW_UPPER){
ra2_changed = !ra2;
ra2 = 1;
} else if (rotsw_avg_ra2 < ROTSW_LOWER){
ra2_changed = ra2;
ra2 = 0;
}
if (rotsw_avg_ra3 > ROTSW_UPPER){
ra3_changed = !ra3;
ra3 = 1;
} else if (rotsw_avg_ra3 < ROTSW_LOWER){
ra3_changed = ra3;
ra3 = 0;
}
// Do rotsw state change count.
if (ra2_changed){
if (ra2 == ra3) count++;
else count--;
}
if (ra3_changed){
if(ra2 == ra3) count--;
else count++;
}
rotsw_count = count;
}
performance algorithm c event-handling device-driver
$endgroup$
add a comment |
$begingroup$
I would like feedback on the correctness and performance of this code.
My priorities are also are readability, simplicity and self-documenting code - but I'm happy with those as they are.
I know I've used C pretty poorly as far as factoring out common code between the two input lines - but I'm brushing up my C and will do that.
RA2 and RA3 are the two digital input lines. My algorithm is not dissimilar to how debouncing would be done with a low pass capacitor and resistor followed by a schmitt trigger. This function is called by the ISR every 0.5ms, and the rotary switch produces transitions as short as 5-10ms.
I am curious how to deal with situations where the rotary switch is turned a bit faster than the algorithm can process. Can further information be deduced from the Gray encoding, even when a step is missed because of the low pass delay and limited sample rate? I suppose this could be taken as far as using neural networks?!
I'm mainly asking this question because I think the running time and the amount of code of the below can both be reduced by a factor of two at least. And I'd just prefer not to get out the logic analyzer and completely reinvent the wheel.
rotsw.h
#define ROTSW_AVG_SIZE 8
#define ROTSW_MAX 7
#define ROTSW_UPPER 5
#define ROTSW_LOWER 2
#define ROTSW_MIN 0
void rotsw_sample_avg_schmitt_count();
extern volatile int rotsw_count_steps;
rotsw.c
unsigned int rotsw_samples[ROTSW_AVG_SIZE];
unsigned char rotsw_write_idx = 0;
int rotsw_avg_ra2 = 0;
int rotsw_avg_ra3 = 0;
int ra2 = 0;
int ra3 = 0;
volatile int rotsw_count = 0;
void rotsw_sample_avg_schmitt_count()
{
int sample, old_sample, ra2_changed, ra3_changed, count = rotsw_count;
// Sample RA2 and RA3
old_sample = rotsw_samples[rotsw_write_idx];
rotsw_samples[rotsw_write_idx] = sample = PORTA & 0b00001100;
if (++rotsw_write_idx >= ROTSW_AVG_SIZE) rotsw_write_idx = 0;
// Moving average, turning digital sample to "analogue"
if (old_sample & 0x04) rotsw_avg_ra2--;
if (old_sample & 0x08) rotsw_avg_ra3--;
if (sample & 0x04) rotsw_avg_ra2++;
if (sample & 0x08) rotsw_avg_ra3++;
// 3. Do limit for Schmitt trigger
if (rotsw_avg_ra2 < ROTSW_MIN) rotsw_avg_ra2 = ROTSW_MIN;
else if (rotsw_avg_ra2 > ROTSW_MAX) rotsw_avg_ra2 = ROTSW_MAX;
if (rotsw_avg_ra3 < ROTSW_MIN) rotsw_avg_ra3 = ROTSW_MIN;
else if (rotsw_avg_ra3 > ROTSW_MAX) rotsw_avg_ra3 = ROTSW_MAX;
// Do Schmitt trigger
if (rotsw_avg_ra2 > ROTSW_UPPER){
ra2_changed = !ra2;
ra2 = 1;
} else if (rotsw_avg_ra2 < ROTSW_LOWER){
ra2_changed = ra2;
ra2 = 0;
}
if (rotsw_avg_ra3 > ROTSW_UPPER){
ra3_changed = !ra3;
ra3 = 1;
} else if (rotsw_avg_ra3 < ROTSW_LOWER){
ra3_changed = ra3;
ra3 = 0;
}
// Do rotsw state change count.
if (ra2_changed){
if (ra2 == ra3) count++;
else count--;
}
if (ra3_changed){
if(ra2 == ra3) count--;
else count++;
}
rotsw_count = count;
}
performance algorithm c event-handling device-driver
$endgroup$
add a comment |
$begingroup$
I would like feedback on the correctness and performance of this code.
My priorities are also are readability, simplicity and self-documenting code - but I'm happy with those as they are.
I know I've used C pretty poorly as far as factoring out common code between the two input lines - but I'm brushing up my C and will do that.
RA2 and RA3 are the two digital input lines. My algorithm is not dissimilar to how debouncing would be done with a low pass capacitor and resistor followed by a schmitt trigger. This function is called by the ISR every 0.5ms, and the rotary switch produces transitions as short as 5-10ms.
I am curious how to deal with situations where the rotary switch is turned a bit faster than the algorithm can process. Can further information be deduced from the Gray encoding, even when a step is missed because of the low pass delay and limited sample rate? I suppose this could be taken as far as using neural networks?!
I'm mainly asking this question because I think the running time and the amount of code of the below can both be reduced by a factor of two at least. And I'd just prefer not to get out the logic analyzer and completely reinvent the wheel.
rotsw.h
#define ROTSW_AVG_SIZE 8
#define ROTSW_MAX 7
#define ROTSW_UPPER 5
#define ROTSW_LOWER 2
#define ROTSW_MIN 0
void rotsw_sample_avg_schmitt_count();
extern volatile int rotsw_count_steps;
rotsw.c
unsigned int rotsw_samples[ROTSW_AVG_SIZE];
unsigned char rotsw_write_idx = 0;
int rotsw_avg_ra2 = 0;
int rotsw_avg_ra3 = 0;
int ra2 = 0;
int ra3 = 0;
volatile int rotsw_count = 0;
void rotsw_sample_avg_schmitt_count()
{
int sample, old_sample, ra2_changed, ra3_changed, count = rotsw_count;
// Sample RA2 and RA3
old_sample = rotsw_samples[rotsw_write_idx];
rotsw_samples[rotsw_write_idx] = sample = PORTA & 0b00001100;
if (++rotsw_write_idx >= ROTSW_AVG_SIZE) rotsw_write_idx = 0;
// Moving average, turning digital sample to "analogue"
if (old_sample & 0x04) rotsw_avg_ra2--;
if (old_sample & 0x08) rotsw_avg_ra3--;
if (sample & 0x04) rotsw_avg_ra2++;
if (sample & 0x08) rotsw_avg_ra3++;
// 3. Do limit for Schmitt trigger
if (rotsw_avg_ra2 < ROTSW_MIN) rotsw_avg_ra2 = ROTSW_MIN;
else if (rotsw_avg_ra2 > ROTSW_MAX) rotsw_avg_ra2 = ROTSW_MAX;
if (rotsw_avg_ra3 < ROTSW_MIN) rotsw_avg_ra3 = ROTSW_MIN;
else if (rotsw_avg_ra3 > ROTSW_MAX) rotsw_avg_ra3 = ROTSW_MAX;
// Do Schmitt trigger
if (rotsw_avg_ra2 > ROTSW_UPPER){
ra2_changed = !ra2;
ra2 = 1;
} else if (rotsw_avg_ra2 < ROTSW_LOWER){
ra2_changed = ra2;
ra2 = 0;
}
if (rotsw_avg_ra3 > ROTSW_UPPER){
ra3_changed = !ra3;
ra3 = 1;
} else if (rotsw_avg_ra3 < ROTSW_LOWER){
ra3_changed = ra3;
ra3 = 0;
}
// Do rotsw state change count.
if (ra2_changed){
if (ra2 == ra3) count++;
else count--;
}
if (ra3_changed){
if(ra2 == ra3) count--;
else count++;
}
rotsw_count = count;
}
performance algorithm c event-handling device-driver
$endgroup$
I would like feedback on the correctness and performance of this code.
My priorities are also are readability, simplicity and self-documenting code - but I'm happy with those as they are.
I know I've used C pretty poorly as far as factoring out common code between the two input lines - but I'm brushing up my C and will do that.
RA2 and RA3 are the two digital input lines. My algorithm is not dissimilar to how debouncing would be done with a low pass capacitor and resistor followed by a schmitt trigger. This function is called by the ISR every 0.5ms, and the rotary switch produces transitions as short as 5-10ms.
I am curious how to deal with situations where the rotary switch is turned a bit faster than the algorithm can process. Can further information be deduced from the Gray encoding, even when a step is missed because of the low pass delay and limited sample rate? I suppose this could be taken as far as using neural networks?!
I'm mainly asking this question because I think the running time and the amount of code of the below can both be reduced by a factor of two at least. And I'd just prefer not to get out the logic analyzer and completely reinvent the wheel.
rotsw.h
#define ROTSW_AVG_SIZE 8
#define ROTSW_MAX 7
#define ROTSW_UPPER 5
#define ROTSW_LOWER 2
#define ROTSW_MIN 0
void rotsw_sample_avg_schmitt_count();
extern volatile int rotsw_count_steps;
rotsw.c
unsigned int rotsw_samples[ROTSW_AVG_SIZE];
unsigned char rotsw_write_idx = 0;
int rotsw_avg_ra2 = 0;
int rotsw_avg_ra3 = 0;
int ra2 = 0;
int ra3 = 0;
volatile int rotsw_count = 0;
void rotsw_sample_avg_schmitt_count()
{
int sample, old_sample, ra2_changed, ra3_changed, count = rotsw_count;
// Sample RA2 and RA3
old_sample = rotsw_samples[rotsw_write_idx];
rotsw_samples[rotsw_write_idx] = sample = PORTA & 0b00001100;
if (++rotsw_write_idx >= ROTSW_AVG_SIZE) rotsw_write_idx = 0;
// Moving average, turning digital sample to "analogue"
if (old_sample & 0x04) rotsw_avg_ra2--;
if (old_sample & 0x08) rotsw_avg_ra3--;
if (sample & 0x04) rotsw_avg_ra2++;
if (sample & 0x08) rotsw_avg_ra3++;
// 3. Do limit for Schmitt trigger
if (rotsw_avg_ra2 < ROTSW_MIN) rotsw_avg_ra2 = ROTSW_MIN;
else if (rotsw_avg_ra2 > ROTSW_MAX) rotsw_avg_ra2 = ROTSW_MAX;
if (rotsw_avg_ra3 < ROTSW_MIN) rotsw_avg_ra3 = ROTSW_MIN;
else if (rotsw_avg_ra3 > ROTSW_MAX) rotsw_avg_ra3 = ROTSW_MAX;
// Do Schmitt trigger
if (rotsw_avg_ra2 > ROTSW_UPPER){
ra2_changed = !ra2;
ra2 = 1;
} else if (rotsw_avg_ra2 < ROTSW_LOWER){
ra2_changed = ra2;
ra2 = 0;
}
if (rotsw_avg_ra3 > ROTSW_UPPER){
ra3_changed = !ra3;
ra3 = 1;
} else if (rotsw_avg_ra3 < ROTSW_LOWER){
ra3_changed = ra3;
ra3 = 0;
}
// Do rotsw state change count.
if (ra2_changed){
if (ra2 == ra3) count++;
else count--;
}
if (ra3_changed){
if(ra2 == ra3) count--;
else count++;
}
rotsw_count = count;
}
performance algorithm c event-handling device-driver
performance algorithm c event-handling device-driver
edited 13 mins ago
CL22
asked 1 hour ago
CL22CL22
233110
233110
add a comment |
add a comment |
0
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f213636%2fde-bouncing-a-gray-rotary-encoder-switch-in-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f213636%2fde-bouncing-a-gray-rotary-encoder-switch-in-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown