PaulStoffregen
Well-known member
It is supports differential mode, negative numbers would be needed for the case where the negative ADC channel is higher than the positive one.
#define ENCODER_DO_NOT_USE_INTERRUPTS
//#define ENCODER_OPTIMIZE_INTERRUPTS
#include <Encoder.h>
#include <ADC.h>
ADC *adc = new ADC(); // adc object
//RingBuffer *buffer = new RingBuffer;
RingBufferDMA *dmaBuffer = new RingBufferDMA(2,ADC_0); // use dma channel 2 and ADC0
//#include <Encoder.h>
Encoder readEnc(5, 6);
const int numReadings = 2500;
const int readAudio = A2; // ADC0
int encoder_scale;
int minus_encoder_scale;
int count = 0;
int encoder_step_count;
int newRead;
int min_time;
int up_thresh;
int down_thresh;
int up_zero;
int down_zero;
int inter_pulse;
int max_pulse_width;
int max_position;
int pause_loops;
int pause_loop_threshold;
int diff;
int center;
int zero_diff;
int zero_check;
int audio_min = 1000; // initialize at high number
int audio_max = 0; // initialize at low number :)
boolean sent_pulse = false;
boolean pause_begin;
boolean got_pause;
boolean playback = false;
// see setup for decoder variables
int audio_in;
int read_in;
int reading_index = 0; // the index of the current reading
int readings[numReadings]; // the readings from the analog input
long total = 0; // the running total
int average = 0; // the average
long countloops;
void setup() {
// digitalWriteFast(13, HIGH);
digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
delay(2000); // this is needed for some fucking reason to let voltage stabilize???
pinMode(1, OUTPUT); // step out clockwise (used to drive audio encoder)
pinMode(2, OUTPUT); // step out counterclockwise (used to drive audio encoder)
pinMode(3, OUTPUT); // step
pinMode(4, OUTPUT); // direction
pinMode(5, INPUT); // encoder, no pullup
pinMode(6, INPUT); // encoder, no pullup
pinMode(9, INPUT_PULLUP); // limit CW
pinMode(10, INPUT_PULLUP); // limit CCW
pinMode(13, OUTPUT);
pinMode(A2, INPUT);
pinMode(A4, INPUT);
pinMode(21, INPUT_PULLUP); // switch for record/playback
encoder_scale = 6; //
minus_encoder_scale = encoder_scale * -1;
diff = 300; // 200 to 300? and is terrible 400 too high
zero_diff = 80; // was 80
zero_check = 25; // was 50 anything from about 7 to 150 probably fine keep it short to allow fast motion
pause_loop_threshold = 3;
max_pulse_width = 50; // 50 seems right, do not change?
inter_pulse = 2; // time between multiple ticks from pulse sub should vary this in playback to smooth playing
pause_loops = 0;
adc->enableDMA(ADC_0);
adc->enableInterrupts(ADC_0);
// set parameters for ADC0
adc->setAveraging(1); // needs to be maybe 5 to 10?
adc->setResolution(10); // set bits of resolution seems to need to be 10
adc->setConversionSpeed(ADC_VERY_HIGH_SPEED); // change the conversion speed
adc->setSamplingSpeed(ADC_VERY_HIGH_SPEED); // change the sampling speed
adc->startContinuous(readAudio, ADC_0); // must be continuous read
int cal_count = 1000;
for (int thisReading = 0; thisReading < cal_count; thisReading++){
total += adc->analogReadContinuous(ADC_0);
delayMicroseconds(100);
}
center = int (total / cal_count);
up_thresh = center + diff;
down_thresh = center - diff;
up_zero = center + zero_diff;
down_zero = center - zero_diff;
}
void loop() {
int read_in;
// buffer->write(adc->analogReadContinuous(ADC_0)); // comment this out if using DMA buffer
newRead = readEnc.read();
// the following could miss a step but the loop is fast enought that it probably won't if it does WTF
if ((newRead > 0 ) and (digitalReadFast(10)== HIGH)){
encoder_step_count ++;
}
if ((newRead < 0 ) and (digitalReadFast(9)== HIGH)){
encoder_step_count --;
}
readEnc.write(0); // reset encodereach loop so it just reads direction single pulses
if (encoder_step_count == encoder_scale){
digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
encoder_step_count = 0; // might need to move this to next loop level
if (!playback){
record_cw();
}
digitalWriteFast(4, LOW);
for (int i=0; i < encoder_scale; i++){
delayMicroseconds(2); // this delay is critical do not remove it but try 1 us
digitalWriteFast(3, HIGH);
delayMicroseconds(1);
digitalWriteFast(3, LOW);
}
}
if (encoder_step_count == minus_encoder_scale){
digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
encoder_step_count = 0;
if (!playback){
record_ccw();
}
digitalWriteFast(4, HIGH);
for (int i=0; i < encoder_scale; i++){
delayMicroseconds(2); // this delay is critical do not remove it but try 1 us
digitalWriteFast(3, HIGH);
delayMicroseconds(1);
digitalWriteFast(3, LOW);
}
}
pause_loops ++; // increments each loops is reset at pause begin
// read_in = buffer->read();
read_in = dmaBuffer->read();
if (! pause_begin){
if ((read_in > down_zero) && (read_in < up_zero)){ // might want && this with above if statement
pause_begin = true;
pause_loops = 0;
}
}
if ((pause_begin) && ((read_in < down_zero) || (read_in > up_zero))){ // just left a pause
if (pause_loops > pause_loop_threshold){
inter_pulse = max(pause_loops/(encoder_scale * 4),max_pulse_width); // need to figure out how ong the loop time is to get this right
if (read_in > up_thresh){
cwpulse();
}
if (read_in < down_thresh){
ccwpulse();
}
pause_begin = false; // reset
}
}
}
void dma_ch2_isr(void) {
//int t = micros();
//digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
// Serial.println("DMA_CH2_ISR"); //Serial.println(t);
DMA_CINT = 2; // clear interrupt
// call write to tell the buffer that we wrote a new value
dmaBuffer->write();
//digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
}
void adc0_isr(void) {
//int t = micros();
// Serial.println("ADC0_ISR"); //Serial.println(t);
ADC0_RA; // clear interrupt
}
void record_cw(void){ // output cw pulse to encoder
digitalWriteFast(1, HIGH); // pin 1 high CW step this was 2 by mistake might be reason for jitter
delayMicroseconds(2); // might need to make this longer was 1 trying 2
digitalWriteFast(1, LOW); // pin 1 low CW step
}
void record_ccw(void){ // output ccw pulse to encoder
digitalWriteFast(2, HIGH); // pin 2 high CCW step
delayMicroseconds(2);
digitalWriteFast(2, LOW); // pin 2 low CCW step
}
void cwpulse(void){ // interrupt code for input CW step (not using interrupt now)
digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
if (digitalReadFast(10)== HIGH){ // pin 10 limit open
digitalWriteFast(4, LOW); // pin 4 low for CW
for (int i=0; i < encoder_scale; i++){
delayMicroseconds(inter_pulse);
digitalWriteFast(3, HIGH); // pin 3 high
delayMicroseconds(1);
digitalWriteFast(3, LOW); // pin 3 low
}
}
}
void ccwpulse(void){ // interrupt code for input CCW step (not using interrupt now)
digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
if (digitalReadFast(9)== HIGH){ // pin 9 limit open
digitalWriteFast(4, HIGH); // pin 4 high for CCW
for (int i=0; i < encoder_scale; i++){
delayMicroseconds(inter_pulse); // needed for time to read the analog input
digitalWriteFast(3, HIGH); // pin 3 high
delayMicroseconds(1);
digitalWriteFast(3, LOW); // pin 3 low
}
}
}
C:\Users\Somniare\Documents\Arduino\libraries\ADC/ADC.h:52:24: fatal error: DMAChannel.h: No such file or directory
compilation terminated.
For proper conversion, the input voltage must fall between VREFH and VREFL. If the input is equal to or exceeds VREFH, the converter circuit converts the signal to 0xFFF (full scale 12-bit representation), 0x3FF (full scale 10-bit representation) or 0xFF (full scale 8-bit representation). If the input is equal to or less than VREFL, the converter circuit converts it to 0x000.
Yes, indeed DMAChannel.h is one of the new features in 1.20. It's so much better than the old, conflict-prone way used with 1.19 and older, so you should definitely install 1.20-rc5.
// FFT Test
//
// Compute a 1024 point Fast Fourier Transform (spectrum analysis)
// on audio connected to the Left Line-In pin. By changing code,
// a synthetic sine wave can be input instead.
//
// The first 40 (of 512) frequency analysis bins are printed to
// the Arduino Serial Monitor. Viewing the raw data can help you
// understand how the FFT works and what results to expect when
// using the data to control LEDs, motors, or other fun things!
//
// This example code is in the public domain.
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <ADC.h>
// CREATE THE ADC OBJECT FIRST, BEFORE ALL AUDIO STUFF!!
ADC *adc = new ADC(); // adc object
const int readPin = A3; // ADC0
// Create the Audio components. These should be created in the
// order data flows, inputs/sources -> processing -> outputs
// Using adafruit mic-amp, edit library to turn-off internal voltage reference in
// inputAnalog.cpp
AudioInputAnalog adc1(15);
AudioSynthWaveformSine sinewave;
AudioAnalyzeFFT1024 myFFT;
// Connect either the live input or synthesized sine wave
AudioConnection patchCord1(adc1, 0, myFFT, 0);
//AudioConnection patchCord1(sinewave, 0, myFFT, 0);
void setup() {
// Audio connections require memory to work. For more
// detailed information, see the MemoryAndCpuUsage example
AudioMemory(12);
pinMode(15, INPUT);
pinMode(14, INPUT);
// Configure the window algorithm to use
//myFFT.windowFunction(AudioWindowHanning1024);
myFFT.windowFunction(NULL);
// Create a synthetic sine wave, for testing
// To use this, edit the connections above
sinewave.amplitude(0.8);
sinewave.frequency(1034.007);
adc->setAveraging(32, ADC_1); // set number of averages
adc->setResolution(16, ADC_1); // set bits of resolution
adc->setConversionSpeed(ADC_VERY_LOW_SPEED, ADC_1); // change the conversion speed
adc->setSamplingSpeed(ADC_VERY_LOW_SPEED, ADC_1); // change the sampling speed
}
int value = 0;
void loop() {
float n;
int i;
value = adc->analogRead(readPin, ADC_1); // read a new value, will return ADC_ERROR_VALUE if the comparison is false.
if (myFFT.available()) {
// each time new FFT data is available
// print it all to the Arduino Serial Monitor
//Serial.print("T: "); //Testing touchRead
//Serial.print(touchRead(0));
Serial.print("\t FFT: ");
for (i=0; i<40; i++) {
n = myFFT.read(i);
if (n >= 0.005) {
Serial.print(n);
Serial.print(" ");
} else {
Serial.print(" - "); // don't print "0.00"
}
}
Serial.println();
Serial.print("Pin: ");
Serial.print(readPin);
Serial.print(", value ADC1: ");
Serial.println(value*3.3/adc->getMaxValue(ADC_1), DEC);
}
}