• Generating PWM using PIC Microcontroller with MPLAB and XC8 - Tạo PWM bằng Vi điều khiển PIC với MPLAB và XC8

QC

Generating PWM using PIC Microcontroller with MPLAB and XC8 - Tạo PWM bằng Vi điều khiển PIC với MPLAB và XC8

 Generating PWM using PIC Microcontroller with MPLAB and XC8 - Tạo PWM bằng Vi điều khiển PIC với MPLAB và XC8



Đây là hướng dẫn thứ 10 của chúng tôi về Học vi điều khiển PIC sử dụng MPLAB và XC8. Cho đến nay, chúng tôi đã đề cập đến nhiều hướng dẫn cơ bản như nhấp nháy LED với PIC, Bộ hẹn giờ trong PIC, giao diện LCD, giao tiếp 7 đoạn, ADC sử dụng PIC, v.v. Nếu bạn là người mới bắt đầu, vui lòng truy cập danh sách đầy đủ các hướng dẫn về PIC tại đây và bắt đầu học.


Trong hướng dẫn này, chúng ta sẽ học Cách tạo tín hiệu PWM bằng PIC PIC16F877A. MCU PIC của chúng tôi có một mô-đun đặc biệt được gọi là mô-đun So sánh Capture (CCP) có thể được sử dụng để tạo tín hiệu PWM. Ở đây, chúng tôi sẽ tạo ra PWM 5 kHz với chu kỳ nhiệm vụ thay đổi từ 0% đến 100%. Để thay đổi chu kỳ làm việc, chúng tôi đang sử dụng một chiết áp, do đó, chúng tôi khuyên bạn nên tìm hiểu hướng dẫn ADC trước khi bắt đầu với PWM. Mô-đun PWM cũng sử dụng bộ định thời để đặt tần số của nó, do đó hãy tìm hiểu cách sử dụng bộ định thời trước tại đây. Hơn nữa, trong hướng dẫn này, chúng tôi sẽ sử dụng mạch RC và đèn LED để chuyển đổi các giá trị PWM thành điện áp Analog và sử dụng nó để làm mờ đèn LED.

What is a PWM Signal?



Tần suất của một PWM:


Tần số của tín hiệu PWM xác định tốc độ PWM hoàn thành một khoảng thời gian. Một khoảng thời gian hoàn tất BẬT và TẮT tín hiệu PWM như thể hiện trong hình trên. Trong hướng dẫn của chúng tôi, chúng tôi sẽ đặt tần số 5KHz.


PWM using PIC16F877A:

Tín hiệu PWM có thể được tạo trong Vi điều khiển PIC của chúng tôi bằng cách sử dụng mô-đun CCP (So sánh Capture PWM). Độ phân giải của tín hiệu PWM của chúng tôi là 10-bit, nghĩa là đối với giá trị 0 sẽ có chu kỳ nhiệm vụ là 0% và đối với giá trị 1024 (2 ^ 10) sẽ có chu kỳ nhiệm vụ là 100%. Có hai mô-đun CCP trong MCU PIC của chúng tôi (CCP1 và CCP2), điều này có nghĩa là chúng tôi có thể tạo đồng thời hai tín hiệu PWM trên hai chân khác nhau (chân 17 và 16), trong hướng dẫn của chúng tôi, chúng tôi đang sử dụng CCP1 để tạo tín hiệu PWM trên chân 17.

Các thanh ghi sau được sử dụng để tạo tín hiệu PWM bằng MCU PIC của chúng tôi:

CCP1CON (Thanh ghi điều khiển CCP1)
T2CON (Thanh ghi điều khiển bộ định thời 2)
PR2 (Bộ định thời 2 mô-đun Đăng ký định kỳ)
CCPR1L (CCP Đăng ký 1 Thấp)

Programming PIC to generate PWM signals:

