Last active
December 31, 2024 01:00
-
-
Save jschoch/6d10447a211f333098265ef4a2ec4d7f to your computer and use it in GitHub Desktop.
quadrature signal generator generated by qwen coder
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Arduino.h> | |
#include <cmath> | |
#include "driver/timer.h" | |
// Quadrature encoder pins | |
#define PIN_A (16) | |
#define PIN_B (17) | |
#define PIN_Z (18) | |
// Speed and revolutions variables | |
float speed = 10.0; | |
int revolutions = 0; | |
int revolution_count = 0; | |
bool reverseDirection = false; | |
int ppr = 360; | |
volatile int pulse_cntr = 0; | |
bool continuousMode = true; | |
// Z index to keep track of the number of revolutions | |
int z_index = 0; | |
hw_timer_t *timer = NULL; | |
bool timerRunning = false; | |
// Function to initialize quadrature encoder pins | |
void quad_encoder_init() { | |
pinMode(PIN_A, OUTPUT); | |
pinMode(PIN_B, OUTPUT); | |
pinMode(PIN_Z, OUTPUT); | |
} | |
// Function to calculate even timings for each pulse | |
int pulse_delay = 10000; | |
unsigned long calculate_pulse_interval(float rps, int ppr){ | |
//return 1000000L / ((abs(rps) * ppr)); // Calculate interval in microseconds | |
// using 160 divisor so we halve this | |
return 500000L / ((abs(rps) * ppr)); // Calculate interval in microseconds | |
} | |
// Function to generate quadrature signals based on the speed and revolutions | |
void generate_quadrature_signal() { | |
if (revolution_count >= revolutions && !continuousMode){ | |
return; | |
} | |
static unsigned long last_time = 0; | |
static int phase = 0; | |
delayMicroseconds(pulse_delay); // Delay to maintain the desired speed | |
pulse_cntr++; | |
phase++; | |
phase %= 4; // 4 phases in quadrature: A-HIGH, B-LOW; A-LOW, B-HIGH; A-LOW, B-LOW; A-HIGH, B-HIGH | |
unsigned long current_time = micros(); | |
if (pulse_cntr % ppr == 0){ | |
digitalWrite(PIN_Z, LOW); | |
revolution_count++; | |
//Serial.printf(".%d.",current_time); | |
}else{ | |
digitalWrite(PIN_Z, HIGH); | |
} | |
// Reverse the phase if speed is negative | |
if (reverseDirection) { | |
switch (phase) { | |
case 0: | |
digitalWrite(PIN_A, HIGH); | |
digitalWrite(PIN_B, LOW); | |
break; | |
case 1: | |
digitalWrite(PIN_A, HIGH); | |
digitalWrite(PIN_B, HIGH); | |
break; | |
case 2: | |
digitalWrite(PIN_A, LOW); | |
digitalWrite(PIN_B, HIGH); | |
break; | |
case 3: | |
digitalWrite(PIN_A, LOW); | |
digitalWrite(PIN_B, LOW); | |
break; | |
} | |
} else { | |
switch (phase) { | |
case 0: | |
digitalWrite(PIN_A, LOW); | |
digitalWrite(PIN_B, HIGH); | |
break; | |
case 1: | |
digitalWrite(PIN_A, HIGH); | |
digitalWrite(PIN_B, HIGH); | |
break; | |
case 2: | |
digitalWrite(PIN_A, HIGH); | |
digitalWrite(PIN_B, LOW); | |
break; | |
case 3: | |
digitalWrite(PIN_A, LOW); | |
digitalWrite(PIN_B, LOW); | |
break; | |
} | |
} | |
} | |
void IRAM_ATTR onTimer(){ | |
generate_quadrature_signal(); | |
} | |
void setup() { | |
Serial.begin(115200); | |
quad_encoder_init(); | |
Serial.println("setup done"); | |
/* get rid of this, timer better | |
xTaskCreatePinnedToCore( | |
run_gen, | |
"I2S Clock Task", | |
4096, | |
NULL, | |
1, | |
NULL, | |
0 | |
); | |
*/ | |
// Get and print the CPU frequency | |
timer = timerBegin(1, 160, true); // Prescaler = 80 (80MHz / 80 = 1MHz timer clock) | |
timerAttachInterrupt(timer, &onTimer, true); // Attach the ISR | |
timerAlarmWrite(timer, pulse_delay, true); // Set the initial alarm value and auto-reload | |
timerAlarmEnable(timer); // Start the timer | |
bool timerRunning = true; | |
int cpuFrequency = getCpuFrequencyMhz(); | |
Serial.print("CPU Frequency: "); | |
Serial.print(cpuFrequency); | |
Serial.println(" MHz"); | |
Serial.printf("Starting with PPR: %d, Speed (RPS): %f, in continuous mode: %s\n", ppr, speed, continuousMode ? "true" : "false"); | |
Serial.println("Type 'S' to stop generating signals."); | |
Serial.println("Type 'X,Y,Z' where X is speed (RPS), Y is revolutions, and Z is PPR. Example: 1,50,200"); | |
Serial.println("set speed negative to reverse direction: -1,50,200"); | |
} | |
void process_input(){ | |
String input = Serial.readStringUntil('\n'); | |
// Check for stop command | |
if (input == "S") { | |
speed = 0; // Stop the signal generation | |
continuousMode = false; | |
Serial.println("Stopped generating signals."); | |
//timerAlarmDisable(); | |
//bool timerRunning = false; | |
return; | |
} | |
// Parse input for speed, revolutions, and PPR | |
int commaIndex1 = input.indexOf(','); | |
int commaIndex2 = input.lastIndexOf(','); | |
if (commaIndex1 == -1 || commaIndex2 == -1 || commaIndex2 <= commaIndex1) { | |
Serial.println("Invalid input format. speed (rps), revolutions ('I' for infinite), PPR pulses per revolution"); | |
} | |
String speedStr = input.substring(0, commaIndex1); | |
String revolutionsStr = input.substring(commaIndex1 + 1, commaIndex2); | |
String pprStr = input.substring(commaIndex2 + 1); | |
if (!speedStr.toFloat() || !pprStr.toInt()) { | |
Serial.println("Invalid input values. Please ensure all inputs are numeric."); | |
return; | |
} | |
if(!revolutionsStr.toInt() && revolutionsStr == "I") { | |
Serial.println("Setting continuous mode."); | |
continuousMode = true; | |
} else { | |
if(revolutionsStr.toInt()){ | |
continuousMode = false; | |
revolution_count = 0; | |
revolutions = revolutionsStr.toInt(); | |
} | |
else{ | |
Serial.println("invalid revolution input, try again"); | |
return; | |
} | |
} | |
speed = speedStr.toFloat(); | |
ppr = pprStr.toInt(); | |
// Determine direction based on the sign of speed | |
reverseDirection = (speed < 0); | |
Serial.print("\nSpeed: "); | |
Serial.println(speed); | |
Serial.print("Revolutions: "); | |
Serial.println(revolutions); | |
Serial.print("Pulses per Revolution: "); | |
Serial.println(ppr); | |
Serial.print("Reverse Direction: "); | |
Serial.println(reverseDirection ? "Yes" : "No"); | |
Serial.printf("delay in microseconds between pulses: %d\n", calculate_pulse_interval(speed, ppr)); | |
if (!continuousMode) { | |
// If not in continuous mode, reset z_index | |
z_index = 0; | |
Serial.println("Started generating signals."); | |
} | |
pulse_delay = calculate_pulse_interval(speed, ppr); | |
timerAlarmWrite(timer, pulse_delay, true); | |
} | |
void loop() { | |
if (Serial.available() > 0) { | |
process_input(); | |
} | |
//generate_quadrature_signal(); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment