PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : BL-Regler Programmierung Atmega8



MNjuniors42
10.07.2013, 19:59
Hallo liebe Community,

ich bin gerade dabei ein BL-Regler selbst aufzubauen. Den Hardwareteil habe ich bereits fertig, meine Bauteile sind folgende:

Controller: Atmega8
MOSFET-Treiber: IR 2184
MOSFET´s: IRF1010Z
und natürlich ein ganzen Satz an sonstigen Bauteilen (Widerstände, Kondensatoren etc.)

Zur Ansteuerung habe ich mir folgendes überlegt: Die Regelung erfolgt einfach über ein PWM-Signal (kommt von einem anderen Controller). Das Prinzip ist hier zu sehen: http://http://www.mikrocontroller.net/articles/Brushless-Controller_f%C3%BCr_Modellbaumotoren#Beispielschal tung (http://www.mikrocontroller.net/articles/Brushless-Controller_f%C3%BCr_Modellbaumotoren#Beispielschal tung)

Dieser funktioniert ohne Probleme, ich konnte einen Festplattenmotor mit Zwangskommutierung hochdrehen (bis etwa 1ms verzögerung zwischen den Umschaltpunkten). Die Spannungen einer Phase im Floating-Zustand konnte ich mittels eines Sound-Oszis erfolgreich messen. (Hochdrehen lassen, dann alles abschalten (=alles Floating) und aufs Oszi schauen). Ergab eine schöne Sinus-Kurve.

Allerdings scheitere ich an der Programmierung mit BEMF: Timer, ADC, Comparator sind mir leider nicht sehr geläufig. Daher habe ich versucht ein bestehendes Programm für meinen Controller zu verwenden und umzuschreiben. Das Problem liegt nun darin, das Softwareprojekte wie von Ulrich Radig immer andere Controller verwenden (bei ihm wars der Atmega48 glaube ich), damit sind entsprechende Timer nicht mehr verwendbar. Mir ist es nicht gelungen die entsprechenden Register auf den Atmega8 zu legen. (zb hat der Atmega8 andere bzw. weniger Timer)
Daher meine Überlegung: Es gibt sicher Projekte die auch den Atmega8 verwenden, nur leider konnte ich im Netzt keines dazu finden.

Meine Frage an die Community: Wenn jemand ein solches Projekt/Programmcode hat, wäre ich froh darum mal ein Blick hineinzuwerfen. Dabei würden mir auch einzelne Funktionen helfen wie zb. : Analog-Comperator messen und irgendetwas auslösen, oder Timer aktivieren um zeitverzögert weiterschalten zu können. Sollte auf den Atmega8 bezogen sein, oder vergleichbare Controller (mit gleichen Registern, habe von dem relativ wenig Ahnung)

//ja ich weiß gidf.de ist was schönes, konnte mir in diesem Fall aber nicht weiterhelfen ;)



Mfg
MNjuniors42

erik_wolfram
10.07.2013, 20:33
Also ich kann jetzt leider nichts spezifisches dazu schreiben, aber auf der Atmel-Seite gibt es unter dem Suchbegriff "BLDC" zahlreiche Dokumente (.pdf) in Englisch. Dort wird u.a. die Theorie sowie die Umsetzung auf einem MC erklärt. Ich hatte leider noch keine Zeit mich näher damit zu befassen. Aber vielleicht ist es ja hilfreich.

MFG Erik

MNjuniors42
10.07.2013, 20:48
Meinst du vielleicht speziell http://www.atmel.com/images/doc2592.pdf?
Habe ich bereits durchgelesen, bringt mich jedoch nicht weiter...
Mein Porblem ist ich schaffe es einfach nicht ein vernünftiges Programm zu erstellen, meine Programmierkenntnisse sind da etwas mangelhaft. Und ich kann Themen wie ADC und co. nicht in ein paar Tagen erlernen, das gestaltet sich für mich zu kompliziert

erik_wolfram
10.07.2013, 21:07
Also, das ist so ungefähr die einzige PDF die da nicht passt - es sind wirklich viele. (z.B. Suchbegriff "BLDC timer)
Ich habe zum Beispiel grade folgende Seite gefunden:
http://www.atmel.com/tools/ATAVRMC301.aspx?tab=documents
Dort ist u.a. ein Beispiel für den Attiny861 für den Sensorlosen BLDC Betrieb + Erklärung!
Auf den 1. Blick sieht es von den Timer so aus, dass das auch für den Atmega8 passen müsste...

MNjuniors42
10.07.2013, 21:21
Danke für deine Hilfe und entschuldigung für meine vielleicht etwas unpassenden Fragen. ;)
Ich nehme mal an es wird nicht so einfach sein, die C-Dateien und Headerdatein in ein Projekt zu packen (ich verwende AVRStudio5.1)und ein paar Ausgänge neu zu setzen, oder gleich die .hex-Datei zu übertragen. Ansonsten übersteigt es meine Fähigkeiten.. ich wüsste nicht wie ich da etwas umschreiben müsste (sollte ein Register nicht passen etc)

