- 3D-Druck Einstieg und Tipps         
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 13

Thema: Zwei getrennt regelbare PWM-Signale an zwei Pins von PortC

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    07.02.2006
    Ort
    Weimar
    Beiträge
    19

    Zwei getrennt regelbare PWM-Signale an zwei Pins von PortC

    Anzeige

    Praxistest und DIY Projekte
    Hallo, ich möchte am PortC zwei Spulen mit Eisenkern, also zwei Elektromagneten, über eine externe Schaltung anschließen und getrennt voneinander steuern. Hierzu möchte ich an zwei Pins von PortC jeweils zwei unterschiedliche analoge Steuerspannungen über zwei PWM-Signale erzeugen.
    Diese beiden Spannungen (also die PWM-Signale) möchte ich später über das UART vom PC aus steuern können.

    Ich benutze einen Atmel Atmega32.

    Nun meine Frage.: Muss ich zur Erzeugung der beiden PWM-Signale jeweils die beiden 8-bit Timer/Counter (8-bit Timer/Counter0, 8-bit Timer/Counter2) benutzen oder ist das nicht nötig? Reicht es aus den 16-bit Timer/Counter1 zu verwenden und über die beiden Output Compare Register 1A und 1B (OCR1A, OCR1b) zwei getrennte Signale zu erzeugen.

    Hierzu habe ich folgenden Ansatz und weiss nun aber nicht, ob das so funktionieren kann.:

    Code:
    #include <avr/io.h>
    #include <avr/delay.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>
    
    static void enable_pwm(void)
    {
       TCCR1A = 0x00;  //Timer auf 0
       TCCR1B = 0x00;
       
       TCCR1A |= (1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0) | (1<<WGM10);  //Timer einstellen
       TCCR1B |= (1<<CS10) | (1<<CS12); 
    
    }
    
    int main(void)
    {
    
       uint16_t var_a, var_b;
       
       DDRC = (1 << DDC4) | (1 << DDC5);
       PORTC = 0x00;
       
       enable_pwm();
    
       while (1)
    	{  
      
       	OCR1BL = var_b;  // Kanal 1 verschiedene Werte
       	OCR1AL = var_a;  // Kanal 2 verschiedene Werte
    	   	
    	}
       
    }
    Es wäre nett, wenn mir jemand weiterhelfen könnte und gegebenenfalls meinen Quelltext analysiert und korrigiert. Danke.

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Die PWM-Ports sind fest verdrahtet, so etwas wie nen Output-Multiplexer kennt AVR nicht. Also entweder die Pins verweden, die ATmega32 vorsieht (OC2=B3, OC1A=D5, OC1B=D4, OC2=D7) oder selber Hand anlegen und ne Soft-PWM machen und an den Pins wackeln.
    Disclaimer: none. Sue me.

  3. #3
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    21.10.2005
    Ort
    Erde
    Alter
    57
    Beiträge
    1.195
    Der 16bit TC reicht, da Du hier zwei PWM Pins zur Verfügung hast.

    Drei Sachen fallen mir auf die Schnelle auf:
    Du steuerst OCR1B anders an als OCR1A (siehe Settings von COM1Ax und COM1Bx in TCCR1A).

    Du setzt nur die low-register für die PWM. Damit bekommst Du nur ein sehr kleines Tastverhältnis hin (da Du die 16bit PWM verwendest).

    var_a und var_b haben keinen definierten Wert.

  4. #4
    Neuer Benutzer Öfters hier
    Registriert seit
    07.02.2006
    Ort
    Weimar
    Beiträge
    19
    Danke erst einmal für Eure schnelle Hilfe. Wenn ich das richtig verstehe, dann kann ich mit dem 16bit TC zwei unterschiedliche PWM Signale erzeugen, die ich dann an den Ports PD4 (OC1B) und PD5 (OC1A) von PortD abgreifen kann.
    Ich möchte, wie bereits erwähnt, die beiden PWM-Signale über das UART vom PC aus steuern können. Da die Pins PD0 (RXD) und PD1 (TXD) von PortD ja schon für das UART reserviert sind und die beiden PWM-Signale ja auch über PortD ausgegeben werden sollen, hatte ich immer Porbleme mit der richtigen Initialisierung von PortD. Entweder ging die PWM oder das UART nicht. Vielleicht habe ich mich da irgendwie zu blöd angestellt. Vielleicht könnt Ihr mir da weiter helfen. Ich brauche auf jeden Fall die beiden PWM-Signale und das UART gleichzeitig. Wie muss ich denn die PWM auf PortD initialisieren damit das UART nicht blockiert wird?

    Code:
    DDRD = (1 << PD4) | (1 << PD5);
    PORTD = 0x00; // ist das richtig, oder muss ich auch Pin-weise unterscheiden?

    Du steuerst OCR1B anders an als OCR1A (siehe Settings von COM1Ax und COM1Bx in TCCR1A)
    Was genau meinst Du damit? Was müßte ich denn machen um die Register gleich anzusteuern? Die Belegung von TCCR1A und TCCR1B unterscheidet sich ja grundsätzlich oder reden wir gerade aneinander vorbei?

    Du setzt nur die low-register für die PWM. Damit bekommst Du nur ein sehr kleines Tastverhältnis hin (da Du die 16bit PWM verwendest).
    Wie kann ich das denn ändern? Wie kann ich die High-Register setzen um das Tastverhältnis zu vergrößern?

    Ich habe nun die beiden Variablen var_a und var_b mit 0 initialisiert.

    var_a und var_b haben keinen definierten Wert.
    Die Werte von var_a und var_b sollen später vom PC aus über das UART gesendet werden und in der while-Schleife jeweils var_a und var_b zugewiesen werden. Im Moment sind das Dummy-Variablen.
    Für den PWM-Test möchte ich erstmal OCR1AL und OCR1BL feste Werte zuweisen und sehen das die beiden LEDS an den Ports PD4 und PD5 unterschiedlich hell leuchten.

    Danke nochmals für Eure Hilfe.

  5. #5
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Die UART-Pins werden automatisch bei Verwendung des UART so eingestellt wie gebraucht, und sind nicht mehr für "normale" I/O verwendbar.

    OCR1A und OCR1B sind 16-bit-Register, die auch so gesetzt werden können:
    OCR1A = var_a;

    Wie die PWM-Pins wackeln, ist abhängig vom PWM-Modus und den Einstellungen COM1Ax und COM1Bx im TCCR1A.

    Dein PWM-Mode ist #1, also ist TOP=255 und sinnvolle Werte für OCR1B/B sind 0...255. Welchem Duty das entspricht, ist von COM1xy Konfiguration abhängig. In deinem Fall ist das Tastverhältnis OCR1A/255, also in 256 Schritten von 0% bis 100% einstellbar. Mit OCR1A = 0x80 (0der 0x7f?) bekommst du 50%.

    Zu bedenken ist noch, daß zwar die Intensität einer LED linear mit dem Tastverhältnis geht, der Helligkeitseindruck jedoch nicht.


    Port D4 und D4 werden als OUT geschaltet:

    DDRD |= (1 << PD4);
    DDRD |= (1 << PD5);
    Disclaimer: none. Sue me.

  6. #6
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    21.10.2005
    Ort
    Erde
    Alter
    57
    Beiträge
    1.195
    @hender, sorry hatte mich verlesen. Die beiden Pins werden gleich angesteuert. Alles andere hat Georg-Johann ja schon erwähnt.

  7. #7
    Neuer Benutzer Öfters hier
    Registriert seit
    07.02.2006
    Ort
    Weimar
    Beiträge
    19
    Nochmals Danke für Eure Hilfe. Ich habe es nun geschafft zwei unterschiedliche PWM-Signale zu erzeugen. Im nächsten Schritt wollte ich nun versuchen die beiden PWM Signale (erst einmal zusammen) über das UART vom PC aus zu steuern. Sobald ich aber die Funktion "uart_getc()" aufrufe und versuche den Wert, also das empfangene Zeichen, einer Variablen zuzuweisen "var=uart_getc()", dann tut sich gar nichts mehr. Mein im Folgenden abgebildetes Programm bietet ebenfalls die Möglichkeit die PWMs über zwei Taster, die am PortA angeschlossen sind, zu steuern. Über die Taster lässt sich der Wert der Variable "status" erhöhen und senken. Die Variable "status" wird danach OCR1AL und OCR1BL zugewiesen.
    Sobald ich die Funktion "uart_getc()" aufrufe, dann geht auch die Tastensteuerung der PWM nicht mehr. Kommentiere ich die Zeile "var = uart_getc();" aus, dann funktioniert die Tastensteuerung wieder.
    Vielleicht habt Ihr da ja ne Idee woran das liegt und wie ich das Problem lösen kann? Die Uart-Funktionen sind sehr einfach und funktionieren im Moment noch ohne Interupts.

    Code:
    #include <avr/io.h>
    #include <avr/delay.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>
    
    
    
    // Delay Funktion
    void delay_ms (uint16_t delay_time)
    {
    	uint16_t k=0;
    	while (k++<delay_time) {}
    
    }
    
    
    // Initialisierung der PWM
    static void enable_pwm(void)
    {
       TCCR1A = 0x00;  //Timer auf 0
       TCCR1B = 0x00;
       
       // PWM: 8-bit, phasenkorrekt 
       TCCR1A |= (1<<COM1A1) | (0<<COM1A0) | (1<<COM1B1) | (0<<COM1B0) | (1<<WGM10);  //Timer einstellen
       //TCCR1B |= (1<<CS10) | (1<<CS12);
       //TCCR1B |= (1<<CS10) | (1<<CS11) | (1<<CS12); 
       TCCR1B |= (1<<CS10);  //kein Prescaling
    
    }
    
    
    // Initialisierung UART
    void uart_init (void)
    {
    /* USART-Init 38400 Baud bei 8MHz für Mega32 */
      UCSRB = ( (1<<RXCIE) | (1<<RXEN) | (1<<TXEN) );
      UCSRC = (_BV (URSEL) /*| _BV (USBS) */| _BV (UCSZ1) | _BV (UCSZ0)); //syncron usart modus UMSEL
      UBRRH  = 0;                                   // Highbyte ist 0
      UBRRL  = 12;                                  // Lowbyte ist 51 ( dezimal )
    
    }
    
    
    // Zeichen senden
    int uart_putc(unsigned char c)
    {
        while (!(UCSRA & (1<<UDRE))); /* warten bis Senden moeglich */
        UDR = c;                      /* sende Zeichen */
        return 0;
    }
    
    
    // String senden
    void uart_puts (char *s)
    {
        while (*s)
        {   /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
            uart_putc(*s);
            s++;
        }
    }
    
    
    // Zeichen empfangen 
    uint8_t uart_getc (void)
    {
        while (!(UCSRA & (1<<RXC)));  // warten bis Zeichen verfuegbar
        return UDR;                   // Zeichen aus UDR an Aufrufer zurueckgeben
    }
    
    
    int main(void)
    {
    	uint16_t status=0;
      	uint8_t var;
    
    	DDRA=0;     //PORTA as Input
      	PORTA=255;
      	
      	DDRD |= (1 << PD4);
       	DDRD |= (1 << PD5);
      	
    	//uart_init();
    	enable_pwm();
    	
    	
    	/* Loop forever */
    	while (1)
    	{
    		// Steuerung der PWM-Kanäle über 2 Taster (Up/Down)
    		if (status>127)
    		  {
    		  status=128;
    		  }
    		if (status<2)
    		  {
    		  status=1;
    		  }		
    		if (( PINA & (1<<PINA3))==0 )
    		 {
    		    delay_ms(50000);
    		    status=status+1;
    		 }
    		if (( PINA & (1<<PINA4))==0 )
    		 {
    		    delay_ms(50000);
    		    status=status-1;
    		 } 
    		
    		OCR1BL = status;  // Kanal 1 verschiedene Werte
       		OCR1AL = status;  // Kanal 2 verschiedene Werte
    		
    			
    		// Versuch: Wertzuweisung über das UART vom PC aus 
    		var = uart_getc();  /// AN DIESER STELLE KOLLIDIERT ES MIT DER PWM
    		///status=var;
    		
    	}
    }

  8. #8
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Du hast den Receive-Interrupt aktiviert. Mich dünkt du willst via Poll empfangen (warten) , und machst es auch. Dich haut's aus der Kurve, weil für die Receive-IRQ keine ISR implementiert ist.

    Nimm mal das RXCIE aus UCSRB raus.
    Disclaimer: none. Sue me.

  9. #9
    Neuer Benutzer Öfters hier
    Registriert seit
    07.02.2006
    Ort
    Weimar
    Beiträge
    19
    Danke erst einmal. Ich habe das RXCIE jetzt mal rausgenommen, aber ich kann die PWM über die Taster immer noch nicht steuern. Ich habe nun zusätzlich im Quelltext die Zeile "uart_putc(var);" gleich nach "var = uart_getc();" eingefügt. Das empfangene Zeichen wird sofort zurück gesendet. Das klappt mit Hyperterminal auch. Die PWM lässt sich aber über die beiden Taster komischerweise immer noch nicht steuern.
    Die ISR für den Receive-IRQ "SIGNAL(SIG_UART_RECV){...}" will ich später mal noch mit einbauen. Jetzt soll erstmal die einfache Variante funktionieren.

    Mein Quelltext sieht jetzt so aus.:
    Code:
    #include <avr/io.h>
    #include <avr/delay.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>
    
    
    
    // Delay Funktion
    void delay_ms (uint16_t delay_time)
    {
    	uint16_t k=0;
    	while (k++<delay_time) {}
    
    }
    
    
    // Initialisierung der PWM
    static void enable_pwm(void)
    {
       TCCR1A = 0x00;  //Timer auf 0
       TCCR1B = 0x00;
       
       // PWM: 8-bit, phasenkorrekt 
       TCCR1A |= (1<<COM1A1) | (0<<COM1A0) | (1<<COM1B1) | (0<<COM1B0) | (1<<WGM10);  //Timer einstellen
       //TCCR1B |= (1<<CS10) | (1<<CS12);
       //TCCR1B |= (1<<CS10) | (1<<CS11) | (1<<CS12); 
       TCCR1B |= (1<<CS10);  //kein Prescaling
    
    }
    
    
    // Initialisierung UART
    void uart_init (void)
    {
    /* USART-Init 38400 Baud bei 8MHz für Mega32 */
      UCSRB = (1<<RXEN) | (1<<TXEN);
    /* Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit */
      UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
      UBRRH  = 0;                                   // Highbyte ist 0
      UBRRL  = 12;                                  // Lowbyte ist 51 ( dezimal )
    
    }
    
    
    // Zeichen senden
    int uart_putc(unsigned char c)
    {
        while (!(UCSRA & (1<<UDRE))); /* warten bis Senden moeglich */
        UDR = c;                      /* sende Zeichen */
        return 0;
    }
    
    
    // String senden
    void uart_puts (char *s)
    {
        while (*s)
        {   /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
            uart_putc(*s);
            s++;
        }
    }
    
    
    // Zeichen empfangen 
    uint8_t uart_getc (void)
    {
        while (!(UCSRA & (1<<RXC)));  // warten bis Zeichen verfuegbar
        return UDR;                   // Zeichen aus UDR an Aufrufer zurueckgeben
    }
    
    
    int main(void)
    {
    	uint16_t status=0;
      	uint8_t var;
    
    	DDRA=0;     //PORTA as Input
      	PORTA=255;
      	
      	DDRD |= (1 << PD4);
       	DDRD |= (1 << PD5);
      	
    	uart_init();
    	enable_pwm();
    	
    	
    	/* Loop forever */
    	while (1)
    	{
    		// Steuerung der PWM-Kanäle über 2 Taster (Up/Down)
    		if (status>127)
    		  {
    		  status=128;
    		  }
    		if (status<2)
    		  {
    		  status=1;
    		  }		
    		if (( PINA & (1<<PINA3))==0 )
    		 {
    		    delay_ms(50000);
    		    status=status+1;
    		 }
    		if (( PINA & (1<<PINA4))==0 )
    		 {
    		    delay_ms(50000);
    		    status=status-1;
    		 } 
    		
    		OCR1BL = status;  // Kanal 1 verschiedene Werte
       		OCR1AL = status;  // Kanal 2 verschiedene Werte
    		
    			
    		// Versuch: Wertzuweisung über das UART vom PC aus 
    		var = uart_getc();  /// AN DIESER STELLE KOLLIDIERT ES MIT DER PWM
    		uart_putc(var);
    		//status=var;
    		
    	}
    }

  10. #10
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    21.10.2005
    Ort
    Erde
    Alter
    57
    Beiträge
    1.195
    In Deiner routine kannst Du die Tasten genau in dem Moment erkennen, wenn gerade das Zeichen gesendet wurde, und noch nicht wieder auf ein Zeichen gewartet wird.

    Wenn Du also mal testweise die serielle Kommunikation in main() auskommentierst, wird es schon besser funktionieren. Zum Testen würde ich auch um mehr als 1 in-/dekrementieren, ansonsten musst Du zu oft den Taster drücken.

    Da Du Dich wahrscheinlich fragst, wie man beides - serielle Kommunikation und Taster - vernünftig zum Laufen bekommt: Mindestens eine dieser beiden Funktionen sollten über eine Interrupt-Routine gelöst werden.

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

12V Akku bauen