There is an internal clock in the microcontroller. By default, this clock ticks one million times per second (1 megahertz or 1 MHz). The AVR microcontroller that you see in these videos actually ticks 8 million times per second (8 MHz), but the fuses in the microcontroller are set for an 8 prescaler to this clock. So, for every 8 ticks, the clock ticks by one.
TCNT1 is the 16-bit counter. TCNT0 is the 8-bit counter. TCNT counts with the internal clock. Of course, since these are 8 and 16 bits, TCNT cannot count up to one million, but can count up to 255 for 8 bit and 65535 for 16 bit.
You can have the timer/counter react with a signal coming in from a pin, or have it send a signal to a pin at ever set interval.
The internal clock can also be omitted and two other pins of the microcontroller XTAL can be connected to another clock source, like a crystal or a ceramic resonator. This is usually done to get a more precise clock since the internal clock has a + or - 10% error.
The obvious use of a timer would be for an alarm, but in microcontrollers, there would be a host of applications for timers. Timers could be used in data collecting applications, collecting data at set time intervals. You might want pulses output from a pin at certain time intervals to control other devices.
The control register of the timer/counter is TCCR1A and TCCR1B since the register is 16-bit, two 8-bit register designations are made. Each bit of the register is like a switch to turn on or off to control some aspect of the timer/counter.
TCCR1A has these switches: COM1A1, COM1A0, COM1B1, COM1B0, FOC1A, FOC1B, WGM11, WGM10.
To start the times, we will use the Clock Select CS12, CS11 and CS10. These control the prescaling of the clock source (i.e. how many actual clock ticks to ignore when counting). Setting only CS10 to 1 or high, this will set the timer/count to count with the clock source with no prescaling.
The Timer/Counter is used to count against a known clock frequency, the internal clock source for the AVR microcontroller. In the first part of the experiment, an LED, connected to PORTB and Pin 0 is toggled every time the TCNT1 exceeds 10000. That makes the LED toggle 100 times per second, which is too fast for the eye to discern the blink.
The TCCR1B Timer/Counter Control 16-bit Register B is used to turn on the CS10 (Clock Select) option of the control register to enable the timer for no prescaling.
The Timer/Counter is used to count against a known clock frequency, the internal clock source for the AVR microcontroller. In the first part of the experiment, an LED, connected to PORTB and Pin 0 is toggled every time TCNT1 is counted to 10000 * 100 using another loop. This makes the LED toggle every second
The TCCR1B Timer/Counter Control 16-bit Register B is used to turn on the CS10 (Clock Select) option of the control register to enable the timer for no prescaling.
The Timer/Counter is used to count against a known clock frequency, the internal clock source for the AVR microcontroller. In the first part of the experiment, a set of LEDs (14 in all) is connected to PORTB and PORTD and will produce a chasing effect every second and every 7th of a second using the TCNT1 timer/counter.
The prescaling is investigated using the CS10, CS11 and CS12 prescaler control bits in the TCCR1B timer/counter control register.
An interrupt is an event that stops regular program flow to run a separate set of code that relates to the interrupt. Interrupts have many uses and applications. Interrupts can be used with:
- Timers and counters (When a timer matches a specific value)
- Serial communications (USART, UART - tell you when data is received, or when the transmit is ready to take data to transmit)
- When a pin goes from high to low or vice verse
- ADC (Analog to Digital Converter) completes the conversion
- Software interrupt (custom)
- And many others.
The interrupt can be used to create an event when the timer/counter TCNT1 or TCNT0 achieves a specific value. The OCR1A is used to hold this value.
The TCCR1B is set to a prescaler of 64 using the Clock Select bits (CS10, CS11 and CS 12) and another control bit called WGM12 (Waveform Generation Mode) CTC Mode (Clear Timer on Compare). This will cause the TCNT1 to go back to 0 when the OCR1A value is hit.
sei() is used to enable global interrupts along with the timer interrupts enable control TIMSK.
The interrupt can be used to create an event when the timer/counter TCNT1 or TCNT0 achieves a specific value. The OCR1A is used to hold this value.
The TCCR1B is set to a prescaler of 64 using the Clock Select bits (CS10, CS11 and CS 12) and another control bit called WGM12 (Waveform Generation Mode) CTC Mode (Clear Timer on Compare). This will cause the TCNT1 to go back to 0 when the OCR1A value is hit.
sei() is used to enable global interrupts along with the timer interrupts enable control TIMSK.
The interrupt can be used to create an event when the timer/counter TCNT1 or TCNT0 achieves a specific value. The OCR1A is used to hold this value.
The TCCR1B is set to a prescaler of 64 using the Clock Select bits (CS10, CS11 and CS 12) and another control bit called WGM12 (Waveform Generation Mode) CTC Mode (Clear Timer on Compare). This will cause the TCNT1 to go back to 0 when the OCR1A value is hit.
sei() is used to enable global interrupts along with the timer interrupts enable control TIMSK.
To test the output, an LED is connected to PORTB pin 0 and toggled on the interrupt.
To use the interrupt for the Timer/Counter, an ISR (Interrupt Service Routine) must be written.
Specifically relating to enabling the interrupt for the Timer/Counter, the WGM12 (Waveform Generation Mode) in the TCCR1B must be set so the TCNT1 CTCs (Clears on Timer Compare). The Timer Mask TIMSK must set the OCIE1A (Output Compare Interrupt Enable). This bit is related to the OCR1A. Alternatively, the OCIE1B and OCR1B could be used.
The OCR1A must be equal to the count that will invoke the interrupt.
When using the ADC, a prescaler must be established to have the ADC timer fall within an acceptable range. This input clock frequency acceptable range is between 50kHz and 200kHz.
To determine the prescaler value for these frequency ranges, take your clock frequency, usually defaulting at 1,000,000 for an Atmega32 and dividing that with the 50kHz and 200kHz to find the high and low prescaler values. With these values, just go to the table and determine the prescaler that falls between these results. (i.e. 1,000,000/50,000 = 20 and 1,000,000 / 200,000 = 5, so a prescaler between 5 and 20 is acceptable which is either 8 or 16).
Configuring the prescaler entails setting the ADPS2, ADPS1, and/or ADPS0 in the ADCSRA control and status register.
In the case of using a 16 prescaler, ADPS2 is the bit to be set.
The 8-bit timer for the AVR can create a PWM using OCR (Output Compare Register). The OCR can be used as an overflow for the timer (CTC - Clear on Timer compare), or start the pulse on the OCR. If the former is used, the OCR can create the period. If the latter is used, the OCR creates the start of the pulse and the period is always at the 255 count (the overflow for the 8-bit timer).
This video specifically applies to hobby servo control, but is a good discussion on using the 16-bit timer to create a PWM.
The period can be created using the 16-bit timer overflow at 65535, or the ICR (Input Capture Register) can be used as the top of the timer count so the timer overflows at the value given to the ICR. This allows for a very precise PWM period.
The OCR (Output Compare Register) is used to start the pulse. When the overflow, or the ICR is hit by the timer/counter, the pulse ends and the signal goes to 0v.
Phase Correct PWM is just the pulse positioned at the middle of the period. The timer/counter is able to do this because instead of the timer overflowing and resetting the count to 0, it counts backward back to 0.
With the 8-bit timer, the OCR (Output Compare Register) can be used to create this pulse. When the timer arrives to the OCR value as it counts up, the pulse starts. The timer will start to count downward and will hit the OCR value again, the pulse will end. This creates a symmetrical characteristic with the counting and pulse, so the pulse is at the middle of the period.
This can also be done with the 16-bit timer/counter and would be more versatile with the ICR (Input Capture Register) being the top of the count (where the count starts to count downward) and the OCR value as the start and end of the pulse.
The steps to consider to output a PWM signal using the 16-bit timer/counter is:
- set the WGM (Waveform Generation Mode)
- Determine the prescaler CS10-12 (Clock Select)
- Create the Period using the ICR (Input Capture Register)
- Determine Output (Inverted or not inverted)
- Decide to use the OCR1A or OCR1B (Output Compare Register)
There are two types of WGM (Waveform Generation Modes), phase correct or fast PWM. Within those modes, you can set the WGM to be CTC (Clear on Timer Compare) where the timer resets to 0 when it reaches a specific number.
The top of the timer/counter can be 8-bit or a 16-bit top value (depending on the timer used 8 to 16 bit).
For fast PWM, WGM13, WGM12 and WGM11 are set (WGM10 is not set) and the ICR1 value determines the top of the counter.
The period is determined according to what period the device that you will be delivering the PWM to will accept. In this case, the PWM is being sent to a hobby sery which accepts a 50 Hz signal. The period for 50Hz is 20ms. To determine the period time frame: 1 / 50 Hz = .02 seconds or 2 centiseconds, or 20 milliseconds.
First, the period may rely on having a prescaler. To determine if a prescaler is needed with the 16-bit timer (which can count up to 65535), use the frequency of the AVR which is 1,000,000 Hz (1 MHz - megahertz) and divide that by the required frequency 50 Hz. 1,000,000 Hz / 50 Hz = 20,000. The 16-bit timer can handle counting up to 20,000, so the ICR1 will need to have the value of 19,999, since it is indexed from 0.
What if the clock frequency is at 8 MHz? Then the 50 Hz would require a count of 8,000,000 Hz / 50 Hz = 160,000. That's too high for the 16-bit count since it's only 65535. A prescaler of 4 or 8 would be required for this scenario.
Inverted mode is where the pulse happens at the end of the period. Non-Inverted mode is where the pulse happens at the beginning of the period.
In inverted mode, the signal will jump up to 5v (creating the start of the pulse) when the timer/counter hits the OCR1A (Output Compare Register) value. In non-inverted mode, the signal starts at 5v and jumps down to 0v when the timer/counter hits the OCR1A value.
To set the output mode to inverted mode, the COM1A1 and COM1A0 bits are set.
To set the output mode to non-inverted mode, the COM1A1 bit is set, but the COM1A0 is not set.
If the OCR1B is desired rather than the OCR1A, the use the COM1B1 and COM1B0 instead.
In non-inverted mode, the pulse is stared at the beginning of the period. The Period to match 50 Hz (20 ms period time frame), a timer/counter is used and the top value ICR1 is set at 19,999.
To set non-inverted mode, the COM1A1 is set and COM1A0 is not set.
The OCR value is set to correspond to the non-inverted mode so it is set at the low end of the timer/counter count. 2 ms would be equal to 2000. In inverted mode, the 2 ms would be equal to 19,999 - 2000 since the pulse is at the end.
In non-inverted mode, the pulse is stared at the beginning of the period. The Period to match 50 Hz (20 ms period time frame), a timer/counter is used and the top value ICR1 is set at 19,999.
To set non-inverted mode, the COM1A1 is set and COM1A0 is not set.
The OCR value is set to correspond to the non-inverted mode so it is set at the low end of the timer/counter count. 2 ms would be equal to 2000. In inverted mode, the 2 ms would be equal to 19,999 - 2000 since the pulse is at the end.
In non-inverted mode, the pulse is stared at the beginning of the period. The Period to match 50 Hz (20 ms period time frame), a timer/counter is used and the top value ICR1 is set at 19,999.
To set non-inverted mode, the COM1A1 is set and COM1A0 is not set.
The OCR value is set to correspond to the non-inverted mode so it is set at the low end of the timer/counter count. 2 ms would be equal to 2000. In inverted mode, the 2 ms would be equal to 19,999 - 2000 since the pulse is at the end.
In this case, a Hitec hobby servo is controlled using the PWM signal, but any device could be controlled using this method with a change to the ICR value to conform to the device's PWM frequency requirement. The 19,999 (20,000 indexed from 0) is used because this translates to a 50 Hz frequency, or 20 ms period that the Hitec servo requires.
The TCNT1 will be used to bring the pin low within the period for the specific pin. The TCNT1 is a timer/counter that holds the value of the clock.
In this program, interrupts are used to provide an interrupt every time the PWM counter reaches the top value in ICR1 (Input Capture Register 1).
Within the ISR (Interrupt Service Routine), all of the pins that will output the PWM signal will go high. This is to start all of the pins off as a pulse. When the timer reaches the desired width, that single pin will go low. This is using the TCNT1 register to determine the counts.
To enable the interrupt for the Timer, the TIMSK1 (Timer Mask) OCIE1A (Output Compare Interrupt Enable 1A) bit is set.
In this program, interrupts are used to provide an interrupt every time the PWM counter reaches the top value in ICR1 (Input Capture Register 1).
Within the ISR (Interrupt Service Routine), all of the pins that will output the PWM signal will go high. This is to start all of the pins off as a pulse. When the timer reaches the desired width, that single pin will go low. This is using the TCNT1 register to determine the counts.
To enable the interrupt for the Timer, the TIMSK1 (Timer Mask) OCIE1A (Output Compare Interrupt Enable 1A) bit is set.
The oscilloscope is also used to show the PWM output on the pin of choice.
The interrupts library must be included. The OCIE1A (Output Compare Interrupt Enable) is set in the TIMSK1 (Timer mask) register to enable the interrupts for the timer/counter when the ICR (Input Capture Register) is reached. The Global Interrupt is used sei();. When the ICR value is reached, the ISR (Interrupt Service Routine) for the TIMER1_COMPA_vect is called.