Hi guys I need help with my project.
I don't understand how to include a library to another library that I'm building for my project. I'm writing a library Encoders.h able to control movements and button click of my encoders. To read the movement I use the famous Encoder.h library that you can find here.
Here my code
Encoders.h
#ifndef ENCODER_h
#define ENCODER_h
#include <Arduino.h>
#include <Timer.h>
#include <joyconf.h>
#include <Encoder.h>
class Encoders_ {
private:
// one encoder input
int _clk;
// the other encoder input
int _dt;
// click push button
int _sw;
// read state of sw
int _sw_read;
// last sw state
int _sw_last_state;
// current state encoder pin A
int _current_clk;
// current state encoder pin B
int _current_dt;
// last state pin A
int _last_clk;
// last state pin B
int _last_dt;
// last direction state
int _last_res;
//last saved direction result
int _res;
//ready to encode?
int _ready;
// timer class to debounce clicks
Timer_ _Timer1;
// timer class to debounce directions
Timer_ _Timer2;
// set pinA and pinB in the external lib
Encoder _Myenc(uint8_t pina, uint8_t pinb);
//Encoder _Myenc;
public:
/**
* to initialize the encoder with input pins and click pin.
* All af them are digital inputs.
*/
Encoders_(int clk, int dt, int sw);
/**
* give the direction (one step change)
*
* #param how long time give the same output before reset to 0 output
*
* #return 1 if clockwise (right) or 0 if no changes or -1 if anticlock-wise (left)
*/
int direction(long out_t);
/**
* return the SW push button state. It is debounced to avoid false clicks.
* Please check the mechanical condition of every encoder.
* Some encoder can need longer delay.
*
* #param long deboucing time
*
* #return int 0 LOW (clicked) or 1 HIGH (released).
*/
int click(long deb_time);
/**
* return the last direction state of the encoder
*
* #return int 1 (right), -1 (left).
*/
int lastState();
};
#endif
Encoders.cpp
#include <Encoders.h>
#include <Encoder.h>
Encoders_::Encoders_(int clk, int dt, int sw){
_Myenc(clk,dt);
_clk = clk;
_dt = dt;
_sw = sw;
_last_clk = HIGH;
_last_dt = HIGH;
_current_clk = HIGH;
_current_dt = HIGH;
_sw_last_state = HIGH;
_last_res = 0;
_ready = 0;
}
int Encoders_::direction(long out_t){
long newPosition = _Myenc.read();
newPosition;
}
int Encoders_::click(long deb_time){
// read the state of the switch into a local variable:
// normal open state is HIGH
_sw_read = digitalRead(_sw);
/*if(_sw_read) Serial.println("HIGH");
else Serial.println("LOW");*/
/*save the state before timer check to not stuck on a
specific state*/
_sw_last_state = _sw_read;
//Serial.println(_sw_last_state);
if(_Timer1.expired(deb_time)){
_Timer1.update();
if (!_sw_read){
return 0;
} else {
return 1;
}
}
return _sw_last_state;
}
int Encoders_::lastState(){
return _res;
}
Please note that Encoders with "s" is my library and without "s" is the external library.
In long newPosition = Myenc.read(); I get the error "'Myenc' was not declared in this scope" and "expression must have class type"
I don't understand how can I include Encoder library and initialize it with two parameters. I'm following the same logic of my Timer.h library but is not the same (in Timer_ my constructor is empty and this make everything easy)
Thanks so much for helping me.
_Myenc is a function, not an object. You probably meant to write _Myenc().read() rather than _Myenc.read();.
Related
I wrote this code for my bike computer; however, the Alt, Course, and Speed are not displaying on the LCD display although it is on the Serial monitor. The GPS module isn't returning values either.
/* BaldwinOS by John Seong
An Open-Source Project
Version 1.0
*/
#include <SPI.h>
#include <SD.h>
#include <TinyGPS++.h> // Include the TinyGPS++ library
#include <Wire.h>
TinyGPSPlus tinyGPS; // Create a TinyGPSPlus object
#define ARDUINO_USD_CS 10 // uSD card CS pin (pin 10 on SparkFun GPS Logger Shield)
/////////////////////////
// Log File Defintions //
/////////////////////////
// Keep in mind, the SD library has max file name lengths of 8.3 - 8 char prefix,
// and a 3 char suffix.
// Our log files are called "gpslogXX.csv, so "gpslog99.csv" is our max file.
#define LOG_FILE_PREFIX "gpslog" // Name of the log file.
#define MAX_LOG_FILES 100 // Number of log files that can be made
#define LOG_FILE_SUFFIX "csv" // Suffix of the log file
char logFileName[13]; // Char string to store the log file name
// Data to be logged:
#define LOG_COLUMN_COUNT 8
char * log_col_names[LOG_COLUMN_COUNT] = {
"longitude", "latitude", "altitude", "speed", "course", "date", "time", "satellites"
}; // log_col_names is printed at the top of the file.
//////////////////////
// Log Rate Control //
//////////////////////
#define LOG_RATE 5000 // Log every 5 seconds
unsigned long lastLog = 0; // Global var to keep of last time we logged
#define GPS_BAUD 9600 // GPS module baud rate. GP3906 defaults to 9600.
#define SerLCD_Address 0x72
#include <SoftwareSerial.h>
#define ARDUINO_GPS_RX 9 // GPS TX, Arduino RX pin
#define ARDUINO_GPS_TX 8 // GPS RX, Arduino TX pin
SoftwareSerial ssGPS(ARDUINO_GPS_TX, ARDUINO_GPS_RX); // Create a SoftwareSerial
#define gpsPort ssGPS
#define SerialMonitor Serial
const int statusLED = 9;
const int blueLeftLED = 8;
const int redLeftLED = 7;
const int blueRightLED = 0;
const int redRightLED = 3;
const int leftButton = A3;
const int rightButton = 11;
const int modeButton = 12;
const int buzzer = 13;
void setup() {
SerialMonitor.begin(9600);
gpsPort.begin(GPS_BAUD);
SerialMonitor.println("Setting up SD card.");
// see if the card is present and can be initialized:
if (!SD.begin(ARDUINO_USD_CS))
{
SerialMonitor.println("Error initializing SD card.");
}
updateFileName(); // Each time we start, create a new file, increment the number
printHeader(); // Print a header at the top of the new file
Wire.begin();
Wire.setClock(400000);
Wire.beginTransmission(SerLCD_Address);
Wire.write('|'); // Put LCD into setting mode
Wire.write('-'); // Send clear display command
Wire.write('|'); // Put LCD into setting mode
Wire.write('+'); // Send the Set RGB command
Wire.write(0xFF); // Send the red value
Wire.write(0x00); // Send the green value
Wire.write(0x00); // Send the blue value
Wire.println("Welcome to");
Wire.print("BaldwinOS!");
Wire.endTransmission();
delay(2000);
}
void loop() {
Wire.beginTransmission(SerLCD_Address);
Wire.write('|'); // Put LCD into setting mode
Wire.write('-'); // Send clear display command
Wire.println("Pathfinder");
Wire.print("Bike Computer");
if ((lastLog + LOG_RATE) <= millis())
{ // If it's been LOG_RATE milliseconds since the last log:
if (tinyGPS.location.isUpdated()) // If the GPS data is vaild
{
if (logGPSData()) // Log the GPS data
{
SerialMonitor.println("GPS logged."); // Print a debug message
lastLog = millis(); // Update the lastLog variable
}
else // If we failed to log GPS
{ // Print an error, don't update lastLog
SerialMonitor.println("Failed to log new GPS data.");
}
}
else // If GPS data isn't valid
{
// Print a debug message. Maybe we don't have enough satellites yet.
SerialMonitor.print("No GPS data. Sats: ");
SerialMonitor.println(tinyGPS.satellites.value());
}
}
printStats1();
smartDelay(1000);
}
byte logGPSData()
{
File logFile = SD.open(logFileName, FILE_WRITE); // Open the log file
if (logFile)
{ // Print longitude, latitude, altitude (in feet), speed (in mph), course
// in (degrees), date, time, and number of satellites.
logFile.print(tinyGPS.location.lng(), 6);
logFile.print(',');
logFile.print(tinyGPS.location.lat(), 6);
logFile.print(',');
logFile.print(tinyGPS.altitude.feet(), 1);
logFile.print(',');
logFile.print(tinyGPS.speed.mph(), 1);
logFile.print(',');
logFile.print(tinyGPS.course.deg(), 1);
logFile.print(',');
logFile.print(tinyGPS.date.value());
logFile.print(',');
logFile.print(tinyGPS.time.value());
logFile.print(',');
logFile.print(tinyGPS.satellites.value());
logFile.println();
logFile.close();
return 1; // Return success
}
return 0; // If we failed to open the file, return fail
}
void printHeader()
{
File logFile = SD.open(logFileName, FILE_WRITE); // Open the log file
if (logFile) // If the log file opened, print our column names to the file
{
int i = 0;
for (; i < LOG_COLUMN_COUNT; i++)
{
logFile.print(log_col_names[i]);
if (i < LOG_COLUMN_COUNT - 1) // If it's anything but the last column
logFile.print(','); // print a comma
else // If it's the last column
logFile.println(); // print a new line
}
logFile.close(); // close the file
}
}
// updateFileName() - Looks through the log files already present on a card,
// and creates a new file with an incremented file index.
void updateFileName()
{
int i = 0;
for (; i < MAX_LOG_FILES; i++)
{
memset(logFileName, 0, strlen(logFileName)); // Clear logFileName string
// Set logFileName to "gpslogXX.csv":
sprintf(logFileName, "%s%d.%s", LOG_FILE_PREFIX, i, LOG_FILE_SUFFIX);
if (!SD.exists(logFileName)) // If a file doesn't exist
{
break; // Break out of this loop. We found our index
}
else // Otherwise:
{
SerialMonitor.print(logFileName);
SerialMonitor.println(" exists"); // Print a debug statement
}
}
SerialMonitor.print("File name: ");
SerialMonitor.println(logFileName); // Debug print the file name
}
void printStats1() {
Wire.beginTransmission(SerLCD_Address);
Wire.write('|'); // Put LCD into setting mode
Wire.write('-'); // Send clear display command
Wire.print("Alt: "); Wire.print(tinyGPS.altitude.feet());
Wire.print(" Course: "); Wire.println(tinyGPS.course.deg());
Wire.print("Speed: "); Wire.println(tinyGPS.speed.mph());
Serial.print("Alt: "); SerialMonitor.println(tinyGPS.altitude.feet());
Serial.print("Course: "); SerialMonitor.println(tinyGPS.course.deg());
Serial.print("Speed: "); SerialMonitor.println(tinyGPS.speed.mph());
}
static void smartDelay(unsigned long ms)
{
unsigned long start = millis();
do
{
// If data has come in from the GPS module
while (gpsPort.available())
tinyGPS.encode(gpsPort.read()); // Send it to the encode function
// tinyGPS.encode(char) continues to "load" the tinGPS object with new
// data coming in from the GPS module. As full NMEA strings begin to come in
// the tinyGPS library will be able to start parsing them for pertinent info
} while (millis() - start < ms);
}
If you are using a passive GPS antenna, you should test it outside (or in an open window pointing the antenna to the sky) to get the satellite fix. TinyGPS lib won't give you back any data if you don't have the fix value
I have problem with results (on serial monitor) of rotary encoder.
I am using Arduino UNO and RotaryEncoder library.
When I am running example code serial monitor show proper values when rotating with any speed.
I want to use encoder to change volume in Df-player.
Problem starts when I want to use this code together with more complicated one - Mp3 player.
It actually works only when I am rotating encoder very very slowly
#include <SPI.h>
#include <MFRC522.h>
#include <Arduino.h>
#include <SoftwareSerial.h>
#include <DFRobotDFPlayerMini.h>
#include <RotaryEncoder.h>
#define RST_PIN 9 // Configurable, see typical pin layout above
#define SS_PIN 10 // Configurable, see typical pin layout above
#define PIN_IN1 2
#define PIN_IN2 3
#define ROTARYSTEPS 1
#define ROTARYMIN 0
#define ROTARYMAX 30
const int playPauseButton = 4;
const int shuffleButton = 5;
boolean isPlaying = false;
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
SoftwareSerial mySoftwareSerial(5, 6); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int value);
// Setup a RotaryEncoder with 2 steps per latch for the 2 signal input pins:
RotaryEncoder encoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);
// Last known rotary position.
int lastPos = -1;
//*****************************************************************************************//
void setup() {
Serial.begin(9600); // Initialize serial communications with the PC, COMMENT OUT IF IT FAILS TO PLAY WHEN DISCONNECTED FROM PC
mySoftwareSerial.begin(9600);
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522 card
while (! Serial);
encoder.setPosition(5 / ROTARYSTEPS); // start with the value of 5.
pinMode(playPauseButton, INPUT_PULLUP);
pinMode(shuffleButton, INPUT_PULLUP);
Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));
if (!myDFPlayer.begin(mySoftwareSerial)) { //Use softwareSerial to communicate with mp3.
Serial.println(F("Unable to begin:"));
Serial.println(F("1.Please recheck the connection!"));
Serial.println(F("2.Please insert the SD card!"));
}
Serial.println(F("DFPlayer Mini online. Place card on reader to play a spesific song"));
//myDFPlayer.volume(15); //Set volume value. From 0 to 30
//volumeLevel = map(analogRead(volumePot), 0, 1023, 0, 30); //scale the pot value and volume level
myDFPlayer.volume(5);
//prevVolume = volumeLevel;
//----Set different EQ----
myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);
// myDFPlayer.EQ(DFPLAYER_EQ_POP);
// myDFPlayer.EQ(DFPLAYER_EQ_ROCK);
// myDFPlayer.EQ(DFPLAYER_EQ_JAZZ);
// myDFPlayer.EQ(DFPLAYER_EQ_CLASSIC);
// myDFPlayer.EQ(DFPLAYER_EQ_BASS);
}
//*****************************************************************************************//
void loop() {
encoder.tick();
// get the current physical position and calc the logical position
int newPos = encoder.getPosition() * ROTARYSTEPS;
if (newPos < ROTARYMIN) {
encoder.setPosition(ROTARYMIN / ROTARYSTEPS);
newPos = ROTARYMIN;
} else if (newPos > ROTARYMAX) {
encoder.setPosition(ROTARYMAX / ROTARYSTEPS);
newPos = ROTARYMAX;
} // if
if (lastPos != newPos) {
Serial.println(newPos);
myDFPlayer.volume(newPos);
lastPos = newPos;
} // if
// Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
MFRC522::MIFARE_Key key;
for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;
//some variables we need
byte block;
byte len;
MFRC522::StatusCode status;
if (digitalRead(playPauseButton) == LOW) {
if (isPlaying) {
myDFPlayer.pause();
isPlaying = false;
Serial.println("Paused..");
}
else {
isPlaying = true;
myDFPlayer.start();
Serial.println("Playing..");
}
delay(500);
}
if (digitalRead(shuffleButton) == LOW) {
myDFPlayer.randomAll();
Serial.println("Shuffle Play");
isPlaying = true;
delay(1000);
}
//-------------------------------------------
// Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
if ( mfrc522.PICC_IsNewCardPresent()) {
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial()) {
return;
}
Serial.println(F("**Card Detected:**"));
//-------------------------------------------
mfrc522.PICC_DumpDetailsToSerial(&(mfrc522.uid)); //dump some details about the card
//mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); //uncomment this to see all blocks in hex
//-------------------------------------------
Serial.print(F("Number: "));
//---------------------------------------- GET NUMBER AND PLAY THE SONG
byte buffer2[18];
block = 1;
len = 18;
status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 1, &key, &(mfrc522.uid)); //line 834
if (status != MFRC522::STATUS_OK) {
Serial.print(F("Authentication failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
status = mfrc522.MIFARE_Read(block, buffer2, &len);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("Reading failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
//PRINT NUMBER
String number = "";
for (uint8_t i = 0; i < 16; i++)
{
number += (char)buffer2[i];
}
number.trim();
Serial.print(number);
//PLAY SONG
myDFPlayer.play(number.toInt());
isPlaying = true;
//----------------------------------------
Serial.println(F("\n**End Reading**\n"));
delay(1000); //change value if you want to read cards faster
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
}
}
Any ideas what is wrong?
You have a delay(1000) in your main loop, and since your RotaryEncoder object seems to need a tick() function, i am assuming that it is not interrupt driven. This means that it will check only once per second if it has moved to the next step.
If a rotary encoder is stepped twice, and the middle step is missed by the MCU, the latter has no way of knowing which way round the encoder has turned.
So in this case you can only turn it one step per second.
What you need is, either:
a free running main loop, which goes round at least 100 times per second. (less nice)
a rotary encoder driver that is interrupt driven. (very nice)
I don't know if such a library exists, because i tend not to use arduino libs, but it is a very good exercise to write your own using GPIO interrupts.
First I'd like to say I'm very new to c++, that's why I'm using the Arduino core and libraries on ESP32, and I would like to apologize for the dumpster fire you're about to see below.
Simply making a custom keyboard with buttons and encoders. When booted, select one of two modes: blekeyboard or ble midi control surface.
The button works in both modes but the encoder only works in whichever mode is declared last. (so in this script order, both the encoder and button in mode 1 blekeyboard works, while only the button works in mode 2.)
What did I do wrong and what can I do? Any suggestions regarding the problem or the overall script is welcome.
Thank you in advance.
#include <Arduino.h>
#include <BleKeyboard.h>
BleKeyboard bleKeyboard;
#define ESP32
#include <encoder.h>
#include <Control_Surface.h>
#include <MIDI_Interfaces/BluetoothMIDI_Interface.hpp>
BluetoothMIDI_Interface midi;
const int usermodebutton1 = 2;
const int usermodebutton2 = 0;
int usermode = 0;
// ---------------------- mode 2 MIDI Input Elements ------------------------ //
using namespace MIDI_Notes;
NoteButton csButton1 = {
2,
note(C, 4),
};
CCRotaryEncoder csEnc1 = {
{26, 25}, // pins
MCU::V_POT_1, // MIDI address (CC number + optional channel)
1, // optional multiplier if the control isn't fast enough
};
// -------------------------- mode 1 blekeyboard --------------------------- //
int kbutton1 = 2;
int kbutton1State;
int keyInterval = 400000;
Encoder kencoder1(25, 26);
int encInterval = 5000;
TickType_t currentTime;
TickType_t previousTime;
long enc1_oldPos = -999;
// ============================================================================= //
void setup()
{
pinMode(usermodebutton1, INPUT_PULLUP);
pinMode(usermodebutton2, INPUT_PULLUP);
Serial.begin(115200);
Serial.println("");
Serial.println("select mode:");
// ----------------------------------------------------------------------------- //
while (true)
{
if (digitalRead(usermodebutton1) == LOW)
{
usermode = 1;
Serial.println("mode 1 selected");
break;
}
if (digitalRead(usermodebutton2) == LOW)
{
usermode = 2;
Serial.println("mode 2 selected");
break;
}
delay(1000);
}
// ----------------------------------------------------------------------------- //
if (usermode == 1)
{
Serial.println("setup mode 1");
Serial.println("Starting BLE work...");
bleKeyboard.begin();
pinMode(kbutton1, INPUT_PULLUP);
previousTime = 0;
}
if (usermode == 2)
{
Serial.println("setup mode 2");
Serial.println("Control Surface BLE starting...");
RelativeCCSender::setMode(relativeCCmode::TWOS_COMPLEMENT);
Control_Surface.begin(); // Initialize Control Surface
}
}
// ============================================================================= //
void loop()
{
while (usermode == 1)
{
while (bleKeyboard.isConnected())
{
// mode 1 encoders
long enc1_newPos = kencoder1.read();
currentTime = esp_timer_get_time();
if (enc1_newPos < enc1_oldPos && currentTime - previousTime > encInterval)
{
enc1_oldPos = enc1_newPos;
previousTime = currentTime;
// bleKeyboard.write(KEY_MEDIA_VOLUME_DOWN);
Serial.print("enc1: ");
Serial.println(enc1_newPos);
}
if (enc1_newPos > enc1_oldPos && currentTime - previousTime > encInterval)
{
enc1_oldPos = enc1_newPos;
previousTime = currentTime;
// bleKeyboard.write(KEY_MEDIA_VOLUME_UP);
Serial.print("enc1: ");
Serial.println(enc1_newPos);
}
// mode 1 keys
kbutton1State = digitalRead(kbutton1);
if (kbutton1State == LOW && currentTime - previousTime > keyInterval)
{
previousTime = currentTime;
Serial.println("button 1 pressed");
bleKeyboard.print("1");
}
}
}
while (usermode == 2)
{
Control_Surface.loop(); // Refresh all elements
}
}
First of all, your code needs general tidying up. Do not instantiate an object after the #include or #define section.
Avoid doing this:
#include <BleKeyboard.h>
BleKeyboard bleKeyboard;
#include <MIDI_Interfaces/BluetoothMIDI_Interface.hpp>
BluetoothMIDI_Interface midi;
I generally organise my code as:
// Include libraries
#include <lib1.h>
#include <lib2.h>
...
// Macros
#define SOMETHING_FUNNY value // see the Macro name in capitals?
#define SOMETHING_USEFUL anothervalue
...
/*
* Variables Section.
* Also, I usually categorize my variables section by type: floats, integers, chars, etc. If I ever use booleans I pack them in a section called 'flags'. Also, if a boolean is used inside an interrupt it should be volatile
*/
Type var_name1 = initial_value; // the initaliztion is optional
AnotherType var_name2;
...
// Object instantiation
ClassName object1;
AnotherClassName object2 = new AnotherClassName(constructor_parameters);
...
//Setup Function
void setup(){
// Serial Port initialization goes first
Serial.begin(baudrate);
// Initialization routines --> use functions!
}
void loop(){
// Check for states of your FSM and call the respective function
}
// Functions definitions
output type myFunction1(args){
// Routine
}
...
Second, your code shouts to me 'Finite-States Machines', which is basically what you are implementing but not in a conventional way. Please read Nick Gammon's amazing tutorial on FSMs. This way, you will enumerate your states and trigger actions or events depending on the user's selection or hardware inputs without blocking the flow of the code.
Now, I assume that you have read both the .cpp files from your two libraries and checked if there are no conflicts between them? Also, which encoder.h library are you using? It looks like Paul Stoffregen's library, is it? I ask because his library is heavily based on interrupts and it was coded with some ASM blocks that might be not optimized for the ESP32, but please don't quote me on that. As enhzflep said:
I'd suspect there to be a problem with clashing interrupts.
and I could not agree more on that. If you are using that library, there is a Macro that could save your life:
#define ENCODER_DO_NOT_USE_INTERRUPTS
used in this example from the library's repo
As usual, I know how to bypass this problem with some ugly patch work, but I want to make it elegant: I would like to make a small wrapper for motors commanded by an Arduino, which would unfortunately mean writing a distinct interrupt routine for each instance of motor because it has to modify the right step counter (member variable of the motor class) to determine its rate. However those functions would obviously have the same processing...
My question is: how can I determine which counter to modify in a unique interrupt routine?
Here is what I have so far, I'd like to hide interrupts from the user.
class Motor {
volatile int counter;
unsigned long lastUpdate; //Last timestamp update (for calculating the rate)
static const unsigned int RESOLUTION = 1024; //Number of steps in one rev
static const unsigned int RPMS_TO_RPM = 60000; //Convers rev/ms to rpm
public:
Motor() : counter(0)
{
lastUpdate = millis();
}
void encoderInput(bool pinA, bool pinB)
{
counter += (pinA ^ pinB)*(-1)+!(pinA ^ pinB);
}
int getRate() {
int ret = float(counter)/RESOLUTION/(millis() - lastUpdate)*RPMS_TO_RPM;
lastUpdate = millis();
counter = 0;
return ret;
}
};
/* Example:
* Motor motor1;
*
* void motor1_isr(void) {
* motor1.encoderInput(PIN_A, PIN_B);
* }
*
* void setup() {
* attachInterrupt(PIN_I, motor1_isr, CHANGE);
* Serial.begin(9600);
* }
*
* void loop() {
* Serial.println(motor1.getRate());
* delay(1000);
* }
*/
Thanks for your help, I think it would be useful to other people as well once it's done with :)
Regards,
Mister Mystère
You are facing a fundamental problem: an ISR is called with no data. In other words, the ISR function is not provided any data that indicates its source of the interrupt.
The basic approach is that the person writing the code provides the linkage between input and action by hardcoding a function. The tricky approach you are looking for is a method by which the ISR can figure out what the source was.
So you want to have N motors with 2N inputs from quadrature encoders. A single interrupt handler is attached to all the input pins on a CHANGE condition. The same handler gets called for all N motors. It can figure out which Motor to update by comparing the input pins to the values the last time it was called. If the input pins changed, then call that motor. Here is a psuedo code
Motor motor1;
Motor motor2;
onSomethingChanged() {
static int in1aprev, in1bprev;
static int in2aprev, in2bprev;
int in1a, in1b;
int in2a, in2b;
in1a = digitalRead(....
same for other in's
if( (in1a!=in1alast) || (in1b!=in1blast)) {
motor1.encoderInput(in1a,in1b);
in1alast = in1a;
in1blast = in1b;
}
if( (in2a!=in2alast) || (in2b!=in1blast)) {
motor2.encoderInput(in2a,in2b);
in1a2ast = in2a;
in1b2ast = in2b;
}
return;
}
Not so long ago this type of function would be handled in an entire chip (see programmable interrupt controller ). The chip implements all the logic to trigger and capture the source of the interrupt. The main CPU just gets a trigger "something happened". The handler polls the chip to ask "what happened".
Having offered this method, I'm not sure I would recommend. You cannot hide what is going on with your code. The motor must be physically wired to the correct pins. You have consumed a scarce resource -- you have to tell people.
In my Arduino IDE I have set up a program that runs eight LEDs through a shift register and now am trying to make a class to control the shift register. So far I have created the file and created a constructor with a few functions for the class, but when I try to verify the code the IDE says that I am redefining the class shiftreg here is the error message:
In file included from Lab9_step3.cpp:97:
shiftreg.h:2: error: redefinition of 'class shiftreg'
shiftreg.h:3: error: previous definition of 'class shiftreg'
and my code for lab_9 is:
/* ---------------------------------------------------------
* | Arduino Experimentation Kit Example Code |
* | CIRC-05 .: 8 More LEDs :. (74HC595 Shift Register) |
* ---------------------------------------------------------
*
* We have already controlled 8 LEDs however this does it in a slightly
* different manner. Rather than using 8 pins we will use just three
* and an additional chip.
*
*
*/
#include "shiftreg.h"
//Pin Definitions
//Pin Definitions
//The 74HC595 uses a serial communication
//link which has three pins
shiftreg a(2, 3, 4);
int sensorPin = 0; // select the input pin for the potentiometer
int sensorValue = 0; // variable to store the value coming from the sensor
/*
* setup() - this function runs once when you turn your Arduino on
* We set the three control pins to outputs
*/
void setup()
{
a.pinmode();
}
/*
* loop() - this function will start after setup finishes and then repeat
* we set which LEDs we want on then call a routine which sends the states to the 74HC595
*/
void loop() // run over and over again
{
for(int i = 0; i < 256; i++){
a.update(i);
// read the value from the sensor:
sensorValue = analogRead(sensorPin);
delay(sensorValue);
}
}
/******************************
/*
* updateLEDsLong() - sends the LED states set in ledStates to the 74HC595
* sequence. Same as updateLEDs except the shifting out is done in software
* so you can see what is happening.
*/
// void updateLEDsLong(int value){
// digitalWrite(latch, LOW); //Pulls the chips latch low
// for(int i = 0; i < 8; i++){ //Will repeat 8 times (once for each bit)
// int bit = value & B10000000; //We use a "bitmask" to select only the eighth
// //bit in our number (the one we are addressing this time thro
// //ugh
// value = value << 1; //we move our number up one bit value so next time bit 7 will
// // be
// //bit 8 and we will do our math on it
// if(bit == 128){digitalWrite(data, HIGH);} //if bit 8 is set then set our data pin high
// else{digitalWrite(data, LOW);} //if bit 8 is unset then set the data pin low
// digitalWrite(clock, HIGH); //the next three lines pulse the clock pin
// delay(1);
// digitalWrite(clock, LOW);
// }
// digitalWrite(latch, HIGH); //pulls the latch high shifting our data into being displayed
// }
//
//
// //These are used in the bitwise math that we use to change individual LEDs
// //For more details http://en.wikipedia.org/wiki/Bitwise_operation
// int bits[] = {B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000};
// int masks[] = {B11111110, B11111101, B11111011, B11110111, B11101111, B11011111, B10111111, B01111111};
// /*
// * changeLED(int led, int state) - changes an individual LED
// * LEDs are 0 to 7 and state is either 0 - OFF or 1 - ON
// */
// void changeLED(int led, int state){
// ledState = ledState & masks[led]; //clears ledState of the bit we are addressing
// if(state == ON){ledState = ledState | bits[led];} //if the bit is on we will add it to le
// //dState
// updateLEDs(ledState); //send the new LED state to the shift register
// }
// **********************************/
and my code for shiftreg.h is:
/*Shift Register
*/ (Error occurs here)
class shiftreg (and here)
{
private:
//Pin Definitions
//Pin Definitions
//The 74HC595 uses a serial communication
//link which has three pins
int data;
int clock;
int latch;
public:
shiftreg (int _data, int _clock, int _latch);
void update(int value);
void pinmode();
};
and my code for shiftreg.cpp is:
#include "shiftreg.h"
/*shiftreg constructor:
*/
shiftreg::shiftreg (int _data, int _clock, int _latch)
{
data = _data;
clock = _clock;
latch = _latch;
//Used for single LED manipulation
int ledState = 0;
const int ON = HIGH;
const int OFF = LOW;
}
/*
* updateLEDs() - sends the LED states set in ledStates to the 74HC595
* sequence
*/
void shiftreg::update(int value)
{
digitalWrite(latch, LOW); //Pulls the chips latch low
shiftOut(data, clock, MSBFIRST, value); //Shifts out the 8 bits to the shift register
digitalWrite(latch, HIGH); //Pulls the latch high displaying the data
}
/*
*/
void shiftreg::pinmode()
{
pinMode(data, OUTPUT);
pinMode(clock, OUTPUT);
pinMode(latch, OUTPUT);
}
Thanks for the help!
According to the error message you're including shiftreg.h on line 97 of Lab9_step3.cpp. What's on the 96 lines above that? The error probably lies somewhere in there.
If I had to guess, I'd say you're, either directly, or indirectly, including shiftreg.h twice (or more) in Lab9_step3.cpp, and the error's occurring because you don't have include guards in your header file.
Try adding the following to shiftreg.h
#ifndef SHIFTREG_H
#define SHIFTREG_H
class shiftreg
{
// ...
};
#endif