Trong chương trình của chúng tôi, chúng tôi sẽ đọc điện áp Analog 0-5v từ một chiết áp và ánh xạ nó thành 0-1024 bằng cách sử dụng mô-đun ADC của chúng tôi. Sau đó, chúng tôi tạo ra một tín hiệu PWM với tần số 5000Hz và thay đổi chu kỳ nhiệm vụ của nó dựa trên điện áp Analog đầu vào. Đó là 0-1024 sẽ được chuyển đổi thành 0% -100% Chu kỳ nhiệm vụ. Hướng dẫn này giả định rằng bạn đã học cách sử dụng ADC trong PIC, nếu chưa, hãy đọc nó từ đây, vì chúng tôi sẽ bỏ qua chi tiết về nó trong hướng dẫn này.

Vì vậy, khi các bit cấu hình được thiết lập và chương trình được viết để đọc một giá trị Analog, chúng ta có thể tiến hành PWM.

Các bước sau nên được thực hiện khi định cấu hình mô-đun CCP cho hoạt động PWM:

Đặt khoảng thời gian PWM bằng cách ghi vào thanh ghi PR2.
Đặt chu kỳ nhiệm vụ PWM bằng cách ghi vào thanh ghi CCPR1L và các bit CCP1CON <5: 4>.
Đặt chân CCP1 làm đầu ra bằng cách xóa bit TRISC <2>.
Đặt giá trị tỷ lệ đặt trước TMR2 và bật Timer2 bằng cách ghi vào T2CON.
Định cấu hình mô-đun CCP1 cho hoạt động PWM.
Có hai chức năng quan trọng trong chương trình này để tạo tín hiệu PWM. Một là hàm PWM_Initialize () sẽ khởi tạo các thanh ghi cần thiết để thiết lập mô-đun PWM và sau đó đặt tần số mà PWM sẽ hoạt động, hàm còn lại là hàm PWM_Duty () sẽ thiết lập chu kỳ nhiệm vụ của tín hiệu PWM trong các thanh ghi cần thiết.
PWM_Initialize()
{
  PR2 = (_XTAL_FREQ/(PWM_freq*4*TMR2PRESCALE)) - 1; //Setting the PR2 formulae using Datasheet // Makes the PWM work in 5KHZ
    CCP1M3 = 1; CCP1M2 = 1;  //Configure the CCP1 module 
    T2CKPS0 = 1;T2CKPS1 = 0; TMR2ON = 1; //Configure the Timer module
    TRISC2 = 0; // make port pin on C as output
}

Chức năng trên là chức năng khởi tạo PWM, trong chức năng này Mô-đun CCP1 được thiết lập để sử dụng PWM bằng cách đặt bit CCP1M3 và CCP1M2 lên cao.



Bộ đếm trước của mô-đun bộ hẹn giờ được đặt bằng cách đặt bit T2CKPS0 ở mức cao và T2CKPS1 ở mức thấp đối với bit TMR2ON được đặt để bắt đầu bộ định thời.



Bây giờ, chúng ta phải thiết lập Tần số của tín hiệu PWM. Giá trị của tần số phải được ghi vào thanh ghi PR2. Tần suất mong muốn có thể được đặt bằng cách sử dụng các công thức dưới đây

PWM Period = [(PR2) + 1] * 4 * TOSC * (TMR2 Prescale Value)
Sắp xếp lại các công thức này để có được PR2 sẽ cho
PR2 = (Period / (4 * Tosc * TMR2 Prescale )) - 1

Chúng ta biết rằng Kỳ = (1 / PWM_freq) và Tosc = (1 / _XTAL_FREQ). Vì vậy.....

PR2 = (_XTAL_FREQ/ (PWM_freq*4*TMR2PRESCALE)) – 1;

Khi tần số được thiết lập, hàm này không cần được gọi lại trừ khi và cho đến khi chúng ta cần thay đổi lại tần số. Trong hướng dẫn của chúng tôi, tôi đã gán PWM_freq = 5000; để chúng tôi có thể nhận được tần số hoạt động 5 KHz cho tín hiệu PWM của chúng tôi.


Bây giờ chúng ta hãy thiết lập chu kỳ nhiệm vụ của PWM bằng cách sử dụng hàm bên dưới


