[VI ĐIỀU KHIỂN PIC] - BÀI 9: KHỞI TẠO PWM TRONG PIC 16F877A VỚI CCS - BeeLab

Monday, June 5, 2017

[VI ĐIỀU KHIỂN PIC] - BÀI 9: KHỞI TẠO PWM TRONG PIC 16F877A VỚI CCS

I. Module CCP (Capture / Campare / PWM) là gì?

CCP (Capture/Compare/PWM) bao gồm các thao tác trên các xung đếm cung cấp bởi các bộ đếm Timer1 và Timer2. PIC16F877A được tích hợp sẵn hai khối CCP: CCP1 và CCP2. Mỗi CCP có một thanh ghi 16 bit (CCPR1H:CCPR1L và CCPR2H:CCPR2L), pin điều khiển dùng cho khối CCPx là RC2/CCP1 và RC1/T1OSI/CCP2. Các chức năng của CCP bao gồm:
- Capture.
- So sánh (Compare).
- Điều chế độ rộng xung PWM (Pulse Width Modulation).
Cả CCP1 và CCP2 về nguyên tắc hoạt động đều giống nhau và chức năng của từng khối là khá độc lập. Tuy nhiên trong một số trường hợp ngoại lệ CCP1 và CCP2 có khả năng phối hợp với nhau để để tạo ra các hiện tượng đặc biệt (Special event trigger) hoặc các tác động lên Timer1 và Timer2. Các trường hợp này được liệt kê trong bảng sau: 


Bài này chúng ta sẽ tìm hiểu về chế độ PWM.
II. Chế độ PWM.
PWM (Pulse Width Modulation) có thể tạo ra tín hiệu tần số và chu kỳ khác nhau trên một hoặc nhiều chân đầu ra hay còn thường gọi là điều chế độ rộng xung.
Quá trình hoạt động của chức năng PWM như sau: 

Hình 1. Sơ đồ khối CCP (PWM mode)

Khi hoạt động ở chế độ PWM (Pulse Width Modulation _ khối điều chế độ rộng xung), tín hiệu sau khi điều chế sẽ được đưa ra các pin của khối CCP (cần ấn định các pin này là output). Để sử dụng chức năng điều chế này trước tiên ta cần tiến hành các bước cài đặt sau:

  • B1: Thiết lập thời gian của 1 chu kì của xung điều chế cho PWM (period) bằng cách đưa giá trị thích hợp vào thanh ghi PR2.
  • B2: Thiết lập độ rộng xung cần điều chế (duty cycle) bằng cách đưa giá trị vào thanh ghi CCPRxL và các bit CCP1CON<5:4>.
  • B3: Điều khiển các pin của CCP là output bằng cách clear các bit tương ứng trong thanh ghi TRISC.
  • B4: Thiết lập giá trị bộ chia tần số prescaler của Timer2 và cho phép Timer2 hoạt động bằng cách đưa giá trị thích hợp vào thanh ghi T2CON.
  • B5: Cho phép CCP hoạt động ở chế độ PWM.
Quá trình hoạt động của chức năng PWM như sau:

- Với PIC 16F877A chúng ta có 2 chân điều chế độ rộng xung là CCP1 và CCP2, sau chọn chức năng PWM bằng cách điều khiển 4 bít thấp của thanh ghi CCPxCON, chúng ta sẽ nạp giá trị cho thanh ghi PR2 và thanh ghi CCPRx. Khi Timer2 hoạt động giá trị của thanh TMR2 sẽ tăng cho đến khi bằng giá trị của thanh ghi PR2 lúc này chân CCPx tương ứng sẽ lên mức 1 đồng thời thanh ghi TMR2 sẽ bị xoá về giá trị ban đầu. Mức 1 tại chân CCPx sẽ được dữ cho đên khi giá trị thanh ghi TMR2 bằng giá tri thanh ghi CCPRx sau đó chân CCPx lại trở về 0 cho đến khi giá trị thanh ghi TMR2=PR2 cứ như vậy quá trình sẽ lặp lại như ban đầu.- Như vậy chúng ta có thể rút ra như sau: Chu kì xung là khoảng thời gian để giá trị thanh ghi TMR2 tăng đến giá trị thanh ghi PR2 Khoảng xung dương là khoảng thời gian để thanh ghi TMR2 tăng đến giá trị thanh ghi CCPRx Để hiểu rõ hơn chúng ta có thể xem trong sơ đồ sau:



Hình 3. Các tham số của PWM

Trong đó giá trị 1 chu kì (period) của xung điều chế được tính bằng công thức:

PWM period = [(PR2)+1]*4*TOSC*(giá trị bộ chia tần số của TMR2)

