Anda di halaman 1dari 10

Timer dan Counter Mikrokontroler

I Putu Giovanni Eliezer | 17 October 2013 | Microcontroller, Theory | 2 Comments


Pengenalan Timer & Counter
Timer & Counter merupakan fitur yang telah tertanam di mikrokontroler AVR yang memiliki
fungsi terhadap waktu. Fungsi pewaktu yang dimaksud disini adalah penentuan kapan program
tersebut dijalankan, tidak hanya itu saja fungsi timer yang lainnya adalah PWM, ADC, dan
Oscillator. Prinsip kerja timer dengan cara membagi frekuensi (prescaler) pada clock yang
terdapat pada mikrokontroler sehingga timer dapat berjalan sesuai dengan frekuensi yang di
kehendaki.
Timer merupakan fungsi waktu yang sumber clocknya berasal dari clock internal. Sedangkan
counter merupakan fungsi perhitungan yang sumber clocknya berasal dari external
mikrokontroler. Salah satu contoh penggunaan fungsi timer yaitu pada jam digital yang sumber
clocknya bisa menggunakan crystal oscillator dan contoh penggunaan counter pada penghitung
barang pada konveyor yang sumber clocknya berasal dari sensor yang mendeteksi barang
tersebut.
Pada mikrokontroler ATMEGA 16 memiliki 3 buah timer yaitu timer 0 (8bit), timer1 (16bit), dan
timer 2 (8bit). Untuk mengenai register lengkapnya bisa dibaca pada datasheet. Namun yang
akan dibahas pada tulisan kali ini hanya timer 0(8bit) dan timer1 (16 bit) saja.
Register yang Digunakan untuk Timer & Counter

TCNT0 = Register Timer 1

TCNT 1 = Register Timer 0

Ttimer0 = Periode Timer 0

Ttimer 1 =Periode Timer 1

Tosc = Periode Clock

Fosc = Frekuensi Crystall Clock

N = Prescaler (1, 8, 64, 256, 1024)

Prescaler

Pada dasarnya Timer hanya menghitung pulsa clock. Frekuensi pulsa clock yang dihitung
tersebut bisa sama dengan frekuensi crystal yang digunakan atau dapat diperlambat
menggunakan prescaler dengan faktor 8, 64, 256 atau 1024.
Contoh penggunaan prescaler :
Suatu mikrokontroler menggunakan crystal dengan frekuensi 8 MHz dan timer yang digunakan
adalah Timer 1 (16 Bit) maka maksimum waktu Timer yang bisa dihasilkan adalah :
TMAX=1/fCLK

(FFFFh

+
=0.125 s

1)
65536

= 0.008192 s
Untuk menghasilkan waktu Timer yang lebih lama dapat menggunakan prescaler 1024, maka
waktu Timer yang bisa dihasilkan adalah :
TMAX=1/fCLK
=0.125 s
= 8.388608 s

(FFFFh+1)
655536

x
x

N
1024

Tujuan Penggunaan Timer & Counter


1. Melaksanaan tugas secara ber-ulang
2. Mengendalikan kecepatan motor DC (PWM)
3. Melakukan perhitungan (Counter)
4. Membuat penundaan waktu (delay)
TIMER 0 (8 Bit)

Untuk perhitungan timer 0 dapat menggunakan rumus :


Ttimer0 = Tosc*(256-TCNT0)*N

(8 Bit = 256 2^8)

Sebenarnya Timer 0 tidak dapat menghasilkan periode selama 1 detik karena keterbatasan jumlah
bit nya (8 bit = 256). Namun dengan penggunaan rumus dapat dilakukan pemanipulasian agar
timer 0 dapat menghasilkan periode waktu selama 1 detik. Dengan cara membuat timer selama
0.01 detik lalu dilakukan perulangan sebanyak 100 kali sehingga akan menghasilkan waktu 1
detik (0.01 detik x 100 kali = 1 detik).
Contoh penggunaan untuk timer 0 dengan crystal 12 MHz dan menggunakan skala clock 1024
maka akan menghasilkan :

Tosc=1/Fosc=1/12=0,083
0.01=0.083*(256-TCNT0)*1024
TCNT = 128= 8A (Hexadesimal)
Berdasarkan perhitungan tersebut di dapatkan 8A, maka nilai tersebut harus di inputkan ke
register TCNT0 agar timer 0 bernilai 1 detik. Berikut ini contoh penggunaan nya pada
Codevision AVR :

TIMER 1 (16 Bit)

Untuk perhitungan timer 1 dapat menggunakan rumus :


Ttimer 1 = Tosc*(65536-TCNT1)*N

(16 Bit = 65536 2^16)

Contoh penggunaan untuk timer 1 detik (Timer1 = 1 detik) dengan crystal 12 MHz dan
menggunakan skala clock 1024 maka akan menghasilkan :
Tosc
=
1/Fosc
1
=
TCNT = 53818 = D23A (Hexadesimal)

1/12

=
0,083
0.083*(65536-TCNT1)*1024

Berdasarkan perhitungan tersebut di dapatkan D23A, maka nilai tersebut harus di inputkan ke
register TCNT1 agar timer 1 bernilai 1 detik. Berikut ini contoh penggunaan nya pada
Codevision AVR :

Counter 0 & 1
Untuk penggunaan fungsi counter pada mikrokontroler lebih mudah jika dibandingkan dengan
fungsi timer, karena tidak memerlukan perhitungan untuk penginputan nilai ke register TCNT.
Register TCNT akan secara otomatis akan mencacah jika ada input yang masuk, input yang
masuk contohnya dapat berupa push button.
Pada Counter 0, input berasal dari T0 atau PORT B 0 yang mampu mencacah input hingga 256
(8 Bit). Berikut ini konfigurasi Counter 0 pada Codevision AVR :
Pada Counter 1, input berasal dari T1 atau PORT B 1 yang mampu mencacah hingga 65536 (16
Bit).
Untuk konfigurasi counter 0 & 1 pada Codevision AVR sama seperti konfigurasi Timer 0 dan 1.

By default, the successive approximation circuitry requires an input clock frequency between 50
kHz and 200 kHz to get maximum resolution.
Rekomendasi dari pabrikan mengatakan bahwa kecepatan detak yang direkomendasikan adalah
antara 50 kHz sampai dengan 200 kHz pada resolusi maksimum 10-bit. Kecepatan yang lebih
tinggi daripada 200 kHz akan menurunkan akurasi. Umumnya, mikrokontroler Arduino
menggunakan clock sebesar 16 MHz, dan umumnya ADC akan memiliki sumber clock yang
sama dengan mikrokontroler. Nilai ini jauh lebih besar dari yang dibutuhkan oleh ADC, yaitu
maksimum hanya 200 kHz. Oleh karena itu, terdapat suatu prescaler pada mikrokontroler.
Prescaler ini yang akan membagi nilai clock sumber yang digunakan oleh mikrokontroler. Nilai
prescaler dapat diatur menggunakan 3 bit ADPS, yaitu ADPS0, ADPS1 dan ADPS2. Amatilah
Gambar 3, berikut.

Gambar 3. ADC Prescaler


Nilai prescaler yang disediakan adalah 2, 4, 8, 16, 32, 64, dan 128. Nilai-nilai ini yang akan
digunakan untuk membagi detak (clock) sumber. Karena kita menggunakan clock 16 MHz pada
Arduino kita, maka diperoleh nilai-nilai detak hasil pembagian sebagai berikut:
16 MHz / 2 = 8 MHz
16 MHz / 4 = 4 MHz
16 MHz / 8 = 2 MHz
16 MHz / 16 = 1 MHz
16 MHz / 32 = 500 kHz
16 MHz / 64 = 250 kHz
16 MHz / 128 = 125 kHz
Karena clock ADC yang direkomendasikan berada diantara 50 kHz dan 200 kHz, maka prescaler
yang tepat digunakan adalah sebesar 128. Nilai 128 ini diperoleh dengan mengatur ADPS2,
ADPS1 dan ADPS0 masing-masing bernilai 1. Tabel selengkapnya untuk mengatur nilai pada
ADPS diperlihatkan pada Tabel 1.
Tabel 1. Seleksi Nilai ADPS