Zameer
10.07.2013, 23:26
Schau dir mal die Sourcen von dem Simonk(irby) oder Blheli an.
Sind zwar eher für Quads (wegen der Ansteuerfrequenz) bzw Heli/Quad (Blheli) gedacht aber das Funktionsprinzip ist ja das gleiche.

White_Fox
11.07.2013, 11:22
Vllt findest du hier was...das ist auf jeden Fall hochkompliziert, besonders Langsamlauf.

http://www.wettringer-modellbauforum.de/forum/index.php?page=Thread&threadID=36848

MNjuniors42
11.07.2013, 18:41
Also diese Software (habe mir beide angeschaut) kann ich definitiv ohne größeren Aufwand nicht leicht umschreiben. Zudem ist die Schaltung dazu anders, es werden zb. keine Gatetreiber-ICs verwendet. Das bedeutet ich müsste die Ausgänge neu beschreiben nud die Funktion dessen und soweit ich es gesehen hab gibt es dort keine einfachen Makros wo ich Ausgägne neu setzen könnte.
Gibt es keine einfache Software die man leicht umschreiben könnte? Ich denke es gibt sicher mehr Leute, die sowas im Selbstbau verwirklicht haben :D

Klebwax
11.07.2013, 22:29
Ein BLDC ist etwas für Fortgeschrittene, sowohl bei der Hardware, insbesondere aber bei der Software. So mit Cut und Paste wird das nichts.

MfG Klebwax

MNjuniors42
14.07.2013, 16:40
Ok hier mein erster Versuch:

#include <avr/interrupt.h>
#include <avr/io.h>
#define F_CPU 8000000UL //Fusebit auf interner 8 Mhz Oscillator gesetzt
#include <util/delay.h>


//PHASE1 (U)

#define U_PWM DDRB|=(1<<4);PORTB|=(1<<4);DDRB&=~(1<<5)
#define U_Floating DDRB|=(1<<4);PORTB&=~(1<<4)
#define U_HIGH DDRB|=(1<<4);PORTB|=(1<<4);DDRB|=(1<<5);PORTB|=(1<<5)
#define U_LOW DDRB|=(1<<4);PORTB|=(1<<4);DDRB|=(1<<5);PORTB&=~(1<<5)

//PHASE2 (V)

#define V_PWM DDRB|=(1<<2);PORTB|=(1<<2);DDRB&=~(1<<3)
#define V_Floating DDRB|=(1<<2);PORTB&=~(1<<2)
#define V_HIGH DDRB|=(1<<2);PORTB|=(1<<2);DDRB|=(1<<3);PORTB|=(1<<3)
#define V_LOW DDRB|=(1<<2);PORTB|=(1<<2);DDRB|=(1<<3);PORTB&=~(1<<3)

//PHASE3 (W)

#define W_PWM DDRB|=(1<<7);PORTB|=(1<<7);DDRB&=~(1<<6)
#define W_Floating DDRB|=(1<<7);PORTB&=~(1<<7)
#define W_HIGH DDRB|=(1<<7);PORTB|=(1<<7);DDRB|=(1<<6);PORTB|=(1<<6)
#define W_LOW DDRB|=(1<<7);PORTB|=(1<<7);DDRB|=(1<<6);PORTB&=~(1<<6)

#define SENSE_U ADMUX&=~((1<<MUX2)|(1<<MUX1)|(1<<MUX0));
#define SENSE_V ADMUX&=~((1<<MUX2)|(1<<MUX1)); ADMUX|=(1<<MUX0);
#define SENSE_W ADMUX&=~((1<<MUX2)|(1<<MUX0)); ADMUX|=(1<<MUX1);

volatile uint8_t rotor_state=1;

//setzt den übergebenen Status der Rotoren und setzt den Analog Komparator neu
void set_commutate_state(uint8_t state){
switch (state){
case 1:
U_PWM;
V_Floating;
W_LOW;
SENSE_V;
break;
case 2:
U_Floating;
V_PWM;
W_LOW;
SENSE_U;
break;
case 3:
U_LOW;
V_PWM;
W_Floating;
SENSE_W
break;
case 4:
U_LOW;
V_Floating;
W_PWM;
SENSE_V;
break;
case 5:
U_Floating;
V_LOW;
W_PWM;
SENSE_U;
break;
case 6:
U_PWM;
V_LOW;
W_Floating;
SENSE_W;
break;
}
}

ISR (ANA_COMP_vect)
{
set_commutate_state(rotor_state);
rotor_state++;
(rotor_state==7)?(rotor_state=1):(rotor_state=roto r_state);

}

void anlaufvorgang();