PWM_Duty(unsigned int duty)
{
      if(duty<1023)
  {

    duty = ((float)duty/1023)*(_XTAL_FREQ/(PWM_freq*TMR2PRESCALE)); // On reducing //duty = (((float)duty/1023)*(1/PWM_freq)) / ((1/_XTAL_FREQ) * TMR2PRESCALE);
    CCP1X = duty & 1; //Store the 1st bit
    CCP1Y = duty & 2; //Store the 0th bit
    CCPR1L = duty>>2;// Store the remining 8 bit
  }
}


Tín hiệu PWM của chúng tôi có độ phân giải 10 bit do đó giá trị này không thể được lưu trữ trong một thanh ghi vì PIC của chúng tôi chỉ có các đường dữ liệu 8 bit. Vì vậy, chúng tôi đã sử dụng hai bit khác của CCP1CON <5: 4> (CCP1X và CCP1Y) để lưu trữ hai LSB cuối cùng và sau đó lưu trữ 8 bit còn lại trong thanh ghi CCPR1L.


Thời gian chu kỳ nhiệm vụ PWM có thể được tính bằng cách sử dụng các công thức dưới đây:

PWM Duty Cycle = (CCPRIL:CCP1CON<5:4>) * Tosc * (TMR2 Prescale Value)
Sắp xếp lại các công thức này để nhận giá trị CCPR1L và CCP1CON sẽ cho:
CCPRIL:CCP1Con<5:4> = PWM Duty Cycle / (Tosc * TMR2 Prescale Value)

Giá trị của ADC của chúng tôi sẽ là 0-1024, chúng tôi cần giá trị đó ở 0% -100%, do đó, PWM Duty Cycle = duty / 1023. Hơn nữa, để chuyển đổi chu kỳ nhiệm vụ này thành một khoảng thời gian, chúng ta phải nhân nó với khoảng thời gian (1 / PWM_freq)


Chúng ta cũng biết rằng Tosc = (1 / PWM_freq), do đó ..


Duty = ( ( (float)duty/1023) * (1/PWM_freq) ) / ( (1/_XTAL_FREQ) * TMR2PRESCALE) ;

Giải phương trình trên sẽ cho chúng ta:

Duty = ( (float)duty/1023) * (_XTAL_FREQ / (PWM_freq*TMR2PRESCALE));

Schematics and Testing:

   Như thường lệ, chúng ta hãy xác minh kết quả đầu ra bằng cách sử dụng mô phỏng Proteus. Sơ đồ mạch được hiển thị bên dưới.



Kết nối chiết áp vào chân thứ 7 để cấp điện áp 0-5. Mô-đun CCP1 có chân 17 (RC2), ở đây PWM sẽ được tạo ra và có thể được xác minh bằng cách sử dụng Máy hiện sóng kỹ thuật số. Hơn nữa để chuyển đổi điều này thành điện áp thay đổi, chúng tôi đã sử dụng bộ lọc RC và đèn LED để xác minh đầu ra mà không có phạm vi.


Bộ lọc RC là gì?


Bộ lọc RC hay bộ lọc thông thấp là một mạch đơn giản với hai phần tử thụ động là điện trở và tụ điện. Hai thành phần này được sử dụng để lọc tần số của tín hiệu PWM và biến nó thành điện áp DC có thể thay đổi được.


Nếu ta kiểm tra mạch điện, khi đặt một hiệu điện thế thay đổi được vào đầu vào R thì tụ điện C sẽ bắt đầu tích điện. Bây giờ dựa trên giá trị của tụ điện, tụ điện sẽ mất một khoảng thời gian để được sạc đầy, sau khi được sạc nó sẽ chặn dòng điện một chiều (Hãy nhớ tụ điện chặn dòng điện một chiều nhưng cho phép dòng điện xoay chiều) do đó điện áp một chiều đầu vào sẽ xuất hiện trên đầu ra. PWM tần số cao (tín hiệu AC) sẽ được nối đất qua tụ điện. Do đó thu được một điện một chiều thuần trên tụ điện. Giá trị 1000Ohm và 1uf được tìm thấy là thích hợp cho dự án này. Tính toán các giá trị của R và C liên quan đến phân tích mạch bằng cách sử dụng hàm truyền, nằm ngoài phạm vi của hướng dẫn này.



