The timer/counters can generate a PWM signal on pins designated as OCnx, where n is the timer/counter number and x is A or B.
This page gives example code useful for Servo PWM and DC Motor PWM. However, the examples may not be applicable for all timers on a particular AVR. Check the specs of the AVR you are using before adapting this code.
Servo PWM. (Phase and Frequency Correct PWM).¶
DC Motor PWM. (Phase Correct PWM).¶
Example given for Timer/Counter 2 on Atmega328, output on OC2A pin:
The counter will start at 0x00 and increment until it reaches 0xff, then decrement to 0x00 and repeat. The rate at which the timer increments/decrements is controlled by the prescaler bits described below. To control the pulse width of the PWM output, change the value in OCR2A. When the timer reaches the value in OCR2A on upcounting, it will either set the output on the OC2A pin as high or low, and on downcounting low or high. Once you set up the timer, you only need to change the value in OC2A to change the pulse-width and speed of the motor.
Example code to output PWM on PINB3 (OC2A) using Atmega328:
// Put in setup code
TCCR2A = (0b10<<COM2A0)| //Clear OC2A on upcount, set on downcount
(0b00<<COM2B0)| //Don't use OC2B
(0b01<<WGM20); //TOP = 0xff
TCCR2B = (0<<WGM22)|
(0b100<<CS20); //1/64 prescaler
OCR2A = 0x40; //Initial output
// Put in main code
OCR2A = 0x80; //Change OCR2A as needed.
- The PWM mode described above is set using the WGM bits, in this case WGM22 = 0 and WGM21:20 = 0b01. There is another Phase correct PWM mode where WGM22 = 1, but this makes the counter decrement when it reaches OCR2A, not 0xff, so pin will always be high in the above implementation.
- Set the prescaler using the CS (Clock Select) bits. This will depend on the CPU clock rate of the AVR, however, it is best to start in the middle (0b100, for example) and increase CS for larger periods. Note that the Phase Correct PWM module does not work at very small prescalers.
- Set the output mode using the COM2A bits. 0b00 and 0b01 will turn the pin off. 0b10 will set the output low on reaching OCR2A on upcounting and high on downcounting. 0b11 will set the output high on reaching OCR2A on upcounting and low on downcounting.
- To independently control two motors, set COM2B to 0b10 or 0b11 and change the value in OCR2B to change the speed of the second motor. Although OCR2A and OCR2B are in the same timer/counter, changing the OCR2A value for the output on the OC2A pin will not affect the output on the OC2B pin and vice versa.
- For more information, read section 17 in the ATmega328 datasheet. If you are using a different AVR, the code should be identical or very similar, but check the datasheet for more details.