My most reliable freq source that i can get is i think arduino analogWrite, but it gives only 490hz and 980hz...
unsigned long waveHz = 100000;
unsigned int exacttime, numofovf;
volatile unsigned int timeovf;
unsigned long waveTime;
void setup() {
pinMode(2, OUTPUT);
waveTime = (1.0/(waveHz*2.0))*16000000;
numofovf = waveTime/65536;
exacttime = waveTime-(numofovf*65536UL);
if(exacttime>38){
exacttime = exacttime-38;
} else {
exacttime = 65535-38+exacttime;
numofovf = numofovf - 1;
}
cli();
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = exacttime;
TCCR1B |= (1 << CS10);
TIMSK1 |= (1 << OCIE1A);
TIMSK1 |= (1 << TOIE1);
sei();
}
void loop() {
}
ISR(TIMER1_COMPA_vect){
if(timeovf == numofovf){
TCNT1 = 0;
timeovf = 0;
PORTD ^= bit(2);
}
}
ISR(TIMER1_OVF_vect){
timeovf++;
}
Wouldn't be easier to just use PWM mode with 50% duty cycle to generate the square wave?
Ye but wont i be limited by min freq? For example i would be able to generate like i guess 4Mhz pwm but if i want 2hz thats a no go. Correct me if im wrong.
With TIMER1 and 16MHz Arduino, you can go as low as ~0.25 Hz (or 4 seconds per cycle)
Perhaps try a simple loop that toggles an LED (aka output pin). Then use a NOP loop to slow it down. Should be very consistent.
Also disable the millis() timer. Or simply shut off all interrupts.
I believe this will be as stable as an arduino is capable of.
uint_16 i
for ( i, i = 16384, i++){
asm(“nop\n\t”) //16Mhz Arduino ~ 62.5ns
asm ("sbi %0, %1 \n": : "I" (_SFR_IO_ADDR(PINB)), "I" (PINB5)); // Toggle LE
}
Here is an example of generating frequencies using Timer1. It can for 0.2Hz (5 seconds per cycle) to 500 kHz.
// Generating Two 180° Out of Phase Variable-Frequency
// Square Waves on Timer1 of an Arduino UNO (Pins 9 and 10)
// Good for frequencies from 0.2 Hz to 500 kHz.
// Written June 1st, 2020 by John Wasser
void TwoPhaseBegin()
{
digitalWrite(9, LOW);
pinMode(9, OUTPUT);
digitalWrite(10, LOW);
pinMode(10, OUTPUT);
// Stop Timer/Counter1
TCCR1A = 0; // Timer/Counter1 Control Register A
TCCR1B = 0; // Timer/Counter1 Control Register B
TIMSK1 = 0; // Timer/Counter1 Interrupt Mask Register
// Set Timer/Counter1 to Waveform Generation Mode 8:
// Phase and Frequency correct PWM with TOP set by ICR1
TCCR1B |= (1 << WGM13); // WGM=8
TCCR1A |= (1 << COM1A1); // Normal PWM on Pin 9
TCCR1A |= (1 << COM1B1) | (1 << COM1B0); // Inverted PWM on Pin 10
TwoPhaseFrequency(1000.0); // Default to 1 kHz
}
bool TwoPhaseFrequency(float frequency)
{
byte prescaleBits; // 1, 2, 3, 4, 5
uint16_t prescaleFactor; // 1, 8, 64, 256, 1024
uint32_t top32;
// Find the smallest prescale factor that will fit the TOP value within 16 bits.
// frequency = F_CPU / (2 * prescale * TOP)
// TOP = F_CPU / (2UL * prescale * frequency);
prescaleBits = 1;
prescaleFactor = 1; // Used for 123 Hz to 500 kHz
top32 = F_CPU / (2UL * prescaleFactor * frequency);
if (top32 > 65535UL) // Too many clocks to count in 16 bits?
{
prescaleBits = 2;
prescaleFactor = 8; // Used for 16-122 Hz
top32 = F_CPU / (2UL * prescaleFactor * frequency);
if (top32 > 65535UL) // Too many clocks to count in 16 bits?
{
prescaleBits = 3;
prescaleFactor = 64; // Used for 2-15 Hz
top32 = F_CPU / (2UL * prescaleFactor * frequency);
if (top32 > 65535UL) // Too many clocks to count in 16 bits?
{
prescaleBits = 4;
prescaleFactor = 256; // Only used for 1 Hz
top32 = F_CPU / (2UL * prescaleFactor * frequency);
if (top32 > 65535UL) // Too many clocks to count in 16 bits?
{
prescaleBits = 5;
prescaleFactor = 1024;
top32 = F_CPU / (2UL * prescaleFactor * frequency);
if (top32 > 65535UL) // Too many clocks to count in 16 bits?
{
return false;
}
}
}
}
}
// Serial.print("Freq: ");
// Serial.print(frequency);
// Serial.print(" prescale: ");
// Serial.print(prescaleFactor);
// Serial.print(" TOP: ");
// Serial.println(top32);
if (top32 < 16)
return false; // Require at least 16 levels of PWM
TCCR1B &= ~((1 << CS12) | (1 << CS11) | (1 << CS10)); // Clear the three clock select bits
TCCR1B |= prescaleBits; // Set clock prescale to prescaleBits
ICR1 = top32;
OCR1A = top32 / 2;
OCR1B = (top32 / 2) + 1;
return true;
}
void setup()
{
Serial.begin(115200);
TwoPhaseBegin(); // Start output at 1000 Hz
}
void loop()
{
// Call TwoPhaseFrequency(uint16_t frequency) any time to change the output frequency
}
Now that is a keeper.
Its in LC_baseTools. You can install it using the IDE library manager. The Wokwi simulator has it installed as a default.
-jim lee
How about 90 degrees ?
Sorry, just 180°. I can't think of a way to get the AVR timer hardware to generate a quadrature signal without interrupts and software.
This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.