Đầu ra của chương trình có thể được xác minh bằng Máy hiện sóng kỹ thuật số như được hiển thị bên dưới, thay đổi chiết áp và chu kỳ nhiệm vụ của PWM sẽ thay đổi. Chúng ta cũng có thể nhận thấy điện áp đầu ra của mạch RC bằng cách sử dụng Vôn kế. Nếu mọi thứ hoạt động như mong đợi, chúng tôi có thể tiến hành với phần cứng của mình. Kiểm tra thêm Video ở cuối để biết toàn bộ quy trình.



Working on Hardware:


Thiết lập phần cứng của dự án rất đơn giản, chúng tôi chỉ sử dụng lại bảng PIC Perf của chúng tôi được hiển thị bên dưới.




Đó là chúng tôi đã lập trình để đọc điện áp Analog từ POT và chuyển đổi thành tín hiệu PWM, đến lượt nó đã được chuyển đổi thành Điện áp biến bằng bộ lọc RC và kết quả được xác minh bằng phần cứng của chúng tôi. Nếu bạn có một số nghi ngờ hoặc gặp khó khăn ở đâu đó, vui lòng sử dụng phần bình luận bên dưới, chúng tôi sẽ sẵn lòng trợ giúp bạn.



CODE :


// CONFIG
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = ON         // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3/PGM pin has PGM function; low-voltage programming enabled)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

#define _XTAL_FREQ 20000000
#define TMR2PRESCALE 4

#include <xc.h>

long PWM_freq = 5000;

PWM_Initialize()
{
  PR2 = (_XTAL_FREQ/(PWM_freq*4*TMR2PRESCALE)) - 1; //Setting the PR2 formulae using Datasheet // Makes the PWM work in 5KHZ
    CCP1M3 = 1; CCP1M2 = 1;  //Configure the CCP1 module 
    T2CKPS0 = 1;T2CKPS1 = 0; TMR2ON = 1; //Configure the Timer module
    TRISC2 = 0; // make port pin on C as output
}

PWM_Duty(unsigned int duty)
{
      if(duty<1023)
  {

    duty = ((float)duty/1023)*(_XTAL_FREQ/(PWM_freq*TMR2PRESCALE)); // On reducing //duty = (((float)duty/1023)*(1/PWM_freq)) / ((1/_XTAL_FREQ) * TMR2PRESCALE);
    CCP1X = duty & 1; //Store the 1st bit
    CCP1Y = duty & 2; //Store the 0th bit
    CCPR1L = duty>>2;// Store the remining 8 bit
  }
}

void ADC_Initialize()
{
  ADCON0 = 0b01000001; //ADC ON and Fosc/16 is selected
  ADCON1 = 0b11000000; // Internal reference voltage is selected
}
unsigned int ADC_Read(unsigned char channel)
{
  ADCON0 &= 0x11000101; //Clearing the Channel Selection Bits
  ADCON0 |= channel<<3; //Setting the required Bits
  __delay_ms(2); //Acquisition time to charge hold capacitor
  GO_nDONE = 1; //Initializes A/D Conversion
  while(GO_nDONE); //Wait for A/D Conversion to complete
  return ((ADRESH<<8)+ADRESL); //Returns Result
}

void main()
{
    int adc_value;
  TRISC = 0x00; //PORTC as output
  TRISA = 0xFF; //PORTA as input
  TRISD = 0x00;
  ADC_Initialize(); //Initializes ADC Module
  PWM_Initialize();  //This sets the PWM frequency of PWM1

  do
  {
    adc_value = ADC_Read(4); //Reading Analog Channel 0 
    PWM_Duty(adc_value);
    
      __delay_ms(50); 
      
  }while(1); //Infinite Loop
  
}








Nap Code vào PY32F003 dùng Stlink

 Nap Code vào PY32F003 dùng Stlink Bước 1: Cài đặt  KeilC v5.39 theo link sau ( chú ý 5.39 keil c mới nạp ok). https://edge07.111.ir.cdn.ir/...