i'm having a issue that i kind of already explained in another thread i had running, but it was not related to the issue of that thread so i thought it was better to start a new one, i'm making a coil winder for guitar/bass pickups, i'm using a arduino uno, a ibt_2 12v 30A motor driver, a d1robot lcd keypad shield, a opto interruptor (slotted type), and a rotary encoder.
so ive got a little menu going, the opto interruptor is being used to count revolutions/windings, and the rotary encoder is being used to controll speed and direction (ideally, if you tur the knob down to speed zero and continue turning down it will start increasing speed in reverse, and viceversa), and most of it is working, but strangely enough, somewhere in the sketch something is making the oncoder part fail, i know its in the sketch, because if i upload the example sketch i used, with exact the same setup, it works fine...
i think it might be the fact that i'm checking the rotary encoder inside a while loop (menu item), but dont know why that would mess with the functionality.
my sketch and example sketch are in the attachments, hope someone can help, have been looking for a while and can't get my head around it.
the preveous thread is this one, in the zip fie is my sketch, but its also posted in my two last messages on that thread, but the help i recieved there was all related to a different problem...
btw, sorry for the zip file, i know it doesn't feel right but my sketch is divided into three .ino files, to keep it a bit more organized, and i didn't post a simplified version, because i have genuinely no clue what could be causing the issue (have been trying to debug it for two and a half days now), should i upload the .ino files of my proyect separately?
what i know untill now, is that when i upload the example code, both encoder pins read around 4,8v on the multimeter, but when i upload my code, only pin 12/encoderPinB reads 4,8v, pin 2/encoderPinA reads 0-0,1v, and the 'up' boolean is always 0 in my sketch for some reason, in the example sketch it is 0 for clockwise, and 1 for counterclockwise...
There is too much code for me to get a good overall sense of it quickly.
It seems to me you are checking the output of the ISR in only 2 menus. I think I would check it in loop() and save the value to a variable so it could be used anywhere it is needed throughout an iteration of loop(). That also has the value of eliminating duplicate code.
yeah, it's quite a lot of stuff going on :''D .
yes, i had to check the isr inside each menu's, because they are a while loop, so anything in the loop() befor the menu gets executed, will be done once, untill you get out of the menu, so if i check for the output of the isr in the loop(), instead of the menu, it will execute only once, but i need to check constantly or near constantly, because its the speed control during operation, i could put the check in its own function, that would simplify my code a bit, but i dont think that it would have impact on the problem, the only thing i can think of that might help is use a menu that doesnt rely on while loops, but i dont know how to do that or if it is even possible, but still, as i have it now must be possible i believe
First, you should adopt "State Machine" techniques to make your menu code non-blocking. I know lots of examples have been posted in the forum. Don't have the links right now, but try searching. Maybe a helpful member can provide some.
Also, if you can afford to use both interrupts on the Uno (pins 2 and 3), take a look at this Encoder class that I just posted to GitHub: NewEncoder.
It handles all state updates in the ISRs. All you have to do is read the current value whenever you want. It also allows you to set upper and lower "saturation" values for the encoder. Check out the SingleEncoder example.
gfvalvo:
First, you should adopt "State Machine" techniques to make your menu code non-blocking. I know lots of examples have been posted in the forum. Don't have the links right now, but try searching. Maybe a helpful member can provide some.
Also, if you can afford to use both interrupts on the Uno (pins 2 and 3), take a look at this Encoder class that I just posted to GitHub: NewEncoder.
It handles all state updates in the ISRs. All you have to do is read the current value whenever you want. It also allows you to set upper and lower "saturation" values for the encoder. Check out the SingleEncoder example.
thanks for the tip, have been reading and learning about it, man thats a deep topic haha, but the way i understand it it kind of works like i already have, i see they use a case switch which reacts to a certain state, and changes the state value so its able to react differently the next time around, or am i missing something here??
sadly i can't use both interrupt pins, since i use a breakout lcd shield with buttons and it ocupies pins from 4 to 10, and for the motor controller i need two pwm pins(11, 3), so i'm stuck with one interrupt or make a messy pin rearrangement on the lcd shield... but i'll still have a look at your library, maybe for a future proyect
took a break yesterday afternoon, since some times you focus so much on a problem that you just completely overlook a very obvious issue, but came back to it this morning and am still mind boggled :'D
got rid of all but one while loop, the only thing this while loop does is keep running the function i use to be able to program the ammount of turns at wich it has to stop, and still get only 0 from the rotary encoder, so it treats it as if its continuously turning clockwise
#include <LiquidCrystal.h>
LiquidCrystal lcd(8,9,4,5,6,7);
int Ver = 1;
//timing
unsigned long previousMillis = 0;
const long interval = 1000;
const long interval2 = 400;
int Blinkstate = 0;
volatile bool fired;
volatile bool up;
int usMotor_Status;
int pwm_right=3;
int pwm_left=11;
int EN_l=13;
int RevSpeed;
const int buttonPin = A1; //red
int buttonState = 0;
short usSpeed = 0;
const byte encoderPinA = 2; //white
const byte encoderPinB = 12; //greem
int stationary = 0;
unsigned int stopV[5] = {0,0,0,0,0};
int stop_var_n= 0;
//lcd variables
bool executable = false;
unsigned int charsel = 4;
unsigned int stopvar;
int stopvarC = 0;
int sens_pin = A2;
int screen_delay =500;
unsigned int count = 0;
unsigned int sens_outp = 0;
unsigned int sens_temp_state = 0;
int keypad_pin = A0;
int keypad_value = 0;
int keypad_value_old = 0;
char btn_push;
// Interrupt Service Routine for a change to encoder pin A
void isr ()
{
if (digitalRead (encoderPinA))
up = digitalRead (encoderPinB);
else
up = !digitalRead (encoderPinB);
fired = true;
} // end of isr
void setup() {
pinMode(pwm_right, OUTPUT);
pinMode(pwm_left, OUTPUT);
pinMode(EN_l, OUTPUT);
pinMode(buttonPin, INPUT);
pinMode (encoderPinA, INPUT_PULLUP); // enable pull-ups
pinMode (encoderPinB, INPUT_PULLUP);
attachInterrupt (digitalPinToInterrupt (encoderPinA), isr, CHANGE); // interrupt 0 is pin 2
usMotor_Status = 0;
// put your setup code here, to run once:
Serial.begin(9600);
Serial.println("1. STOP");
Serial.println("2. FORWARD");
Serial.println("3. REVERSE");
Serial.println("4. READ CURRENT");
Serial.println("+. INCREASE SPEED");
Serial.println("-. DECREASE SPEED");
Serial.println();
lcd.begin(16,2); //Initialize a 2x16 type LCD
pinMode(keypad_pin, INPUT);
pinMode(sens_pin, INPUT);
lcd.setCursor(2,0);
lcd.print("Vosse pickup ");
lcd.setCursor(3,1);
lcd.print("winder v");
lcd.print(Ver);
delay(4000);
lcd.clear();
}
void loop()
{
Serial.println(up);
char user_input;
if (fired)
{
if (up)
IncreaseSpeed();
else
DecreaseSpeed();
fired = false;
} // end if fired
if ((stationary != 0) && (count == stopvar)) {
Stop();
stationary = 0;
delay(500);
}
buttonState = analogRead(buttonPin);
if (stationary != 0) {
if ((buttonState == 0)){
Stop();
stationary = 0;
delay(500);
}
}
lcd.setCursor(0,0);
lcd.print("turns =");
while(stopvarC == 0)
{
setStopVar();
}
/*if (ReadKeypad() == 'S'){
stopvarC = 0;
}*/
Count();
lcd.setCursor(8,0);
lcd.print(stopvar);
if (ReadKeypad() == 'L'){
count = 0;
stopvarC = 0;
stopV[0] = 0;
stopV[1] = 0;
stopV[2] = 0;
stopV[3] = 0;
stopV[4] = 0;
Blinkstate = 0;
usMotor_Status = 0;
}
}
void setStopVar() {
unsigned long currentMillis = millis();
lcd.setCursor(8,0);
lcd.print(stopV[0]);
lcd.print(stopV[1]);
lcd.print(stopV[2]);
lcd.print(stopV[3]);
lcd.print(stopV[4]);
if (currentMillis - previousMillis >= interval2) {
// save the last time you blinked the LED
previousMillis = currentMillis;
if (Blinkstate == 0){
lcd.setCursor((charsel +8),1);
lcd.print("^");
Blinkstate = 1;
} else if (Blinkstate == 1){
lcd.setCursor((charsel +8),1);
lcd.print(" ");
Blinkstate = 0;
}
if (ReadKeypad() == 'L') {
lcd.setCursor((charsel +8),1);
lcd.print(" ");
charsel = charsel -1;
} else if (ReadKeypad() == 'R'){
lcd.setCursor((charsel +8),1);
lcd.print(" ");
if (charsel > 4){
charsel = 4;
} else {
charsel = charsel +1;
}
}
}
if (ReadKeypad() == 'U'){
if (stopV[charsel] >= 9){
stopV[charsel] = 0;
} else {
stopV[charsel] = stopV[charsel] +1;
}
delay(250);
}
if (ReadKeypad() == 'D'){
if (stopV[charsel] <= 0){
stopV[charsel] = 9;
} else{
stopV[charsel] = stopV[charsel] -1;
}
delay(250);
}
if (ReadKeypad() == 'S') {
stopvarC = 1;
lcd.setCursor(8,0);
lcd.print(" ");
lcd.setCursor(8,1);
lcd.print(" ");
delay(1000);
}
stopvar = ((((stopV[0]*10+stopV[1])*10+stopV[2])*10+stopV[3])*10+stopV[4]);
}
NookV17:
sadly i can't use both interrupt pins, since i use a breakout lcd shield with buttons and it ocupies pins from 4 to 10, and for the motor controller i need two pwm pins(11, 3), so i'm stuck with one interrupt or make a messy pin rearrangement on the lcd shield... but i'll still have a look at your library, maybe for a future proyect
NookV17:
sadly i can't use both interrupt pins, since i use a breakout lcd shield with buttons and it ocupies pins from 4 to 10, and for the motor controller i need two pwm pins(11, 3), so i'm stuck with one interrupt or make a messy pin rearrangement on the lcd shield...
All pins on the Uno support interrupts, they are called pin-change interrupts. attachInterrupt only
handles the direct interrupt pins.
Note this is not true of the Mega, only a few pins on the Mega support pin-change interrupts.
thats my speed/direction controll part of it, if i take the
Move()
function out of the equation, the encoder works, but as soon as i put it back in (need it to update the function when speed variable is changed) it goes crazy, even if instead of move i just do a
analogWrite()
for each direction, it looks like its conflicting somewhere, but cant find where, yet....
this is it, right now, if i remove the forward analogWrite the rest works, but as soon as i add it back in it goes crazy, i'm trying to re do the entire speed/direction control, but i don't have much hopes at this point
Your code is very badly formatted which makes it very hard to read. In some places you have the opening { on the end of a line and sometimes on the next line. And sometimes the closing } is on the end of a line and other times not. And the indentation is all over the place. When the code is nicely and consistently formatted it is much easier to see the different blocks - like this
#include <LiquidCrystal.h>
LiquidCrystal lcd(8,9,4,5,6,7);
int Ver = 1;
//timing
unsigned long previousMillis = 0;
const long interval = 1000;
const long interval2 = 400;
int Blinkstate = 0;
bool CW;
volatile bool fired;
volatile bool up;
int usMotor_Status;
int pwm_right=3;
int pwm_left=11;
int prevSpeed = 0;
int FwdSpeed;
int EN_l=13;
int RevSpeed;
const int buttonPin = A1; //red
int buttonState = 0;
short usSpeed = 0;
const byte encoderPinA = 2; //white
const byte encoderPinB = 12; //greem
int stationary = 0;
unsigned int stopV[5] = {0,0,0,0,0};
int stop_var_n= 0;
//lcd variables
bool executable = false;
unsigned int charsel = 4;
unsigned int stopvar;
int stopvarC = 0;
int sens_pin = A2;
int screen_delay =500;
unsigned int count = 0;
unsigned int sens_outp = 0;
unsigned int sens_temp_state = 0;
int keypad_pin = A0;
int keypad_value = 0;
int keypad_value_old = 0;
char btn_push;
byte mainMenuPage = 1;
byte mainMenuPageOld = 1;
byte mainMenuTotal = 4;
// Interrupt Service Routine for a change to encoder pin A
void isr ()
{
if (digitalRead (encoderPinA)) {
up = digitalRead (encoderPinB);
}
else {
up = !digitalRead (encoderPinB);
}
fired = true;
} // end of isr
void setup() {
pinMode(pwm_right, OUTPUT);
pinMode(pwm_left, OUTPUT);
// pinMode(EN_l, OUTPUT);
pinMode(buttonPin, INPUT);
pinMode (encoderPinA, INPUT_PULLUP); // enable pull-ups
pinMode (encoderPinB, INPUT_PULLUP);
attachInterrupt (digitalPinToInterrupt (encoderPinA), isr, CHANGE); // interrupt 0 is pin 2
usMotor_Status = 0;
// put your setup code here, to run once:
Serial.begin(9600);
Serial.println("1. STOP");
Serial.println("2. FORWARD");
Serial.println("3. REVERSE");
Serial.println("4. READ CURRENT");
Serial.println("+. INCREASE SPEED");
Serial.println("-. DECREASE SPEED");
Serial.println();
lcd.begin(16,2); //Initialize a 2x16 type LCD
pinMode(keypad_pin, INPUT);
pinMode(sens_pin, INPUT);
lcd.setCursor(2,0);
lcd.print("Vosse pickup ");
lcd.setCursor(3,1);
lcd.print("winder v");
lcd.print(Ver);
delay(4000);
lcd.clear();
}
void loop() {
char user_input;
static long rotaryCount = 0;
//Serial.println(up);
if (fired){
if (up){
DecreaseSpeed();
delay(20);
}
else{
IncreaseSpeed();
delay(20);
}
fired = false;
} // end if fired
while(Serial.available()) {
user_input = Serial.read(); //Read user input and trigger appropriate function
if (user_input =='1')
{
Stop();
}
else if(user_input =='2')
{
//Forward();
}
else if(user_input =='3')
{
//Reverse();
}
else if(user_input =='+')
{
IncreaseSpeed();
}
else if(user_input =='-')
{
DecreaseSpeed();
}
else
{
Serial.println("Invalid option entered.");
}
}
if ((stationary != 0) && (count == stopvar)) {
Stop();
}
buttonState = analogRead(buttonPin);
if (stationary != 0) {
if ((buttonState == 0)){
Stop();
}
}
lcd.setCursor(0,0);
lcd.print("turns =");
while(stopvarC == 0) {
setStopVar();
}
if (ReadKeypad() == 'S') {
stopvarC = 0;
}
Count();
lcd.setCursor(8,0);
lcd.print(stopvar);
if (ReadKeypad() == 'L') {
count = 0;
stopvarC = 0;
stopV[0] = 0;
stopV[1] = 0;
stopV[2] = 0;
stopV[3] = 0;
stopV[4] = 0;
Blinkstate = 0;
usMotor_Status = 0;
}
}
void Stop() {
stationary = 0;
Serial.println("Stop");
digitalWrite(EN_l, LOW);
digitalWrite(pwm_left, LOW);
digitalWrite(pwm_right, LOW);
usMotor_Status= 0;
usSpeed = 0;
delay(500);
}
void Move() {
stationary = 1;
digitalWrite(EN_l, HIGH);
if (((usSpeed > -15) && (usSpeed < 0)) || ((usSpeed < 15) && (usSpeed > 0))){
Stop();
}
else {
if (usSpeed > 0){
Serial.println("forward");
//analogWrite(pwm_left, 0);
//usMotor_Status = 1;
analogWrite(pwm_right, usSpeed);
}
else{
Serial.println("reverse");
//analogWrite(pwm_right, 0);
//usMotor_Status = 2;
analogWrite(pwm_left, RevSpeed);
}
}
}
void IncreaseSpeed() {
if (usSpeed < 255){
usSpeed += 5;
}
if (usSpeed > 0) {
if((usSpeed > 0) && (usSpeed < 15)){
usSpeed = 15;
}
prevSpeed = usSpeed;
}
else if((usSpeed < 0) && (usSpeed > -15)){
usSpeed = 0;
}
Move();
Serial.print("Speed +: ");
Serial.println(usSpeed);
}
void DecreaseSpeed() {
if (usSpeed < 255) {
usSpeed -= 5;
}
if(usSpeed < 0) {
if((usSpeed < 0) && (usSpeed > -15)){
usSpeed = -15;
}
RevSpeed = abs(usSpeed);
if(RevSpeed > 255) {
usSpeed = -255;
}
prevSpeed = usSpeed;
}
else if ((usSpeed > 0) && (usSpeed < 15)){
usSpeed = 0;
}
Move();
Serial.print("Speed -: ");
Serial.println(usSpeed);
}
When did this problem emerge?
Presumably you had a recent version that did not have a problem and you made some change that gave rise to the problem. What was that change?
yeah, sorry for that, thats the result of me kind of rage editing the code out of frustration.
the last itteration that i know that worked was before i introduced the menu, but i already reverted that, and still...
going to try to start again from the code i used to test the driver, thats the only thing i have from before the menu...