I thought I had this shield prototyped and working well until it was put into service. It appears to be a timing issue with how fast the serial string is requested vs reading the shift registers?
Anyway... I have 2 pins configured for an encoder, and 80 sensors to read. I want to read the sensor bank from start to finish and then report a binary string via serial to my GUI software running on a Windows 10 machine.
What's the best way to read (80) 3.3v or 5.0v + DC inputs based on an encoder click count?
I had a pretty decent setup before running 2 arduino mega boards and using 2 com ports on a PC before... but I wanted to make the software a bit simpler and easier to use by running 1 arduino. So i prototyped a board using (10) CD4021B shift registers and a RedBoard. Worked great in testing on the bench, but in service it gives very erratic data.
Thoughts on how to pull off reading that many high/low sensor inputs?
Review your software and see if you can speed it up.
Define how quickly you want to have the sensors read.
Send the data in a more efficient way than a binary string.
Read How to use this forum
Because your post is breaking the rules about posting code.
Don't print in an interrupt service routine.
My knowledge with small electronics and shift registers is enough to be dangerous.. when it comes to troubleshooting my circuit of registers I'm a bit lost. Seems like that was the best route to go with, but in service it's not working out. A bit lost.
So leads me back to my original question of.. Is there a better way?
Running a serial string input at 250000 baud seems like it would be more than fast enough for what I'm doing...
Who told you that not me. I told you it was not posted correctly.
If you want help you have to tell us what you have done, you have given us very little to go on so far.
So a schematic of your hardware, a photograph showing the wiring, information about what you are sending the data into (GUI on a PC doesn't cut it ), and what transfer time are you aiming for.
I also told you not to print in an ISR so why have you not tried removing it and seeing if that improves the matter?
Ok I'll get a schematic tomorrow when I'm back at work. Let's eliminate the custom software. From using the serial monitor I can tell the data is in correct. What is printed to the serial monitor is a single line with 80 values 0 or 1 depending on pin state. 3.8v DC + is fed into each input of the shift register. Max read interval is 3 encoder revolutions per second. I will do the math tomorrow as well... Sorry.
You can't use the noInterrupts() function like that. You are pausing interrupts for far too long. Also Serial.print() require interrupts to be active. Normally you would halt interrupts for a few microseconds to read a value that is updated within an ISR.
You also have a print() statement inside your ISR and interrupts are automatically off inside an ISR. As well as which print() is much too slow to put it inside an ISR even if it would work properly.
And I don't understand what is your purpose in halting interrupts. Why bother to stop the encoder?
If I don't print the data to the screen (serial monitor) how am I going to know if it's correct?
You can print it but not in an interrupt routine. Once you know the data is correct comment it out and connect up this mystery top secret Windows program.
Robin2:
You can't use the noInterrupts() function like that. You are pausing interrupts for far too long. Also Serial.print() require interrupts to be active. Normally you would halt interrupts for a few microseconds to read a value that is updated within an ISR.
You also have a print() statement inside your ISR and interrupts are automatically off inside an ISR. As well as which print() is much too slow to put it inside an ISR even if it would work properly.
And I don't understand what is your purpose in halting interrupts. Why bother to stop the encoder?
...R
I stopped the interrupt because it would continue to tick and interrupt my code for reading and printing. I only run the read and print every so many clicks to not send any more serial data than needed...
May be on to something here though. I really appreciate the feedback here.
If you want to stop reading an encoder, you can disable the interrupt for that encoder. No need to disable ALL interrupts (there is much more to interrupts than those produced by the pins).
Switching off interrupts altogether will mess up things like timers and Serial communications.
All good information here. I did some google research and I now understand the fault in my ISR and disabling of all interrupts. Not understanding the full scope of the functions used would surely create the behavior I've been seeing. This is some great information here and I really appreciate the help!
I have made the changes to my program and soon I'll have some new data to evaluate.
If this was my project my ISR would be much simpler - like this
void doThis(void) {
//Check Rotation, only count if going forward
byte encAval = digitalRead(encPinA);
byte encBval = digitalRead(encPinB);
if (encAval == HIGH and encBval == LOW) { // I may have this backwards
encCount++;
newEncVal = true; // signal to loop() that there is a new value
}
}
And I cannot see any need to reset the value of encCount - in loop() just compare the current value with the previous value.
Robin2:
If this was my project my ISR would be much simpler - like this
void doThis(void) {
//Check Rotation, only count if going forward
byte encAval = digitalRead(encPinA);
byte encBval = digitalRead(encPinB);
if (encAval == HIGH and encBval == LOW) { // I may have this backwards
encCount++;
newEncVal = true; // signal to loop() that there is a new value
}
}
And I cannot see any need to reset the value of encCount - in loop() just compare the current value with the previous value.
...R
I do agree there are more ways to do it.. Not too sure storing the prevEncVal is any more efficient than just resetting the current one back to 0. But I'm sure either way would get the job done.
Thanks again. She seems to be working rather well now. Glad it wasn't a hardware issue..