- Wat is een PWM-signaal?
- PIC programmeren om PWM op GPIO-pinnen te genereren
- Schakelschema
- Simulatie
- Hardware-instellingen voor het besturen van servomotor met behulp van PIC-microcontroller
PWM-signaalgeneratie is een essentieel hulpmiddel in elk arsenaal van embedded ingenieurs, ze zijn erg handig voor veel toepassingen zoals het regelen van de positie van de servomotor, het schakelen van een paar vermogenselektronische IC's in converters / invertors en zelfs voor een eenvoudige LED-helderheidsregeling. In PIC-microcontrollers kunnen PWM-signalen worden gegenereerd met behulp van de Compare, Capture en PWM (CCP) -modules door de vereiste registers in te stellen, we hebben al geleerd hoe we dat moeten doen in de PIC PWM-tutorial. Maar er is een aanzienlijk nadeel aan die methode.
De PIC16F877A kan alleen PWM-signalen genereren op de pinnen RC1 en RC2, als we de CCP-modules gebruiken. Maar we kunnen situaties tegenkomen waarin we meer pinnen nodig hebben om PWM-functionaliteit te hebben. In mijn geval wil ik bijvoorbeeld 6 RC-servomotoren aansturen voor mijn robotarmproject waarvoor de CCP-module hopeloos is. In deze scenario's kunnen we de GPIO-pinnen programmeren om PWM-signalen te produceren met behulp van timermodules. Op deze manier kunnen we zoveel PWM-signalen genereren met elke gewenste pin. Er zijn ook andere hardware-hacks zoals het gebruik van een multiplexer-IC, maar waarom zou u in hardware investeren als hetzelfde kan worden bereikt met programmeren? Dus in deze tutorial zullen we leren hoe we een PIC GPIO-pin in een PWM-pin kunnen converteren en om deze te testen zullen we deze simuleren op proteus met een digitale oscilloscoop en ookcontroleer de positie van de servomotor met behulp van het PWM-signaal en varieer de inschakelduur door een potentiometer te variëren.
Wat is een PWM-signaal?
Laten we, voordat we ingaan op de details, een beetje opfrissen over wat PWM-signalen zijn. Pulsbreedtemodulatie (PWM) is een digitaal signaal dat het meest wordt gebruikt in regelcircuits. Dit signaal wordt hoog (5v) en laag (0v) ingesteld in een vooraf gedefinieerde tijd en snelheid. De tijd dat het signaal hoog blijft, wordt de "aan-tijd" genoemd en de tijd dat het signaal laag blijft, wordt de "uit-tijd" genoemd. Er zijn twee belangrijke parameters voor een PWM, zoals hieronder besproken:
Inschakelduur van de PWM
Het percentage van de tijd waarin het PWM-signaal HOOG (op tijd) blijft, wordt de duty-cycle genoemd. Als het signaal altijd AAN is, is het in 100% inschakelduur en als het altijd uit is, is het 0% inschakelduur.
Duty Cycle = Inschakeltijd / (Inschakeltijd + Uitschakeltijd)
Variabele naam |
Verwijst naar |
PWM_Frequency |
Frequentie van het PWM-signaal |
T_TOTAL |
Totale tijd die nodig is voor een volledige cyclus van PWM |
TON |
Op tijd van het PWM-signaal |
T_OFF |
Uitschakeltijd van het PWM-signaal |
Arbeidscyclus |
Duty-cycle van het PWM-signaal |
Laten we nu eens rekenen.
Dit zijn de standaardformules waarbij frequentie simpelweg het omgekeerde is van tijd. De waarde van de frequentie moet worden bepaald en ingesteld door de gebruiker op basis van zijn / haar toepassingsvereiste.
T_TOTAL = (1 / PWM_Frequency)
Wanneer de gebruiker de duty cycle-waarde wijzigt, moet ons programma automatisch de T_ON-tijd en T_OFF-tijd overeenkomstig aanpassen. De bovenstaande formules kunnen dus worden gebruikt om T_ON te berekenen op basis van de waarde van Duty_Cycle en T_TOTAL.
T_ON = (Duty_Cycle * T_TOTAL) / 100
Omdat de totale tijd van het PWM-signaal voor een volledige cyclus de som is van de tijd aan en uit. We kunnen de uitschakeltijd T_OFF berekenen zoals hierboven weergegeven.
T_OFF = T_TOTAL - T_ON
Met deze formules in gedachten kunnen we beginnen met het programmeren van de PIC-microcontroller. Het programma omvat de PIC-timermodule en de PIC ADC-module om een PWM-signaal te creëren op basis van een variërende werkcyclus volgens de ADC-waarde van de POT. Als u deze modules nog niet eerder hebt gebruikt, wordt het ten zeerste aanbevolen om de betreffende tutorial te lezen door op de hyperlinks te klikken.
PIC programmeren om PWM op GPIO-pinnen te genereren
Het complete programma voor deze tutorial is zoals altijd onderaan de website te vinden. Laten we in dit gedeelte begrijpen hoe het programma eigenlijk is geschreven. Zoals alle programma's beginnen we met het instellen van de configuratiebits. Ik heb de optie voor geheugenweergaven gebruikt om het voor mij in te stellen.
// CONFIG #pragma config FOSC = HS // Oscillator Selectie bits (HS oscillator) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT uitgeschakeld) #pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT uitgeschakeld) #pragma config BOREN = ON // Brown-out Reset Enable bit (BOR ingeschakeld) #pragma config LVP = OFF // Laagspanning (enkele voeding) In-Circuit Serial Programming Enable bit (RB3 is digitale I / O, HV op MCLR moet worden gebruikt voor het programmeren) #pragma config CPD = OFF // Data EEPROM-geheugencodebeschermingsbit (Data EEPROM- codebescherming uit) #pragma config WRT = OFF // Flash-programmageheugen Schrijven inschakelen bits (schrijfbeveiliging uit; naar alle programmageheugen kan worden geschreven door EECON-besturing) #pragma config CP = OFF // Flash-programmageheugencodebeschermingsbit ( codebescherming uit) // #pragma-configuratie-instructies moeten voorafgaan aan het projectbestand include. // Gebruik projectenums in plaats van #define voor AAN en UIT. # omvatten
Vervolgens noemen we de klokfrequentie die in de hardware wordt gebruikt, hier gebruikt mijn hardware 20MHz-kristal, u kunt de waarde invoeren op basis van uw hardware. Gevolgd door dat is de frequentiewaarde van het PWM-signaal. Aangezien het mijn doel hier is om een hobby RC-servomotor te besturen die een PWM-frequentie van 50Hz vereist, heb ik 0,05KHz ingesteld als de frequentiewaarde.U kunt dit ook wijzigen op basis van uw toepassingsvereisten.
#define _XTAL_FREQ 20000000 #define PWM_Frequency 0.05 // in KHz (50Hz)
Nu we de waarde van Frequentie hebben, kunnen we de T_TOTAL berekenen met behulp van de hierboven besproken formules. Het resultaat wordt met 10 gedoken om de waarde van tijd in milliseconden te krijgen. In mijn geval is de waarde van T_TOTAL 2 milli seconden.
int T_TOTAL = (1 / PWM_Frequency) / 10; // bereken de totale tijd op basis van frequentie (in milli sec)) // 2msec
Vervolgens initialiseren we de ADC-modules voor het lezen van de positie van de potentiometer, zoals besproken in onze ADC PIC-tutorial. Vervolgens hebben we de Interrupt-serviceroutine die elke keer wordt aangeroepen, de timer loopt over, we komen hier later op terug, laten we nu de hoofdfunctie bekijken.
Binnen de hoofdfunctie configureren we de timermodule. Hier heb ik de timermodule geconfigureerd om voor elke 0,1 ms over te lopen. De waarde voor de tijd kan worden berekend met behulp van onderstaande formules
RegValue = 256 - ((Delay * Fosc) / (Prescalar * 4)) vertraging in sec en Fosc in hz
In mijn geval zou voor een vertraging van 0,0001 seconden (0,1 ms) met prescalar van 64 en Fosc van 20 MHz de waarde van mijn register (TMR0) 248 moeten zijn. Dus de configuratie ziet er als volgt uit
/ ***** Poortconfiguratie voor timer ****** / OPTION_REG = 0b00000101; // Timer0 met externe freq en 64 als prescalar // Activeert ook PULL UPs TMR0 = 248; // Laad de tijdwaarde voor 0.0001s; delayValue kan tussen 0-256 liggen alleen TMR0IE = 1; // Schakel timer-interruptbit in PIE1-register GIE = 1 in; // Schakel Global Interrupt PEIE = 1 in; // Schakel de perifere onderbreking in / *********** ______ *********** /
Dan moeten we de Input en Output configuratie instellen. Hier gebruiken we de AN0-pin voor het lezen van de ADC-waarde en PORTD-pinnen om de PWM-signalen uit te voeren. Dus start ze als uitvoerpinnen en maak ze laag door de onderstaande coderegels te gebruiken.
/ ***** Poortconfiguratie voor I / O ****** / TRISD = 0x00; // Instrueer de MCU dat alle pinnen op PORT D worden uitgevoerd PORTD = 0x00; // Initialiseer alle pinnen naar 0 / *********** ______ *********** /
Binnen de oneindige while- lus moeten we de waarde van on time (T_ON) uit de duty-cycle berekenen. De aan-tijd- en inschakelduur variëren op basis van de positie van de POT, dus we doen dit herhaaldelijk binnen de while- lus, zoals hieronder wordt weergegeven. 0,0976 is de waarde die moet worden vermenigvuldigd met 1024 om 100 te krijgen en om T_ON te berekenen hebben we deze vermenigvuldigd met 10 om de waarde in milliseconden te krijgen.
while (1) { POT_val = (ADC_Read (0)); // Lees de waarde van POT met behulp van ADC Duty_cycle = (POT_val * 0.0976); // Kaart 0 tot 1024 tot 0 tot 100 T_ON = ((Duty_cycle * T_TOTAL) * 10/100); // Bereken op tijd met behulp van formules-eenheid in milli seconden __delay_ms (100); }
Aangezien de timer is ingesteld op overflow voor elke 0,1 ms, wordt de timeronderbrekingsserviceroutine ISR elke 0,1 ms aangeroepen. Binnen de serviceroutine gebruiken we een variabele met de naam count en verhogen deze voor elke 0.1ms. Op deze manier kunnen we de tijd bijhouden. Volg de links voor meer informatie over Interrupts in PIC-microcontroller
if (TMR0IF == 1) // Timervlag is geactiveerd vanwege timeroverloop -> ingesteld op overloop voor elke 0,1 ms { TMR0 = 248; // Laad de timerwaarde TMR0IF = 0; // Wis timer-interruptvlaggetelling ++; // Telstappen voor elke 0,1 ms -> tel / 10 geeft de waarde van het aantal in ms }
Eindelijk is het tijd om de GPIO-pin om te schakelen op basis van de waarde van T_ON en T_OFF. We hebben de telvariabele die de tijd in milliseconden bijhoudt. Dus we gebruiken die variabele om te controleren of de tijd korter is dan op tijd , zo ja, dan houden we de GPIO-pin ingeschakeld, anders zetten we hem uit en houden hem uit tot de nieuwe cyclus begint. Dit kan worden gedaan door het te vergelijken met de totale tijd van één PWM-cyclus. De code om hetzelfde te doen, wordt hieronder weergegeven
if (count <= (T_ON)) // If tijd minder dan op tijd RD1 = 1; // Schakel GPIO anders RD1 = 0 in; // Schakel anders GPIO uit als (count> = (T_TOTAL * 10)) // Houd het uitgeschakeld totdat een nieuwe cyclus begint count = 0;
Schakelschema
Het schakelschema voor het genereren van PWM met GPIO-pin van PIC-microcontroller is heel eenvoudig, voed gewoon de PIC met oscillator en sluit de potentiometer aan op pin AN0 en Servomotor op pin RD1, we kunnen GPIO-pin gebruiken om het PWM-signaal te krijgen, ik heb geselecteerd RD1 gewoon niet willekeurig. Zowel de potentiometer als de servomotor worden aangedreven door 5V die wordt geregeld vanaf de 7805 zoals hieronder weergegeven in het schakelschema.
Simulatie
Om het project te simuleren heb ik mijn proteus-software gebruikt. Bouw het onderstaande circuit en koppel de code aan je simulatie en voer het uit. U zou een PWM-signaal op de RD1 GPIO-pin moeten krijgen volgens ons programma en de duty-cycle van de PWM moet worden geregeld op basis van de positie van de potentiometer. De onderstaande GIF laat zien hoe het PWM-signaal en de servomotor reageren wanneer de ADC-waarde wordt gewijzigd via de potentiometer.
Hardware-instellingen voor het besturen van servomotor met behulp van PIC-microcontroller
Mijn complete hardware set-up wordt hieronder getoond, voor mensen die mijn tutorials volgen, zou dit board er bekend uit moeten zien, het is hetzelfde board dat ik tot nu toe in al mijn tutorials heb gebruikt. U kunt de Knipperende LED-zelfstudie raadplegen als u wilt weten hoe ik deze heb gebouwd. Volg anders gewoon het bovenstaande schakelschema en alles zou goed moeten werken.
Upload het programma en verander de potentiometer en je zou de servo de positie moeten zien veranderen op basis van de positie van de potentiometer. De volledige werking van het project wordt getoond in de video aan het einde van deze pagina. Ik hoop dat je het project hebt begrepen en met plezier hebt gebouwd, als je katernen hebt, plaats ze dan gerust op het forum en ik zal mijn best doen om te antwoorden.
Ik ben van plan om dit project voort te zetten door opties toe te voegen om meerdere servomotoren te besturen en er zo een robotarm van te bouwen, vergelijkbaar met de Arduino Robotic Arm die we al hebben gebouwd. Dus tot dan, zie je !!