I want to make a circuit where I have to use a rotary encoder to control the brightness of LEDS. I managed to get a single LED to work, but when trying to connect 6 more LEDs I can't seem to get it to work.
My setup basic: https://imgur.com/a/Idxcuqi (as the note says, I have a 5 pin Encoder, only a six pin was available)
int Brightness = 120;
int StepBrightness = 10;
unsigned long RealTime;
unsigned long CyclicTime;
const int pin_A = 2; // pin 2 de CLK aansluiting van de Rotary encoder
const int pin_B = 3; // pin 3 De DT aansluiting van de Rotary encoder
unsigned char encoder_A;
unsigned char encoder_B;
unsigned char encoder_A_vorige=0;
void setup() {
pinMode(9, OUTPUT); //I can only get pin 9 and no other pins work if I put different digit
pinMode(pin_A, INPUT);
pinMode(pin_B, INPUT);
RealTime = millis();
CyclicTime = RealTime;
}
void loop() {
RealTime = millis();
if(RealTime >= (CyclicTime + 5)){
encoder_A = digitalRead(pin_A);
encoder_B = digitalRead(pin_B);
if((!encoder_A) && (encoder_A_vorige)){
if(encoder_B) {
if(Brightness + StepBrightness <= 255) Brightness += StepBrightness;
}
else {
if(Brightness - StepBrightness >= 0) Brightness -= StepBrightness;
}
}
encoder_A_vorige = encoder_A;
analogWrite(9, Brightness);
CyclicTime = RealTime;
}
}
You need to declare output pins and write to them using analog write which is now set to turn a single (9) pin and not a variable (the pin you would want to turn at that point).
For Arduino Uno, only the following pins have PWM -> 3, 5, 6, 9, 10, 11
Therefore, only these few pins will work with the analogWrite() function and the other pins are not.
You do not need to call pinMode() to set the pin as an output before calling analogWrite().
Related
So I'm a novice in programming and is helping my friend with coding an automatic clothes line for a project.
Each component works fine individually but when I put all the code together the motors are confused in which direction to go. can anyone take a look at it and give us feedback?
We have a rain sensor, light sensor, 2 switches , and a motor.
When it rains OR when it is dark the motors pulls the clothes in and when the the clothes reaches the end it touches switch 1 and stops the motors.
When it stop rains/sunny AND/OR when there light it pulls the clothes out in the open.
Here is the code I was provided:
**
#include <Stepper.h>
//motors
const int stepsPerRevolution = 400;
//motor speeds
Stepper myStepper = Stepper(stepsPerRevolution, 2,4, 3, 5);//clockwise
Stepper myStepper2 = Stepper(stepsPerRevolution, 5, 3, 4, 2);//counterclockwise
//rain sensor
const int capture_D =4;
const int capture_A = A0;
int val_analogique;
int led = 8;
//switches
const int switch1 = A3;
const int switch2 =A4;
void setup() {
// put your setup code here, to run once:
// motors
myStepper.setSpeed(60);
myStepper2.setSpeed(60);
//rain sensor
pinMode(capture_D, INPUT);
pinMode(capture_A, INPUT);
pinMode(led, OUTPUT);
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
//light sensors
unsigned int AnalogValueL;
AnalogValueL = analogRead(A5);
Serial.println(AnalogValueL);
delay(2000);
//rainsensor
if((digitalRead(capture_A) && digitalRead(capture_D)) ==LOW)
{
digitalWrite(led, HIGH);
myStepper2.step(stepsPerRevolution); // bringclothesout
Serial.println("DRY");
delay(1000);
}
else
{
//when it rains the clolthes re brought in
digitalWrite(led, LOW);
Serial.println("WET");
myStepper.step(stepsPerRevolution);//bring clothes in
delay(1000);
}
if(AnalogValueL < 1010)
{
digitalWrite(led, HIGH);
Serial.println("SUNNY");
myStepper2.step(stepsPerRevolution);
delay(1000);
}
else
{
digitalWrite(led, LOW);
Serial.println("Dark");
myStepper.step(stepsPerRevolution);
delay(1000);
}
//switches
unsigned int AnalogValueS;
AnalogValueS = analogRead(switch1);
Serial.println(AnalogValueS);
delay(2000);
if(AnalogValueS <= 1000)
{
digitalWrite(led, HIGH);
Serial.println("Off");
myStepper.setSpeed(0);
}
else
{
digitalWrite(led, LOW);
Serial.println("on");
}
unsigned int AnalogValueSS;
AnalogValueSS = analogRead(switch2);
Serial.println(AnalogValueSS);
delay(2000);
if(AnalogValueSS <= 1000)
{
digitalWrite(led, HIGH);
Serial.println("ON");
}
else
{
digitalWrite(led, LOW);
Serial.println("Off");
}
*/
}//end of program
**
Feedback?
Here's my feedback:
Your code needs a little bit of tidying up for the sake of clarity and readability.
It is always recommended to declare your Serial.begin(); at the beginning of the setup() function.
You forgot to declare the switches pins as inputs:
pinMode(switchX, INPUT); // where X = 1, 2
Why are you using analog pins as switch inputs? (const int switch1 = A3). If you are connecting ON/OFF switches here you should rather use digital pins. In case your switches are the light sensors, then they are fine (read comment 9 below). Otherwise, this:
AnalogValueS = analogRead(switch1);
is wrong as you cannot read a digital switch with an analogRead()
Additionally, you don't say if your switches are active HIGH or active LOW, namely, if they pulse LOW when pressed and HIGH when released or viceversa.
One important mistake is that you are assigning pin 4 twice for different functions. First as a motor pin, then as capture_D:
Stepper myStepper = Stepper(stepsPerRevolution, 2, 4, 3, 5);
Stepper myStepper2 = Stepper(stepsPerRevolution, 5, 3, 4, 2);
const int capture_D = 4;
You read the analog value in a variable declared inside the main() loop while you previously declared int val_analogique without using it. This is poor consistency.
Similarly, you read from analog pin A5 without previously declaring it as an INPUT:
AnalogValueL = analogRead(A5);
The flow of your loop could be affected by that many delay() throughout the code.
You expressed having three sensors:
We have a rain sensor, light sensor, 2 switches, and a motor.
It is good practice to label the pins from these sensors with a representative name from the sensor in question: e.g.:
const int lightSensor1 = 4;
In the C++ mindset is common practice to use enums to define states from a specific event or scenario. For instance:
typedef enum {
RAINING,
DARK,
NOT_RAINING,
SUNNY
}WEATHER_CONDITIONS;
WEATHER_CONDITIONS currentCondition = SUNNY;
where the typedef means that you are creating your own data type WEATHER_CONDITIONS and their assigned values are 0,1, 2,... according to their order.
With regards to the Stepper.h library you are declaring two Stepper instances expecting that in that way you will reverse the direction of the motor. That is NOT how it works. According to the library (Stepper.cpp) to reverse the motor, you need to send a negative value as an argument to reverse its direction. Please read line 184 from this file from the library.
On this line:
if((digitalRead(capture_A) && digitalRead(capture_D)) ==LOW)
you are attempting to read a digital value from an analog pin. While it might work if the voltage on that pin is at a logic level, this is not recommended.
Finally, you SHOULD connect the switches for stopping the motor to INTERRUPT pins. This is a more effective way to detect when the switch has been pressed and take immediate action by changing a state. You would have to use pins 2 and 3 (INT0 and INT1).
This is my take on this code. Compiled correctly but UNTESTED!
#include <Arduino.h>
#include <Stepper.h>
/*Constants*/
//motor speeds
const int stepsPerRevolution = 400;
/*Pinout declarations*/
// Motor pins
const int motorPins[4] = {2, 3, 4, 5};
//rain sensor
const int capture_D = 4; // capture_D
const int capture_A = A0; // A0
const int lightSensor = A5;
//switches
const int switch1 = 9; // Previously: A3 So this is an analog switch?
const int switch2 = 10; // Previously: A4 You should assing this to other two digital pins
//Led
const int led = 8;
/*Custom variables*/
typedef enum {
DARK,
SUNNY
} LIGHT_CONDITIONS;
LIGHT_CONDITIONS lightState = SUNNY;
const char* lightLabels[] = {"DARK",
"SUNNY"};
typedef enum {
DRY,
WET
} HUMIDITY_CONDITIONS;
HUMIDITY_CONDITIONS humidityState = DRY;
const char* humidityLabels[] = {"DRY",
"WET"};
typedef enum {
CW, // Let's assume that this is bring them in
CCW, // this is take them out
STOP
} MOTOR_DIRECTION;
MOTOR_DIRECTION currentDirection = STOP; // This declares a default state
const char* directionLabels[] = {"Clothes In",
"Clothes Out"};
/*General variables*/
int rawLightValue;
// Objects declaration
Stepper myStepper = Stepper(stepsPerRevolution,
motorPins[0],
motorPins[1],
motorPins[2],
motorPins[3]);
void activateMotor(int direction) {
switch (direction) {
case MOTOR_DIRECTION::CW:
myStepper.step(-stepsPerRevolution);
currentDirection = CW;
break;
case MOTOR_DIRECTION::CCW:
myStepper.step(stepsPerRevolution);
currentDirection = CCW;
break;
case MOTOR_DIRECTION::STOP:
currentDirection = STOP;
myStepper.step(0);
break;
default:
// so much empty
break;
}
}
void setup() {
Serial.begin(9600);
// motors
myStepper.setSpeed(60);
//rain sensor
pinMode(capture_D, INPUT);
pinMode(capture_A, INPUT);
pinMode(switch1, INPUT);
pinMode(switch2, INPUT);
pinMode(lightSensor, INPUT);
pinMode(led, OUTPUT);
}
void loop() {
// First, read light sensor
rawLightValue = analogRead(lightSensor);
Serial.println(rawLightValue);
if (rawLightValue < 1010) {
digitalWrite(led, HIGH);
lightState = SUNNY;
Serial.println(lightLabels[lightState]);
} else {
digitalWrite(led, LOW);
lightState = DARK;
Serial.println(lightLabels[lightState]);
}
// Then read rain sensor --> digital portion only, granted that you have calibrated
// its pulsing voltage corectly. I am assuming that you are using one of these sensors:
// https://circuitdigest.com/microcontroller-projects/rain-detector-using-arduino
if (digitalRead(capture_D) == LOW) {
digitalWrite(led, HIGH);
humidityState = DRY;
Serial.println(humidityLabels[humidityState]);
}
else {
//when it rains the clolthes re brought in
digitalWrite(led, LOW);
humidityState = WET;
Serial.println(humidityLabels[humidityState]);
}
// Based on these conditions, activate the motor accordingly
/* When it rains OR when it is dark the motors pulls the clothes in and when
the the clothes reaches the end it touches switch 1 and stops the motors.
*/
if ((humidityState == WET) || (lightState == DARK)) {
// While the switch is released, meaning that the switch has NOT been pressed:
while (digitalRead(switch1) == HIGH) {
activateMotor(CCW);
Serial.println(directionLabels[currentDirection]);
}
// Finally, let the motors go until the swithces tell the system to stop the motor
activateMotor(STOP);
}
if ((humidityState == DRY) && (lightState == SUNNY)) {
// While the switch is released, meaning that the switch has NOT been pressed:
while (digitalRead(switch2) == HIGH) {
activateMotor(CW);
Serial.println(directionLabels[currentDirection]);
}
// Finally, let the motors go until the swithces tell the system to stop the motor
activateMotor(STOP);
}
}
I'm trying to Read values from LM35 sensor on Arduino UNO and send it to another Arduino board through a PWM pin and an analog Pin
When I run this project, The Serial Emulator of Arduino A is showing right values but Second one is always 0.00.
Here is my first Arduino Code:
int pin = 2;
int TempPin = A0;
int pinAnalog = 3;
void setup() {
pinMode(3, OUTPUT);
Serial.begin(9600);
}
void loop() {
float tmp = analogRead(TempPin);
float Result = (tmp/1024.0) * 500;
Serial.println(Result);
analogWrite(pinAnalog, Result);
delay(3000);
}
And Here is My Second Arduino Code:
void setup() {
Serial.begin(9600);
}
void loop() {
float res = analogRead(A0);
Serial.println(res);
delay(3000);
}
What's wrong with my project or code?
I understand this is an exercise only, as PWM itself is not suitable to feed analogRead. (better measure pulse durations, if you really want to use it for data transmission.)
For a 400 Hz PWM you need a RC Value of e.g. 20 ms to filter the PWM pulses reasonably.
(e.g 1µF * 20k)
As you work in a 3sec Cycle, much bigger values are fine as well.
BTW: Sender could be simplified to:
const byte inPin = A0;
const byte outPin = 3;
void setup() {
Serial.begin(9600);
}
void loop() {
byte tmp = analogRead(inPin)/4; // 0 .. 255
analogWrite(outPin, tmp);
Serial.println((int)tmp);
delay(3000);
}
I'm trying to use an IR sensor with my Arduino Uno and only want a HIGH or LOW signal without decoding making any IR signal turn the state to a 1 or 0. There is also a motion sensor but that code has been removed.
int ledPin = 13; // choose the pin for the LED
int inputPin = 2; // choose the input pin (for PIR sensor)
int pirState = LOW; // we start, assuming no motion detected
int val = 0; // variable for reading the pin status
int relayPin = 4; //PIN FOR RELAY OPERATION
int irPin = 7; //IR Sensor pin
int lightState = 0;
int irVal = 0;
void setup() {
pinMode(ledPin, OUTPUT); // declare LED as output
pinMode(inputPin, INPUT); // declare sensor as input
pinMode(relayPin, OUTPUT);
pinMode(irPin, INPUT);
Serial.begin(9600);
}
void loop() {
irVal = digitalRead(irPin);
if (irVal == HIGH) {
lightState = 1;
Serial.println("IR received");
while(irVal == HIGH) {
irVal = digitalRead(irPin);
if(irVal == HIGH) {
irVal = LOW;
} else {
irVal = HIGH;
}
}
}
Are you trying to say that the input is not working correctly? Maybe try INPUT_PULLUP instead of INPUT in the setup loop.
For example:
pinMode(inputPin, INPUT_PULLUP);
Information about this principle you can find here:
https://www.arduino.cc/en/Tutorial/InputPullupSerial
I have an LTC2365/1 Msps 12bit-ADC with SPI pins. Somehow I only could achieve a maximum of 200 Ksps with this ADC rather than something close to 1 Msps using an Arduino Due. I wonder if anyone could help me with this issue. I tried many ways but couldn't figure it out.
Datasheet for the ADC:
http://cds.linear.com/docs/en/datasheet/23656fb.pdf
Here is the code I use for Arduino:
#include <SPI.h>
const int spi_ss = 10; // set SPI SS Pin
uint8_t byte_0, byte_1; // First and second bytes read
uint16_t spi_bytes; // final 12 bit shited value
long int starttime,endtime;
long int count=0;
void setup() {
SerialUSB.begin(2000000); // begin serial and set speed
pinMode(spi_ss, OUTPUT); // Set SPI slave select pin as output
digitalWriteDirect(spi_ss, HIGH); // Make sure spi_ss is held high
SPI.begin();
SPI.beginTransaction(SPISettings(16000000, MSBFIRST, SPI_MODE0));
loop2();
SPI.endTransaction();
}
void loop2() {
starttime=millis();
endtime=starttime;
while((endtime-starttime)<=1000) {
// write the LTC CS pin low to initiate ADC sample and data transmit
digitalWriteDirect(spi_ss, LOW);
byte_0 = spi_read(0x00); // read firt 8 bits
byte_1 = spi_read(0x00); // read second 8 bits
digitalWriteDirect(spi_ss, HIGH);
// wite LTC CS pin high to stop LTC from transmitting zeros.
spi_bytes = ( ( (byte_0 <<6) ) + (byte_1 >>2) );
SerialUSB.println(spi_bytes);
count=count+1;
endtime=millis();
}
//samples per second
SerialUSB.println(count);
}
static inline uint8_t spi_read(uint8_t b) {
return SPI.transfer(b);
}
inline void digitalWriteDirect(int pin, boolean val) {
if(val) g_APinDescription[pin].pPort -> PIO_SODR = g_APinDescription[pin].ulPin;
else g_APinDescription[pin].pPort -> PIO_CODR = g_APinDescription[pin].ulPin;
}
I'm trying to control the speed of two DC motors using an Arduino Uno and encoders that are connected to the motors.
I've written a code to check whether there's a change in the position of the encoder and according to that calculate the velocity of the motors.
Ive used this website for the code:
I'm having problems when calculating the difference between the new position of the encoder and the old position of the encoder. For some reason that difference keeps going up even though the speed stays the same.
This is my code so far:
#define pwmLeft 10
#define pwmRight 5
#define in1 9
#define in2 8
#define in3 7
#define in4 6
//MOTOR A
int motorSpeedA = 100;
static int pinA = 2; // Our first hardware interrupt pin is digital pin 2
static int pinB = 3; // Our second hardware interrupt pin is digital pin 3
volatile byte aFlag = 0; // let's us know when we're expecting a rising edge on pinA to signal that the encoder has arrived at a detent
volatile byte bFlag = 0; // let's us know when we're expecting a rising edge on pinB to signal that the encoder has arrived at a detent (opposite direction to when aFlag is set)
volatile long encoderPos = 0; //this variable stores our current value of encoder position. Change to int or uin16_t instead of byte if you want to record a larger range than 0-255
volatile long oldEncPos = 0; //stores the last encoder position value so we can compare to the current reading and see if it has changed (so we know when to print to the serial monitor)
volatile long reading = 0; //somewhere to store the direct values we read from our interrupt pins before checking to see if we have moved a whole detent
//MOTOR B
static int pinC = 12; // Our first hardware interrupt pin is digital pin 2
static int pinD = 33; // Our second hardware interrupt pin is digital pin 3
volatile byte cFlag = 0; // let's us know when we're expecting a rising edge on pinA to signal that the encoder has arrived at a detent
volatile byte dFlag = 0; // let's us know when we're expecting a rising edge on pinB to signal that the encoder has arrived at a detent (opposite direction to when aFlag is set)
volatile long encoderPosB = 0; //this variable stores our current value of encoder position. Change to int or uin16_t instead of byte if you want to record a larger range than 0-255
volatile long oldEncPosB = 0; //stores the last encoder position value so we can compare to the current reading and see if it has changed (so we know when to print to the serial monitor)
volatile long readingB = 0;
int tempPos;
long vel;
unsigned long newtime;
unsigned long oldtime = 0;
void setup() {
//MOTOR A
pinMode(pinA, INPUT_PULLUP); // set pinA as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
pinMode(pinB, INPUT_PULLUP); // set pinB as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
attachInterrupt(0, PinA, RISING); // set an interrupt on PinA, looking for a rising edge signal and executing the "PinA" Interrupt Service Routine (below)
attachInterrupt(1, PinB, RISING); // set an interrupt on PinB, looking for a rising edge signal and executing the "PinB" Interrupt Service Routine (below)
//MOTOR B
pinMode(pinC, INPUT_PULLUP); // set pinA as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
pinMode(pinD, INPUT_PULLUP); // set pinB as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
attachInterrupt(0, PinC, RISING); // set an interrupt on PinA, looking for a rising edge signal and executing the "PinA" Interrupt Service Routine (below)
attachInterrupt(1, PinD, RISING);
Serial.begin(9600); // start the serial monitor link
pinMode (in1, OUTPUT);
pinMode (in2, OUTPUT);
pinMode (in3, OUTPUT);
pinMode (in4, OUTPUT);
digitalWrite (8, HIGH);
digitalWrite (9, LOW); //LOW
digitalWrite (7, LOW); //LOW
digitalWrite (6, HIGH);
pinMode (pwmLeft, OUTPUT);
pinMode (pwmRight, OUTPUT);
}
void PinA(){
cli(); //stop interrupts happening before we read pin values
reading = PIND & 0xC; // read all eight pin values then strip away all but pinA and pinB's values
if(reading == B00001100 && aFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
encoderPos --; //decrement the encoder's position count
bFlag = 0; //reset flags for the next turn
aFlag = 0; //reset flags for the next turn
} else if (reading == B00000100) bFlag = 1; //signal that we're expecting pinB to signal the transition to detent from free rotation
sei(); //restart interrupts
}
void PinB(){
cli(); //stop interrupts happening before we read pin values
reading = PIND & 0xC; //read all eight pin values then strip away all but pinA and pinB's values
if (reading == B00001100 && bFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
encoderPos ++; //increment the encoder's position count
bFlag = 0; //reset flags for the next turn
aFlag = 0; //reset flags for the next turn
} else if (reading == B00001000) aFlag = 1; //signal that we're expecting pinA to signal the transition to detent from free rotation
sei(); //restart interrupts
}
void PinC(){
cli(); //stop interrupts happening before we read pin values
readingB = PIND & 0xC; // read all eight pin values then strip away all but pinA and pinB's values
if(readingB == B00001100 && cFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
encoderPosB --; //decrement the encoder's position count
dFlag = 0; //reset flags for the next turn
cFlag = 0; //reset flags for the next turn
} else if (readingB == B00000100) dFlag = 1; //signal that we're expecting pinB to signal the transition to detent from free rotation
sei(); //restart interrupts
}
void PinD(){
cli(); //stop interrupts happening before we read pin values
readingB = PIND & 0xC; //read all eight pin values then strip away all but pinA and pinB's values
if (readingB == B00001100 && dFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
encoderPosB ++; //increment the encoder's position count
dFlag = 0; //reset flags for the next turn
cFlag = 0; //reset flags for the next turn
} else if (readingB == B00001000) cFlag = 1; //signal that we're expecting pinA to signal the transition to detent from free rotation
sei(); //restart interrupts
}
void loop(){
analogWrite(pwmLeft, motorSpeedA);
analogWrite(pwmRight, motorSpeedA);
if(oldEncPos != encoderPos) {
newtime = millis();
tempPos = encoderPos - oldEncPos;
vel = tempPos / (newtime - oldtime);
Serial.println(tempPos);
oldEncPos = encoderPos;
oldtime = newtime;
delay(250);
}
if(oldEncPosB != encoderPosB) {
Serial.println(encoderPosB);
oldEncPosB = encoderPosB;
}
}
The two if statements are just made to check that the encoders are working properly. In the first if statement I'm trying to do the calculations of the velocity.
I would appreciate any feedback.
Thank you.
EDIT:
I found out theres an encoder library which makes everything a lot easier.
so now my code looks like this:
#include <Encoder.h>
#define pwmLeft 10
#define pwmRight 5
Encoder myEncA(3, 2);
Encoder myEncB(13, 12);
unsigned long oldtimeA = 0;
unsigned long oldtimeB = 0;
int speedA = 100;
int speedB = 130;
void setup() {
Serial.begin(9600);
digitalWrite (8, HIGH);
digitalWrite (9, LOW); //LOW
digitalWrite (7, LOW); //LOW
digitalWrite (6, HIGH);
pinMode (pwmLeft, OUTPUT);
pinMode (pwmRight, OUTPUT);
}
long oldPositionA = -999;
long oldPositionB = -999;
void loop() {
analogWrite(pwmLeft, speedA);
analogWrite(pwmRight, speedB);
long newPositionA = myEncA.read();
long newPositionB = myEncB.read();
if ((newPositionA != oldPositionA) || (newPositionB != oldPositionB)) {
unsigned long newtimeA = millis ();
long positionA = newPositionA - oldPositionA;
long positionB = newPositionB - oldPositionB;
long velB = (positionB) / (newtimeA - oldtimeA);
long velA = (positionA) / (newtimeA - oldtimeA);
oldtimeA = newtimeA;
oldPositionA = newPositionA;
oldPositionB = newPositionB;
Serial.println(velB);
}
}
I am still having problems with my "B" motor, the calculation is still way off for some reason.
Motor "A" works fine
A couple of issues, including a divide by zero error in loop(). This scan cause a reset of your controller. Always check the value of the divisor when doing a division!
Using only positive transitions unnecessarily reduces the resolution of your readings by 2.
The Arduino is an 8bit controller... Reading an int requires multiple instruction, which means you should disable interrupts before reading an int that's modified by an interrupt routine. Failure to do so will cause odd jumps in the vakue read. This is usually done like this:
//...
NoInterrupts();
int copyOfValue = value; // use the copy to work with.
interrupts();
//...
In your case, a single byte value is likely enough to store movement, with a reset every 30 ms, this should give you a top speed of 255 pulses/30ms = 8500 pulses/second or 1275000 rpm for a 24 ticks/turn encoder. :) in that case, no need to disable interrupts for a reading.
with one reading per 30ms, 1 tick /30ms = 33 tick/seconds, or 85 RPM. It's a bit high for motion. You may need to average readings, depending on your application.
Also, the algorithm you are using will definitely not work. The main reason is that the delay between reads and adjustments is too small. Most readings will be of zero. You will run into the problem when removing the println() calls. I suggest a pacing of at least 30 ms between readings. 100 ms may work a bit better, depending on your application. Using a float variable for speed average will definitely help.
void loop()
{
//...
if(oldEncPos != encoderPos) {
newtime = millis();
tempPos = encoderPos - oldEncPos;
vel = tempPos / (newtime - oldtime); // <-- if newtime == oltime => divide by zero.
//...
}
//...
}
The encoder reading code seems awfully complex...
#define PIN_A 2 // encoder bit 0
#define PIN_B 3 // encoder bit 1
volatile char encVal1;
volatile unsigned char encPos1; // using char
void OnEncoder1Change()
{
char c = (digitalRead(pinA) ? 0b01 : 0)
+ (digitalRead(pinB) ? 0b10 : 0); // read
char delta = (c - encVal1) & 0b11; // get difference, mask
if (delta == 1) // delta is either 1 or 3
++encPos1;
else
--encPos1;
encVal1 = c; // keep reading for next time.
encPos1 += delta; // get position.
// no need to call sei()
}
setup()
{
pinMode(pinA, INPUT_PULLUP);
pinMode(pinB, INPUT_PULLUP);
// get an initial value
encValA = digitalRead(pinA) ? 0b01 : 0;
encValA += digitalRead(pinB) ? 0b10 : 0;
// use digitalPinToInterrupt() to map interrupts to a pin #
// ask for interrupt on change, this doubles .
attachInterrupt(digitalPinToInterrupt(PIN_A), OnEncoder1Change, CHANGE);
attachInterrupt(digitalPinToInterrupt(PIN_B), OnEncoder1Change, CHANGE);
//...
}
unsigned char oldTime;
unsigned char oldPos;
int speed;
void loop()
{
unsigned char time = millis();
if (time - oldTime > 30) // pace readings so you have a reasonable value.
{
unsigned char pos = encPos1;
signed char delta = pos - oldPos;
speed = 1000 * delta) / (time - oldTime); // signed ticks/s
encPos1 -= pos; // reset using subtraction, do you don't miss out
// on any encoder pulses.
oldTime = time;
}
}