- Labornetzteil AliExpress         
Ergebnis 1 bis 5 von 5

Thema: mega16 PWM und L298 - Problem

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    17.10.2004
    Ort
    PB
    Beiträge
    123

    mega16 PWM und L298 - Problem

    Anzeige

    Praxistest und DIY Projekte
    Hallo zusammen!

    Ich zerbreche mir schon seit Wochen den Kopf, weshalb mein Roboter der Linie nicht folgen möchte. Ich fasse mal kurz die wichtigsten Daten des Roboters zusammen:

    • * Batteriespannung 9,6V (8 Akkus)
      * 5,1V Logikspannung (Schaltung mit Schaltregler L4960)
      * 18V über Spannungsverdopplung für den Motortreiber (Ganz normale L298 Schaltung)
      * 2 Faulhaber Motoren
      * AVR mega16 Grundschaltung @ 7,3728 MHz (https://www.roboternetz.de/phpBB2/al...php?pic_id=153)
      * Liniensensor mit 8 CNY70's am ADC des µC


    Die Grundschaltung funktioniert, ebenso mein Liniensensor.
    Beim Motortreiber bin ich mir nicht sicher ob der 100%ig funktioniert. Er treibt die Motoren zwar wunderbar, d.h. wenn ich die Enable Eingänge ganz normal auf High schalte drehen sich die Motoren und auf Low drehen sie sich eben nicht.
    Doch bei der PWM will es einfach nicht hinhauen.
    Den mega16 habe ich bereits einmal ausgetauscht, was jedoch keine Verbesserung brachte.
    Hier der Code:

    linienfolger.c mit der main() Funktion:
    Code:
    #include <avr/io.h>
    #include <stdint.h>
    #include <avr/delay.h>
    #define trigger 512															// Schwellwert für get_adc_bit
    
    #define verdammtschnell 1024
    #define sehrschnell 854
    #define schnell 684
    #define mittel 514
    #define langsam 344
    #define sehrlangsam 174
    #define verdammtlangsam 1
    
    // Motordrehrichtung:
    
    #define vorwaerts (0 << PC7) | (1 << PC6) | (1 << PC5) | (0 << PC4) 
    
    
    uint8_t channel = 0;														// A/D Konverter Channel
    	uint16_t adc_result;
    	struct 
    	{
    		uint8_t sen1:1;
    		uint8_t sen2:1;
    		uint8_t sen3:1;
    		uint8_t sen4:1;
    		uint8_t sen5:1;
    		uint8_t sen6:1;
    		uint8_t sen7:1;
    		uint8_t sen8:1;
    	} sensor;
    int8_t line_position;													// Linienposition (-127 - +127)
    
    int main(void)
    {
    	init_pwm();															// Initialisiere Timer1 mit PWM
    	init_adc();															// Initialisiere A/D Konverter
    	DDRC = (1 << PC7) | (1 << PC6) | (1 << PC5) | (1 << PC4);			// Datenleitungen für L298
    	for (;;)															// Endlosschleife
    	{
    		// Sensorwerte holen:
    		sensor.sen1 = get_adc_bit(channel,trigger);						// Rückgabewert: 1 Bit
    		channel++;															// Nächsten Channel
    		sensor.sen2 = get_adc_bit(channel,trigger);
    		channel++; 
    		sensor.sen3 = get_adc_bit(channel,trigger);
    		channel++;
    		sensor.sen4 = get_adc_bit(channel,trigger);
    		channel++;
    		sensor.sen5 = get_adc_bit(channel,trigger);
    		channel++;
    		sensor.sen6 = get_adc_bit(channel,trigger);
    		channel++;
    		sensor.sen7 = get_adc_bit(channel,trigger);
    		channel++;
    		sensor.sen8 = get_adc_bit(channel,trigger);
    		channel = 0;														// Channel zurücksetzen
    		// Errechne Linienposition:
    		line_position = sensor.sen1 * (-4) + sensor.sen2 * (-3) + sensor.sen3 * (-2) + sensor.sen4 * (-1) + sensor.sen5 * (1) + sensor.sen6 * (2) + sensor.sen7 * (3) + sensor.sen8 * (4);
    		switch (line_position)
    		{
    			// Siehe case -7:
    			case -4:
    				PORTC = (0 << PC7) | (1 << PC6) | (1 << PC5) | (0 << PC4);
    				OCR1A = verdammtschnell; 		// Rechts: Volle Kraft
    				OCR1B = verdammtlangsam;    // Links: Stop
    				break;
    			// Linie befindet sich weit rechts -> Motoren vorwärts, links Stop
    			case -7:
    				PORTC = (0 << PC7) | (1 << PC6) | (1 << PC5) | (0 << PC4);
    				OCR1A = verdammtschnell; 		// Rechts: Volle Kraft
    				OCR1B = verdammtlangsam;    // Links: Stop
    				break;
    			case -9:
    				PORTC = vorwaerts;
    				OCR1A = verdammtschnell;
    				OCR1B = sehrlangsam;
    				break;
    			case -5:
    				PORTC = vorwaerts;
    				OCR1A = verdammtschnell;
    				OCR1B = langsam;
    				break;
    			case -6: 
    				PORTC = vorwaerts;
    				OCR1A = verdammtschnell;
    				OCR1B = mittel;
    				break;
    			case -3:
    				PORTC = vorwaerts;
    				OCR1A = verdammtschnell;
    				OCR1B = schnell;
    				break;
    			case -2:
    				PORTC = vorwaerts;
    				OCR1A = verdammtschnell;
    				OCR1B = sehrschnell;
    				break;
    			case 0:
    				PORTC = vorwaerts;
    				OCR1A = OCR1B = verdammtschnell;
    				break;
    			case 2:
    				PORTC = vorwaerts;
    				OCR1A = sehrschnell;
    				OCR1B = verdammtschnell;
    				break;
    			case 3:
    				PORTC = vorwaerts;
    				OCR1A = schnell;
    				OCR1B = verdammtschnell;
    				break;
    			case 6:
    				PORTC = vorwaerts;
    				OCR1A = mittel;
    				OCR1B = verdammtschnell;
    				break;
    			case 5:
    				PORTC = vorwaerts;
    				OCR1A = langsam;
    				OCR1B = verdammtschnell;
    				break;
    			case 9:
    				PORTC = vorwaerts;
    				OCR1A = sehrlangsam;
    				OCR1B = verdammtschnell;
    				break;
    			case 7: 
    				PORTC = vorwaerts;
    				OCR1A = verdammtlangsam;
    				OCR1B = verdammtschnell;
    				break;
    			case 4:
    				PORTC = vorwaerts;
    				OCR1A = verdammtlangsam;
    				OCR1B = verdammtschnell;
    				break;
    			default: 
    				PORTC = (0 << PC7) | (1 << PC6) | (1 << PC5) | (0 << PC4);
    				OCR1A = OCR1B = verdammtlangsam;
    				break;
    		}
    	}
    		
    	return 0;
    }

    PWM:

    Code:
    #include <avr/io.h>
    #include <stdint.h>
    
    
    void init_pwm(void);
    
    void init_pwm(void)
    {
    	DDRD = (1 << PD4) | (1 << PD5);		// OCR1A und B an PD4 und 5 (mega16)
    	PORTD = ~(1 << PD4) & ~(1 << PD5);		
    	TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<COM1A0) | (1<<COM1B0) | (1<<WGM11) | (1<<WGM10); // 10 Bit Pwm, invertierend
    	TCCR1B = (1<<CS11) | (1<<CS10);      // Prescaler 64
    }

    Und zu guter Letzt noch die adc.c um den Liniensensor auszuwerten:

    Code:
    #include <avr/io.h>
    #include <stdint.h>
    
    void init_adc(void);
    void disable_adc(void);
    void get_adc_char(uint8_t channel);
    uint16_t get_adc_int(uint8_t channel);
    uint8_t get_adc_bit(uint8_t channel, uint16_t trigger);
    
    void init_adc(void)
    {
    	ADCSRA =  (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1); 	// ADC Anschalten, Prescaler von 64 (7378200/64=115200 Hz oder 115.2 kHz
    }
    
    void disable_adc(void)
    {
    	ADCSRA &= ~(1 << ADEN); 		// Disable ADC
    }
    
    uint16_t get_adc_int(uint8_t channel)
    {
    	uint16_t result = 0;
    	ADMUX = channel;				// Channel auswählen
    	ADCSRA |= (1<<ADSC);			// Konvertierung starten
    	while (ADCSRA & (1<<ADSC));   // Warte bis ADSC gelöscht wird --> Konvertierung fertig
    	result = ADC;
    	return result;
    }
    
    void get_adc_print(uint8_t channel)
    {
    	uint16_t result = 0;
    	unsigned char sresult[4];
    	ADMUX = channel;				// Channel auswählen
    	ADCSRA |= (1<<ADSC);			// Konvertierung starten
    	while (ADCSRA & (1<<ADSC));   // Warte bis ADSC gelöscht wird --> Konvertierung fertig
    	result = ADC;
    	itoa(result, sresult, 10);
    	print_string_usart(sresult);
    }
    
    uint8_t get_adc_bit(uint8_t channel, uint16_t trigger)
    {
    	uint16_t result = 0;
    	ADMUX = channel;				// Channel auswählen
    	ADCSRA |= (1<<ADSC);			// Konvertierung starten
    	while (ADCSRA & (1<<ADSC));   // Warte bis ADSC gelöscht wird --> Konvertierung fertig
    	result = ADC;
    	if (result >= trigger)
    	{
    		return 1;
    	}
    	else 
    	{
    		return 0;
    	}
    }
    Achja, mir ist gerade noch eingefallen, dass ich die Überprüfung der Sensoren bisher nur mit einem Bascomprogramm erledigt habe, es könnte also sein, dass mein ADC Code nicht funktioniert.
    Wäre echt nett, wenn mir jemand helfen könnte!

    Grüße,
    Jonas

  2. #2

    Faulhaber braucht 100 kHz PWM

    Hallo!

    Ich komme zwar aus dem Modellbahnbereich, aber auch dort sind bekanntlich Gleichstrommotoren in Verwendung.

    Erst heute habe ich bezüglich PWM recherchiert und erfahren, dass Faulhaber Motoren besser mit einer Gleichspannung betrieben werden sollen. Will man sie mit PWM betreiben, sind Frequenzen von 100 bis 150 kHz (KILOHERTZ) erforderlich.

    Baue mir übrigens gerade einen Prototyp für einen computersteuerbaren Fahrregler für unsere Vereins-Modellbahn (Mit Schieberegister, DAC, NE555 und L298, bin aber am überlegen, nicht doch lieber einen PIC zu verwenden)

    grüße
    martin mö

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    23.08.2005
    Ort
    95688
    Beiträge
    15
    hallo!

    das mit den 100 bis 150 khz sollte doch mit der PWM locker zu machen sein
    wie mcmoe beschreibt.

    an welchen pin hast du denn enable des L298(PIN6 bzw. PIN11 am L298?
    mit den enable-signal aktivierst du den l298 nur.
    das pwm-signal musst du in INPUT1(PIN5) bzw. INPUT3(PIN10) legen und dann die INPUT2 oder INPUT4 (PIN7 oder PIN12) auf GND ziehen bzw. umgekehrt.
    Die INPUT-PINS übernehmen also die Steuerung der Ausgänge

    Michael

  4. #4
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    17.10.2004
    Ort
    PB
    Beiträge
    123
    Hallo,

    erstmal ein großes Dankeschön an euch, hätte nicht gedacht dass noch Antworten kommen.
    Die Enableeingänge hab ich an den entsprechenden PWM Ausgängen des ATmegas.
    Das sollte doch eigentlich funktionieren, ich schalte den L298 eben schnell an und wieder aus und das ist dann meine PWM.
    Die INPUT Signale verwende ich zu Richtungssteuerung der Motoren. Oder ist da irgendwo ein Denkfehler?!

    Grüße,
    Jonas

  5. #5
    Neuer Benutzer Öfters hier
    Registriert seit
    23.08.2005
    Ort
    95688
    Beiträge
    15
    tschuldigung erstmal das ich so spät zurückschreibe war ne zeit
    im urlaub.
    ich würde das pwm-signal mit dem richungssignal logisch verknüpfen und dann auf die jeweiligen input eingänge geben.
    das enable-signal würde ich seperat schalten und dadurch den baustein
    länger enabled lassen.
    das schalten übernehmen ja die input-eingänge.
    könnt dir morgen nen beispielplan schicken habe mit dem baustein so ziemlich des gleiche gemacht wie du.

Berechtigungen

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

MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad