You are on page 1of 14

Pengenalan

Pengaturan lebar pulsa modulasi atau PWM merupakan salah satu teknik yang ampuh yang digunakan dalam sistem kendali (control system) saat ini. Pengaturan lebar modulasi dipergunakan di berbagai bidang yang sangat luas, salah satu diantaranya adalah: speed control (kendali kecepatan), power control (kendali sistem tenaga), measurement and communication (pengukuran atau instrumentasi dan telekomunikasi). Di dalam tutorial yang akan saya bahas kali ini akan mengajak anda mengenal dasar-dasar PWM dan implementasi PWM dengan menggunakan microcontroller.

Prinsip Dasar PWM


Modulasi lebar pulas (PWM) dicapai/diperoleh dengan bantuan sebuah gelombang kotak yang mana siklus kerja (duty cycle) gelombang dapat diubah-ubah untuk mendapatkan sebuah tegangan keluaran yang bervariasi yang merupakan nilai rata-rata dari gelombang tersebut. Lebih jelasnya mari kita simak gambar dibawah ini,

Ton adalah waktu dimana tegangan keluaran berada pada posisi tinggi (baca: high atau 1) dan, Toff adalah waktu dimana tegangan keluaran berada pada posisi rendah (baca: low atau 0). Anggap Ttotal adalah waktu satu siklus atau penjumlahan antara Ton dengan Toff , biasa dikenal dengan istilah periode satu gelombang.

Siklus kerja atau duty cycle sebuah gelombang di definisikan sebagai,

Tegangan keluaran dapat bervariasi dengan duty-cycle dan dapat dirumusan sebagai berikut,

sehingga: Dari rumus diatas dapat ditarik kesimpulan bahwa tegangan keluaran dapat diubah-ubah secara langsung dengan mengubah nilai Ton. Apabila Ton adalah 0, Vout juga akan 0. Apabila Ton adalah Ttotal maka Vout adalah Vin atau katakanlah nilai maksimumnya. Penjelasan tersebut diatas merupakan keseluruhan dari teori dasar dibalik sistem PWM. Sekarang, mari kita kita lihat pada implementasi praktek dari teori PWM tersebut diatas pada sebuah microcontroller.
PWM menggunakan TIMER 0

Seorang temen meminta saran tentang bagaimana menghasilkan signal PWM menggunakan microcontroller AVR. Dia menggunakan ATmega 16 dengan crystal 11.0592MHz. Dia pengen 2 signal PWM, inverting dan non inverting. Tapi masalahnya ada delay antara 2 signal tersebut. berikut ilustrasi signal PWM yang diinginkan:

t0 : time delay antara 2 signal (1 millisecond) tH : time signal HIGH (9 millisecond) tL: time signal LOW (11 millisecond) Pertama kali ide buat alur programmnya menggunakan Fast PWM. Jadi untuk mengatur lebar

PWM tinggal mengubah nilai OCR. Namun kita kesulitan dalam setting delay antara 2 signal. Akhirnya kita coba pake interrupt Timer 0. Disini interrupt diatur tiap 1 millisecond. Rumus yg digunakan untuk mengatur waktu interrupt Timer 0 adalah: TCNT0=(1+0xFF) (waktu * (XTAL/PRESCALER)) nilai waktu adalah waktu interrupt yang kita inginkan. Dalam kasus ini kita menggunakan XTAL (crystal) 11,0592 MHz dengan waktu interrupt 1 millisecond dan prescaler 256(bingung nilai prescaler itu apa??? klik disini). Sesuai dengan karakter sistem diatas maka nilai yang diisikan ke TCNT0 adalah: TCNT0=256-(0.001*43200) =212,8 TCNT0=0xD4 (format heksadesimal) Dengan menggunakan interrupt timer 0 , signal PWM yang dihasilkan nampak seperti berikut:

Code program yang digunakan:

#include <mega16.h> #define Ch1 PORTB.3 #define Ch2 PORTD.7 unsigned int time_value; // Timer 0 overflow interrupt service routine interrupt [TIM0_OVF] void timer0_ovf_isr(void) { TCNT0=0xd4; time_value++; if(time_value>=20) { time_value=0; } if(time_value<=1) {

