Hello. I'm new to the whole Arduno scene.
A while back I bought an Arduino Micro from ADA Fruit.
I've had a lot of fun but I've moved on to working with timers and that's where I run into problems.
I'm trying to build an audio circuit (that will, hopefully, one day go into an Apple IIe).
I am following the tutorial here:
Seems like every tutorial I find assumes I have a different Arduino than the Micro and reference timers or settings that are different. Anyway...
The tutorial above has the follow section of code:
/****Set timer1 for 8-bit fast PWM output ****/
pinMode(9, OUTPUT); // Make timer’s PWM pin an output
TCCR1B = (1 << CS10); // Set prescaler to full 16MHz
TCCR1A |= (1 << COM1A1); // Pin low when TCNT1=OCR1A
TCCR1A |= (1 << WGM10); // Use 8-bit fast PWM mode
TCCR1B |= (1 << WGM12);
/******** Set up timer2 to call ISR ********/
TCCR2A = 0; // No options in control register A
TCCR2B = (1 << CS21); // Set prescaler to divide by 8
TIMSK2 = (1 << OCIE2A); // Call ISR when TCNT2 = OCRA2
OCR2A = 32; // Set frequency of generated wave
sei(); // Enable interrupts to generate waveform!
Well, I'm pretty sure that the Micro (or, more accurately, the ATmega32u4) doesn't have Timer2. But I believe it does have Timer0 and Timer1.
I also assume that Timer0 is 8bit and Timer1 is 16bit.
So, I changed the above code to:
/******** Set timer1 for 8-bit fast PWM output ********/
TCCR1B = (1 << CS10); // Set prescaler to full 16MHz
TCCR1A |= (1 << COM1A1); // Pin low when TCNT1=OCR1A
TCCR1A |= (1 << WGM10); // Use 8-bit fast PWM mode
TCCR1B |= (1 << WGM12);
/******** Set up timer0 to call ISR ********/
TCCR0A = 0; // No options in control register A
TCCR0B = (1 << CS01); // Set prescaler to divide by 8
TIMSK0 = (1 << OCIE0A); // Call ISR when TCNT0 = OCRA0
OCR0A = 32; // Set frequency of generated wave
sei(); // Enable interrupts to generate waveform!
When I try to upload it, everything breaks. Including the IDE can no longer find the USB port!
I found the following line is the line that breaks everything:
TIMSK0 = (1 << OCIE0A); // Call ISR when TCNT0 = OCRA0
When I comment it out, all is fine and I can upload. BUT, the timer does not work. At least not that I can tell.
Here is the code that I have for the ISR:
/******** Called every time TCNT1 = OCR1A ********/
ISR(TIMER1_COMPA_vect) { // Called when TCNT1 == OCR1A
static byte index=0; // Points to each table entry
OCR1AL = wave[index++]; // Update the PWM output
// asm(“NOP;NOP”); // Fine tuning
TCNT1 = 6; // Timing to compensate for ISR run time
}
I had to comment out the "asm" line because I got an error about "NOP;" not being defined.
But, from what I can tell, that code isn't being called anyway.
So, my questions are:
-
Where can I go to learn about these timers for the Arduino and MICRO (NOTE, MICRO and/or ATmega32u4) ? Preferably something that doesn't assume I'm already a 40 year veteran in electrical engineering. lol
-
Can anyone find what is wrong with the code shown below?
BTW, I have pin 9 attached to a piezo speaker. I have confirmed that I can play tones through the circuit when I don't use interrupts but use straight "tone" instead.
Thanks!
// Tone.ino
#include <avr/interrupt.h> // Use timer interrupt library
#include <notes.h>
/******** Sine wave parameters ********/
#define PI2 6.283185 // 2*PI saves calculation later
#define AMP 127 // Scaling factor for sine wave
#define OFFSET 128 // Offset shifts wave to all >0 values
/******** Lookup table ********/
#define LENGTH 256 // Length of the wave lookup table
byte wave[LENGTH]; // Storage for waveform
const int TxPin = 8;
const int pwmPin = 9;
int melody[] = {
NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4
};
int noteDurations[] = {
4, 8, 8, 4,4,4,4,4
};
void setupTimers() {
/******** Set timer1 for 8-bit fast PWM output ********/
TCCR1B = (1 << CS10); // Set prescaler to full 16MHz
TCCR1A |= (1 << COM1A1); // Pin low when TCNT1=OCR1A
TCCR1A |= (1 << WGM10); // Use 8-bit fast PWM mode
TCCR1B |= (1 << WGM12);
/******** Set up timer0 to call ISR ********/
TCCR0A = 0; // No options in control register A
TCCR0B = (1 << CS01); // Set prescaler to divide by 8
TIMSK0 = (1 << OCIE0A); // Call ISR when TCNT0 = OCRA0
OCR0A = 32; // Set frequency of generated wave
sei(); // Enable interrupts to generate waveform!
}
void setup() {
Serial1.begin(9600);
delay(50);
clear();
backlightOn();
printStr("Ready...");
pinMode(TxPin, OUTPUT);
pinMode(pwmPin, OUTPUT);
delay(50);
/* Populate the waveform table with a sine wave */
for (int i=0; i<LENGTH; i++) { // Step across wave table
float v = (AMP*sin((PI2/LENGTH)*i)); // Compute value
wave[i] = int(v+OFFSET); // Store value as integer
}
for (int thisNote = 0; thisNote < 8; thisNote++) {
// to calculate the note duration, take one second
// divided by the note type.
//e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
int noteDuration = 1000/noteDurations[thisNote];
tone(8, melody[thisNote],noteDuration);
// to distinguish the notes, set a minimum time between them.
// the note's duration + 30% seems to work well:
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);
// stop the tone playing:
noTone(8);
}
setupTimers();
clear();
printStr("Timers");
cr();
printStr(" initialized...");
}
/******** Called every time TCNT1 = OCR1A ********/
ISR(TIMER1_COMPA_vect) { // Called when TCNT1 == OCR1A
static byte index=0; // Points to each table entry
OCR1AL = wave[index++]; // Update the PWM output
// asm(“NOP;NOP”); // Fine tuning
TCNT1 = 6; // Timing to compensate for ISR run time
}
void backlightOn() {
Serial1.write(17);
delay(50);
}
void backlightOff() {
Serial1.write(18);
delay(50);
}
void clear() {
Serial1.write(12);
delay(50);
}
void cr() {
Serial1.write(13);
delay(50);
}
void playTone(int duration, int scale, int note) {
duration = constrain(duration, 208, 214);
scale = constrain(scale, 215, 219);
note = constrain(note, 220, 232);
Serial1.write(scale);
Serial1.write(note);
Serial1.write(duration);
delay(50);
}
void printStr(String str) {
Serial1.print(str);
delay(50);
}
void loop() {
}