Forum: Mikrocontroller und Digitale Elektronik Attiny 44a PWM getrennt ausgeben


von Sebastian S. (schrammi)


Lesenswert?

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

von Michael F. (sharpals)


Lesenswert?

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
von Peter D. (peda)


Lesenswert?

Für die PWMs sind COM1A1 COM1A0 COM1B1 COM1B0 in TCCR1A zuständig.
Und nach Abschalten der COMxxx wird der Pegel lt. PORTA angelegt.

von Michael F. (sharpals)


Lesenswert?

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 ?

von Schrammi (Gast)


Lesenswert?

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.

von Michael F. (sharpals)


Lesenswert?

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
von Thomas E. (thomase)


Lesenswert?

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
von Michael F. (sharpals)


Lesenswert?

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.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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
von Thomas E. (thomase)


Lesenswert?

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.

von Schrammi (Gast)


Lesenswert?

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?

von Peter D. (peda)


Lesenswert?

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.

von Michael F. (sharpals)


Lesenswert?

@ 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

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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.

von Schrammi (Gast)


Lesenswert?

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);
    }
}

von Michael F. (sharpals)


Lesenswert?

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 ...

von Schrammi (Gast)


Lesenswert?

Was genau muss ich da dann anpassen?

von Michael F. (sharpals)


Lesenswert?

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
von Schrammi (Gast)


Lesenswert?

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 :-)

von Schrammi (Gast)


Lesenswert?

Vom Grundsatz her ist es egal welche Wellenform. Aber jetzt bin ich eine 
ganze Ecke weiter gekommen. Danke Michael

von Michael F. (sharpals)


Lesenswert?

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.

von Stromtuner (Gast)


Lesenswert?

>    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
Noch kein Account? Hier anmelden.