Berdasarkan pembagian di atas, jika kita menggunakan prescaler sebesar 128, maka kecepatan
ADC sebesar 125 kHz. Bagaimana caranya agar kita dapat menaikkan kecepatan ADC kita?
Caranya adalah menurunkan clock sumber. Misalnya kecepatan clock dari 16 MHz kita turunkan
menjadi 12 MHz, dan precaler diturunkan menjadi 64. Maka, kecepatan ADC sekarang menjadi
12 MHz/64 = 187 kHz. Nilai ini lebih besar 187 125 = 62 kHz daripada perhitungan kita
sebelumnya. Namun, menurunkan clock sumber berarti menurunkan kecepatan mikrokontroler.
Inilah yang menjadi untung-rugi (trade-off) dari desain kita. Lagipula, sangat tidak praktis untuk
mencabut clock yang sudah terpasang dengan baik di Arduino kita dan menggantinya dengan
yang baru.
Mari kita kembali ke nilai 125 kHz di atas (clock sumber 16 MHz dan prescaler 128). Karena
ADC kita membutuhkan waktu 13 detak dalam sekali konversi, maka banyaknya sampel yang
bisa dikonversi oleh ADC harus dibagi lagi sebanyak 13 dari kecepatan ADC, yaitu 125/13 = 9.6
kSa/s (kilo sampel per detik). Untuk aplikasi khusus, misalnya untuk pencuplikan gelombang
suara, maka nilai maksimal bandwidth ADC harus dibagi dua lagi, yaitu 9,6/2 = 4,8 kHz. Hal ini
sesuai dengan hukum Nyquist, yaitu frekuensi sampling paling tidak dua kali lipat dari frekuensi
tertinggi gelombang tercuplik untuk menghindari aliasing.
Mari kita amati ke Arduino kita. Perintah untuk menggunakan ADC adalah analogRead().
Pertanyaan kita, berapa sebenarnya kecepatan sampling dari sintaks analogRead() ini?
Jika kita menginstal software Arduino, mari kita amati file wiring.c (biasanya berada pada
C:\Program Files\arduino-1.0.4-windows\arduino1.0.4\hardware\arduino\cores\arduino\wiring.c). Tentunya letakknya disesuaikan dengan tempat
dimana kita menginstal dan versi software Arduino kita. Kalau kita buka wiring.c dan amati
dibagian paling bawah dari kumpulan koding tersebut, diperoleh keterangan sebagai berikut:
#if defined(ADCSRA)
// set a2d prescale factor to 128
// 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
// XXX: this will not work properly for other clock speeds, and
// this code should use F_CPU to determine the prescale factor.
sbi(ADCSRA, ADPS2);
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);

// enable a2d conversions


sbi(ADCSRA, ADEN);
#endif

Sesuai dugaan kita, prescaler yang digunakan adalah 128. Hal ini terbukti dari sintaks sbi (set
bit) yang dikerjakan pada ADPS2, ADPS1 dan ADPS0. Sesuai dengan Tabel 1, maka jika ketiga
bit ini diset (diberi nilai 1), maka prescaler yang dihasilkan adalah 128. Melihat kenyataan ini,
sintaks analogRead(), Arduino kita dibatasi mencuplik sebanyak 9.6 kSa/s, atau jika kita
bulatkan menjadi 9.000 sampel perdetik. Jika kita menggunakan Arduino Uno, maka inilah opsi
yang kita peroleh. Untuk beberapa seri mikrokontroler keluarga Xmega keluaran Atmel, kita
diperkenankan untuk memperoleh kecepatan yang lebih tinggi.
Namun, adakah cara lain untuk meningkatkan clock pada Arduino Uno kita?
Mari kita amati petunjuk pada datasheet (AVR120: Characterization and Calibration of the ADC
on an AVR), sebagai berikut:
The ADC accuracy also depends on the ADC clock. The recommended maximum ADC clock
frequency is limited by the internal DAC in the conversion circuitry. For optimum performance,
the ADC clock should not exceed 200 kHz. However, frequencies up to 1 MHz do not reduce the
ADC resolution significantly.
Dikatakan bahwa frekuensi ADC sampai 1 MHz tidak mengurangi resolusi ADC terlalu
signifikan. Namun, jika di atas 1 MHz tidak dijamin oleh pabrikan. Dengan demikian, kita dapat
mengambil kesimpulan kalau clock ADC kita naikkan sampai maksimal 1 MHz tidak menjadi
persoalan. Melihat kenyataan ini, dengan clock sebesar 16 MHz, kita dapat memilih prescaler
yaitu sebesar 16, 32, 64 dan 128.
Mari kita coba mengamati bagaimana jika prescaler kita mainkan dalam pemrograman Arduino.
Seperti yang sudah dibahas sebelumnya, prescaler diatur pada bit ADPS2, ADPS1, dan ADPS0
pada register ADCSRA. Dengan demikian, nilai ketiga bit inilah yang digunakan untuk
mengubah kecepatan sampling dari ADC kita.
Sekarang kita akan memprogram Arduino untuk membaca sampel sebanyak 50 kali, dan
menghitung berapa waktu yang diperlukan untuk proses konversi tersebut. Waktu yang
dibutuhkan akan dikeluarkan melalui serial monitor. Sebuah potensiometer kita masukkan di pin
A0.
// Array
unsigned
unsigned
unsigned

