PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : mega16 PWM und L298 - Problem



vish
18.05.2005, 17:43
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/album_pic.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:


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



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



#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

mcmoe
02.09.2005, 11:49
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ö

lundi
02.09.2005, 12:08
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

vish
02.09.2005, 14:56
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

lundi
12.09.2005, 14:07
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.