Hallo Leute!
Mit folgendem Code möchte ich alle LEDs meines STK500s einschalten, wenn
irgendein Zeichen vom UART empfangen wird.
Wenn nichts empfangen wird, soll die Endlosschleife ein Lauflicht
(später Schrittmotor) leuchten lassen.
Ich habe nun versucht, mit einem Terminal ein Zeichen zum Board zu
schicken, leider reagiert es nicht (springt nicht in die
Interrupt-Routine), sodass ständig nur das Lauflicht leuchtet.
Wisst ihr wo mein Fehler ist?
Hier ist mein Code:
Ok, habe es herausgefunden, das Flag "RXCIE" im UCSRA-Register war nicht
gesetzt, welches für Interrupts über UART zuständig ist.
Nun eine weitere Frage:
Mein Controller empfängt nun das Zeichen, springt auch in die
Interrupt-Routine, leider kommt er aber aus der Interrupt-Routine nicht
mehr raus.
(es blinken nun alle LEDs ( ~(0xFF) und ~(0x00) ) )...
Wisst ihr woran das liegen könnte?
Aus dem Datenblatt (hier zu atmegaXX8):
When the Receive Complete Interrupt Enable (RXCIEn) in UCSRnB is set,
the USART Receive Complete interrupt will be executed as long as the
RXCn Flag is set (provided that global inter- rupts are enabled). When
interrupt-driven data reception is used, the receive complete routine
must read the received data from UDRn in order to clear the RXCn Flag,
otherwise a new interrupt will occur once the interrupt routine
terminates.
Das RXC Flag wird gelöscht, indem die Daten abgeholt werden. Wie das in
der Hardware verdrahtet ist - irgendwas mit FlipFlop.
So...das Programm läuft jetzt soweit, allerdings habe ich noch zwei
Problemchen:
Wenn ich die Taste "1", "2" oder "3" im Terminal drücke, dann ändert der
Controller die Delaytime leider nicht.
Außerdem ist mein Flash jetzt schon 25 % voll! Woran liegt das?
Hier der Code:
Jap, lag wohl an dem volatile.
Wie könnte man das mit der Delaytime machen, damit die Werte "konstant"
werden bzw. der Flashspeicher eben nicht zu sehr belegt wird?!
Gruß
Ralf
@ Ralf (Gast)
>Wie könnte man das mit der Delaytime machen, damit die Werte "konstant">werden bzw. der Flashspeicher eben nicht zu sehr belegt wird?!
Glotzn ofmachn, geeene Fedbemm fressen und orweidn!
Soo...Heute wollte ich dann mal wieder eine kleine Änderung am Code
vornehmen, leider ohne Erfolg.
Da ich gerne mittels Eingabe über das Terminal von "e" und "a" (ein,
aus) den Motor einschalten und ausschalten möchte, habe ich folgendes
gecodet.
Leider funktioniert es aber nicht.
Anfangs soll der Motor stillstehen. Sobald ein "e" gesendet wird, soll
der Motor eingeschaltet werden. Sobald (währenddessen) ein "a" geschickt
wird, soll der Motor ausgeschaltet werden.
Wenn man das Board einschaltet, soll der Motor stillstehen und der
Controller auf einen Befehl warten
.
Wo liegt mein Problem?
Wozu sollen die sei() in motor_einschalten und motor_ausschalten gut
sein?
_delay_ms mit einer Variable als Parameter ist ein no-go. Bitte
Dokumentation zu der Funktion lesen.
Dein Hauptproblem hier ist aber die fehlende Endlosschleife in main.
das mit der delay_ms und den Variablen habe ich bereits gelesen und
werde es auch ändern.
Aber was ist das Problem, dass in der main keine Endlosschleife ist?
Ich schalte doch den Interrupt scharf (sei()), sodass ein Interrupt
kommen kann wann und wie er will, oder sehe ich das falsch?
Was stimmt in meinem Code denn (außer der delay_ms) nicht , dass es
nicht so funktioniert wie ich es gerne hätte? ;)
Gruß
Ralf
Ralf schrieb:> Aber was ist das Problem, dass in der main keine Endlosschleife ist?> Ich schalte doch den Interrupt scharf (sei()), sodass ein Interrupt> kommen kann wann und wie er will, oder sehe ich das falsch?
Aber ohne die Endlosschleife verlässt du main() (beendest also quasi das
Programm), und der exit-Code der AVR-Libc beinhaltet ein cli(), schaltet
also deine Interrupts gleich wieder ab.
Ralf schrieb:> Und wie ist nun die Lösung zu meinem Problem?
Ach komm, das kannst du auch alleine lösen.
Ich wiederhole das Problem nochmal:
"Du hast keine Endlosschleife in main()."
Zusätzlicher Hinweis: eine Schleife kann auch leer sein.
@Ralf
>> Und wie ist nun die Lösung zu meinem Problem?>> Ach komm, das kannst du auch alleine lösen.> Ich wiederhole das Problem nochmal:> "Du hast keine Endlosschleife in main().">> Zusätzlicher Hinweis: eine Schleife kann auch leer sein.
Allerdings will man das eigentlich gar nicht.
> Ach komm, das kannst du auch alleine lösen.
Wenns nur das wäre. Der ganze Programmaufbau ist Mist.
Die Arbeit kommt in die Hauptschleife in main (oder später mal in eine
Interrupt Funktion die von einem Timer angetrieben wird). Der UART
Interrupt wertet meinetwegen das empfangene Zeichen aus und stellt ein
paar globale Variablen (Flags) so, dass in der Hauptschleife das
Richtige getan wird.
Delays in einer ISR sind ein absolutes NoNo. (ausser vielleicht ganz
kurze delays im µs Bereich). Und eine Endlosschleife in einer ISR, die
dann wieder durch einen anderen Interrupt unterbrochen wird ... dafür
sollte man dir den µC gleich wieder wegnehmen :-)
Dass dieses Projekt wohl eines meiner Ersten mit Mikrocontrollern ist,
solltet ihr vielleicht wissen.
Dass ihr den Controller in- und auswändig kennt, das glaube ich euch
gerne und schätze es sehr.
Doch immer vom hohen Ross auf die "Kleinen" abfällig zu kommentieren
finde ich nicht unbedingt angebracht a la:
> Wenns nur das wäre. Der ganze Programmaufbau ist Mist.
Traurig. Wirklich traurig.
Ralf schrieb:> Dass dieses Projekt wohl eines meiner Ersten mit Mikrocontrollern ist,> solltet ihr vielleicht wissen.
Ist ok. Jeder muss mal anfangen
> Dass ihr den Controller in- und auswändig kennt, das glaube ich euch> gerne und schätze es sehr.
Das hat mit 'dem Controller' an sich nichts zu tun.
> Doch immer vom hohen Ross auf die "Kleinen" abfällig zu kommentieren> finde ich nicht unbedingt angebracht a la:>> Wenns nur das wäre. Der ganze Programmaufbau ist Mist.>> Traurig. Wirklich traurig.
Aber die Wahrheit :-)
Und ob es dir gefällt oder nicht, deinem µC ist es völlig wurscht ob es
dein erster Kontakt mit ihm ist oder nicht. Der schlägt erbarmungslos
zu. In deinem Fall wird nach dem (geschätzten) 300sten hintereinander
empfangenen Zeichen 'e' Schluss mit lustig sein und dein µC wird
erbarmungslos abstürzen oder eventuell noch schlimmere Sachen machen.
Also.
Der Grundaufbau 'jedes' µC-Programmes sieht so aus
1
intmain()
2
{
3
Hardwareinitialisierenundeinstellen
4
5
eventuellsei(),wennmitInterruptsgearbeitetwird
6
7
while(1){
8
9
HierdrinnwirddieeigentlicheArbeitgemacht
10
11
}
12
}
Wenn es Interrupts gibt, dann machen deren Funktionen relativ wenig
Arbeit selber. Wenn sie auf den Rest des Programmes einen Einfluss
haben, dann maximal so, dass sie in globalen Variablen Kennwerte
hinterlassen, die den Programmteil in main() der innerhalb der
Hauptschleife steht, dazu veranlassen das Richtige zu tun.
Das ist dein grundsätzlicher Programmaufbau. Es gibt auch Ausnahmen und
es gibt auch Variationen dazu. Aber die nächsten 20 bis 30 Projekte
wirst du praktisch immer gut fahren, wenn du dich an diesen
Programmaufbau hältst.
AVR-GCC-Tutorial
Hallo Karl Heinz
Das hast du super erklärt! Und sogar gleich eine Lösung angeboten.. Da
hat es der Ralf aber einfach. Ob er damit jetzt noch einen Lerneffekt
hat?
Hoffen wir es mal.
Steffen
Ach ja, wie würde es denn aussehen wenn "MotorRunning" nicht gleich ein
ganzes Byte einnehmen würde sondern wirklich nur ein Flag (Bit) in einem
Byte? Mal angenommen das Byte sollte "Control" heißen und das Flag
"MotorRunning" ?
Lerne nämlich auch gerade "C"
Gruß Steffen
Steffen H. schrieb:> Ach ja, wie würde es denn aussehen wenn "MotorRunning" nicht gleich ein> ganzes Byte einnehmen würde sondern wirklich nur ein Flag (Bit) in einem> Byte?
Grundsätzlich ist die kleinste Einheit, die du in C ansprechen kannst
immer ein komplettes Byte. Willst du auf einzelne Bits runter, dann
musst du mittels | bzw & die entsprechende Bitposition ausmaskieren.
> Mal angenommen das Byte sollte "Control" heißen und das Flag> "MotorRunning" ?
OK. Für die Bitposition benutze ich ein #define, damit ich mir keine
Zahlen merken muss :-) Bin ja auch schon älter und ausserdem wird so der
Code schon mal einen ersten Schritt in Richtung selbstdokumentierend
nehmen.
1
#define MOTOR_RUNNING 0 // Bit 0 in Control
2
volatileuint8_tControl;
3
4
ISR(...)
5
{
6
7
....
8
9
switch'a':
10
Control&=~(1<<MOTOR_RUNNING);// Bit löschen
11
break;
12
13
switch'b'
14
Control|=(1<<MOTOR_RUNNING);// Bit setzen
15
break;
16
17
....
18
}
19
20
21
....
22
23
intmain()
24
{
25
....
26
while(1){
27
28
if(Control&(1<<MOTOR_RUNNING)){
29
...
30
}
31
}
32
}
Ganz normale Bit-Setz, Bit-Lösch und Bit-Abfrage Operationen, wie sie in
jedem Programm zu Hauf vorkommen. Nur war bei dir wahrscheinlich Bit
setzen bzw. Bit löschen meistens auf einen Port bezogen um damit einen
Portpin zu schalten. Aber die Syntax ist ja nicht auf Ports beschränkt.
Die Operationen setzen bzw. löschen bzw. fragen ein Bit ab. Wo das
zugehörige Byte herkommt interessiert ja die Operationen nicht.
Danke Karl Heinz.
Mir ist nämlich aufgefallen das in C schnell mal ein ganzes Byte für nur
ein Bit herhalten muss. Ich finde die Lösung über nur einem Bit besser,
da man nicht so viel Resourcen verschwendet, natürlich nur wenn noch ein
paar Flags mehr in das Byte "Control" kommen. Also geht es in C genauso
einfach wie in asm.
Steffen
Das ist die Version, die du als C-Neuling machen wirst.
Wenn deine C-Kentnisse umfangreicher sind (werden) (Lehrbücher lesen und
studieren!), dann wirst du das anders schreiben und dem Compiler mehr
Arbeit aufhalsen :-)
1
structcontrol_{
2
uint8_tmotorRunning:1;
3
uint8_tmotorDirection:1;
4
}
5
6
volatilestructcontrol_Control;
7
8
ISR(...)
9
{
10
11
....
12
13
switch'a':
14
Control.motorRunning=1;
15
break;
16
17
switch'e'_
18
Control.motorRunning=0;
19
break;
20
21
switch'+':
22
Control.motorDirection=0;
23
break;
24
25
switch'-':
26
Control.motorDirection=1;
27
28
....
29
}
30
31
....
32
33
// zur Vereinfachung der Schreibweise wieder ein paar Makros
Steffen H. schrieb:> Danke Karl Heinz.> Mir ist nämlich aufgefallen das in C schnell mal ein ganzes Byte für nur> ein Bit herhalten muss. Ich finde die Lösung über nur einem Bit besser,> da man nicht so viel Resourcen verschwendet, natürlich nur wenn noch ein> paar Flags mehr in das Byte "Control" kommen. Also geht es in C genauso> einfach wie in asm.
Kommt drauf an.
Wenn du die Bytes im SRAM hast, dann ist es kein Problem dafür jeweils
ein komplettes Byte zu benutzen. Wenn du den Platz nicht hast, dann muss
man wohl oder übel zusammenlegen.
die Überlegung
* du bekommst für nicht benutztes SRAM kein Geld zurück
* Bits auszumaskieren bringt zwar ein paar Bytes SRAM, kostet
aber immer etwas Programmcode. Umsonst ist nun mal nur der Tod
Karl Heinz Buchegger schrieb:
>* du bekommst für nicht benutztes SRAM kein Geld zurück
Da hast du Recht (-:
Aber diese Sache mit einem Struct anzugehen finde ich ja toll:
1
structcontrol_{
2
uint8_tmotorRunning:1;
3
uint8_tmotorDirection:1;
4
}
Das sieht dann auch sehr übersichtlich aus.
1
switch'a':
2
Control.motorRunning=1;
3
break;
4
5
switch'e'_
6
Control.motorRunning=0;
7
break;
8
9
switch'+':
10
Control.motorDirection=0;
11
break;
12
13
switch'-':
14
Control.motorDirection=1;
-> Und wieder was dazu gelernt..
Dank an dieses tolle Forum! Hier lernt mann mehr als in manch einem
Studium!
Weiter so..
Hallo Karl-Heinz!
Vielen Dank für deinen umfangreichen Lösungsansatz, finde ich wiederum
super, dass du mir so geholfen hast.
Ich werde den Programmablauf mal so in etwas übernehmen und testen.
Ob es für mein Referat allerdings nicht etwas zu umfangreich ist (Leute,
die noch NIE etwas von einem Mikrocontroller gehört haben), wage ich zu
bezweifeln :-/
Denn der Code selbst würde wohl schon die Zeit des Referats (10-12
Minuten) sprengen.
Gruß
Ralf