I’m able to read the change in state on the serial with the code below.
I however need to be able to output a voltage range to correspond with the RPM the encoder is spinning at.
My Shaft’s MAX RPM is 100, hence I’d like 100RPM to equate to 5v, RPM to 0v, 50RPM to 2.5v. Ect (IE clear range from 0v - 5v)
Can someone please write the code for me to accomplish this on the Arduino UNO
/* Arduino Rotary Encoder Tutorial
*
* by Dejan Nedelkovski, www.HowToMechatronics.com
*
*/
#define outputA 6
#define outputB 7
int counter = 0;
int aState;
int aLastState;
void setup() {
pinMode (outputA,INPUT);
pinMode (outputB,INPUT);
Serial.begin (9600);
// Reads the initial state of the outputA
aLastState = digitalRead(outputA);
}
void loop() {
aState = digitalRead(outputA); // Reads the "current" state of the outputA
// If the previous and the current state of the outputA are different, that means a Pulse has occured
if (aState != aLastState){
// If the outputB state is different to the outputA state, that means the encoder is rotating clockwise
if (digitalRead(outputB) != aState) {
counter ++;
} else {
counter --;
}
Serial.print("Position: ");
Serial.println(counter);
}
aLastState = aState; // Updates the previous state of the outputA with the current state
}
lyndon:
Sure, what’s your budget? Alternately, research frequency-to-voltage converter circuits.
Hi Lyndon, thanks for your reply. My first attempt was using the LM331 but it was notoriously imprecise, the second issue was getting the parts to improve the circuit.
I chose to use the microcontroller route because of two things (1.) I have a couple of Arduinos laying around and (2.) The lead time for getting LM33 or Similar circuit components is quite long.
My budget is really a time issue, that’s why I opted to using an Arduino alongside one of the MCP4725 I had lying around.
Can you please recommend an effective solution for me?
const int encoder_a = 3; // Pin 3
const int encoder_b = 5; // Pin 5
long encoder_pulse_counter = 0;
long direction = 1;
void encoderPinChangeA()
{
encoder_pulse_counter += 1;
direction = digitalRead(encoder_a) == digitalRead(encoder_b) ? -1 : 1;
}
void encoderPinChangeB()
{
encoder_pulse_counter += 1;
direction = digitalRead(encoder_a) != digitalRead(encoder_b) ? -1 : 1;
}
void setup()
{
Serial.begin(9600);
pinMode(encoder_a, INPUT_PULLUP);
pinMode(encoder_b, INPUT_PULLUP);
attachInterrupt(0, encoderPinChangeA, CHANGE);
attachInterrupt(1, encoderPinChangeB, CHANGE);
}
void loop()
{
long speed = encoder_pulse_counter/1000.00*60; // For encoder plate with 1000 Pulses per Revolution
Serial.print("RPM: ");
Serial.println(direction*speed);
encoder_pulse_counter = 0; // Clear variable just before counting again
delay(1000);
}
My final step is now having the RPM value scaled down proportional to my (0v-5v) voltage range and converted to a clean voltage (0v-5v) output using the MCP4725.
On adafruit.com there aren’t any projects similar to mine using the MCP4725. Can you help?
As you can see, V=5 if RPM=100, V=2.5 if RPM=50, etc.
The Adafruit tutorial I linked shows you how to output a voltage.
Keep in mind that 5V output from the MCP4725 corresponds numerically to 4095 at 12 bit resolution, so the formula that you will actually be using is V=4095.*RPM/100.
jremington:
Sure, just output a voltage V = RPM*5.0/100.0
As you can see, V=5 if RPM=100, V=2.5 if RPM=50, etc.
The Adafruit tutorial I linked shows you how to output a voltage.
Keep in mind that 5V output from the MCP4725 corresponds numerically to 4095 at 12 bit resolution, so the formula that you will actually be using is V=4095.*RPM/100.
Hi jremington, thanks a lot for your reply. I’m new to coding with the Arduino. Can you please help me modify the existing sketch provided by adafruit to work with my application. I understand the mathematical calculation but don’t know how to code it.
/**************************************************************************/
/*!
@file trianglewave.pde
@author Adafruit Industries
@license BSD (see license.txt)
This example will generate a triangle wave with the MCP4725 DAC.
This is an example sketch for the Adafruit MCP4725 breakout board
----> http://www.adafruit.com/products/935
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
*/
/**************************************************************************/
#include <Wire.h>
#include <Adafruit_MCP4725.h>
Adafruit_MCP4725 dac;
void setup(void) {
Serial.begin(9600);
Serial.println("Hello!");
// For Adafruit MCP4725A1 the address is 0x62 (default) or 0x63 (ADDR pin tied to VCC)
// For MCP4725A0 the address is 0x60 or 0x61
// For MCP4725A2 the address is 0x64 or 0x65
dac.begin(0x62);
Serial.println("Generating a triangle wave");
}
void loop(void) {
uint32_t counter;
// Run through the full 12-bit scale for a triangle wave
for (counter = 0; counter < 4095; counter++)
{
dac.setVoltage(counter, false);
}
for (counter = 4095; counter > 0; counter--)
{
dac.setVoltage(counter, false);
}
}
If you want to succeed in this hobby, you need to learn the material.
Arduino is a learning tool, and the designers have bent over backwards to make it easy to use. Start with simpler projects, like the examples that come with Arduino (and tutorials on the web), and work your way up.
If you don’t intend to pursue the hobby, and just want to get something done, post on the Gigs & Collaborations section of the Arduino forum and be prepared to pay for the help.
This is 1 of 3 different types of encoders I’m working on. Reverse engineering code or circuits helps the learning process but typically one needs to start from a working solution backwards. Projects too different from what I’m trying to accomplish in terms of length and complexity of code will take a long time than I have to learn. Right about now I’m not even sure what I’m trying to accomplish is possible because its not yet done.
Difficulty is relative when it comes to learning anything and although I’m good with discrete electronics I’m new to programming and know I’ll eventually learn a lot at the end of the project as a whole. Just like you have sample circuits on a datasheet, solutions are helpful to the learning process.
As noted earlier I’ve been working on this for a while so my asking for help comes not from an unwillingness to learn but a desire to.
What jremington is getting at is exactly your problem: you’re unskilled at programming and this is primarily a programming task. So you should start by learning to program something simpler and work up.
What you are asking for is certainly possible and not particularly difficult. A basic algorithm would be:
S = 0
Interrupted = false
Setup:
{
Configure interrupt for rising edge
}
Loop:
{
if (Interrupted)
{
Interrupted = false;
Now = millis()
Period = Now - S
S = Now
Calculate RPM from Period
Update DAC
}
}
ISR:
{
Interrupted = true
}
That will work. However, getting it to work well is where experience and time comes in.