Close

PWM on ATtiny85

A project log for Mechatronic Ears

Wearable cat ears that move

Radomir Dopieralski 02/23/2016 at 22:053 Comments

So I decided to go for this miniaturized version, and ordered the PCB at OSHPark. Since it was so small, it's quite cheap. But that means that now I need to port my code to ATtiny85. I can use an Arduino core, but I still need to come up with a way to control the hobby servos. The obvious way is to use Fast PWM mode.

The usual way to do it is to set a timer with two triggers -- one that switches the pin low, and one that resets the counter and switches the pin back to high. This gives you precise control over the exact frequency and duty cycle of the signal. ATtiny85 has two such timers, so I should be all set.

There is a small problem, however. I will also need 3 ADC pins, and one of those is the same as the Timer1 PWM pin. There is an ADC on the reset pin too, but I don't have a high voltage programmer to make use of that. So I can't use the second timer.

What I can do, is to use Timer0 but don't reset it on the second trigger, but let it overflow. Then use the second trigger for the second PWM pin. That however removes the precise control over the frequency -- now I can only use the frequencies that are available with the given prescalers and CPU speeds. Turns out I can do 62.5Hz with the ATtiny85 at 1Mhz. This is close enough for most servos.

With some diving into the datasheet and a bit of experimenting, I came up with this code:

void setup() {
    pinMode(0, OUTPUT);
    pinMode(1, OUTPUT);

    // Setup the PWM clock to ~62.5Hz for the servos.
    TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
    TCCR0B = 0<<WGM02 | 1<<CS00 | 1<<CS01 | 0<<CS02;

    OCR0A = 0;
    OCR0B = 0;
}

void loop() {
    for (int i=10; i<30; ++i) {
        OCR0A = i;
        OCR0B = i;
        delay(100);
    }
}
Note that since I'm messing with Timer0, which is also used by the Arduino core to keep track of millis(), the delay() is no longer accurate. But I can live with that.

Here's the servo in action:

Discussions

Gio Benitez Torres wrote 07/11/2016 at 15:08 point

Hey, thanks for that. But I have a question I will like to output a frequency from 2000 Hz to 3000 Hz. A square wave signal. Do you have any idea how that can be done? Thank you very much. 

  Are you sure? yes | no

Radomir Dopieralski wrote 07/11/2016 at 15:19 point

If you only need a single signal, all you have to do is figure out the clock prescaler and ticks count for your desired frequency, and use the first timer with a reset on the counter. For instance, with prescaler 1024  you should be able to get anything from ~61Hz to 15625Hz in steps of ~60Hz, depending on the tick counter.

  Are you sure? yes | no

Radomir Dopieralski wrote 07/11/2016 at 15:21 point

Actually, there is a tone() function, that should work for you, I used it in my #Nyan Board

  Are you sure? yes | no