Ch1=0; } if((time_value>=1)&(time_value<=9)) { Ch1=1; } else { Ch1=0; } if(time_value<=10) { Ch2=0; } else { Ch2=1; } // Declare your global variables here void main(void) { PORTA=0x00; DDRA=0x00; PORTB=0x00; DDRB=0xff; PORTC=0x00; DDRC=0x00; PORTD=0x00; DDRD=0xff; // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: 43.200 kHz ---> XTAL/prescaler // Mode: Normal top=FFh // OC0 output: Disconnected TCCR0=0x04;//--------->nilai ini utk menset nilai prescaler 256 TCNT0=0xd4;//-------> nilai dari rumus TCNT = (1+0xFF) - (waktu *( XTAL / prescaler) ) //waktu yg diinginkan 1 ms OCR0=0x00; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x01; // Analog Comparator initialization

// Analog Comparator: Off // Analog Comparator Input Capture by Timer/Counter 1: Off ACSR=0x80; SFIOR=0x00; // Global enable interrupts #asm("sei") while (1) { // Place your code here }; }

YOOO.. sekarang saatnya memenggal code-code program diatas:

#include <mega16.h> menyertakan file library mega16.h karena kita menggunakan ATmega16 klo menggunakan ATmega 8535 ya tinggal diganti #include<mega8535.h>

#define Ch1 PORTB.3 #define Ch2 PORTD.7 PORTB.3 diganti namanya menjadi Ch1 PORTD.7 diganti namanya menjadi Ch2 Ini untuk memudahkan penulisan program aja, biar lebih gampang diinget. Ch1 ato Ch2 bisa diubah sesuka hati misal: ChannelA, ChannelB dan seterusnya. PORT yang digunakan pun terserah anda. Tinggal diganti aja. Disini enaknya menghasilkan PWM pake interrupt timer, port yg di pakai tidak harus menggunakan port PWM microcontroller (port PWM micrcontroller atmega 16 adalah: PORTB.3(OC0), PORTD.4(OC1B), PORTD.5(OC1A), PORTD.7(OC2),)>_<.

unsigned int time_value; mendefinisikan variabel bertipe unsigned integer dengan nama time_value. varibel time_value ini yang nantinya dijadikan acuan dalam menghasilkan sinyal PWM.

// Timer 0 overflow interrupt service routine interrupt [TIM0_OVF] void timer0_ovf_isr(void) { ..

. } code-code program yg ada di antara 2 kurung kurawal itu yang dijalankan jika terjadi interrupt Timer 0

TCNT0=0xd4; nilai TCNT diisi nilai yg dihasilkan dari rumus (rumus diawal artikel). nilai ini yg menentukan interval waktu terjadinya interrupt

time_value++; setiap terjadi interrupt nilai time_value ditambah 1.

if(time_value>=20) { time_value=0; } jika nilai time_value lebih atau sama dengan 20 maka nilai time_value di nol kan

if(time_value<=1) { Ch1=0; } if((time_value>=1)&(time_value<=9)) { Ch1=1; } else { Ch1=0; } code di atas untuk menghasilkan PWM di Ch1 (PORTB.3) sesuai dengan nilai variabel time_value.

if(time_value<=10) { Ch2=0; } else { Ch2=1; } code di atas untuk menghasilkan PWM di Ch2 (PORTD.7) sesuai dengan nilai variabel time_value.

void main(void) { .. . } main program, program utama yang selalu dijalankan microcontroller.

PORTA=0x00; DDRA=0x00; PORTB=0x00; DDRB=0xff; PORTC=0x00; DDRC=0x00; PORTD=0x00; DDRD=0xff; setting port microntroller mau dijadikan input atau output.

// Timer/Counter 0 initialization // Clock source: System Clock // Clock value: 43.200 kHz ---> XTAL/prescaler // Mode: Normal top=FFh // OC0 output: Disconnected TCCR0=0x04;//--------->nilai ini utk menset nilai prescaler 256 TCNT0=0xd4;//-------> nilai dari rumus TCNT = (1+0xFF) - (waktu *( XTAL / prescaler) ) //waktu yg diinginkan 1 ms OCR0=0x00;

inisialisasi timer 0 sesuai rumus.

TIMSK=0x01; inisialisasi interrupt Timer 0.

ACSR=0x80; SFIOR=0x00; me non-aktifkan analog comparator

#asm("sei") mengaktifkan interrupt