berikut digunakan untuk menyimpan data


long nilaiADC[50];
long waktu_mulai[50];
long waktu_berhenti[50];

void setup() {
//kecepatan serial
Serial.begin(9600);
}
void loop() {

unsigned int i;
// catat waktu mulai dan berhenti
//simpan hasilnya di memori
for(i=0;i<50;i++) {
waktu_mulai[i] = micros();
nilaiADC[i] = analogRead(0);
waktu_berhenti[i] = micros();
}
// tampilkan hasilnya ke serial monitor
for(i=0;i<50;i++) {
Serial.print(" Nilai ADC = ");
Serial.print(nilaiADC[i]);
Serial.print(" Waktu konversi = ");
Serial.print(waktu_berhenti[i] - waktu_mulai[i]);
Serial.print(" us\n");
}
delay(5000);
}

Dari waktu konversi diperoleh nilai 116 mikrodetik, atau 0.116 milidetik tiap sampel, atau
0.000116 detik tiap sampel. Dengan demikian, frekuensi sampling yang digunakan adalah
(1/0.000116) = 8.620, 689 Hz, atau sekitar 8.6 kHz. Jika merujuk pada kecepatan pengambilan
sampel nilai ini dikatakan sebagai 8.6 kSa/s. Nilai ini mendekati dugaan awal kita, yaitu tanpa
modifikasi prescaler, kecepatan dari analogRead() mendekati nilai 9.6 kSa/s. Nilai ini sedikit
lebih kecil karena penggunaan sintaks micros() juga membutuhkan waktu eksekusi.

Mari sekarang kita maenkan prescaler-nya. Kita mempunyai pilihan nilai selain 128 yaitu 16, 32
dan 64. Mari kita modif program kita yang sebelumnya. Kita gunakan prescaler sebesar 64, dan
potensiometer saya putar agar diperoleh variasi hasil. Programnya adalah sebagai berikut:
// Array
unsigned
unsigned
unsigned

berikut digunakan untuk menyimpan data


long nilaiADC[50];
long waktu_mulai[50];
long waktu_berhenti[50];

// Tentukan nilai-nilai Prescaler


// Lakukan pengaturan pada bit ADPS2 sampai ADPS0
const unsigned char PS_16 = (1 << ADPS2);
const unsigned char PS_32 = (1 << ADPS2) | (1 << ADPS0);
const unsigned char PS_64 = (1 << ADPS2) | (1 << ADPS1);
const unsigned char PS_128 = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
void setup() {
//kecepatan serial
Serial.begin(9600);
// Lakukan inisialisasi.
// Hapus pengaturan oleh library Arduino
ADCSRA &= ~PS_128;
// pilih prescaler yang digunakan.
// Saat ini gunakan nilai 64
ADCSRA |= PS_64;
}
void loop() {
unsigned int i;
// catat waktu mulai dan berhenti
//simpan hasilnya di memori
for(i=0;i<50;i++) {
waktu_mulai[i] = micros();
nilaiADC[i] = analogRead(0);
waktu_berhenti[i] = micros();
}
// tampilkan hasilnya ke serial monitor
for(i=0;i<50;i++) {
Serial.print(" Nilai ADC = ");
Serial.print(nilaiADC[i]);
Serial.print(" Waktu konversi = ");
Serial.print(waktu_berhenti[i] - waktu_mulai[i]);
Serial.print(" us\n");
}
delay(5000);
}

Amati bahwa waktu konversi sebesar 60 mikrodetik = 0,00006 detik, atau setara dengan 16
kSa/s. Ya, hasil kita masih cukup masuk akal. Hasil konversi juga cukup stabil. Bagaimana kalau
kita naikkan sampai batas toleransi yang diperbolehkan? Kita gunakan prescaler paling kecil
yaitu 16. Dengan mengganti satu baris koding, yaitu ADCSRA |= PS_64; menjadi ADCSRA |=
PS_16; kita peroleh hasil sebagai berikut:

Kecepatan tercepat yang diperoleh adalah 20 mikrodetik, dan ini setara dengan 50 kSa/s.
Terdapat variasi lebih banyak pada Nilai ADC yang diperoleh. Ini menunjukkan ADC semakin
tidak stabil. Namun demikian, variasi tidak terlalu timpang. Bisa kita tarik kesumpulan bahwa
dengan resolusi maksimal ADC, yaitu 10-bit, maka kecepatan maksimum yang dapat dicapai
adalah 50 kSa/s. Hasil yang cukup mengesankan ketimbang kecepatan default Arduino, yaitu
sekitar 9 kSa/s.