- Hvad er et PWM-signal?
- Programmering af PIC til at generere PWM på GPIO Pins
- Kredsløbsdiagram
- Simulation
- Hardwareopsætning til styring af servomotor ved hjælp af PIC Microcontroller
PWM-signalgenerering er et vigtigt værktøj i ethvert integreret ingeniørarsenal, de er meget nyttige til mange applikationer som styring af servomotorens position, skift af få elektroniske IC'er til omformere / inverter og endda til en simpel LED-lysstyringskontrol. I PIC-mikrocontrollere kan PWM-signaler genereres ved hjælp af sammenlignings-, capture- og PWM- modulerne (CCP) ved at indstille de krævede registre, vi har allerede lært, hvordan man gør det i PIC PWM-tutorial. Men der er en betydelig ulempe ved denne metode.
Den PIC16F877A kan generere PWM-signaler kun på ben RC1 og RC2, hvis vi bruger de CCP moduler. Men vi kan støde på situationer, hvor vi har brug for flere ben for at have PWM-funktionalitet. For eksempel i mit tilfælde vil jeg kontrollere 6 RC-servomotorer til mit robotarmprojekt, som CCP-modulet er håbløst for. I disse scenarier kan vi programmere GPIO-benene til at producere PWM-signaler ved hjælp af timermoduler. På denne måde kan vi generere så mange PWM-signaler med enhver ønsket pin. Der er også andre hardware-hacks som at bruge en multiplexer-IC, men hvorfor investere i hardware, når det samme kan opnås gennem programmering. Så i denne vejledning lærer vi, hvordan man konverterer en PIC GPIO-pin til en PWM-pin, og for at teste den simulerer vi den på proteus med digitalt oscilloskop og ogsåstyr servomotorens position ved hjælp af PWM-signalet og varier dens driftscyklus ved at variere et potentiometer.
Hvad er et PWM-signal?
Før vi går ind i detaljerne, lad os pusse lidt op om, hvad PWM-signaler er. Pulse Width Modulation (PWM) er et digitalt signal, der oftest bruges i kontrolkredsløb. Dette signal er indstillet højt (5v) og lavt (0v) i en foruddefineret tid og hastighed. Den tid, hvor signalet forbliver højt, kaldes "til tiden" og den tid, hvor signalet forbliver lavt, kaldes "slukketid". Der er to vigtige parametre for en PWM som beskrevet nedenfor:
PWM's driftscyklus
Den procentdel af tid, hvor PWM-signalet forbliver HØJ (til tiden) kaldes som driftscyklus. Hvis signalet altid er TIL, er det i 100% driftscyklus, og hvis det altid er slukket, er det 0% driftscyklus.
Arbejdscyklus = Tænd tid / (Tænd tid + Sluk tid)
Variabelt navn |
Hentyder til |
PWM_Frekvens |
Frekvens af PWM-signalet |
T_TOTAL |
Samlet tid taget for en komplet PWM-cyklus |
TON |
Til tiden for PWM-signalet |
T_OFF |
Slukketid for PWM-signalet |
Duty_cykel |
PWM-signalets driftscyklus |
Så nu, lad os lave matematikken.
Dette er standardformlerne, hvor frekvens simpelthen er gensidig af tid. Værdien af frekvensen skal bestemmes og indstilles af brugeren på baggrund af hans / hendes ansøgningskrav.
T_TOTAL = (1 / PWM_Frekvens)
Når brugeren ændrer driftscyklusværdien, skal vores program automatisk justere T_ON-tiden og T_OFF-tiden efter det. Så ovenstående formler kan bruges til at beregne T_ON baseret på værdien af Duty_Cycle og T_TOTAL.
T_ON = (Duty_Cycle * T_TOTAL) / 100
Da den samlede tid for PWM-signalet for en hel cyklus er summen af tid til og fra. Vi kan beregne slukketiden T_OFF som vist ovenfor.
T_OFF = T_TOTAL - T_ON
Med disse formler i tankerne kan vi begynde at programmere PIC-mikrocontrolleren. Programmet involverer PIC-timermodulet og PIC ADC-modulet til at skabe et PWM-signal baseret på en varierende driftscyklus i henhold til ADC-værdien fra POT. Hvis du er ny med at bruge disse moduler, anbefales det stærkt at læse den relevante vejledning ved at klikke på hyperlinks.
Programmering af PIC til at generere PWM på GPIO Pins
Det komplette program til denne tutorial kan findes nederst på hjemmesiden som altid. Lad os i dette afsnit forstå, hvordan programmet faktisk er skrevet. Som alle programmer begynder vi med at indstille konfigurationsbits. Jeg har brugt hukommelsesvisningsmuligheden til at indstille den til mig.
// CONFIG #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT deaktiveret) # pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT deaktiveret) #pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled) #pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 er digital I / O, HV på MCLR skal bruges til programmering) #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; al programhukommelse kan skrives til af EECON-kontrol) #pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off) // #pragma config statements should be preceding project file includes. // Brug projekt-enums i stedet for #define til ON og OFF. #omfatte
Derefter nævner vi urfrekvensen, der bruges i hardwaren, her bruger min hardware 20MHz krystal, du kan indtaste værdien baseret på din hardware. Efterfulgt af det er PWM-signalets frekvensværdi. Siden mit mål her er det at styre en hobby RC servomotor, der kræver en PWM-frekvens på 50Hz, har jeg indstillet 0,05 KHz som frekvensværdi, du kan også ændre dette baseret på dine applikationskrav.
#define _XTAL_FREQ 20000000 #define PWM_Frequency 0.05 // in KHz (50Hz)
Nu hvor vi har værdien af Frekvens, kan vi beregne T_TOTAL ved hjælp af de ovenfor diskuterede formler. Resultatet dykkes med 10 for at få værdien af tiden i millisekunder. I mit tilfælde er værdien af T_TOTAL 2 milli sekunder.
int T_TOTAL = (1 / PWM_Frekvens) / 10; // beregne total tid fra frekvens (i milli sek)) // 2 msek
Efterfulgt af det initialiserer vi ADC-modulerne til aflæsning af potentiometerets position som beskrevet i vores ADC PIC-tutorial. Dernæst har vi afbrydelsesrutinen, som kaldes hver gang, timeren løber over, vi kommer tilbage til dette senere, lad os nu kontrollere hovedfunktionen.
Inde i hovedfunktionen konfigurerer vi timermodulet. Her har jeg konfigureret Timer-modulet til at løbe for hver 0,1 ms. Værdien for tiden kan beregnes ved hjælp af nedenstående formler
RegValue = 256 - ((Delay * Fosc) / (Prescalar * 4)) forsinkelse i sek og Fosc i hz
I mit tilfælde med en forsinkelse på 0,0001 sekunder (0,1 ms) med prescalar på 64 og Fosc på 20 MHz skal værdien af mit register (TMR0) være 248. Så konfigurationen ser sådan ud
/ ***** Portkonfiguration til timer ****** / OPTION_REG = 0b00000101; // Timer0 med ekstern freq og 64 som prescalar // Aktiverer også PULL UPs TMR0 = 248; // Indlæs tidsværdien for 0,0001s; delayValue kan være mellem 0-256 kun TMR0IE = 1; // Aktivér timerinterruptbit i PIE1-registeret GIE = 1; // Aktiver Global Interrupt PEIE = 1; // Aktivér den perifere afbrydelse / *********** ______ *********** /
Derefter er vi nødt til at indstille input- og outputkonfigurationen. Her bruger vi AN0-stiften til at læse ADC-værdien og PORTD-stifter til at udsende PWM-signalerne. Så start dem som outputstifter og lav dem lave ved hjælp af nedenstående kodelinjer.
/ ***** Portkonfiguration til I / O ****** / TRISD = 0x00; // Instruer MCU'en om, at alle ben på PORT D er output PORTD = 0x00; // Initialiser alle ben til 0 / *********** ______ *********** /
Inde i den uendelige mens sløjfe skal vi beregne værdien af til tiden (T_ON) fra driftscyklussen. Den til tiden og duty cycle varierer baseret på placeringen af POT så vi gør det gentagne gange inde i mens løkken som vist nedenfor. 0,0976 er den værdi, der skal ganges med 1024 for at få 100, og for at beregne T_ON har vi ganget den med 10 for at få værdi i milli sekunder.
mens (1) { POT_val = (ADC_Read (0)); // Læs værdien af POT ved hjælp af ADC Duty_cycle = (POT_val * 0,0976); // Kort 0 til 1024 til 0 til 100 T_ON = ((Duty_cycle * T_TOTAL) * 10/100); // Beregn tid med formlenheden i milli sekunder __delay_ms (100); }
Da timeren er indstillet til overstrøm for hver 0,1 ms, kaldes timer-afbrydelsesrutinen ISR for hver 0,1 ms. Inde i servicerutinen bruger vi en variabel kaldet count og øger den for hver 0,1 ms. På denne måde kan vi holde styr på tid. Hvis du vil lære mere om afbrydelser i PIC-mikrocontroller, skal du følge linkene
hvis (TMR0IF == 1) // Timer-flag er udløst på grund af timeroverløb -> indstillet til overløb for hver 0,1 ms { TMR0 = 248; // Indlæs timeren Værdi TMR0IF = 0; // Ryd timer afbryde flagantal ++; // Tællingsforøgelser for hver 0,1 ms -> tæller / 10 giver værdien af tællingen i ms }
Endelig er det tid til at skifte GPIO-pin baseret på værdien af T_ON og T_OFF. Vi har tællevariablen, der holder styr på tiden i millisekunder. Så vi bruger den variabel til at kontrollere, om tiden er mindre end til tiden , hvis ja, så holder vi GPIO-stiften tændt ellers slukker vi den og holder den slukket, indtil den nye cyklus starter. Dette kan gøres ved at sammenligne det med den samlede tid for en PWM-cyklus. Koden til at gøre det samme vises nedenfor
if (count <= (T_ON)) // If time less than on time RD1 = 1; // Tænd GPIO ellers RD1 = 0; // Sluk ellers GPIO hvis (count> = (T_TOTAL * 10)) // Hold den slået fra, indtil en ny cyklus starter count = 0;
Kredsløbsdiagram
Kredsløbsdiagrammet til at generere PWM med GPIO-pin af PIC-mikrocontroller er virkelig enkel, bare tænd PIC med oscillator og tilslut potentiometeret til pin AN0 og Servomotor til pin RD1, vi kan bruge GPIO-pin til at få PWM-signalet, jeg har valgt RD1 bare tilfældigt. Både potentiometeret og servomotoren drives af 5V, som reguleres fra 7805 som vist nedenfor i kredsløbsdiagrammet.
Simulation
For at simulere projektet brugte jeg min proteus-software. Byg kredsløbet vist nedenfor og link koden til din simulation og kør den. Du skal få et PWM-signal på RD1 GPIO-stiften i henhold til vores program, og PWM's driftscyklus skal styres baseret på potentiometerets position. Nedenstående GIF viser, hvordan PWM-signalet og servomotoren reagerer, når ADC-værdien ændres gennem potentiometeret.
Hardwareopsætning til styring af servomotor ved hjælp af PIC Microcontroller
Min komplette hardwareopsætning er vist nedenfor, for folk, der følger mine tutorials, skal dette board se bekendt ud, det er det samme board, som jeg har brugt i alle mine tutorials hidtil. Du kan henvise Blinking LED tutorial, hvis du er interesseret i at vide, hvordan jeg bygger det. Ellers skal du bare følge kredsløbsdiagrammet ovenfor, og alt skal fungere fint.
Upload programmet, og varier potentiometeret, så ser du, at servoen ændrer position baseret på potentiometerets position. Den komplette bearbejdning af projektet vises i videoen, der er vist i slutningen af denne side. Håber du forstod projektet og nød at bygge, hvis du har spørgsmål, er du velkommen til at sende dem på forummet, så prøver jeg mit bedste for at svare.
Jeg planlægger at tage dette projekt frem ved at tilføje muligheder for at styre flere servomotorer og dermed bygge en robotarm ud af det, svarende til Arduino Robotic Arm, som vi allerede har bygget. Så indtil da, se dig !!