Hi, Im having problems and I dont know how to fix them.
for my setup im using a arduino nano, and AMT 102-V(only looking at the B channel), at the moment its set at 1024ppr but ideally I would want 2048. Im writing the results to an SD card (after data is recorded)
My problem is that im getting fairly regular dips in the values im reading. Ive done non-exhaustive testing and havent found anything that gets rid of these so far.(there used to be more when I was writing to SD within my loop so maybe its something else doing a similar thing but I dont understand enough about arduino to say). The picture below shows a test done at an approximate steady state, the data was trunkated to the nearest 10 RPM for memory storage, so small fluctuations are ok. The problem im seeing is the regularly spaced spikes down 20+ RPM.
#include <SPI.h>
#include <SD.h>
#define buttonPin 2
// Motor encoder output pulse per rotation (change as required)
#define ENC_COUNT_REV 1024
// Encoder output to Arduino Interrupt pin
#define ENC_IN 3
// Pulse count from encoder
volatile long encoderValue = 0;
// Define CS port
#define chipSelect 10
// interval for measurements RPMMultiplier = 60000 / 4;
#define RPMMultiplier 15000
//Setup Prototype
void updateEncoder();
// Variable for RPM measuerment
uint8_t var[800];
//for loop variable
int i = 0;
// Variable for button position
int buttonState = 0;
// Timer
unsigned long start_;
void setup() {
// Set encoder as input with internal pullup
pinMode(ENC_IN, INPUT_PULLUP);
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.print("Initializing SD card...");
// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// don't do anything more:
while (1)
;
}
Serial.println("card initialized.");
Serial.end();
// Attach interrupt
attachInterrupt(digitalPinToInterrupt(ENC_IN), updateEncoder, RISING);
buttonState= digitalRead(buttonPin);
while (buttonState == LOW) {
buttonState = digitalRead(buttonPin);
}
start_ = millis();
for (i = 0; i < 800; i++) { //Calculate RPM change
var[i] = (encoderValue * RPMMultiplier / ENC_COUNT_REV)/10;
encoderValue = 0;
while (millis() < start_ + ((i + 1) * 4)) {} //simple wait up to 2 ms
}
File dataFile = SD.open("datalog.txt", FILE_WRITE);
for (i = 0; i < 800; i++) {
dataFile.println(var[i]*10);
}
dataFile.close();
Serial.begin(9600);
Serial.println("Experiment Complete");
Serial.end();
}
void loop() {}
void updateEncoder() {
// Increment value for each pulse from encoder
encoderValue++;
}
Can you please post link to specs/data of the encoder?
Can we please have a circuit diagram?
An image of a hand drawn schematic will be fine, include ALL power supplies, component names and pin labels.
Here you go.
Encoder data sheet - https://www.cuidevices.com/product/resource/amt10.pdf
I dont know the name of the exact nano im using, the SD card reader is from adafruit. the SD card is a 32GB apacer card. I dont know the brand of any of the stuff for the button.
I tried that, my cable doesnt let me use anything above 9600 its just gives out garbarge text if I do.
Thinking about it im not sure what that would do to help, at the moment im only setting baud rate for my serial communications which end before my main loop runs. all the data gets written to RAM not through a serial connection (until later when its written to SD).
Not normally the case - did you remember to also set the serial baud rate in the Serial Monitor?
The serial output you sent went into a serial buffer in the Arduino, and is transmitted very slowly at 9600; it's likely still going quite a ways into your test. Raising the baudrate pushes the data out faster, getting it gone before your loop runs. You could also just add a 5s delay before your test, that should take care of the buffered data.
The first bit of serial is used to print whether or not the SD card was detected. the test always begins after that message has been sent and the serial closed. would that still have an effect? (there is a wait untill button push between the serial stuff and my experiment).
You'd have to dig into the Serial code, see if it waits until the last char is sent. I didn't note the Serial.end, that may be sufficient, or not, I do not know. It was just a thought.
One other note, I see encoderValue is declared volatile, long, but I don't see you protecting against interrupts (disabling interrupts) when you read and clear it. You'll need to do that, though I don't think it's related to your problem, that's too periodic. It looks like a timer or other interrupt action is causing interrupts to be blocked for a period of time, causing you to miss counts, hence I immediately thought of Serial.
Ok. I used the "search Forum", looking for How to use interrupts.
This thread is long and involved, so be patient. You'll see what needs to be done, I think.
I'm sorry, but it's been a long time since I worked at the hardware level on interrupts, on old microprocessor systems. I hope someone will come along here and give you more succinct information. Basically, what you're looking for is, wherever you read the counter that the interrupt routine is changing, you need to first, disable interrupts, do the read, and enable interrupts; that prevents the ISR from changing half of your counter value, as an example.
Reading assignment(more, and much better quality, information):
In particular, look for the word "atomically", as that's the keyword for the problem I'm describing.
As for your interrupts, keep in mind you need to keep your ISR as short as possible. Consider, an ISR that runs for longer than the period between interrupts. Your interrupt, while processing, is blind to the fact that it's been triggered again, and will only increment your counter once.