Arduino Uno & ATTiny84

Hi,

I am working on a project that requires a variable frequency square wave as an input to an A3977. I currently have it working well using just an Arduino uno, using the "blink without delay" idea. The problem that I have is that the Arduino needs to be used for other processes, with serial input and output. Each time the Arduino reads or writes the serial, there is a slight disturbance in the generated square wave. This is not an option, unfortunately. What I would like is for the Arduino to receive the appropriate instruction (the frequency of the wave) and set another IC accordingly. This way the brunt of the work is processed by the IC, not the Arduino. I have been looking at avrious options, including an AD9833, which may be unnecessarily complicated for this application. Another option is to use an ATTiny84, which is where my question comes in. If I were to go with the ATTiny84, and chose to continue with the "blink without delay" thing, would it be possible for the arduino to send this instruction? My thinking is that I could write a basic sketch for the ATTiny84 using the Arduino IDE, and use the serial input to change the length of the the on / off phases of the wave...is this feasible?

Any help would be greatly appreciated,

Thanks

Use the hardware timer of the Uno. You can vary the time, and have it produce a perfect square wave on one of the outputs even when the CPU is busy doing other things.

Can you explain further? The Arduino will be doing many different tasks, so I cannot modify the timers, if that is what you mean?

An Uno has 3 hardware timers. Timer0 is used by Arduino for millis(), micros() and delay(). Timer1 is a 16 bit timer which is unused. Timer2 is an 8 bit timer that is unused.

Assuming you are not using PWM (analogWrite()), then Timer1 should be free to use for this task without affecting the rest of your program.

The timers are a seperate peice of hardware to the CPU.

Here is an example of using the timers:
http://arduino.cc/playground/Code/Timer1

You may be better not using that library, but instead using the timer setup in CTC mode, which can be setup to toggle a pin every time the timer count reaches a set number, where the output frequency can be determined by:
Fout = FCPU / (2N(1+OCR1A))
Where:
FCPU = 16000000Hz
N = prescaler, which can be 1, 8, 64, 256, or 1024.
Fout = your required frequency
OCR1A = a number between 0 and 65535 inclusive which you set to control the frequency.

Here is an example of how you could use timer:

typedef enum {
  prescaler_off = 0,
  prescaler_divide1 = 1,
  prescaler_divide8 = 2,
  prescaler_divide64 = 3,
  prescaler_divide256 = 4,
  prescaler_divide1024 = 5
} Prescaler; //This is a list of available prescalers (bits for CS[2..0] in TCCR1B)

unsigned int prescalerValue[6] = {0,1,8,64,256,1024}; //Converts the prescaler into its actual value

Prescaler mode = prescaler_off;

void setup(){
  pinMode(9,OUTPUT); //Output must be on digital pin 9.
  TCCR1A = _BV(COM1A0); //Toggle OC1A on compare match
  TCCR1B = _BV(WGM12); //set to CTC mode with match at OCR register.
  TIMSK1 = 0; //don't need any interrupts from this timer.
  mode = prescaler_divide8; //set to FCPU/8
  startTimer(10000L); //pin 9 now outputs a 10kHz square wave.
}

void loop(){
}

void startTimer(unsigned long frequency){
  unsigned long period = (unsigned int)(F_CPU / (2UL*(unsigned long)prescalerValue[mode]*frequency)) - (unsigned int)1; //calculate the required rate
  TCNT1 = 0; //reset the timer to 0
  OCR1A = (unsigned int)period; //This is your period based on the calculation above
  TCCR1B |= ((byte)mode << CS10); //start the clock with the correct prescaler
}

void stopTimer(){
  TCCR1B = _BV(WGM12); //Keeps the correct mode, but disconnects the clock.
}

You could modify this to automatically choose the correct prescaler based on whether the calculation overflows

Thank you for the detailed response.

Most of that means nothing to me, but I shall study it and hopefully get somewhere with it.

Thanks again.

A bit of expaination is in order:

TCCR1A, TCCR1B, OCR1A,TCNT1 are all registers for the timer1 module. You would need to look in the Atmega328 datasheet for a better explaination of what things do.

_BV() means bit value, so for example:
_BV(1);
Takes bit 1 and converts it into a mask, i.e. 0b00000010
_BV(WGM12);
Takes the bit named WGM12 (see datasheet), and converts it into a mask.

The “typedef enum” statement basically creates a variable which can only take a specific set of numbers. In this case it can only take the numbers 0-5 inclusive. Not only this, but it gives each of the numbers a name, such as prescaler_divide1, which allows you to use those specific numbers with more meaningful names.

Hopefully that is helpful :slight_smile:

[quote author=Tom Carpenter link=topic=118417.msg891455#msg891455 date=1344894080] Timer1 is a 16 bit timer which is unused. Timer2 is an 8 bit timer that is unused.

Assuming you are not using PWM (analogWrite()), then Timer1 should be free to use for this task without affecting the rest of your program. [/quote]

All three timers are 'used' on the Arduino, but use of Timer 1 or Timer 2 will only prevent the use of PWM (analogWrite) on a few pins.

http://arduino.cc/playground/Main/TimerPWMCheatsheet

wanderson: [quote author=Tom Carpenter link=topic=118417.msg891455#msg891455 date=1344894080] Timer1 is a 16 bit timer which is unused. Timer2 is an 8 bit timer that is unused.

Assuming you are not using PWM (analogWrite()), then Timer1 should be free to use for this task without affecting the rest of your program.

All three timers are 'used' on the Arduino, but use of Timer 1 or Timer 2 will only prevent the use of PWM (analogWrite) on a few pins.

http://arduino.cc/playground/Main/TimerPWMCheatsheet [/quote]

Well, ok, you got me. I guess I was meaning unused in the sense that the system doesn't rely on them like it does Timer0 for millis(),delay() etc.