Bộ chia tần số prescaler của Timer2 chỉ có thể nhận các giá trị 1,4 hoặc 16 (xem lại Timer2 để biết thêm chi tiết). Khi giá trị thanh ghi PR2 bằng với giá trị thanh ghi TMR2 thì quá trình sau xảy ra:
Thanh ghi TMR2 tự động được xóa.
-  Pin của khối CCP được set.
- Giá trị thanh ghi CCPR1L (chứa giá trị ấn định độ rộng xung điều chế duty cycle) được đưa vào thanh ghi CCPRxH.
Độ rộng của xung điều chế (duty cycle) được tính theo công thức:

PWM duty cycle = (CCPRxL:CCPxCON<5:4>)*TOSC*(giá trị bộ chia tần số TMR2)

Như vậy 2 bit CCPxCON<5:4> sẽ chứa 2 bit LSB. Thanh ghi CCPRxL chứa byte cao của giá trị quyết định độ rộng xung. Thanh ghi CCPRxH đóng vai trò là buffer cho khối PWM. Khi giá trị trong thanh ghi CCPRxH bằng với giá trị trong thanh ghi TMR2 và hai bit CCPxCON<5:4> bằng với giá trị 2 bit của bộ chia tần số prescaler, pin của khối CCP lại được đưa về mức thấp, như vậy ta có được hình ảnh của xung điều chế tại ngõ ra của khối PWM như hình 3.




Ví dụ:
Với value la kiểu 8bit:
%duty = (value/(PR2 +1))*100%
==> value =(duty%*(PR2+1))/100% 
(value = 128 = 50% duty)
Với value kiểu 16bit:
%duty = (value & 1023)/(4*(PR2 +1))*100%
Một số điểm cần chú ý khi sử dụng khối PWM:

  • Timer2 có hai bộ chia tần số prescaler và postscaler. Tuy nhiên bộ postscaler không được sử dụng trong quá trình điều chế độ rộng xung của khối PWM.
  • Nếu thời gian duty cycle dài hơn thời gian chu kì xung period thì xung ngõ ra tiếp tục được giữ ở mức cao sau khi giá trị PR2 bằng với giá trị TMR2.

III. CCP (Capture/Compare/PWM) trong CCS
 - Xác định chu kì: 

setup_timer_2(Prescaler,PR2,postscaler); 

Mode: có thể kết hợp với nhau bằng đấu “ | ”

- T2_DISABLED: tắt hoạt động của Timer2    
- T2_DIV_BY_1: Sử dụng bộ chia tần với tỉ lệ 1:1 
- T2_DIV_BY_4: Sử dụng bộ chia tần với tỉ lệ 1:4
- T2_DIV_BY_16: Sử dụng bộ chia tần với tỉ lệ 1:16
Period: số nguyên từ 0_255 xác định giá trị xung reset
Postcale: xác định số reset trước khi ngắt
Xem thêm các lệnh tại bài viết Timer/Counter

- Thiết lập PWM:
setup_CCPx(mode);

Dùng trước tiên để thiết lập chế độ hoạt động hãy vô hiệu hóa các chức năng của CCPx

  • X: tên chân CCP trên vdk (pic16f877a là RC1-CCP2, RC2-CCP1)
  • Mode: CCP_PWM (bật chế độ PWM)
- Xác định độ rộng xung (duty)

set_CCPx_duty(value);

  • X: tên chân CCP tren vdk
  • Value: giá trị 8bit hay 16bit, nó sẽ ghi 10bit vào thanh ghi CCPx, nếu value chỉ có 8bit thì nó sẽ dịch thêm 2bit nữa để đủ 10bit nạo vào CCPx. Tùy vào độ phân giải của value không phải lúc nào cũng đạt tới giá trị 1023. 
VD1: sau sẽ tạo ra xung tần số 100khz với độ rộng xung là 30%.

void main(){    
    unsigned char str[20];    
    LCD_Init();   
    sprintf(str,"DEMO PWM");   
    delay_ms(10);   
    LCD_Puts(str);   
    delay_ms(1000);   
    LCD_Clear();   
    sprintf(str,"beelab.info");   
    LCD_Gotoxy(0,0);   
    LCD_Puts(str);  
    setup_timer_2(T2_DIV_BY_1,49,1); 
    setup_ccp1(CCP_PWM);
    set_pwm1_duty(15);
    while(TRUE) { }
    
                     

VD2: sau sẽ tạo ra xung tần số 20khz với độ rộng xung là thay đổi (OSC=20MHz)

#include <lcd.c>
int16 duty;
void main(){   
setup_timer_2(T2_DIV_BY_1,249,1);      //50.0 us ~ f=0.02MHz ~ f= 20 kHz   //chu ki PWM = (PR2 (8bit) + 1)*4*Tosc * ti le chia TMR2 
setup_ccp1(CCP_PWM); 
set_pwm1_duty(512);//1024*25%    
lcd_init();    
while(TRUE)   {      //TODO: User Code     
    for(int i=0;i<100;i++)      {       
        duty=duty+10;         
        set_pwm1_duty(duty);         
        delay_ms(50);     
        }     
    duty=0;   
    }
}

Link code