Pages: 1 [2]   Go Down
Author Topic: Creating Square Waves with Programmable Frequencies?  (Read 1489 times)
0 Members and 1 Guest are viewing this topic.
Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 92
Posts: 4702
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Appreciate your help.  How about like this:

Code:
const int trimPot = A0;            //voltage divider to adjust speedometer output
const int speedPin = 21;          //pin for new speed pulse train
int pulseState = LOW;             // state used to set the pulse
volatile unsigned long currentMicros = 0;   //to measure new pulse   
volatile unsigned long previousMicros= 0;   //to mark prior pulse 
unsigned long currentSpeed = 0;    //to measure incoming pulse
unsigned long previousSpeed = 0;   //to mark prior pulse
unsigned long interval = 1;        //original pulse length
float adjustPercent = 1; //adjustment to original pulse length

void setup()
{
pinMode(speedPin, OUTPUT);   
pinMode(13, OUTPUT);
attachInterrupt (3, iSr, CHANGE);
}

void loop()
{
   currentMicros = micros();  //get the current micros count
   adjustPercent = (analogRead(trimPot)/512);
   interval=interval*adjustPercent;
   if(currentMicros - previousMicros > interval) //check to see if it's time to change
    {
    previousMicros = currentMicros;   //keep track of the last time pulse changed
    if (pulseState == LOW) pulseState = HIGH; else pulseState = LOW;
    digitalWrite(13, pulseState); //show pulse train on built in LED
    digitalWrite(speedPin, pulseState);  //flip the state of the new sqaure wave
    }
}
 
void iSr()
{
  currentSpeed=micros();
  interval=(currentSpeed-previousSpeed);  //how long since last change
  previousSpeed=currentSpeed;
}


interval needs to be volatile and decide what it's really for.

pulseState should be type byte.

Code:
   adjustPercent = (analogRead(trimPot)/512);
   interval=interval*adjustPercent;

The above code may run many times before interval is up, the dial does not set frequency and the ISR interval change is another mystery, also there's better ways than float.

Are you wanting to set the frequency with a dial? And the ISR to read the frequency? Or control frequency at least partly through the ISR?

Is that variable interval supposed to be changed by the ISR (triggered by writes in the code after interval is up) and then changed/initialized next time through loop()?

C code ^ is bitwise xor.
bool A xor bool B returns 1 if A and B are different, 0 if the same.

You could try
pulseState ^= 1; // flips pulseState between 0 and 1
or if that doesn't compile:
pulseState = pulseState ^ 1; // flips pulseState between 0 and 1


 
Logged

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

United Kingdom
Offline Offline
Tesla Member
***
Karma: 223
Posts: 6593
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You can use timer 1 to generate the signal you want directly. Here is the code I use:

Code:
#include "arduino.h"

#if defined(__AVR_ATtiny85__)

// Output is on physical pin 6 (= PB1/MISO/OCR1A)

#else

// Output is on Arduino pin 9 (= PB1/OC1A)
const int ocr1aPin = 9;

#endif

// Set the frequency that we will get on pin OCR1A
void setFrequency(uint16_t freq)
{
  uint32_t requiredDivisor = (F_CPU/2)/(uint32_t)freq;

#if defined(__AVR_ATtiny85__)
  // Code for attiny85
  uint16_t prescalerVal = 1;
  uint8_t prescalerBits = 1;
  uint32_t maxVal = 256;
  while (requiredDivisor > maxVal)
  {
    ++prescalerBits;
    maxVal <<= 1;
  }
  
  uint8_t top = ((requiredDivisor + (prescalerVal/2))/prescalerVal) - 1;
  TCCR1 = (1 << CTC1) | prescalerBits;
  GTCCR = 0;
  OCR1A = top;
#else
  // Code for atmega328p
  uint16_t prescalerVal;
  uint8_t prescalerBits;
  if (requiredDivisor < 65536UL)
  {
    prescalerVal = 1;
    prescalerBits = 1;
  }
  else if (requiredDivisor < 8 * 65536UL)
  {
    prescalerVal = 8;
    prescalerBits = 2;
  }
  else if (requiredDivisor < 64 * 65536UL)
  {
    prescalerVal = 64;
    prescalerBits = 3;
  }
  else if (requiredDivisor < 256 * 65536UL)
  {
    prescalerVal = 256;
    prescalerBits = 4;
  }
  else
  {
    prescalerVal = 1024;
    prescalerBits = 5;
  }

  uint16_t top = ((requiredDivisor + (prescalerVal/2))/prescalerVal) - 1;
  TCCR1A = 0;
  TCCR1B = (1 << WGM12) | prescalerBits;
  TCCR1C = 0;
  OCR1A = (top & 0xFF);
#endif
}

// Turn the frequency on
void on()
{
#if defined(__AVR_ATtiny85__)
  TCNT1 = 0;
  TCCR1 |= (1 << COM1A0);
#else
  TCNT1H = 0;
  TCNT1L = 0;  
  TCCR1A |= (1 << COM1A0);
#endif
}

// Turn the frequency off and turn off the output
void off()
{
#if defined(__AVR_ATtiny85__)
  TCCR1 &= ~(1 << COM1A0);
#else
  TCCR1A &= ~(1 << COM1A0);
#endif
}

void setup()
{
#if defined(__AVR_ATtiny85__)
#else
  digitalWrite(ocr1aPin, LOW);
  pinMode(ocr1aPin, OUTPUT);
#endif
}

Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Offline Offline
Jr. Member
**
Karma: 0
Posts: 51
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks again.  I am trying to measure the frequency of a square wave on interrupt 3, alter it slightly with the trim pot, and output the altered frequency on pin 20.
Logged

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 92
Posts: 4702
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Per frequency generated you need an start micros and interval micros.

If you want to adjust one, change the interval but do it where the adjustment won't get made as many times as there are micros in the interval.

Logged

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

Pages: 1 [2]   Go Up
Jump to: