Hallo Zusammen,
ich möchte mir gerne einen Regler für einen Bürstenmotor bauen. Diesen
soll man über eine Fernsteuerung steuern können. Der Microcontroller ist
ein Atmega8, dieser steuert den Halbbrücken Mosfettreiber IR2184. Ein
Testprogramm in dem ich den Motor einfach mal hochlaufen und dann wieder
runterlaufen lasse habe ich schon. Nur wie kann ich jetzt die Signale
der Fernsteuerung auswerten? Soweit ich weiss gibt sie ein PWM Signal
mit 50Hz aus und einem Tastverhältnis von 0,5 bis 1,5ms aus.
Danke. Gruß Steffen
Wenn es eine Wald-und-Wiesen Fernbedienung ist, such Dir einen der 1000
Servo-Beispiele aus oder hier
http://www.mikrocontroller.net/articles/AVR-Tutorial:_Servo oder schau
Dir an, wie die Quadcopter-Leute das Signal lesen.
Im Prinzip musst Du also die Pulslänge messen (z.B. über
capture-interrupt oder pollen)und entsprechend Deinen Vorstellung
reagieren.
Ich möchte ja kein Servo ansteuern. Das Problem ist ja, dass das Signal
der Fernsteuerung zwar auch ein PWM Signal ist aber nur mit einer
Frequenz von 50Hz und einem Tastverhältnis von 0,5 bis 1,5ms. Der
Mosfettreiber wird aber mit einem PWM Signal von 8kHz angesteuert. Das
Tastverhältnis geht über den ganzen bereich. Eher gesagt 8kHz geteilt
durch 256. Ich weiss nur nicht wie ich das Signal einlesen soll.
Gruß Steffen
@ Steffen Ha (stef_fen)
>Tastverhältnis geht über den ganzen bereich. Eher gesagt 8kHz geteilt>durch 256. Ich weiss nur nicht wie ich das Signal einlesen soll.
Per ICP Funktiion kann man die Pulsbreite des Fernsteuersignals messen
und daraus einen Steuerwert für den MOtor ableiten. Per Timer und OCR
Funktion generiert man eine PWM mit 8kHz, deren PWM-Wert durch eben
diesen Steuerwert gebildet wird. Fettig.
Steffen Ha schrieb:> Ich möchte ja kein Servo ansteuern.
Es hilft aber, wenn man weiss wie es aussieht.
ok. du hast das schon gewusst. Von daher war der Link nicht sehr
zielführend.
> Das Problem ist ja, dass das Signal> der Fernsteuerung zwar auch ein PWM Signal ist aber nur mit einer> Frequenz von 50Hz und einem Tastverhältnis von 0,5 bis 1,5ms. Der> Mosfettreiber wird aber mit einem PWM Signal von 8kHz angesteuert.
Ähm. Du sollst ja nicht das Servosignal direkt auf den MOSFET
durchschalten.
Du misst mittels Capture INterrupt den Puls aus und aus der Pulslänge
überlegst du dir eine Formel, wie du den MOSFET, repektive die PWM die
den MOSFET ansteuert, ansteuerst.
> durch 256. Ich weiss nur nicht wie ich das Signal einlesen soll.
Input Capture Interrupt vom Timer 1.
Wobei: Da der µC sonst sowieso nichts zu tun hat und sowieso die meiste
Zeit Däumchen dreht, kann man das Ausmessen zur Not auch der Einfachheit
halber auch in der main-Loop machen.
micha schrieb:> Im Prinzip musst Du also die Pulslänge messen (z.B. über> capture-interrupt oder pollen)und entsprechend Deinen Vorstellung> reagieren.
:-)
Der Capture-Interupt macht das fast in Hardware, aber pollen würde in
etwa so funktionieren:
main
...
loop
Teste_Pin_Fernsteuersignal
if Flanken_wechsel_low->high
starte_zähler
if Flanken_wechsel_high_low
stop_zähler
setzte_motor_pmw (zähler_stand)
if time_out
reset_zähler
else
zähler++
delay_x
loop_ende
"zählerstand" hängt von der Dauer der Schleife ab, die wiederum von der
Geschwindigkeit und delay_x. "setzte_motor_pwm" musst Du nach Deinen
Vorstellungen programmieren (vorwärts, rückwärts, 0-100% was_auch_immer)
Steffen Ha schrieb:> angeschaut. Nur bin ich mir nicht sicher was ich noch alles brauche.
Input Capture Methode:
Du brauchst einen Zähler der vor sich hinzählt.
Und du brauchst einen Eingang (eben den Input Capture Eingang), der ein
Ereignis auslösen kann. Dieses Ereignis macht nichts anderes als das es
den momentanten Zählerstand in einem Register (den ICR1-Registern)
zwischenspeichert. Und du brauchst die zum Input Capture gehörende
Interrupt Routine.
Das Prinzip ist einfach.
Dein Kumpel zählt vor sich hin. Jede Sekunde zählt er 1 weiter.
1, 2, 3, 4, 5, 6, 7
Du hingegen beobachtest das Badzimmer-Fenster vom Nachbar. Jedesmal wenn
dort das Licht von 'dunkel auf hell' bzw 'hell auf dunkel' wechselt
rufst du 'Jetzt'. Wann immer du jetzt rufst notiert sich deine Freundin
die Zahl, die dein Kumpel zuletzt genannt hat
1
2
3
Jetzt Sabine schreibt auf 3
4
5
6
7
Jetzt Sabine schreibt auf 7
8
9
....
wie lange hat also beim Nachbarn das Licht gebrannt?
Da das ausschalten bei 7 passiert ist und das Einschalten bei 3, hat
daher das Licht 4 Sekunden gebrannt ( 7 - 3 )
Woher weiß Sabine, welches das Einschalten und welches das Ausschalten
war? Na, da kann Sabine ganz einfach nachsehen. Wenn du 'jetzt' rufst,
weil sich am Lichtzustand etwas geändert hat, dann schreibt Sabine nicht
nur den Zählerstand auf, sondern schaut auch mal kurz rüber zum
Badezimmerfenster. Wenn es erleuchtet ist, dann muss dein 'Jetzt'
offenbar gekommen sein, weil das Licht eingeschaltet wurde. Wenn das
Fenster dunkel ist, dann kennzeichnet das 'Jetzt' den Ausschaltvorgang.
Und so kann Sabine deine 'Jetzt' eindeutig zuordnen und die Zeit der
Hellphase von der Zeit der Dunkelphase unterscheiden.
Dein Kumpel ist der Timer
Du bist der Input Capture, der so eingestellt wurde, dass er bei jeder
Änderung reagiert.
Und Sabine ist sowohl ICR1 Register als auch die zum Input Capture
gehörende ISR (also die Interrupt Service Routine), die deine 'Jetzt' so
auswertet, dass letztendlich nur die Zeit der Hellphase übrig bleibt.
Wenn sie ein Einschalten registriert, dann merkt sie sich den letzten
Zählerstand und wenn sie ein Ausschalten registriert, dann zieht sie vom
aktuellen Zählerstand den gemerkten Wert ab. Die Differenz ist ein Mass
für die Pulszeit. Und da du weißt, wie schnell der Timer zählt, kann man
das auch in eine Zeit umrechnen, wenn man die Zeit direkt als Zahlenwert
benötigt. (BRauchst du aber in deinem Fall nicht wirklich. Du brauchst
nur eine Zahl, die proportional zur Pulsdauer ist.)
Hehehe, nett erklärt :-) Nur meine Sabine würde sich schön bedanken,
wenn ich sie mit Zettel, Stift und Fernglas ans Fenster setze. Aber das
Prinzip ist genau das.
Matthias Sch. schrieb:> Hehehe, nett erklärt :-) Nur meine Sabine würde sich schön bedanken,> wenn ich sie mit Zettel, Stift und Fernglas ans Fenster setze. Aber das> Prinzip ist genau das.
:-)
Der 'schwierige Teil' kommt jetzt allerdings noch.
Jetzt kommt dann nämlich auch noch Erwin ins Spiel, der sich die Sache
ansehen muss und (in seinem Fall) regelmässig Entscheiden muss, ob da
überhaupt ein Puls zu sehen war, sprich ob nicht zb der
Fernsteuerungssender ausgeschaltet ist. Denn was er nicht haben will
ist, dass sein Motor ohne eingeschalteten Sender losläuft.
Aber das ist wie bei der Dampfmaschin. Die hat 2 Löcher, in das eine
geht der Dampf rein und das andere Loch, det kriegn wa späta.
http://www.youtube.com/watch?v=JKY-3qUioPc
Steffen Ha schrieb:> Danke für die super Erklärungen. Verstanden habe ich es. Aber welche> Befehle brauche ich dann noch:
Dann hast du es nicht wirklich verstanden :-)
> //PWM Auswertung Fernsteuerung> DDRB &= ~(1 << PB0); //Fernsteuerung = Eingang> PORTB |= (1 << PB0); //Pullup aktiviert
OK. Ich hoffe mal das das auf deinem µC dir ICP Eingang ist
> TCCR1B |= (1 << ICES1); //steigende Flanke zur Auswertung des ICP
Nö. In der Geschichte rufst du sowohl beim Einschalten als auch beim
Ausschalten 'Jetzt'.
Hier, laut Kommentar, nur beim Einschalten
> TCCR1B |= (1 << CS10); //Quelle fuer Timer/Counter = CPU-Takt[/c]
Darüber wird noch zu reden sein, da müssen wir dann noch ein bischen
rechnen.
Mal sehen. Du hast jetzt
* deinen Kumpel der zählt
* den 'Jetzt'-Schreier
welche Teile aus der Geschichte fehlen noch?
> Benötige ich auch noch:> TIMSK |= (1 << TICIE1);
Schon wärmer. Du must Sabine die Erlaubnis geben aufzuschreiben. Soweit
ok. Du gibst die ISR-Bearbeitung für den Capture Interrupt frei
> TIMSK |= (1 << TOIE1);
Der Overflow Interrupt. Wo kam der in der Geschichte vor?
Richtig: nirgends
AN keiner Stelle wurde ein Wort darüber verloren, dass dein Kumpel
wieder bei 0 zu zählen anfängt und das deshalb Erwin was machen muss.
> Was ist mit dem ICR1H/ICR1L?
Das ist Sabine, wie sie sich den jeweils letzten Zählerstand von deinem
Kumpel holt. in ICR1 steht dieser letzte Zählerstand zum Zeitpunkt an
dem das 'Jetzt' gerufen wurde.
PS: man kann das auch einfach als ICR1 schreiben. Dein C-Compiler weiss
schon das das in Wirklichkeit ein ICR1H und ein ICR1L sind und das die
beiden zusammen gehören.
Was jetzt noch fehlt ist die ISR. Oder um bei der Geschichte zu bleiben:
der Teil in dem Sabine feststellt ob ein/aus und wenn 'aus', dann die
Differenz ausrechnen.
Ich mach dirs nicht leicht. Aber du willst das ja lernen und nicht nur
einfach von mir abschreiben.
Und nein: die nächste Frage 'welche Teile fehlen noch' beantworte ich
nicht mehr. Ich hab mir die Geschichte nicht ausgedacht um eine
Geschichte zu erzählen. Jeder Teil in der Geschichte findet sich im
Programm wieder! Da gibt es eine mehr oder weniger 1:1 Entsprechnung.
Wenn man so will: Die Geschichte ist eine Beschreibung des Kerns deines
Programms. Nur mit anderen Worten und anderen handelnden Personen.
Und beim nächsten mal bitte dann schon ein etwas vollständiges Programm.
Lass fürs erste deine PWM und deinen Motor links liegen. Das erste
Teilziel ist es, dass eine LED sich ein/ausschaltet, je nachdem in
welcher Position sich der Knüppel an der Fernsteuerung befindet.
> TCCR1B |= (1 << ICES1); //steigende Flanke zur Auswertung des ICP>Nö. In der Geschichte rufst du sowohl beim Einschalten als auch beim>Ausschalten 'Jetzt'.>Hier, laut Kommentar, nur beim Einschalten
Der 1 << ICES1 ist ja für die steigende Flanke. Also sozusagen wenn das
Licht angemacht wird. 0 << ICES1 wäre dann wenn das Licht ausgemacht
wird. Wenn man die beiden hätte und die voneinander abziehen würde hätte
man genau die Impulslänge oder?
Ich habe mir die Aufgaben nochmal zusammengefaßt:
Kumpel = Timer
Input Capture = Ich
ICR1 sowie ISR = Sabine
Also gibt es drei Teile aus denen das Programm bestehen muss + die
Umrechnung.
Steffen Ha schrieb:> Der 1 << ICES1 ist ja für die steigende Flanke. Also sozusagen wenn das> Licht angemacht wird. 0 << ICES1 wäre dann wenn das Licht ausgemacht> wird. Wenn man die beiden hätte und die voneinander abziehen würde hätte> man genau die Impulslänge oder?
Ach Mist.
Ich hätte schwören können, den kann man mit 2 Bits auf beides
einstellen. OK. Dann muss man eben in der ISR die Richtung umstellen.
Ist jetzt auch kein Beinbruch.
Also: mein Fehler.
Ist aber lösbar und kein Problem.
Ich habe mir nochmal Gedanken zum ganzen gemacht. Heute hatte ich die
Möglichkeit die Fernsteuerungsimpulse nochmal genau am Oszilloskop
anzuschauen. Bei den alten Graupner 35MHz Empfängern liegt Uein bei 5V,
Knüppelstellung unten 1,1ms und Knüppelstellung oben 1,9ms. Bei dem
neuen Graupner Hott System liegt Uein bei 3V, die ms sind gleich. Macht
der Spannungsunterschied was? Oder kann der Mikrocontroller nur mit den
5V umgehen?
Mein Programm habe ich auch nochmal geändert. Aber irgendwo ist noch ein
Denkfehler. Der Mikrocontroller ist auf 2MHz eingetellt d.h. das ein
Timerzählen 0,5us dauert. Da der Servokanal bei der Mittelstellung einen
Wert von 1,5ms hat müsste der Timer dann einen Wert von 3000 haben.
1
#include<avr/io.h>
2
#define F_CPU 2000000
3
#include<util/delay.h>
4
#include<stdlib.h>
5
6
intpwm;
7
intflanke;
8
9
intmain(void)
10
{
11
TCCR1B|=(1<<ICES1);// steigende Flanke zur Auswertung des ICP
12
TCCR1B|=(1<<CS10);//Quelle für Timer/Counter = CPU-Takt
13
TIMSK|=(1<<TICIE1);//Capture Interrupt Enable
14
DDRD&=~(1<<PB0);// Impuls von Fernsteuerung (Atmega8 ICP1)
15
PORTD|=(1<<PB0);//Pullup aktiviert
16
DDRD|=(1<<PD6);//LED = Ausgang
17
18
while(1)
19
{
20
if(pwm<3000)
21
{
22
PORTD|=(1<<PD6);//wenn der Knüppel unterhalb der Mittelposition LED = ein
23
}
24
if(pwm>3000)
25
{
26
PORTD&=~(1<<PD6);//wenn der Knüppel oberhalb der Mittelposition LED = aus
27
}
28
}
29
}
30
31
ISR(TIMER1_CAPT_vect)
32
{
33
if(flanke==0)
34
{
35
TCNT1H=0;//Timer auf null
36
TCNT1L=0;//Timer auf null
37
TCCR1B&=~(1<<ICES1);// fallende Flanke zur Auswertung des ICP
38
flanke=1;
39
}
40
else
41
{
42
flanke=0;
43
TCCR1B|=(1<<ICES1);// steigende Flanke zur Auswertung des ICP
> if (pwm < 3000)> {> PORTD|=(1<<PD6); //wenn der Knüppel unterhalb der Mittelposition LED = >ein> }> if (pwm > 3000)> {> PORTD&= ~(1<<PD6); //wenn der Knüppel oberhalb der Mittelposition LED >=
aus
> }
und wenn pwm nun genau 3000 ist, passiert was?
Gruß Jonas
> Mein Programm habe ich auch nochmal geändert. Aber irgendwo ist> noch ein Denkfehler.
Sei vorsichtig mit den exakten Zeiten.
Gerade bei älteren Fernsteuerungen war das alles nicht so genau. Deshalb
hat man ja auch Trimmungen am Fernsteuersender, damit man da die
Feineinstellung machen kann.
Gab man einen Sender zum Service, dann wurden all die Schwingkreise neu
eingestellt und abgeglichen. Kam der Sender vom Service zurück, dann
konnte es schon passieren, dass die vorherigen Trimmungseinstellungen
nicht mehr genau stimmten und alle Servos ein wenig verstellt waren. Mit
der Zeit hat sich dann alles wieder ein wenig verschoben.
D.h. wenn du es Praxistauglich machen willst, dann siehst du einen
Mechanismus vor, mit der Benutzer sagen kann: Das hier sind meine
Knüppelendpositionen, bitte merk dir das.
Mit den modernen Computersendern hat sich das geändert, die sind
stabiler. Aber auch da ist es praktisch, wenn man einmal den Knüppel von
einem Ende zum anderen durchfährt, der Elekronik sagt: ich binn jetzt am
unteren Ende und der µC merkt sich ganz einfach den Zahlenwert und
leitet alles andere davon ab. Letzten Endes interssiert ja die exakte
Pulszeit keinen, sondern es interessiert die Wirkung an den Servos die
man damit erreicht. D.h. der Zusammenhang ist nicht über die Pulszeit,
sondern es interessiert der direkte Zusammenhang Knüppelstellung zu
Servoposition. Egal wie lang dann der Puls ist, der aus der
Knüppelstellung entsteht.
> Der Mikrocontroller ist auf 2MHz eingetellt
Nominell.
In der Praxis hast du Abweichungen. Der interne RC-Oszillator ist nicht
besonders genau und auch nicht besonders frequenzstabil.
Generell: wenn Timings wichtig sind, kommst du um einen Quarz nicht
herum.
Nachdem du die Flankenrichtung umgestellt hast, solltest du noch
sicherheitshalber das Capture Interrupt Flag im TIFR Register löschen.
Das Datenblatt sagt sogar, du musst es tun. Durch den Vorgang des
Umstellens spricht nämllich die Auswerteelektronik an, die einen
Flankenwechsel detektiert.
1
ISR(TIMER1_CAPT_vect)
2
{
3
if(flanke==0)
4
{
5
TCNT1H=0;//Timer auf null
6
TCNT1L=0;//Timer auf null
7
TCCR1B&=~(1<<ICES1);// fallende Flanke zur Auswertung des ICP
8
flanke=1;
9
}
10
else
11
{
12
flanke=0;
13
TCCR1B|=(1<<ICES1);// steigende Flanke zur Auswertung des ICP
14
pwm=ICR1L;// Zählerstand speichern
15
}
16
17
TIFR=(1<<ICF1);
18
}
(Die seltsame Form mit Zuweisung stimmt schon)
Edit: noch gesehen
1
pwm=ICR1L;// Zählerstand speichern
und wie soll da ein Wert von 3000 raus kommen können? Ein einzelnes
AVR-Register kann als 8 Bit Register logischweise nie größer als 255
sein.
1
pwm=ICR1;// Zählerstand speichern
Der Compiler weiß schon, dass ICR1 eigentlich kein AVR Register ist,
sondern sich aus ICR1H und ICR1L zusammensetzt. Der macht das schon
richtig.
Hier genauso
1
if(flanke==0)
2
{
3
TCNT1H=0;//Timer auf null
4
TCNT1L=0;//Timer auf null
1
if(flanke==0)
2
{
3
TCNT1=0;
Im übrigen musst den Timer gar nicht auf 0 zurückstellen.
Machst du ja bei einer Uhr auch nicht, wenn die keine Stoppuhr Funktion
hat.
WEnn ein Vorgang startet und der Sekundenzeiger auf 23 ist, und er endet
bei einem Sekundenzeigerstand von 48, dann hat der Vorgang 48-23 = 25
Sekunden gedauert.
Du musst dir also nur den Zählerstand bei der steigenden Flanke merken
und den bei der fallenden Flanke. Die Differenz ergibt dir immer die
Anzahl der Takte dazwischen. Dank unsigned Rechnung funktioniert das
auch, wenn der Timer überläuft, solange nicht mehr als 65535 Takte
Differenz zustande kommen.
1
uint16_tflankeStart;
2
3
...
4
5
ISR(TIMER1_CAPT_vect)
6
{
7
if(flanke==0)
8
{
9
flankeStart=ICR1;
10
TCCR1B&=~(1<<ICES1);// fallende Flanke zur Auswertung des ICP
11
flanke=1;
12
}
13
else
14
{
15
pwm=ICR1-flankeStart;
16
flanke=0;
17
TCCR1B|=(1<<ICES1);// steigende Flanke zur Auswertung des ICP
18
}
19
20
TIFR=(1<<ICF1);
21
}
und pwm solltest ebenfalls als uint16_t definieren (und es muss volatile
sein). Du kannst ja keine negative Differenz haben.
PS:
Wenn du das nächste mal eine µC-SChaltung entwickelst, dann sieh auf
deinem Protoyp eine Möglichkeit vor, wie du dir Zahlenwerte als Zahlen
ansehen kannst.
Ohne LCD oder USART programmierst du nach dem Motto 'Ich stochere
solange im Nebel rum, bis ich zufällig was finde'. Das musst du
abstellen! Eine Ausgabemöglichkeit zu Debug-Zwecken ist bei einem
Protoyp eine unabdingbare Hilfe. Ohne werden die Dinge aufwändig und man
muss schon gut programmieren können, um rein aus dem Source Code
Denkfehler zu erkennen und rauszufinden, wo man sich vertan hat.
Ein Display habe ich dran. Ich habe es auch mal mit in das Programm
aufgenommen.
1
#include<avr/io.h>
2
#define F_CPU 8000000
3
#include<util/delay.h>
4
#include"lcd-routines.h"
5
#include<stdlib.h>
6
7
intflanke;
8
uint16_tflankeStart;
9
volatileuint16_tpwm;
10
11
intmain(void)
12
{
13
TCCR1B|=(1<<ICES1);// steigende Flanke zur Auswertung des ICP
14
TCCR1B|=(1<<CS11)|(1<<CS10);//Quelle für Timer/Counter = CPU-Takt/64
15
TIMSK|=(1<<TICIE1);//Capture Interrupt Enable
16
DDRD&=~(1<<PB0);// Impuls von Fernsteuerung (Atmega8 ICP1)
17
PORTD|=(1<<PB0);//Pullup aktiviert
18
DDRD|=(1<<PD6);//LED = Ausgang
19
20
lcd_init();
21
22
while(1)
23
{
24
if(pwm<187)
25
{
26
PORTD|=(1<<PD6);//wenn der Knüppel unterhalb der Mittelposition LED = ein
27
}
28
if(pwm>188)
29
{
30
PORTD&=~(1<<PD6);//wenn der Knüppel oberhalb der Mittelposition LED = aus
31
}
32
lcd_clear();
33
lcd_string("PWM:");
34
lcd_setcursor(0,2);
35
charBuffer[20];
36
itoa(pwm,Buffer,10);
37
lcd_string(Buffer);
38
_delay_ms(100);
39
}
40
}
41
42
ISR(TIMER1_CAPT_vect)
43
{
44
if(flanke==0)
45
{
46
flankeStart=ICR1;
47
TCCR1B&=~(1<<ICES1);// fallende Flanke zur Auswertung des ICP
48
flanke=1;
49
}
50
else
51
{
52
pwm=ICR1-flankeStart;
53
flanke=0;
54
TCCR1B|=(1<<ICES1);// steigende Flanke zur Auswertung des ICP
55
}
56
TIFR=(1<<ICF1);
57
}
Die Frequenz des uC habe ich auf 8MHz umgestellt und die Werte neu
berechnet.
Für den Wert PWM auf dem Display zeigt es mir 0 an. Die Led leuchtet.
Egal wie der Knüppel an der Fernsteuerung steht es ändert sich nichts.
>DDRD&=~(1<<PB0);// Impuls von Fernsteuerung (Atmega8 ICP1)
2
>PORTD|=(1<<PB0);//Pullup aktiviert
3
>DDRD|=(1<<PD6);//LED = Ausgang
4
>
Beim Mega8 ist der ICP1 Eingang aber am Port B, nicht am Port D
1
DDRB&=~(1<<PB0);// Impuls von Fernsteuerung (Atmega8 ICP1)
2
PORTB|=(1<<PB0);//Pullup aktiviert
3
DDRD|=(1<<PD6);//LED = Ausgang
ja, ich weiss, du hast PB0 geschrieben. Aber dieses PB0 gilt nicht viel,
das ist einfach nur ein #define für 0. Das da das B drinnen vorkommt hat
keine Bedeutung. In meinen Augen wärs besser gewesen, da nicht ein PB0,
PA0, PD0 etc einzuführen, sonder ein BIT0, BIT1, BIT2. Denn genau das
ist die Aussage: Es handelt sich um das Bit 0. Es ist damit nicht gesagt
an welchem Port. Der Port, bzw. das Register, steht links vom =
Jetzt habe ich nochmal die weiteren Fehler verbessert. Leider tut sich
immer noch nichts. Die Platine habe ich auch nochmal überprüft. Es ist
alles richtig angeschlossen. Das Impulssignal von der Fernsteuerung geht
an PB0 (ICP1) Pin 14.
1
#include<avr/io.h>
2
#define F_CPU 8000000
3
#include<util/delay.h>
4
#include"lcd-routines.h"
5
#include<stdlib.h>
6
7
intflanke;
8
uint16_tflankeStart;
9
volatileuint16_tpwm;
10
sei();
11
12
ISR(TIMER1_CAPT_vect)
13
{
14
if(flanke==0)
15
{
16
flankeStart=ICR1;
17
TCCR1B&=~(1<<ICES1);// fallende Flanke zur Auswertung des ICP
18
flanke=1;
19
}
20
else
21
{
22
pwm=ICR1-flankeStart;
23
flanke=0;
24
TCCR1B|=(1<<ICES1);// steigende Flanke zur Auswertung des ICP
25
}
26
TIFR=(1<<ICF1);
27
}
28
29
intmain(void)
30
{
31
TCCR1B|=(1<<ICES1);// steigende Flanke zur Auswertung des ICP
32
TCCR1B|=(1<<CS11)|(1<<CS10);//Quelle für Timer/Counter = CPU-Takt/64
33
TIMSK|=(1<<TICIE1);//Capture Interrupt Enable
34
DDRB&=~(1<<PB0);// Impuls von Fernsteuerung (Atmega8 ICP1)
35
PORTB|=(1<<PB0);//Pullup aktiviert
36
DDRD|=(1<<PD6);//LED = Ausgang
37
38
lcd_init();
39
40
while(1)
41
{
42
if(pwm<187)
43
{
44
PORTD|=(1<<PD6);//wenn der Knüppel unterhalb der Mittelposition LED = ein
45
}
46
if(pwm>188)
47
{
48
PORTD&=~(1<<PD6);//wenn der Knüppel oberhalb der Mittelposition LED = aus
MIr ist nicht klar, wie du DIESEN Code durch den Compiler gebracht hast!
(Wahrscheinlich gar nicht und du hast Warnungen und Fehlermeldungen des
Compilers ignoriert)
Ein sei() ist eine ausführbare Anweisung. Und die muss als solche in C
immer in einer Funktion stehen. Die kann nicht ausserhalb sein!
Ein sei() ist das letzte, was man vor der Hauptschleife macht. Denn dann
ist alles fertig konfiguriert und mit dem sei() setzt man sozusagen das
endgültige Startsignal: Jetzt gehts loohoos! Jetzt gehts loohoos!
1
intmain(void)
2
{
3
TCCR1B|=(1<<ICES1);// steigende Flanke zur Auswertung des ICP
4
TCCR1B|=(1<<CS11)|(1<<CS10);//Quelle für Timer/Counter = CPU-Takt/64
5
TIMSK|=(1<<TICIE1);//Capture Interrupt Enable
6
DDRB&=~(1<<PB0);// Impuls von Fernsteuerung (Atmega8 ICP1)
Vielen Dank. Jetzt ist der Compiler glücklich aber es tut sich immer
noch nichts. Kann es vielleicht an dem aktivierten Pullup liegen? Müsste
es nicht ein Pulldown sein?
Steffen Ha schrieb:> Vielen Dank. Jetzt ist der Compiler glücklich aber es tut sich immer> noch nichts. Kann es vielleicht an dem aktivierten Pullup liegen? Müsste> es nicht ein Pulldown sein?
Kann man so nicht sagen. Hängt davon ab, was die Elektronik macht, die
den Puls generiert. Aber normale Modellbauempfänger machen da
üblicherweise kein Problem. Der Pullup ist hochohmig genug um den
Ausgangstreiber des Empfängers nicht zu stören und sorgt für definierte
Pegel, wenn der EMpfänger nicht an ist.
Ev. SOlltest du mal ganz einfach versuchen, ob der Pegel deines
Empfängers überhaupt ausreicht um den µC anzusteuern. Ich hab jetzt die
genauen VOltzahlen nicht im Kopf, aber 3.3V am Eingang sind schon eher
hart an der Grenze.
1
#include<avr/io.h>
2
3
intmain()
4
{
5
DDRB&=~(1<<PB0);
6
PORTB|=(1<<PB0);
7
8
DDRD|=(1<<PD6);
9
10
while(1){
11
if(PINB&(1<<PB0))
12
PORTD|=(1<<PD6);
13
else
14
PORTD&=~(1<<PD6);
15
}
16
}
Da ich nicht weiß, wie deine LED angesteuert werden muss, schreib ich
das mal so. Probiers mit einem Draht an PB0 aus. Die LED muss darauf
reagieren, wenn du mit dem Draht an Masse gehst (wegen dem Pullup).
Ziel ist es, dass die LED abgeschaltet ist, wenn du an Masse bist. Wenn
nicht, dann drehst du einfach den if-Teil um.
Dann gehst du mit dem Draht an deinen Modellbauempfänger. Die LED müsste
aus sein, bzw. nur ganz schwach glimmen. Wenn du direkt in die LED
hinainschaust, müsstest du das Substrat glimmen sehen. Dies deshalb weil
du im Grunde damit eine kleine vom Servosignal abhängige PWM gebaut
hast. Siehst du jedoch gar nichts, dann reicht der Pegel vom Empfänger
nicht um am µC eine 1 auszulösen. Leuchtet die LED hell durch, dann
schafft der Ausgang es nicht, den Pin gegen den Pullup auf Masse zu
ziehen.
Mehr lässt sich so erst mal mit diesem einfachen Programm nicht
feststellen. Durch Erweiterung zu einem Monoflop könnte man den Test
noch etwas spezifischer machen, aber fürs erste denke ich, könnte man
auch so rauskriegen, was da hardwaremässig los ist.
> Jetzt ist der Compiler glücklich aber es tut sich immer
noch nichts.
'tut sich nichts' heißt hoffentlich, dass dein pwm Wert immer noch
laufend 0 ist. Denn da fehlt noch die atomare Absicherung - die kommt
als nächtes. Aber auf Dauer-0 sollte der Wert nicht sein, selbst wenn
der WErt der rauskommt blödsinnig ist.
Zum LED Test: Wenn ich mit dem Draht gegen Masse gehe geht sie aus. Wenn
ich jetzt an den Empfänger gehe flackert die LED, jedoch nicht ziemlich
hell (Knüppelposition unten). Gehe ich dann mit dem Knüppel hoch wird
sie heller und flackert immer noch. Jedoch glimmt sie in keinem Fall.
Zum tut sich nichts: Auf dem Display steht für den PWM Wert eine dauer
Null. Diese verändert sich auch nicht.
Ich habe nochmal zwei Bilder vom Fernsteuerungssignal hinzugefügt. Bild
1 zeigt die untere Knüppelstellung und Bild 2 die obere
Knüppeleinstellung. Zeitablenkung 0,2ms. Die Bilder sind von dem neuen
2,4GHZ Empfängern diese geben nur noch 3V Impulse aus. Zur Zeit verwende
ich aber einen alten 35MHz Empfänger der 5V ausgibt. Die Impulssignale
sind aber von den Zeiten gleich.
Steffen Ha schrieb:> Zum LED Test: Wenn ich mit dem Draht gegen Masse gehe geht sie aus. Wenn> ich jetzt an den Empfänger gehe flackert die LED, jedoch nicht ziemlich> hell (Knüppelposition unten). Gehe ich dann mit dem Knüppel hoch wird> sie heller und flackert immer noch. Jedoch glimmt sie in keinem Fall.
Das passt schon.
Wichtig ist, dass man an der LED eine Reaktion auf die Knüppelstellung
sieht. Ich wusste nur nicht, wie 'heftig' die Reaktion sein würde. Eine
5% PWM ist nicht besonders hell.
D.h. hardwaremässig ist alles in Ordnung.
Muss also noch was im Programm sein.
Ich spiel mir das mal in den Simulator und seh mal nach, was da noch
nicht stimmt.
Hmm. Im Simulator ist nichts Aussergewöhnliches zu sehen. Schalte ich
den Pin PB0, dann wird die ISR aufgerufen, genauso wie es sein sollte.
Auch die Variable pwm verändert sich, genauso wie es sein sollte.
Leider hab ich keinen Mega8 mehr da, sonst könnte ich das mal brennen
und den µC mal an einen Servoausgang eines Empfängers hängen. Du hängst
doch am Servoausgang und nicht etwa am Summensignal?
Ansonsten bin ich jetzt mit meinem Latein am Ende.
Edit: Mit einem Mega16 könnt ich das mal probieren. Wird aber ein
Weilchen dauern, bis ich die Verkabelung hab. Muss erst mal einen
Empfänger irgendwo ausbauen und mir ein entsprechendes Kabel machen.
Ich habe den uC ganz normal am Kanal 1 des Empfänger angeschlossen.
Die Led habe ich unten im Programm mal auskommentiert und oben in der
ISR eingefügt. Sie geht an. Jetzt habe ich alles wieder rückgängig
gemacht und es geht. Wie kann das sein? Das Display zeigt mir jetzt
Werte von 143 bis 247. Die passen aber noch nicht zu den Zeiten vom
Oszillokskop. Das Problem mit dem Programm habe ich schon mal gehabt.
1
#include<avr/io.h>
2
#define F_CPU 8000000
3
#include<util/delay.h>
4
#include"lcd-routines.h"
5
#include<stdlib.h>
6
#include<avr/interrupt.h>
7
8
9
10
intflanke;
11
uint16_tflankeStart;
12
volatileuint16_tpwm;
13
14
ISR(TIMER1_CAPT_vect)
15
{
16
if(flanke==0)
17
{
18
flankeStart=ICR1;
19
TCCR1B&=~(1<<ICES1);// fallende Flanke zur Auswertung des ICP
20
flanke=1;
21
}
22
else
23
{
24
pwm=ICR1-flankeStart;
25
flanke=0;
26
TCCR1B|=(1<<ICES1);// steigende Flanke zur Auswertung des ICP
27
}
28
TIFR=(1<<ICF1);
29
30
PORTD|=(1<<PD6);
31
}
32
33
intmain(void)
34
{
35
TCCR1B|=(1<<ICES1);// steigende Flanke zur Auswertung des ICP
36
TCCR1B|=(1<<CS11)|(1<<CS10);//Quelle für Timer/Counter = CPU-Takt/64
37
TIMSK|=(1<<TICIE1);//Capture Interrupt Enable
38
DDRB&=~(1<<PB0);// Impuls von Fernsteuerung (Atmega8 ICP1)
39
PORTB|=(1<<PB0);//Pullup aktiviert
40
DDRD|=(1<<PD6);//LED = Ausgang
41
42
lcd_init();
43
44
sei();
45
46
while(1)
47
{
48
if(pwm<187)
49
{
50
//PORTD|=(1<<PD6); //wenn der Knüppel unterhalb der Mittelposition LED = ein
51
}
52
if(pwm>188)
53
{
54
//PORTD&= ~(1<<PD6); //wenn der Knüppel oberhalb der Mittelposition LED = aus
Steffen Ha schrieb:> Sie geht an. Jetzt habe ich alles wieder rückgängig> gemacht und es geht. Wie kann das sein?
Gute Frage :-)
> Das Display zeigt mir jetzt> Werte von 143 bis 247. Die passen aber noch nicht zu den Zeiten vom> Oszillokskop.
Wieso? Passt doch ziemlich gut
8000000 / 64 = 125000
1/125000 * 143 macht 0.001144, also ca. 1.1 ms
1/125000 * 247 macht 0.001976, also ca. 1.9 ms
Ist vollkommen im Rahmen dessen, was mit Servosignalen zu erwarten ist.
Das Phänomen hatte ich schon mal mit dem Programm. Nachdem ich vorher
ein anderes drauf hatte ging dann das eigentliche.
Ja die Werte passen super. Was müsste ich jetzt bei den Fusebits
einstellen wenn ich einen externen 8MHz Quarzoszillator angeschlossen
habe?
Vielen vielen Dank für deine/eure Hilfe.
Gruß Steffen
Steffen Ha schrieb:> Das Phänomen hatte ich schon mal mit dem Programm. Nachdem ich vorher> ein anderes drauf hatte ging dann das eigentliche.>> Ja die Werte passen super. Was müsste ich jetzt bei den Fusebits> einstellen wenn ich einen externen 8MHz Quarzoszillator angeschlossen> habe?AVR Fuses: Taktquellen Fuse Einstellung
Hast du eienn Quarz oder einen Quarzoszillator?
Das sind unterschiedliche Dinge und werden auch unterschiedlich gefused
Hallo Zusammen,
ich habe mal wieder ein kleines Problem. Und zwar funktioniert die
Schaltung mit einem Bürstenmotor der Speed 400 und Speed 600 Klasse ohne
Last einwandfrei. Betreibe ich den Speed 600 mit einer Luftschraube oder
nehme einen Graupner Ultra Motor mit Luftschraube so scheint der
Mikrocontroller abzustürzen wenn ich schnell Gas gebe oder es gegen
Vollgas geht. Nach abstecken des Akkus funktioniert die Schaltung wieder
bis zu dem Punkt. Bei der Schaltung habe ich mich an dem Thema
Motoransteuerung mit PWM
orientiert:http://www.mikrocontroller.net/articles/Motoranste...
Woran kann es liegen? Im Datenblatt von dem Halbbrückentreiber IR2184
wurde noch ein ganz andere Schaltungsmöglichkeit gezeigt. Was sind die
unterschiede zu meiner Variante? Vielen vielen Dank für euere Hilfe.
Schönen Abend. Gruß Steffen
Steffen Ha schrieb:> Woran kann es liegen?
An einer nicht ausreichenden Entstörung deiner Motoren bzw. was im
Grunde dasselbe ist, an nicht ausreichenden Entstörmassnahmen am µC. Da
sind dann die 100n an VCC/GND einfach zu wenig Holz.
Aber getreu dem Motto: Störungen am besten gleich an der Quelle
vernichten, gehören an den Motor Entstörkondensatoren.
Steffen Ha schrieb:> Was für Kondensatoren würden sich dann VCC/GND eignen?
Probier mal sowas
http://www.sv-falkenhagen.de/ubootwiki/index.php/Entst%C3%B6ren_von_B%C3%BCrstenmotoren
Wenns wirklich der Motor ist (wovon ich ausgehe), dann musst du den
Hebel erst mal am Motor ansetzen.
von jedem Motoranschluss 47n zum Gehäuse verlöten und dann noch 47n von
Motoranschluss zu Motoranschluss.
Aber machs wirklich am Motor! Das HF-Zeugs muss an der Quelle "entsorgt"
werden.
Das lese ich mir gleich mal durch. Die 47n besorge ich mir morgen und
teste es dann umgehend. Kannst du mir noch die Frage zu den
unterschiedlichen Schaltungen erklären. Wäre super.
Ich habe jetzt noch mal in den Datenblättern von den Graupner Ultra und
Robbe Sports Motoren nachgeschaut. Da steht das sie alle serienmäßig
entstört sind.
Gruß Steffen