- Hva er et PWM-signal?
- Programmering av PIC for å generere PWM på GPIO Pins
- Kretsdiagram
- Simulering
- Maskinvareoppsett for styring av servomotor ved bruk av PIC Microcontroller
PWM-signalgenerering er et viktig verktøy i alle innebygde ingeniørarsenaler, de er veldig nyttige for mange applikasjoner som å kontrollere posisjonen til servomotoren, bytte noen få elektroniske IC-er i omformere / inverter og til og med for en enkel LED-lysstyrkekontroll. I PIC-mikrokontrollere kan PWM-signaler genereres ved hjelp av sammenlignings-, fangst- og PWM (CCP) -modulene ved å sette de nødvendige registerene, vi har allerede lært hvordan du gjør det i PIC PWM-opplæringen. Men det er en betydelig ulempe med den metoden.
Den PIC16F877A kan generere PWM-signaler på pinnene RC1 og RC2, hvis vi bruker CCP moduler. Men vi kan støte på situasjoner der vi trenger flere pins for å ha PWM-funksjonalitet. For eksempel i mitt tilfelle, vil jeg kontrollere 6 RC-servomotorer for robotarmprosjektet mitt som CCP-modulen er håpløs. I disse scenariene kan vi programmere GPIO-pinnene for å produsere PWM-signaler ved hjelp av tidsmoduler. På denne måten kan vi generere så mange PWM-signaler med hvilken som helst PIN-kode. Det er også andre maskinvarehack som å bruke en multiplexer IC, men hvorfor investere på maskinvare når det samme kan oppnås gjennom programmering. Så i denne opplæringen vil vi lære å konvertere en PIC GPIO-pin til en PWM-pin, og for å teste den, vil vi simulere den på proteus med digitalt oscilloskop og ogsåkontrollere posisjonen til servomotoren ved hjelp av PWM-signalet og variere driftssyklusen ved å variere et potensiometer.
Hva er et PWM-signal?
Før vi kommer inn i detaljene, la oss pusse opp litt på hva PWM-signaler er. Pulse Width Modulation (PWM) er et digitalt signal som oftest brukes i kontrollkretser. Dette signalet er satt høyt (5v) og lavt (0v) i en forhåndsdefinert tid og hastighet. Tiden der signalet holder seg høyt kalles "på tid" og tiden som signalet holder seg lavt kalles "av-tid". Det er to viktige parametere for en PWM som diskutert nedenfor:
Driftssyklus for PWM
Prosentandelen av tid PWM-signalet forblir HØY (i tide) kalles som driftssyklus. Hvis signalet alltid er PÅ, er det i 100% driftssyklus, og hvis det alltid er av, er det 0% driftssyklus.
Driftssyklus = Slå på tid / (Slå på tid + slå av tid)
Variabelnavn |
Refererer til |
PWM_Frekvens |
Frekvens av PWM-signalet |
T_TOTAL |
Total tid det tar for en komplett syklus med PWM |
TONN |
På tidspunktet for PWM-signalet |
T_OFF |
Av-tid for PWM-signalet |
Duty_cycle |
PWM-signalets driftssyklus |
Så nå, la oss gjøre matte.
Dette er standardformlene der frekvensen ganske enkelt er gjensidig av tid. Verdien av frekvens må bestemmes og stilles av brukeren basert på hans / hennes applikasjonskrav.
T_TOTAL = (1 / PWM_Frekvens)
Når brukeren endrer driftssyklusverdien, bør vårt program automatisk justere T_ON-tiden og T_OFF-tiden i henhold til det. Så formlene ovenfor kan brukes til å beregne T_ON basert på verdien av Duty_Cycle og T_TOTAL.
T_ON = (Duty_Cycle * T_TOTAL) / 100
Siden den totale tiden for PWM-signalet for en hel syklus vil være summen av tid og av-tid. Vi kan beregne av-tiden T_OFF som vist ovenfor.
T_OFF = T_TOTAL - T_ON
Med disse formlene i tankene kan vi begynne å programmere PIC-mikrokontrolleren. Programmet involverer PIC Timer Module og PIC ADC Module for å lage et PWM-signal basert med en varierende driftssyklus i henhold til ADC-verdien fra POT. Hvis du ikke har brukt disse modulene, anbefales det sterkt å lese den aktuelle veiledningen ved å klikke på hyperkoblingene.
Programmering av PIC for å generere PWM på GPIO Pins
Hele programmet for denne opplæringen finner du nederst på nettstedet som alltid. La oss i denne delen forstå hvordan programmet egentlig er skrevet. Som alle programmer begynner vi med å sette konfigurasjonsbiter. Jeg har brukt minnevisningsalternativet for å stille det for meg.
// CONFIG #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) # pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT deaktivert) #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 is digital I / O, HV på MCLR må brukes for 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; alt programminnet kan skrives til av EECON-kontroll) #pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off) // #pragma config statements should preceding project project includes. // Bruk prosjekt-enums i stedet for #define for ON og OFF. #inkludere
Så nevner vi klokkefrekvensen som brukes i maskinvaren, her bruker maskinvaren min 20MHz krystall, du kan angi verdien basert på maskinvaren din. Etterfulgt av det er frekvensverdien til PWM-signalet. Siden mitt mål her er det å kontrollere en hobby RC servomotor som krever en PWM-frekvens på 50Hz, har jeg satt 0,05 KHz som frekvensverdien. Du kan også endre dette basert på applikasjonskravene dine.
#define _XTAL_FREQ 20000000 #define PWM_Frequency 0.05 // in KHz (50Hz)
Nå som vi har verdien av Frekvens, kan vi beregne T_TOTAL ved hjelp av de ovenfor diskuterte formlene. Resultatet dykkes med 10 for å få verdien av tiden i milli sekunder. I mitt tilfelle vil verdien T_TOTAL være 2 milli sekunder.
int T_TOTAL = (1 / PWM_Frequency) / 10; // beregne Total tid fra frekvens (i milli sek)) // 2msec
Etterfulgt av det initialiserer vi ADC-modulene for å lese posisjonen til potensiometeret som diskutert i vår ADC PIC-opplæring. Neste har vi avbruddsrutinen som blir ringt hver gang, timeren flyter over, vi kommer tilbake til dette senere, for nå, la oss sjekke hovedfunksjonen.
Inne i hovedfunksjonen konfigurerer vi timermodulen. Her har jeg konfigurert Timer-modulen til å flyte for hver 0,1 ms. Verdien for tiden kan beregnes ved hjelp av formlene nedenfor
RegValue = 256 - ((Delay * Fosc) / (Prescalar * 4)) forsinkelse i sek og Fosc i hz
I mitt tilfelle for en forsinkelse på 0,0001 sekunder (0,1 ms) med prescalar på 64 og Fosc på 20 MHz, skal verdien til registeret mitt (TMR0) være 248. Så konfigurasjonen ser slik ut
/ ***** Portkonfigurasjon for tidtaker ****** / OPTION_REG = 0b00000101; // Timer0 med ekstern freq og 64 som prescalar // Aktiverer også PULL UPs TMR0 = 248; // Last inn tidsverdien for 0,0001s; delayValue kan være mellom 0-256 bare TMR0IE = 1; // Aktiver tidsavbruddsbit i PIE1-registeret GIE = 1; // Aktiver Global Interrupt PEIE = 1; // Aktiver perifer interrupt / *********** ______ *********** /
Da må vi stille inn- og utgangskonfigurasjonen. Her bruker vi AN0-pinnen for å lese ADC-verdien og PORTD-pinnene for å sende ut PWM-signalene. Så start dem som utgangspinner og gjør dem lave ved å bruke kodelinjene nedenfor.
/ ***** Portkonfigurasjon for I / O ****** / TRISD = 0x00; // Instruer MCU at alle pinner på PORT D er utgang PORTD = 0x00; // Initialiser alle pinnene til 0 / *********** ______ *********** /
Inne i den uendelige mens sløyfen må vi beregne verdien på tid (T_ON) fra driftssyklusen. Den på tid og plikt syklus varierer basert på posisjonen til POT slik at vi gjør det gjentatte ganger innenfor mens sløyfen som vist nedenfor. 0,0976 er verdien som må multipliseres med 1024 for å få 100 og for å beregne T_ON har vi multiplisert den med 10 for å få verdi i milli sekunder.
mens (1) { POT_val = (ADC_Read (0)); // Les verdien av POT ved hjelp av ADC Duty_cycle = (POT_val * 0.0976); // Kart 0 til 1024 til 0 til 100 T_ON = ((Duty_cycle * T_TOTAL) * 10/100); // Beregn tid med formelenhet i milli sekunder __delay_ms (100); }
Siden timeren er innstilt på overstrøm for hver 0,1 ms, vil tidsavbruddsrutinen ISR kalles for hver 0,1 ms. Inne i servicerutinen bruker vi en variabel kalt count og øker den for hver 0,1 ms. På denne måten kan vi holde styr på tiden. For å lære mer om avbrudd i PIC-mikrokontroller, følg lenkene
hvis (TMR0IF == 1) // Tidsurflagg har blitt utløst på grunn av tidsuroverløp -> satt til overløp for hver 0,1 ms { TMR0 = 248; // Last timeren Verdi TMR0IF = 0; // Clear timer interrupt flag count ++; // Telle trinn for hver 0,1 ms -> telle / 10 vil gi verdien av teller i ms }
Endelig er det på tide å veksle GPIO-pinnen basert på verdien av T_ON og T_OFF. Vi har antallet variable som holder styr på tid i milli sekunder. Så vi bruker den variabelen for å sjekke om tiden er kortere enn i tide . Hvis ja, holder vi GPIO-pinnen slått på ellers slår vi den av og holder den slått av til den nye syklusen starter. Dette kan gjøres ved å sammenligne den med den totale tiden for en PWM-syklus. Koden for å gjøre det samme er vist nedenfor
if (count <= (T_ON)) // If time less than on time RD1 = 1; // Slå på GPIO annet RD1 = 0; // Ellers slå av GPIO hvis (count> = (T_TOTAL * 10)) // Hold den slått av til en ny syklus starter count = 0;
Kretsdiagram
Kretsskjemaet for å generere PWM med GPIO-pinne av PIC-mikrokontroller er veldig enkelt, bare slå PIC-en med oscillator og koble potensiometeret til pinnen AN0 og Servomotoren til pinnen RD1, vi kan bruke GPIO-pinnen for å få PWM-signalet, jeg har valgt RD1 bare tilfeldig. Både potensiometeret og servomotoren drives av 5V som reguleres fra 7805 som vist nedenfor i kretsskjemaet.
Simulering
For å simulere prosjektet brukte jeg proteus-programvaren min. Bygg kretsen vist nedenfor og koble koden til simuleringen din og kjør den. Du bør få et PWM-signal på RD1 GPIO-pinnen i henhold til vårt program, og driftssyklusen til PWM skal kontrolleres basert på posisjonen til potensiometeret. GIF nedenfor viser hvordan PWM-signalet og servomotoren reagerer når ADC-verdien endres gjennom potensiometeret.
Maskinvareoppsett for styring av servomotor ved bruk av PIC Microcontroller
Min komplette maskinvareoppsett er vist nedenfor, for folk som følger veiledningene mine, bør dette brettet se kjent ut, det er det samme brettet som jeg har brukt i alle veiledningene mine så langt. Du kan se Blinking LED tutorial hvis du er interessert i å vite hvordan jeg bygger den. Ellers er det bare å følge kretsskjemaet ovenfor, og alt skal fungere bra.
Last opp programmet og variér potensiometeret, så ser du at servoen endrer posisjon basert på potensiometerets posisjon. Den komplette arbeider av prosjektet er vist i videoen gitt på slutten av denne siden. Håper du forsto prosjektet og likte å bygge, hvis du har spørsmål, legg dem gjerne ut på forumet, så prøver jeg mitt beste for å svare.
Jeg planlegger å ta dette prosjektet videre ved å legge til alternativer for å kontrollere flere servomotorer og dermed bygge en robotarm ut av den, i likhet med Arduino Robotic Arm som vi allerede har bygget. Så til da, se deg !!