Hallo, ich bin gerade dabei ein PWM Programm in C zu schreiben. Dazu benutze ich ein Poti am AD-Wandler aber irgendwie funktioniert das ganze nicht so wie ich es mir erhoffe. Irgendwo beim ADC habe ich einen Fehler den ich nicht finde. Ich benutze ein Atmega mit externer Referenzspannung, das Poti ist am ADC3, der PWM ausgang ist PB1(OC1A) Hier ist mal mein Programm wenn jemand eine Lösung findet wär echt cool :) #include <avr/io.h> unsigned int ADCwert = 0; unsigned int wert = 0; void PWM_init(void) { DDRB |= (1<<PB1); TCCR1A = (1<<WGM10) | (1<<COM1A1) | (1<<WGM11); //wgm= 10 bit PWM, TCCR1B = (1<<CS10) | (1<<CS12) ; //Clockselect bit } void PWM_set (unsigned int wert) { OCR1A = wert ; // Vergleicher } void ADC_init(void) { ADMUX |= (0b01000011); //Externe Referenzspannung Kanal auswählen ADCSRA = (1<<ADEN)| (1<<ADFR) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADIE) ; // ADC Free run, Teilungsfaktor 64, ADC interrupt aktivieren ADCSRA |= (1<<ADSC); //ADC start } int ADC_get (void) { for (int i = 0 ; i < 2 ; i++) //schleife wegen "Warmlaufen des ADC" ADCwert = ADC; //Wert auslesen while (ADCSRA & (1<<ADSC) ) //auf Abschluss der Konvertierung warten return ADCwert; // Wert zurückgeben } int main(void) { PWM_init(); ADC_init(); ADC_get(); while(1) { PWM_set(ADC_get); // wert von adc an pwm } }
1) ADC-Interrupt eingeschaltet, aber nicht benutzt (keine ISR). 2) While-Schleife mit fehlenden Semikolon. 3) Warten auf gelöschtes ADSC funktioniert im Free-Running-Modus nicht. Zusatz: Das "Warmlaufen des ADC" ist Unsinn.
Hi, du solltest dich entscheiden was du machen willst. Zuerst stelltst du den ADC auf Interrupt ein, dann rufst du aber eine Funktion auf, die zuerst eine Schleife ausführt, die 1. sinnlos ist und 2. wahrscheinlich vom Compiler deshalb wegoptimiert wird, und dann den ADC per polling abfragen will. An deiner Stelle würde ich den ADC im Hintergrund, per Interrupt, einfach immer den Wert in eine Variabel speichern lassen (volatile nicht vergessen!). Diese kannst du dann einfach für die PWM benutzen, wie du es auch vor hattest. Gruß Marcus
Danke für eure Hilfe aber paar fragen hab ich noch :D Ich bin noch ein Anfänger beim C Programmieren also was genau ist ISR und wie benutze ich es und soll ich jetzt nur noch meine while schleife löschen und das "ISR" einfügen?
Ich habe das Tutorial bereits gesehen aber es ist schwer ohne Hilfe durchzuarbeiten. Mein Programm ist ja schon fast fertig kannst du mir da nicht schnell weiterhelfen?
da ist so was gemacht: http://www.mikrocontroller.net/articles/Absolute_Beginner-AVR_Steckbrettprojekte#PWM___Pulsweitenmodulation
Hi, also für die ISRs solltest du dir den Artikel mal ansehen: http://www.mikrocontroller.net/articles/Interrupt Der ist zwar für UART, aber das prinzip ist überall das gleich. welche while()-Schleife willste löschen? Wenn es um die in der Funktion int ADC_get (void) geht, du kannst eigentlich die komplette Funktion löschen. Zudem solltest du dir auch mal gedanken machen WANN du den Vergleichswert der PWM änderst, im moment machst du es nämlich permanend, das kann sich ziemlich komisch auf die PWM auswirken. Dein Programm sollte grob so aussehen. //Anfang volatile char adc_wert int main() PWM init; ADC init; while()-schleife //hier wird nichts gemacht, da alles per Interrupt gemacht wird ;) return; //Main-Ende ISR (adc) adc_wert=ADCW; ISR (pwm) OCR1A = adc_wert; //Ende Gruß Marcus
Hey, @Marcus, die ISR für die PWM würde er ja nach seinen gesetzten Registern nicht benötigen und könnte in der ISR vom ADC gleich den Vergleichswert setzen: ISR (ADC) OCR1A = ADCW; Damit wäre dann auch gleich ein bischen Platz gespart:) MfG Walleby
Hi, das stimmt natürlich, aber ich meinte mal gelesen zu haben, das es "besser" wäre den PWM-Zyklus fertig werden zu lassen, und dann erst den neuen Wert zu übergeben. Einfacher ist es natürlich, es direkt in der ISR(ADC) zu machen. Gruß Marcus
Ja du hast recht. Ich hatte mal das selbe Problem beim Ansteuern von Brushlessmotoren. Habs dann durch pollen gelöst. @Ramon, wenn es nicht unbedingt mit Interrupts gelöst werden muss, kannst du dir mal den folgenden Link anschaun. Hab ich selber damals mit angefangen^^ http://derjulian.net/mikrocontroller#input MfG Walleby
Mein Programm funktioniert immer noch nicht :( ich kriegs echt nicht hin..
Kann mir vielleicht jemand mein Programm einfach verbessern und mir wieder schicken ich sitze schon so lange davor.. wär echt nett
#include <avr/io.h> #include <util/delay.h>//Ka obs die richtige war wenn nicht dann //avr/delay.h #define F_CPU 8000000UL//Hier dein Takt angeben! void PWM_init(void) { DDRB |= (1<<PB1); TCCR1A = (1<<WGM10) | (1<<COM1A1) | (1<<WGM11); //wgm= 10 bit PWM, TCCR1B = (1<<CS10) | (1<<CS12) ; //Clockselect bit } void PWM_set (uint16_t wert) { OCR1A = wert ; // Vergleicher } uint16_t adc(uint8_t admux) { ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0); ADMUX = admux; ADMUX |= (1<<REFS1) | (1<<REFS0); ADCSRA |= (1<<ADSC); while (ADCSRA & (1<<ADSC)); uint16_t val = ADCW; ADCSRA &= ~(1<<ADEN); return val; } int main(void) { PWM_init(); while(1) { PWM_set(adc(3)); // wert von adc an pwm _delay_ms(1000); } } Schnell mal zusammengebastelt. Delay drin um PWM nicht zu stören und Prescaler von ADC musst du noch anpassen MfG Walleby PS. Keine Garantie dasses läuft^^
Es funktioniert leider immer noch nichts.. Wenn ich unter "int ADC_get" bei return statt "ADCwert" nur "400" eingebe müsste er diesen wert ja an die PWM senden, macht er aber nicht also habe ich wahrscheinlich bei der PWM noch einen Fehler. Weis da vielleicht jemand was ich falsch mache??
Habe grade so ein ähnliches Problem...allerdings läuft mein ADC und meine PWM schon! Das Problem bei mir sind gerade bei gleichzeitig laufen zu lassen... Sobald Ich es zum laufen gebracht habe, sage Ich dir bescheid. Dann können wir das ja mal zusammen durchgehen ;) Grüße Martin
Also: Schau dir mal meinen Code aus dem Link an. Beitrag "ADC/Timer läuft nicht zusammen" Dort solltest du alles finden was du noch brauchen könntest um dein Programm laufen zu lassen. Grüße Martin
Ramon B. schrieb: > also habe ich wahrscheinlich bei der PWM noch einen Fehler. Kannst du ja leicht ausprobieren. Lass halt mal den ADC gleich ADC sein und teste nur, ob deine PWM funktioniert
1 | ...
|
2 | |
3 | int main() |
4 | {
|
5 | PWM_init(); |
6 | |
7 | while(1) |
8 | {
|
9 | PWM_set( 400 ); |
10 | }
|
11 | }
|
Wenn sich am Pin nichts rührt, dann hast du ein Problem in der PWM oder in der Schaltung, die am Pin hängt :-) Im Allgemeinen ist es keine gute Idee, 2 Subsysteme ungetestet in Betrieb zu nehmen. Du weißt dann nie, welches das Problem verursacht.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.