int main (void)
{
//PWM an Port PB1(OC1A) einstellen
TCCR1B |= (1<<CS10); //Prescaler 0; Takt des Timers1 = CPU-Takt
TCCR1A |= (1<<WGM10); // 8-Bit PWM Betriebsart aktivieren
TCCR1B |= (1<<WGM12); //Timer1 zählt bis zu einem Vergleichswert, definiert in OCR1AH/L
TCCR1A |= (1<<COM1A1); // nicht invertierter Modus
OCR1A = 128; // Verhältnis einstellen
DDRB |= (1<<PB1); // PB1 als Ausgang definieren, PWM wird aktiviert

DDRC=0x00; //ADC0-2 auf Eingang für Analog Komparator
PORTC=0x00;

DDRB=0xff;
PORTB=0x00;

//Analog Komparator Interrupt

ADCSRA&=~(1<<ADEN); //ADC ausgeschaltet
ACSR&=~(1<<ACD); //Komparator = ein
ACSR&=~(1<<ACBG); //externe Referenzspannug an AIN0
ACSR|=(1<<ACIE); //Komparator Interrupt = ein
ACSR&=~((1<<ACIS1)|(1<<ACIS0)); //löst Komparator bei jedem Flankenwechsel aus
SFIOR|=(1<<ACME); //aktiviert Multiplexer

anlaufvorgang();

U_Floating;
V_Floating;
W_Floating;

_delay_ms(10);

SENSE_U;

sei();

while(1){
}
}

void anlaufvorgang(){
for(uint16_t i=0;i<50;i++){
set_commutate_state(rotor_state);
rotor_state++;
(rotor_state==7)?(rotor_state=1):(rotor_state=roto r_state);
_delay_ms(5);
}
for(uint16_t i=0;i<100;i++){
set_commutate_state(rotor_state);
rotor_state++;
(rotor_state==7)?(rotor_state=1):(rotor_state=roto r_state);
_delay_ms(4);
}
for(uint16_t i=0;i<200;i++){
set_commutate_state(rotor_state);
rotor_state++;
(rotor_state==7)?(rotor_state=1):(rotor_state=roto r_state);
_delay_ms(3);
}
for(uint16_t i=0;i<300;i++){
set_commutate_state(rotor_state);
rotor_state++;
(rotor_state==7)?(rotor_state=1):(rotor_state=roto r_state);
_delay_ms(2);
}
for(uint16_t i=0;i<500;i++){
set_commutate_state(rotor_state);
rotor_state++;
(rotor_state==7)?(rotor_state=1):(rotor_state=roto r_state);
_delay_us(1500);
}
for(uint16_t i=0;i<1000;i++){
set_commutate_state(rotor_state);
rotor_state++;
(rotor_state==7)?(rotor_state=1):(rotor_state=roto r_state);
_delay_us(1250);
}
for(uint16_t i=0;i<1500;i++){
set_commutate_state(rotor_state);
rotor_state++;
(rotor_state==7)?(rotor_state=1):(rotor_state=roto r_state);
_delay_us(1100);
}
}


Der Anlaufvorgang funktioniert so wie er soll, er schaltet schrittweiße nach oben bis zur letzten Drehzahl. (nicht wundern über die komische Verfahrensweiße, für mich ists so fürn Anfang leichter gewesen)

Allerdings gibt der Festplattenmotor, nachdem er per Zwangskommutierung hochgedreht ist, nur ein Pfeifen von sich.
Folgendes habe ich bereits auf ihre Funktionsweiße überprüft:
Analog Komparator / Multiplexer:

ISR (ANA_COMP_vect)
{
DDRC|=(1<<PC5);
PORTC^=(1<<PC5); (LED an/ausschalten)
}

int main(){
// Hier Hochdrehen lassen; siehe Quelltext oben
// hier Analog Komparator und Multiplexer aktivieren; siehe Quelltext oben
SENSE_U;
sei();
while(1){}
}
--> Die LED blinkt sehr schnell

Daher weiß ich nicht was falsch sein sollte, von der Logik sollte es ja funktionieren?
->nach dem Hochdrehen SENSE auf U/V/W (ist egal?) setzen
->nichts machen (while(1)) und warten bis der Interrupt ausgelöst wird
->Phase setzen zb. U an, V Floating, W aus und SENSE auf V (also auf dasjenige das gerade eben auf FLOATING gesetzt wurde) //in der ISR wir die Methode set_commutate_state(); aufgerufen
->wieder warten bis der nächste Interrupt ausgelöst wird, usw.


Einen Timer fürs zeitverzögerte Auslösen hab ich noch nicht drin, die nächste Phase direkt nach dem Komparator-Interrupt zu schalten sollte auch funktionieren?

MNjuniors42
15.07.2013, 19:29
PUSH

Hat jemand eine Idee woran es liegen könnte? Oder ähnlichen Sourcecode mit dem es funktioniert? Ich komm wirklich nicht weiter, das "Grundgerüst" sollte ja passen?

Zameer
16.07.2013, 04:30
Gepostet habe ich dir den Sourcecode..