Lập trình AVR Timer
Basics
Bộ hẹn giờ rất hữu ích khi bạn muốn đặt một khoảng thời gian nào đó như báo thức của mình. Điều này có thể rất chính xác đến vài micro giây.
Bộ hẹn giờ / Bộ đếm là một phần thiết yếu của bất kỳ MCU hiện đại nào. Hãy nhớ rằng nó là cùng một đơn vị phần cứng bên trong MCU được sử dụng làm Bộ định thời hoặc Bộ đếm. Bộ hẹn giờ / bộ đếm là một bộ phận độc lập bên trong bộ điều khiển vi mô. Về cơ bản, chúng chạy độc lập với tác vụ mà CPU đang thực hiện. Do đó, chúng rất tiện dụng và chủ yếu được sử dụng cho những việc sau:
Internal Timer: Là bộ hẹn giờ bên trong thiết bị, đánh dấu vào tần số bộ dao động. Tần số dao động có thể được cấp trực tiếp cho bộ đếm thời gian hoặc nó có thể được điều chỉnh trước. Trong chế độ này, nó được sử dụng tạo ra độ trễ chính xác. Hay như máy đếm thời gian chính xác.
External Counter:Trong chế độ này, đơn vị được sử dụng để đếm các sự kiện trên một chân bên ngoài cụ thể trên MCU.
Pulse width Modulation(PWM) Generator: PWM được sử dụng trong điều khiển tốc độ động cơ và nhiều ứng dụng khác.
Atmega32 có 3 bộ định thời lần lượt là bộ định thời 0, bộ định thời 1 và bộ định thời 2. Hãy để chúng tôi bắt đầu khám phá với bộ đếm thời gian 0.
* Bộ định thời 0 là bộ định thời 8 bit. Về cơ bản nó có nghĩa là nó có thể đếm từ 0 đến 2 ^ 8 255. Hoạt động của bộ định thời 0 là thẳng tiến. Thanh ghi TCNT0 giữ Đếm bộ định thời và nó được tăng lên trên mỗi "tích tắc" của bộ định thời. Nếu bộ hẹn giờ được bật, nó sẽ đánh dấu từ 0 đến 255 và tràn. Nếu nó làm như vậy, một Cờ quá trình hẹn giờ (TOV) được đặt.
Bạn cũng có thể tải giá trị đếm trong TCNT0 và khởi động bộ đếm thời gian từ một số đếm cụ thể. Một tính năng thú vị khác là một giá trị có thể được đặt trong Thanh ghi so sánh đầu ra (OCR0), và bất cứ khi nào TCNT0 đạt đến giá trị đó, cờ Cờ so sánh đầu ra (OCF0) được đặt.
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
The configuration of the Timer can be set using the TCCR0 register shown below. With this you can basically select two things:
- The Frequency of the Clock Source with CS02, CS01, CS00 bits.
- The mode of the timer. For the first example we will use it in normal mode where it ticks from zero to the highest value(255)
TCCR0 | |||||||
---|---|---|---|---|---|---|---|
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
FOC0 | WGM00 | COM01 | COM00 | WGM01 | CS02 | CS01 | CS00 |
D2 | D1 | D0 | Clock Source |
---|---|---|---|
CS02 | CS01 | CS00 | Freq |
0 | 0 | 0 | No Clock (Stopped) |
0 | 0 | 1 | Clk |
0 | 1 | 0 | Clk/8 |
0 | 1 | 1 | Clk/64 |
1 | 0 | 0 | Clk/256 |
1 | 0 | 1 | Clk/1024 |
1 | 1 | 0 | Clk/T0-Falling edge |
1 | 1 | 1 | Clk/T0-Rising Edge |
D6 | D3 | PWM |
---|---|---|
WGM00 | WGM01 | Mode |
0 | 0 | Normal |
0 | 1 | CTC (Clear timer on compare match) |
1 | 0 | PWM (Phase correct) |
1 | 1 | Fast PWM |
Thanh ghi cờ ngắt bộ định thời / bộ đếm (TIFR) giữ hai cờ cơ bản mà chúng ta cần là TOV và OVF. Các bit khác tương ứng với các ngắt bộ định thời, chúng ta sẽ xem xét trong một hướng dẫn khác.
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
OCF2 | TOV2 | ICF1 | OCF1A | OCF1B | TOV1 | OCF0 | TOV0 |
Timer 0 Example
Toggle LED connected to PD4 every 100msec using Timer Zero with 1024 pre-scalar in normal mode.
$$Ftimer = CPU Frequency/Prescalar $$ $$Ftimer = 16MHz/1024 = 15.625KHz $$ $$Ttick = 1/ 15.625K = 64 \mu seconds$$ $$Ttotal = 64\mu s X 255 = 16ms$$
Bộ hẹn giờ nên tràn bao nhiêu lần để tạo ra độ trễ xấp xỉ 100msec?
$$ OverFlowCount = 100ms/16ms = 6.25 ≈ 6 $$
Tải TCNT0 với 0x00
Đặt các bit CS00 và CS02 trong thanh ghi TCCR0. Điều này sẽ bắt đầu thời gian Chúng tôi sẽ tính toán thời gian đánh dấu chỉ trong giây lát. Hoặc ở tốc độ Clk / 1024.
Theo dõi cờ TOV0 trong thanh ghi TIFR0 để kiểm tra xem bộ đếm thời gian có bị quá dòng hay không, giữ một timerOverFlowCount.
Nếu timerOverFlowCount> = 6, chuyển đổi đèn led trên PD4 và đặt lại số
#include<avr/io.h> #define LED PD4 int main() { uint8_t timerOverflowCount=0; DDRD=0xff; //configure PORTD as output TCNT0=0x00; TCCR0 = (1<<CS00) | (1<<CS02); while(1) { while ((TIFR & 0x01) == 0); TCNT0 = 0x00; TIFR=0x01; //clear timer1 overflow flag timerOverflowCount++; if (timerOverflowCount>=6) { PORTD ^= (0x01 << LED); timerOverflowCount=0; } } }
Timer 1 Basics
TCNT1H | TCNT1L | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
D15 | D14 | D13 | D12 | D11 | D10 | D9 | D8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
Timer 3 also has 2 control registers which allow us to configure it and use it in any mode you wish.
TCCR1A | |||||||
---|---|---|---|---|---|---|---|
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
COM1A1 | COM1A0 | COM1B1 | COM1B0 | FOC1A | FOC1B | WGM11 | WGM10 |
TCCR1B | |||||||
---|---|---|---|---|---|---|---|
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
ICNC1 | ICES1 | - | WGM13 | WGM12 | CS12 | CS11 | CS10 |
D2 | D1 | D0 | Clock Source |
---|---|---|---|
CS12 | CS11 | CS10 | Freq |
0 | 0 | 0 | No Clock (Stopped) |
0 | 0 | 1 | Clk |
0 | 1 | 0 | Clk/8 |
0 | 1 | 1 | Clk/64 |
1 | 0 | 0 | Clk/256 |
1 | 0 | 1 | Clk/1024 |
1 | 1 | 0 | Clk/T1-Falling edge |
1 | 1 | 1 | Clk/T1-Rising Edge |
Yes, and indeed we have a Flag register which will tell us the status of Timer 1 as shown below.
TIFR | |||||||
---|---|---|---|---|---|---|---|
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
OCF2 | TOV2 | ICF1 | OCF1A | OCF1B | TOV1 | OCF0 | TOV0 |
Timer 1 Example
Hãy để chúng tôi lặp lại ví dụ về Timer 0 chuyển đổi PD4 cứ sau 100ms. Lần này vì nó là bộ định thời 16 bit, hãy xem độ trễ tối đa mà nó tạo ra với hệ số vô hướng trước là 1024. ( nhấp nháy led PD4 100MS).
#include<avr/io.h> #include <util/delay.h> #define LED PD4 int main() { DDRD |= (1<<LED) ; //configure led as outpout TCCR1B = (1<<CS10) | (1<<CS12); //set the pre-scalar as 1024 OCR1A = 1562; //100ms delay TCNT1 = 0; while(1) { //If flag is set toggle the led while((TIFR & (1<<OCF1A)) == 0);// wait till the timer overflow flag is SET PORTD ^= (1<< LED); TCNT1 = 0; TIFR |= (1<<OCF1A) ; //clear timer1 overflow flag } }