Spørsmål:
Øk PWM-bitoppløsningen
KoenR
2015-06-17 21:10:11 UTC
view on stackexchange narkive permalink

Jeg vil øke PWM-bitoppløsningen til Arduino Uno. For øyeblikket er den 8-bit som jeg anser for lav. Er dette mulig uten å miste muligheten for avbrudd og forsinkelser?

Koen

EDITDette oppsettet leverer en 16-biters resultat

  ugyldig oppsettPWM16 () {DDRB | = _BV (PB1) | _BV (PB2); / * sett pinner som utganger * / TCCR1A = _BV (COM1A1) | _BV (COM1B1) / * ikke-inverterende PWM * / | _BV (WGM11); / * modus 14: rask PWM, TOP = ICR1 * / TCCR1B = _BV (WGM13) | _BV (WGM12) | _BV (CS11); / * prescaler: klokke / 8 * / ICR1 = 0xffff; / * TOP-tellerverdi (frigjør OCR1A * /} / * Kommentarer til oppsettet Endring av ICR1 vil påvirke mengden oppløsningsbiter. ICR1 = 0xffff; (65535) 16-biters oppløsning ICR1 = 0x7FFF; (32767) 15-biters oppløsning ICR1 = 0x3FFF ; (16383) 14-biters oppløsning osv .... Endring av prescaler vil påvirke PWM-signalets frekvens. Frekvens [Hz} = CPU / (ICR1 + 1) hvor i dette tilfellet CPU = 16 MHz 16-bit PWM vil være>>> (16000000/8) / (65535 + 1) = 30,5175Hz * // * 16-biters versjon av analogWrite (). Fungerer bare på pinn 9 og 10. * / ugyldig analogWrite16 (uint8_t pin, uint16_t val) {bryter (pin ) {case 9: OCR1A = val; break; case 10: OCR1B = val; break;}}  
To svar:
Edgar Bonet
2015-06-17 21:19:22 UTC
view on stackexchange narkive permalink

Arduino Uno er basert på en ATmega382P mikrokontroller. Denne brikken har to 8-biters tidtakere, som kjører to PWM-kanaler hver, og en 16-biters tidtakere, som driver de to siste kanalene.

Du kan ikke øke oppløsningen til 8-biters tidtakere. Du kan imidlertid sette 16-bits tidtakeren i 16-bits modus, i stedet for 8-bit-modusen som brukes av Arduino-kjernebiblioteket. Dette gir deg to 16-biters PWM-kanaler, med en redusert frekvens på 244 Hz (maksimum). Du må sannsynligvis konfigurere timeren selv, og vil ikke dra nytte av den enkle å bruke analogWrite () -funksjonen. For detaljer, se seksjonen Timer 1 i ATmega328Pdatasheet.

Oppdatering : Her er en implementering av en 16-bits analogWrite ( ) . Itonly fungerer på pinn 9 og 10, da dette er de eneste pinnene som er koblet til 16-bits tidtakeren.

  / * Konfigurer digitale pinner 9 og 10 16-biters PWM-utganger. * / ugyldig oppsettPWM16 () {DDRB | = _BV (PB1) | _BV (PB2); / * sett pinner som utganger * / TCCR1A = _BV (COM1A1) | _BV (COM1B1) / * ikke-inverterende PWM * / | _BV (WGM11); / * modus 14: rask PWM, TOP = ICR1 * / TCCR1B = _BV (WGM13) | _BV (WGM12) | _BV (CS10); / * ingen forhåndsskalering * / ICR1 = 0xffff; / * TOP-tellerverdi * /} / * 16-biters versjon av analogWrite (). Fungerer bare på pinn 9 og 10. * / void analogWrite16 (uint8_t pin, uint16_t val) {switch (pin) {case 9: OCR1A = val; gå i stykker; tilfelle 10: OCR1B = val; gå i stykker; }}  

Du vil kanskje legge merke til at toppen av motsekvensen er konfigurert eksplisitt. Du kan endre dette til en mindre verdi for å lage PWMfaster, på bekostning av redusert oppløsning.

Og her er et eksempel på en skisse som illustrerer bruken av den:

  ugyldig oppsett () {setupPWM16 ();} / * Test: send veldig sakte sagtannbølger. * / void loop () {statisk uint16_t i; analogWrite16 (9, i);
analogWrite16 (10, 0xffff - i); i ++; forsinkelse (1);}  
Wow tusen takk, dette er akkurat det jeg trenger. Jeg vil at min PWM-resultat skal være den samme som sensoroppløsningen min. Hvis jeg endrer koden din til ville det være en 13-biters resultat? I så fall hva ville frekvensen være? Jeg skal kjøre en DC-motor med den, så 244Hz blir litt mindre antar jeg
@KoenR: Nei, prescaler har ingen innvirkning på oppløsningen, men hensikten er å redusere tellingen. Hvis du setter prescaler til 8, får du en PWM-frekvens på 30,5 Hz. Hvis du vil ha 13-biters oppløsning, sett 'ICR1' til '0x1fff', så blir frekvensen din 1953 Hz (F \ _CPU / (TOP + 1)) med en prescaler på 1.
Takk for forklaringen. Redigerte spørsmålet mitt slik at det dekker disse feilene. Så andre mennesker kan se det direkte. Takk skal du ha!
Kan jeg bruke dette med et CAN-busskjold som CS er på port 9? Er det i så fall bare å endre denne kodelinjen: DDRB | = _BV (PB1) | _BV (PB2);
Fjern `_BV (PB1)` og `_BV (COM1A1)` fra `setupPWM16 ()`, og endre deretter endring `analogWrite16 ()` slik at den _ bare_ fungerer på pin 10.
Fantastisk svar! Men ville dette fungere med en ATmega32u4 - sett på Arduino Micro?
@FlorinAndrei: Jeg kjenner ikke 32u4, men ifølge [sammendrag datablad] (http://www.atmel.com/Images/Atmel-7766-8-bit-AVR-ATmega16U4-32U4_Summary.pdf), skal det fungere, siden den har to 16-bits tidtakere og “Fire PWM-kanaler med programmerbar oppløsning fra 2 til 16 bits”.
@Edgar Bonet Dette er flott, men jeg ser ikke ut til å slå av en LED helt. Jeg bruker `ICR1 = 0x03FF` og klokken 0 ser jeg en liten puls på omfanget nok til å tenne lysdioden. Noen ideer?
@davivid: Ja, du kan ikke ha null-syklus. `analogWrite16 (pin, val)` gir en driftssyklus på (val + 1) / ICR1. Som en løsning, gjør Arduinos `analogWrite ()` hvis (val == 0) digitalWrite (pin, LOW); annet hvis (val == 255) digitalWrite (pin, HIGH); `. Men da kan du ikke få en driftssyklus på 1 / ICR1 ...
@Edgar Bonet: Takk for at du forklarte det - løsningen fungerer for meg.
Russell McMahon
2015-06-17 22:41:04 UTC
view on stackexchange narkive permalink

Med noen kalibreringer kan du oppsummere utgangene til to PWM-kanaler med forskjellige vektningsmotstander. På det ytterste kan du bruke en utgang for å gi 8 bits oppløsning og skalere den andre til 1 / 256th nivået og legge dem til slik at den andre kanalen dekker en bit av området, og du (igjen ideelt) får 16 bits oppløsning. Uten enorm omsorg og justering vil alt du får være et rot.
Men ved å dele den andre kanalen med 16 eller 32, kan du legge til flere ekstra biter av PWM-oppløsning. Bare ved å legge til 2 PWM-kanaler, analoge filtrerte utganger, legger du til en ekstra bit (ettersom potensialområdet er doblet for uendret mV / bit).
Merkelig (igjen) for hver ekstra divisjon med 2 får du en ekstra bit oppløsning, men dette kan bare utføres for kanskje 4 eller 5 eller 6 ekstra biter, med økende nøyaktighetskrav til skaleringsmotstander og vanskeligere kalibrering og tilbøyelighet til feil.

Kort eksempel.
Hvis en PWM skaleres ned for å si si 0 - 255 mV i 1 mV trinn, vil summen av to PWMer med lik amplitude gi et 0 - 510 mV område i trinn på 1 mV .
Hvis en PWM skaleres ned med faktoren 32, vil det i stedet for å legge 255 mV til det opprinnelige PWM-området bare legge til 8 mV til toppenden (0.256,32 = 8 mV, men oppløsningen vil være i 0,03125 (1/32.) MV trinn.

Selv om dette kanskje bare kan oppnås med motstandssummering og RC-filtrering, vil bruk av en op amp sommer forbedre resultatene.

Også PWM-ring kan filtreres med et enkelt RC-filter, men bruk av en opamp som buffer (eller til og med bare en enkelt transistor som emitterfølger) vil gi deg 3 eller 5 poler med lavpasfiltrering og mye bedre sjanse for å oppnå ekstra PWM-oppløsning. har ikke inspisert "fasekoherensen" til PWM-utgangene, men forventer at de beveger seg i relativt låsesteg, slik at du ikke får utjevningsfordelen med å legge til to ukorrelerte bølgeformer.

Mer c omment kan gjøres om nødvendig. Spør hvis du er interessert.

Dette er lurt! Ser ut til at [Mozzi sound synthesis library] (http://sensorium.github.io/Mozzi/) bruker dette trikset for det såkalte “HIFI” -modus.
Det er en stor oss av PWM. Men ville ikke dette glatte ut bølgeformen? Jeg spør dette siden du bruker et RC-filter. Har ikke nevnt dette i spørsmålet mitt, men jeg kjører en DC-motor med den . Takk for innspillene!
@KoenR (fwiw: Jeg ser ikke noe å skamme meg over.) Jeg vet ikke hvilken frekvensrespons / endringshastighet du vil ha i ADC-utgangen. Eller hvorfor du vil ha N-biter eller hvor stor er nok. Motorer vil vanligvis ikke styres med mer enn 8 bits - avhenger av hvor presis en applikasjon du har. Motoren fungerer som en del av et utjevningsfilter på grunn av induktans. Du må si hva slags motor og hvordan kjørt. Og et kretsskjema er omtrent viktig. Med mindre motoren er liten, har du en driver. En børstet motor matet PWM må ha en låsediode for å passere motorstrømmen når PWM er av. Legger til to ...
... PWM-er her er helt gjennomførbare, men kretsdetaljer må være kjent.
Vokt dere! I noen tilfeller er det ikke ønskelig å utjevne PWM med lavpass-RC. Hvis du for eksempel kobler Arduino-utgangen til porten til en MOSFET, vil MOSFET forbli kald så lenge den drives av ren PWM. Men hvis du glatter det, vil MOSFET begynne å spre mye mer varme. Noen ganger er det ikke bra.


Denne spørsmålet ble automatisk oversatt fra engelsk.Det opprinnelige innholdet er tilgjengelig på stackexchange, som vi takker for cc by-sa 3.0-lisensen den distribueres under.
Loading...