Hallo zusammen, Ich habe einen Attiny44a und möchte dass an den Ports Pa5 und Pa6 eine Pulsweite ausgegeben wird (gleiche Wellenform Fast PWM 9bit ohne Vorteiler Prozessortakt intern 8MhZ). Die Register habe ich soweit eingestellt und klappt auch. Nun das Problem: Pa5 und Pa6 dürfen nie gleichzeitig an sein. Also entweder ist Pa5 mit dem PWM ein für 1min oder Pa6 für 1min. Wenn ich nun in C schreibe Porta|=(1<<Pina6); Dann wird auch Pa5 eingeschaltet. Das soll aber nicht. Woran kann das liegen? Danke für eure Hilfe
war er vorher an ? also das hier Porta|=(1<<Pina6); bedeutet ja Porta:=Porta OR ( 1 SHL PINa6). also wir gehen davonn aus, daß am anfang alles null ist. Portx:=%0000 0000; dann setzt du port 5. Portx:=%0000 0000 or %0001 0000 = %0001 0000; So und jetzt willst du port 6 aktiv setzen mit deiner methode. also Portx:=%0001 0000 or %0010 0000 = %0011 0000; Deshalb hast du immernoch den 5er an. du mußt also erst den port 5 wider löschen. Um die 5 zu löschen mußt du also Portx:=portx and not (1 shl Pinx5) setzen.
:
Bearbeitet durch User
Für die PWMs sind COM1A1 COM1A0 COM1B1 COM1B0 in TCCR1A zuständig. Und nach Abschalten der COMxxx wird der Pegel lt. PORTA angelegt.
Nachdem was ich jetzt verstanden habe, macht er eine ,,SOFT"-PWM ... @ Sebastian was für eine PWM machst du ? HW-PWM , oder schaltest du den pin um, wenn der CTC auf überlauf geht ? Könntest du den codeblock zeigen ?
Schon mal Danke für eure Antworten. Ich benutze den Hardware PWM Pa5 und Pa6 sind anfangs aus. Meine Grundidee ist dass ich die Pulsweite für Pa5 und für Pa6 über Ocr1a und Ocr1b einstelle und dann mit Porta&=~(1<<Pina5); Porta|=(1<<Pina6); Oder Porta&=~(1<<Pina6); Porta|=(1<<Pina5); den Pa6 als Pwm-Ausgang 1 und Pa5 dauerhaft auf 0 habe. Bzw umgekehrt. Aber das klappt nicht. Den Programmteil schick ich heute abend.
wenn du die PWM per hardware setzt, dann benötigst du das ein und ausschalten ja garnicht. - Du mußt die besagten ausgänge als ausgang definieren - Den teilerfaktor und modus für für den timer1 - dann kanst du in dem register beide ausgänge für den timer freigeben und den timer starten. jetzt brauchst du nur noch die werte einstellen, die die beiden timer als PWM ausgeben sollen, ( hast du ja auch geschrieben ) also in OCR1A und OCR1B . Nach einer minute setzt du das register auf null und das andere dann auf dem wert, den du möchtest. wenn du dann OCR1A:=0; setzt, ist der pinn auf low (0%).
:
Bearbeitet durch User
Michael F. schrieb: > wenn du dann OCR1A:=0; setzt, ist der pinn auf low (0%). Nicht bei Fast-PWM, denn der PWM-Wert ist OCR1A + 1. Mit Phase Correct wird was draus. Oder man schaltet einfach den Pin auf Eingang. Aber soweit waren wir ja schon. Man kann auch den Timer mit Fast-PWM von Clear auf Set umsteuern und dann 0x1FF ins OCR schreiben. Mit diesem "Trick" gewinnt man sogar 1 Step an Auflösung.
:
Bearbeitet durch User
Ok, ja dann ist es richtig, dann müßte er das register für den inaktiven pin ausschalten und von hand auf null setzen. Also im TCCR1A das besagte bit zurücksetzen und dann den pin auf null ziehen. Also mal warten, wie der code aussieht.
Schrammi schrieb: > Porta&=~(1<<Pina6); > Porta|=(1<<Pina5); Wenn du die PWM abschalten willst, ohne irgendwas an der Timer Konfiguration zu ändern ist es am einfachsten, den abzuschaltenden Port auf Eingang zu stellen, z.B.
1 | DDRA &= ~(1 << PINA6); // schaltet PORTA6 auf Input = PWM inaktiv |
2 | DDRA |= (1 << PINA6); // und wieder auf Output = PWM aktiv |
:
Bearbeitet durch User
Matthias S. schrieb: > Wenn du die PWM abschalten willst, ohne irgendwas an der Timer > Konfiguration zu ändern ist es am einfachsten, den abzuschaltenden Port > auf Eingang zu stellen, z.B. Bleibt aber die Frage, ob er 0 = Nichts oder 0 = GND setzen will.
Oh Leute ihr seid super. Ist ne gute alternative Idee den port als Eingang zu schalten. Aber noch mal für mich zum Verständnis. So wie ich mir das gedacht habe funktioniert das grundsätzlich nicht?
Schrammi schrieb: > Ist ne gute alternative Idee den port als > Eingang zu schalten. Ist ne äußerst schlechte Idee. Einen floatenden Ausgang möchte man in der Regel nicht. Z.B. wenn dahinter ein FET ne Leistungs-LED treiben soll, wird der bei floatendem Gate schön überlastet. Was stört Dich daran, einfach ins TCCR1A zu schreiben? PORTA und DDRA schreibt man einmalig nach dem Reset und gut.
@ Schrammi poste mal , ich gehe davonn aus, daß der wurm am TCCR1A liegen wird , oder du ihn einfach vergessen hast. Wie gesagt, solange die PWM aktiv ist, lässt er sich nicht auf Grund ziehen ( außer auf 1/255 PWM ) :-). Mit dem eingang binn auch der meineung von Peter, mit seiner erklärung und der aufwand ist ja nicht geringer. hier nochmal ein link : http://modelleisenbahn-steuern.de/controller/atmega8/12-13-1-tccr1a-atmega8.htm https://www.mikrocontroller.net/articles/AVR-Tutorial:_PWM
Peter D. schrieb: > Ist ne äußerst schlechte Idee. Nö, das macht Atmel in ihrer BLDC Software genauso. Man kann mit Pullup und -down den gewünschten inaktiven Ausgangspegel vorgeben, was man generell sowieso machen sollte.
So jetzt mal das Programm. Pa5 und Pa6 müssen gegen GND ziehen. #include <avr/io.h> #define F_CPU 8000000UL #include <util/delay.h> int ea1() //Eingäng/Ausgäng 1 { } int ea2() //Eingäng/Ausgäng 2 { } int ea3() //Eingäng/Ausgäng 3 { } int ea4() //Eingäng/Ausgäng 4 { } int ea5() //Eingäng/Ausgäng 5 { } int ea6() //Eingäng/Ausgäng 6 { } void motor_aus() //1=1 2=1 3=0 4=0 { PORTA&=~((1<<PINA5)|(1<<PINA6)); _delay_ms(1); //damit der Mosfet auch wirklich aus ist PORTA|=(1<<PINA0)|(1<<PINA1); } void motor_stopp() //1=0 2=0 3=0 4=0 { PORTA&=~((1<<PINA5)|(1<<PINA6)); _delay_ms(1); //damit der Mosfet auch wirklich aus ist PORTA&=~((1<<PINA0)|(1<<PINA1)); } void motor_rechts() //1=0 2=1 3=0 4=1 { PORTA&=~((1<<PINA5)|(1<<PINA6)); _delay_ms(1); //damit der Mosfet auch wirklich aus ist PORTA=(PORTA|(1<<PINA1)|(1<<PINA5))&(~(1<<PINA0)); } void motor_links() //1=1 2=0 3=1 4=0 { PORTA&=~((1<<PINA5)|(1<<PINA6)); _delay_ms(1); //damit der Mosfet auch wirklich aus ist PORTA=(PORTA|(1<<PINA0)|(1<<PINA6))&(~((1<<PINA1))); } int main(void) { // Takt CLKPR=0b10000000; //Prozessortakt intern 8MHz CLKPR=0b00000000; // Teiler 0 // Ports DDRA =0b01100011; //Ein/Ausgänge an A PORTA=0b00011100; //Pullup an A DDRB =0b00000000; //Ein/Ausgänge an B PORTB=0b00001111; //Pullup an B // ADC ADMUX=0b00000111; // VCC als Ref.spannung Einlesen PA7 ADCSRA|=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1); //adc eingeschaltet vorteiler 64 ADCSRB|=(1<<ADLAR); //Werte linksbündig // PWM / Timer TCCR1A|=(1<<COM1A1)|(1<<COM1B1)|(1<<COM1A0)|(1<<COM1B0)|(1<<WGM11); //Erst aus und bei compare an da die H-Brücke im Ruhezustand durchgeschaltet ist , Top bei 9 bit , Modus6 Fast PWM TCCR1B|=(1<<CS10)|(1<<WGM12); // ohne Teiler /* Replace with your application code */ while (1) { OCR1A=220; OCR1B=220; motor_rechts(); _delay_ms(5000); motor_links(); _delay_ms(5000); } }
ja wie erwartet, demnach laufen die timer voll durch ... Einfach in den besagten routinen noch das TCCR1A anpassen, danach sollten die motoren wirklich aus sein ...
du hast ja zur zeit TCCR1A|= (1<<COM1A1)|(1<<COM1B1)| (1<<COM1A0)|(1<<COM1B0)| (1<<WGM11); also beide pinns werden geändert, sobald der registerinhalt erreicht ist. ich würde es mal umsortieren, so wie es im datenblatt steht. TCCR1A = (1<<COM1A1)| (1<<COM1A0)|(1<<WGM11); // nur Pin 6 geht auf die PWM odert anders geschrieben TCCR1A =(1<<COM1A1)|(0<<COM1B1)|(1<<COM1A0)|(0 <<COM1B0)|(1<<WGM11); oder dasselbe für TCCR1A = (1<<COM1B1)| (1<<COM1B0)|(1<<WGM11); // nur Pin 5 TCCR1A = (0<<COM1A1)|(1<<COM1B1)|(0<<COM1A0)|(1<<COM1B0)|(1<<WGM11); Die TCCR1A|= benötigst du hier garnicht ... du kannst also direkt beide werte setzen. hindert dich eigentlich etwas darann, den phasecorrectmodus zu benutzen ? dann ginge das in etwa so TCCR0A:=(1 shl COM0B1) or (1 shl WGM00); // phase correct PWM mode dann kann man auch bis auf null runtergehen ...
:
Bearbeitet durch User
Ja Danke Danke Danke!!!! hab`s nun so gelöst: void motor_rechts() //1=0 2=1 3=0 4=1 { TCCR1A&=~((1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<COM1B0)); PORTA&=~((1<<PINA5)|(1<<PINA6)); _delay_ms(1); //damit der Mosfet auch wirklich aus ist TCCR1A|=(1<<COM1B1)|(1<<COM1B0); PORTA=(PORTA|(1<<PINA1)|(1<<PINA5))&(~(1<<PINA0)); } funktioniert! Super besten Dank euch :-)
Vom Grundsatz her ist es egal welche Wellenform. Aber jetzt bin ich eine ganze Ecke weiter gekommen. Danke Michael
geht ja jetzt ... das andere wäre nur etwas bequemer gewesen. Aber wenn es geht und der prozessor nocg genügend platz hat, dann würde ich es auch so lassen.
> TCCR1A&=~((1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<COM1B0));
hier würde ich TCCR1A einfach auf NUll setzen und dann komplett neu
laden.
Deine PWM-PINs PORTA5 und PORTA6 kannst Du am Anfang direkt auf Low
setzen.
Die sind dann auch LOW, wenn Du die PINs von der PWM "abkoppelst".
Das einzige, worum du dich noch kümmern musst, sind PA0 und PA1, welche
wohl die anderen beiden Steuerpins deiner Brücke zu sein scheinen. (Bei
Dir mit 3=0|1 bzw. 4=0|1 bezeichnet).
Den Timer kannst Du durchlaufen lassen, gibt dann nur beim "anknüppern"
des PA5 oder PA6 an die PWM-Unit einmalig einen falschen Wert.
Mir sind da auch schon die Fets um die Ohren geflogen, kann ich gut
nachvollziehen. Ich hatte einen mega48mu und FDC64?? für ein
mikromodellbautruck programmiert. der blieb dann hin und wieder mit
rauchendem Führerhaus auf der Tisch-Truck-Trail-Strecke stehen. Ein
OCRx=0 reicht da tatsächlich nicht aus.
1 | TCCR1A = 0; |
und neu setzen des TCCR1A, je nach Motorlaufrichtung half bei mir. Ich hab sogar den Timer noch auf null gesetzt, damit der OCR Wert auch wirklich "stimmt", ist aber Krümelkackerei. Viel Spaß noch, LG StromTuner
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.