while (1) { // Place your code here }; infinite looping. mikro hanya muter disini di dalam while(1){...}; (inget !!! infinite looping di artikel BASIC I/O ).. Jadi mikro sama sekali tidak mengeksekusi perintah. lha kok bisa????? bingungg.... ~_~ ! Disinilah bedanya pake Interrupt!!. saat terjadi Interrupt Timer0, alur program mikro akan meloncat ke:

interrupt [TIM0_OVF] void timer0_ovf_isr(void) { ...................................... ......yoww..... program yg ada disini yg dijalanin... ...................................... } setelah program yg ada di sub rutin INTERRUPT dijalankan, maka alur program mikro akan muter2 lagi di infinite looping ******************

Bermain dengan Timer 1 AVR

Yang namanya timer sering kali kita gunakan. Misal saat mau nampilin rpm, kita butuh timer sebagai acuan. Atau untuk menghidupkan device dengan interval tertentu. AVR yang saya pakai sebagai contoh adalah ATmega 8535. AVR ini memilki 3 timer. Yaitu:
1. TIMER 0 (8 bit) 2. TIMER 1 (16 bit) 3. TIMER 2 (8 bit) Apa yang dimaksud timer 8 bit dan 16 bit? timer 8 bit adalah timer yg bisa mencacah/menghitung sampai maksimal nilai 0xFF heksa (dalam biner = 1111 1111). Pada ATmega 8535 ada 2 timer jenis ini yaitu TIMER 0 dan 2 Klo yg 16 bit nilai maksimalnya 0xFFFF. Pada ATmega8535 timer jenis 16 bit adalah TIMER 1. Artikel kali ini akan membahas TIMER 1. Dulu ak disaranin klo timer mau presisi harus memakai bahasa assembly. Hitung jumlah instruksi yg kita tulis. lalu hitung lama waktunya. Hmmmm.. ribet bener... Untung aja nemu artikel tentang interrupt timer. Dengan Interrupt kita gak perlu susah2 menghitung berapa waktu yang di perlukan untuk meng eksekusi seluruh program kita. Karena saat program dijalanin, timer juga jalan sendiri (digerakkan XTAL). Trus saat nilai tercapai terjadilah interrupt timer. Register yg biasa saya gunakan untuk menset nilai Timer1 adalah register TCNT, register TCNT sendiri dibagi dua: TCNT 1 H dan TCNT 1 L. rumus yang digunakan adalah : TCNT = (1+0xFFFF) - (waktu *( XTAL / prescaler) ) waktu --> waktu yg kita inginkan XTAL --> frekuensi xtal yg dipakai prescaler --> nilai prescaler Apa nilai prescaler itu? Timer membutuhkan clock source. Biasanya clock source yg saya pakai adalah clock sistem (XTAL). Dan kita bisa menset besarnya nilai ini. Maximum sama dengan XTAL, minimum XTAL/1024. Nah nilai pembagi (1024) ini yg disebur nilai prescaler. Macam2 nilai prescaler yg diijinkan: 1, 8 , 64 , 256 , 1024

Untuk mengubah nilai prescaler timer 1, kita harus merubah nilai register TCCR1B bit 0...2

gambar diatas di ambil dari data sheet ATmega 8535 hal.113 Contoh Program: Mengakses Timer 1 dengan interval waktu 1 detik. #include <mega8535.h> #include <stdio.h> // LCD di PORT B #asm .equ __lcd_port=0x18 #endasm #include <lcd.h> unsigned char buff[30]; unsigned long detik; // sub rutin saat terjadi interrupt Timer 1 interrupt [TIM1_OVF] void timer1_ovf_isr(void) { TCNT1H=0xC2; TCNT1L=0xF7; detik++; lcd_clear(); sprintf(buff,"detik %d",detik); lcd_puts(buff); }

void main(void) { // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: kHz // Mode: Normal top=FFFFh // OC1A output: Discon. // OC1B output: Discon. // Noise Canceler: Off // Input Capture on Falling Edge TCCR1A=0x00; TCCR1B=0x04; TCNT1H=0xC2; TCNT1L=0xF7; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x04; // Analog Comparator initialization // Analog Comparator: Off // Analog Comparator Input Capture by Timer/Counter 1: Off // Analog Comparator Output: Off ACSR=0x80; SFIOR=0x00; // LCD module initialization lcd_init(16); // Global enable interrupts #asm("sei") lcd_putsf("wait..."); while (1) { }; } Program di atas menggunakan timer 1 untuk menambah nilai variabel "detik" setiap 1 detik sekali. Kemudian menampilkan hasilnya ke LCD. ayo kita mutilasi code program di atas: yang akan kita bahas dari program diatas adalah code yang kliatan ruwet aja. Klo yg biasa silahkan lihat

di artikel2 sebelumnya .. ^_^ ************** // LCD di PORT B #asm .equ __lcd_port=0x18 -------------->> mendefinisakan bahwa LCD di hubungkan ke PORT B #endasm #include <lcd.h> --------------->> library untuk fungsi2 akses LCD ************** // sub rutin saat terjadi interrupt Timer 1 interrupt [TIM1_OVF] void timer1_ovf_isr(void) { TCNT1H=0xC2; ----------------------> nilai didapat dari rumus ...... TCNT1L=0xF7; ----------------------> ....agar Timer 1 bernilai 1 detik detik++; lcd_clear(); sprintf(buff,"detik %d",detik); --------------> memasukkan karakter-karakter ke variabel buff lcd_puts(buff); --------------------------->menampilkan karakter-karakter variabel buff ke LCD } Saat kita ingin menampilkan sederet tulisan ke LCD maka kita harus memasukkan karakter-karakter tulisan itu ke suatu variabel array (dalam program di atas adalah variabel "buff"). Baru kemudian data yg ada di variabel array kita tampilkan ke LCD ***************

void main(void) { // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: kHz // Mode: Normal top=FFFFh // OC1A output: Discon. // OC1B output: Discon. // Noise Canceler: Off // Input Capture on Falling Edge TCCR1A=0x00; TCCR1B=0x04; ------------------> prescaler 256 TCNT1H=0xC2; ------------------> nilai didapat dari rumus ...... TCNT1L=0xF7; ------------------> ....agar Timer 1 bernilai 1 detik

inget rumus: TCNT = (1+0xFFFF) - (waktu *( XTAL / prescaler) ) waktu yg dinginkan adalah 1 detik , XTAL yg saya pakai adl 4 Mhz dan nilai prescaler=256 Jadi,............... TCNT= (1+65535)-(1detik * (4.000.000/256)) =65536 - (1detik*15625) =65536-15625 = 49911 (desimal) = C2F7 (heksadesimal) Nilai untuk TCNT yang di dapat dari rumus bernilai 16bit (4 angka Heksadesimal), 2 angka yg di depan kita masukkan ke TCNT1H dan 2 angka yg dibelakang kita masukkan ke TCNT1L **************** // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x04; ----------------->Timer/Counter1, Overflow Interrupt Enable code di atas hanya men set "Overflow Interrupt Timer 1". Interrupt baru aktif saat ada perintah: #asm("sei")

pada contoh ini saya pake ATmega 8535, ketika saya coba untuk ATmega 162 nilai TIMSK diubah menjadi TIMSK=0x80; **************** // Analog Comparator initialization // Analog Comparator: Off // Analog Comparator Input Capture by Timer/Counter 1: Off // Analog Comparator Output: Off ACSR=0x80; ------------> me OFF kan analog comparator SFIOR=0x00; jika tidak dipakai, sebaiknya analog comparator di OFF. Untuk menghemat pemakaian daya. Hal ini sangat penting jika sumber daya yg digunakan memakai baterai. ******************* // LCD module initialization lcd_init(16); ----------------------> inisialisasi LCD 16*2 ******************* // Global enable interrupts #asm("sei") ----------------------> meng aktifkan Interrupt-interrupt yg sudah di set sebelumnya Nah... pada saat ini interrupt Timer 1 aktif *******************

lcd_putsf("wait..."); --------------> menampilkan tulisan wait.. ke LCD ********************* while (1) { }; Program ini yg dijalankan oleh microcontroller... mikro hanya muter disini di dalam while(1){...}; (inget !!! infinite looping di artikel BASIC I/O ).. Jadi mikro sama sekali tidak mengeksekusi perintah. lha kok bisa????? bingungg.... ~_~ ! Disinilah bedanya pake Interrupt!!. saat terjadi Interrupt Timer1, alur program mikro akan meloncat ke: // sub rutin saat terjadi interrupt Timer 1 interrupt [TIM1_OVF] void timer1_ovf_isr(void) { ...................................... ......yoww..... program yg ada disini yg dijalanin... ...................................... } setelah program yg ada di sub rutin INTERRUPT dijalankan, maka alur program mikro akan muter2 lagi di infinite looping ******************

You might also like