Archiv verlassen und diese Seite im Standarddesign anzeigen : BackLEDs unabhängig voneinander einschalten?
Hallo,
#include "asuro.h"
main()
{
//linke BackLED an
DDRC=(1<<PC1);
PORTC=(1<<PC1);
Msleep(1000);
//rechte BackLED an
DDRC=(1<<PC0);
PORTC=(1<<PC0);
}
mit diesem Code versuche ich erst die linke BackLED einzuschalten, und eine Sekunde später die rechte dazu. Die linke geht zwar an, aber dann passiert nichts mehr.
Kann mir jemand sagen, was falsch ist?
Gruss
M.
Meiner Meinung nach fehlt das Init
radbruch
02.07.2007, 16:46
Hallo
Die Funktion main() muss immer mit einer Endlosschleife enden! Sie wird eigentlich wie jede andere Funktion aufgerufen, allerdings ist nirgends definiert, wohin das Programm springen soll, wenn main() beendet ist.
Ausserdem sollte sie die Form
int main(void)
{
// hier kommt das eigentliche Programm rein
while(1);
return(1);
}
haben, sonst motzt der Compiler. int für den Rückgabewert, deshalb steht da auch immer return(1), und void für kein Parameter wird benötigt.
Ihr seid immer soooo schnell. asuro.h und Init(); benötigt man nicht, wenn man solche Programm schreibt, es genügt
#include <avr/io.h>
#include <avr/interrupt.h>
für die #defines und die Interrupts. Hab ich doch selbst erst gestern kapiert und erklärt:
https://www.roboternetz.de/phpBB2/viewtopic.php?p=295604#295604
Ohne asuro.h gibt's natürlich auch kein Msleep(), deshalb muss man mit Verzögerungsschleifen arbeiten:
unsigned int i,j;
for (i=0; i < 20; i++) { for (j=0; j < 65535; j++); }
20 in der i-Schleife sind ungefähr 'ne Sekunde Verzögerung.
Gruss
mic
unsigned int i,j;
for (i=0; i < 20; i++) { for (j=0; j < 65535; j++); }
Nur pass auf, daß Dir der Kompiler sowas nicht wegoptimiert...
nur besser ist sowas:
#define F_CPU 8000000
#include <util/delay.h>
...
...
uint8_t a;
for (a=0;a<100;a++)
_delay_ms(10);
Gruß Sebastian
radbruch
02.07.2007, 17:49
Aha, klasse. Bei optimierung=0 scheint er den Code drin zu lassen, aber mit delay.h ist es eleganter.
Ist natürlich fraglich, in wieweit man sich fertiger Funktionen bedient, denn irgendwann wird man dann wieder bei der asuro.h landen. Ich versuche doch jetzt mir das Schritt für Schritt zu erarbeiten, dann kann ich doch nicht schon bei der dritten Hürde auf vorgefertigtes zurückgreifen. 8-[
Gruß
mic
Ja gut,
delay.h ist ein Bestandteil von avr-gcc und beinhaltet noch ein paar "Zeitvernichtungs" Routinen.
Die sind sehr gut geschrieben(schau Dir mal delay.h an)es ist eigentlich Assembler pur, nur pass bloß mit -O0 auf, die Optimierung ganz abzuschalten ist keine gute Idee, vor allem in Verbundung mit _delay* Funktionen.
Es werden Fließkomaoperationen ausgeführt, die mit -Os komplett zu Kompilierzeit aufgelöst werden, bei -O0 bleiben sie drin, und wie gut der M8 damit umgehen kann weißt Du sicherlich selbst ;-)
ch versuche doch jetzt mir das Schritt für Schritt zu erarbeiten, dann kann ich doch nicht schon bei der dritten Hürde auf vorgefertigtes zurückgreifen.
Das ist sehr gut, es macht Spaß sowas zu lesen, wo ich noch mit dem Asuro gespielt hatte, hab ich den in Assembler programmiert, das hat auch viel Spaß gemacht, und vor allem, ich habe sehr viel über die AVR's gelernt !
Achja, noch was, wenn Du willst, daß Deine "sinnlosen" Schleifen nicht wegoptimiert werden, mußt Du die Variablen volatile deklarieren, aber das weißt Du sicherlich auch schon...
Gruß Sebastian
Hallo,
danke für eure Mühe,
habe die asuro.h drin weil ich sie dann sowieso brauche,
Init ist jetzt auch drin...
Jetzt habe ich erstmal versucht die BackLEDs nur auszuschalten
#include "asuro.h"
int main(void)
{
Init();
StatusLED(OFF);
DDRC=(1<<PC1);
DDRC=(1<<PC0);
//beide BackLED aus ?????????? linke ist an!!!!!!!!
PORTC=(0<<PC0);
PORTC=(0<<PC1);
while (1);
return 0;
}
die linke LED geht an, allerdings nicht ganz hell.
Mit BackLED(OFF,OFF) sind beide LEDs wirklich ganz aus
???
Gruss
M.
Nein,nein, überleg mal
DDRC=(1<<PC1);
DDRC=(1<<PC0);
In der ersten Zeile setzt Du PC1 auf Ausgang, Dein DDRC sieht so aus 00000010
In der Zweiten Zeile setzt Du PC0 auf Ausgang und überschreibst Du das was Du zuvor gesetzt hast Dein DDRC sieht jetzt so aus 00000001
Die Lösung:
DDRC=(1<<PC1)|(1<<PC0);
oder
DDRC=(1<<PC1);
DDRC |=(1<<PC0);
Mit der Portzuweisung geht es genauso.
Gruß Sebastian
radbruch
02.07.2007, 21:24
Hallo
als ich noch mit dem Asuro gespielt hatte, hab ich den in Assembler programmiert
Ich hab' mir den asuro ins Haus geholt, weil ich endlich mal in c einsteigen wollte. In Assembler ist halt alles was anspruchsvoller ist etwas zäh, da ist c als "Hochsprache" schon deutlich mächtiger. Außerdem kann man mit c auch recht nahe an der Maschine bleiben, wenn man weis, wie es geht. Mit Hilfe der tollen Tutorials auf deiner HP habe ich nun endlich auch die Timergeschichte kapiert und damit auch die nächste Hürde genommen:
#include <avr/io.h>
#include <avr/interrupt.h>
unsigned int timer_startwert=65536-7812; // 8MHz/1024=7812,5
int main(void)
{
DDRB=0; // nicht benoetigte Ports auf Eingang setzen
DDRC=0;
DDRD=(1 << PD2); //rote StatusLED haengt an PD2(= Port D, Bit2)
PORTD=0; // alles aus
/* Es folgt eine Verzögerung von ca. 1 Sekunde */
TCNT1=timer_startwert; // 16-Bit auf einmal laden?
TCCR1B |= 0b00000101; // Prescaller Timer1 auf 1024 setzen
while(!(TIFR & 0b00000100)); //Warten bis Überlauf Timer1
TCCR1B &= ~0b00000101; // Prescaller löschen bedeutet Timer1 stoppen
TIFR |= 0b00000100; // Flag setzen bedeutet Flag wieder löschen
while(1) PORTD=((PINC & (1<<PC4)) >> 2); // eine Taste schaltet StatusLED aus
return(0);
}
Das lief dann übrigens auf Anhieb, obwohl ich mir nicht sicher bin, ob das Laden eines 16Bit-Wertes nach TCNT1 legitim ist. Meine Optimierung steht übrigens auf "size" habe ich jetzt gesehen.
Gruß
mic
In der ersten Zeile setzt Du PC1 auf Ausgang, Dein DDRC sieht so aus 00000010
In der Zweiten Zeile setzt Du PC0 auf Ausgang und überschreibst Du das was Du zuvor gesetzt hast Dein DDRC sieht jetzt so aus 00000001
Hallo Sebastian,
vielleicht sollte ich die ganze Sache nochmal vertagen - ich weiß eigentlich gar nicht was ein DDRC ist. Die Ports habe ich im Schaltplan gefunden, und da jede LED einen eigenen hat, habe ich gedacht, ich könnte sie unabhängig voneinander ein- und auschalten.
Folgendes habe ich noch probiert
#include "asuro.h"
int main(void)
{
Init();
StatusLED(OFF);
DDRC=(1<<PC1)|(1<<PC0);
//beide BackLED an
PORTC=(1<<PC1);
PORTC|=(1<<PC0);
Msleep(3000);
//beide BackLED aus
PORTC=(0<<PC1);
PORTC|=(0<<PC0);
Msleep(3000);
//linke BackLED an
PORTC=(1<<PC1);
Msleep(3000);
//linke BackLED aus
PORTC=(0<<PC1);
Msleep(3000);
//rechte BackLED an
PORTC=(1<<PC0);
Msleep(3000);
// an dieser Stelle soll die linke BackLED angehen, ohne die rechte zu beeinflussen
// jetzt geht die rechte aber aus
// ???????????????????????
PORTC=(1<<PC1);
Msleep(3000);
while (1);
return 0;
}
aber vielleicht geht das ja gar nicht??????????
Gruss
M.
Hallo,
jetzt wird es hier kompliziert....
Mit Hilfe der tollen Tutorials auf deiner HP habe ich nun endlich auch die Timergeschichte kapiert und damit auch die nächste Hürde genommen:
Danke für die Rosen,
Wo Du es ansprichst, ich glaube es wird Zeit weiterzuschreiben, habe aber seit dem Umzug noch nichtmals meinen Desktop aufgebaut....
Dein Code sieht schonmal gut aus, mit dem Timerwert würde ich mir keine Gedanken machen, es ist schon OK so, schlimmer wäre, wenn Du in der main Routine eine Zahl > 8 Bit veränderst, die ev. in einem Interrupt gebraucht wird, dann knallt es irgendwann, ist auch klar warum , oder ?
da muß man cli() sei() benutzen...
Aber da Du den Overflowflag pollst...
Achja, apropo Flag, das löschen von TOV1 geht bei Dir mit dieser Zeile
TIFR |= 0b00000100;
das ist aber schlecht, warum, überleg mal man löscht einen Flag indem man eine eins in TIFR schreibt, das machst Du auch, aber was passiert, wenn sonst ein Flag in TIFR gesetzt ist(Irgendein 2. Timer)?
Na klingelt es?
Wenn Du es veroderst, schreibst Du eine eins in alle Flags rein, die gesetzt sind...
es sieht etwas komisch aus, aber so ist es richtig:
TIFR = 0b00000100;
ist sehr wichtig, bevor Du irgendeinen anderen Timeroverflow verlierst...
@M1.R
Das Problem bei Dir sind mangelnde C Kenntnisse, aber es kommt noch
DDRC ist Data Directory Register für PortC(hat mit der Deutschen demokratischen Republik nichts zu tun *lol*), Wenn hier ein Bit 1 ist, ist der Pin als Ausgang konfiguriert, bei 0 als Eingang.
Am sonsten sieht es schonmal gut aus nur wenn Du einen Bit löschen willst geht das so:
//linke BackLED aus
PORTC &=~(1<<PC1);
Msleep(3000);
//rechte BackLED an
PORTC=(1<<PC0);
Msleep(3000);
// an dieser Stelle soll die linke BackLED angehen, ohne die rechte zu beeinflussen
// jetzt geht die rechte aber aus
// ???????????????????????
PORTC |= (1<<PC1);
Msleep(3000);
das sind jetzt ziemlich komische Zeichen(C Gegner bezeichnen es als Hyroglyphen) es kommt aber davon, daß C Programmierer faul sind und ungern viel tipen (sei froh, daß es kein Perl ist, da ist es noch schlimmer )
aber PORTC |= (1<<PC1); könnte man auch so schreiben :
PORTC = PORTC | (1<<PC1);
also nimm den alten Zustand von Port C und veroder ihn mit PC1 (00000010)
Gruß Sebastian
radbruch
02.07.2007, 23:09
Das ist ja krass, schon das Löschen des Flags per Setzen ist ja unerwartet. Aber dass man per oder-Verknüpfung ein zufällig auch noch gesetztes Flag mitlöscht, darauf muss man erst mal kommen. Da eine geschrieben 0 nichts löscht, ist TIFR= klar. Danke für Warnung, das ist eine üble Falle. Hätte ich ja eigentlich selbst erkennen können:
ldi arbeitsregister,(1<<TOV1)
out TIFR,arbeitsregister
Ich vermute, ein Interrupt könnte bei Werten > 8Bit genau zwischen HByte und LByte reinfunken, aber zu den Interrupts werde ich wohl erst morgen kommen.
Bitte entschuldigt auch, dass ich mich so mit in den Thread reingedrängt habe, aber ich brauche immer 'nen kleinen Tritt, damit ich mich bewege. Und das war eben diesmal das Setzen der BackLEDs und die geforderte Pause ohne Libary.
Gruß
mic
Ja, Fehler, die man selber gemacht hat, vergißt man nie 8-[
Das verodern bei TIFR ist auch recht einfach zu erklären, wenn man sowas in Assembler geproggt hat, also was erwartet man vm Kompiler bei dieser Zeile
TIFR |= 0b00000100;
Idealerweise sowas
sbi TIFR,0b00000100
Damit hätten wir in einem Takt schön Bit 2 in TIFR geschrieben, fertig.
Das geht leider nicht...
Bei TIFR(und auch anderen Registern) funktioniert sbi nicht :-(
das bleibt dem Kompiler(und dem Assemblerprogrammierer) nichts anderes über als das ganze über einen Arbeitsregister zu machen:
in r16,TIFR
ori r16,0b00000100
out TIFR,r16
auf den ersten Blick kein Problem, aber wie gesagt man löscht sich damit alle anderen Flags.
Ich hoffe etwas Licht in die Sache gebracht zu haben, aber freu Dich, wenn Du einen Interrupt benutzt wird der Flag automatisch gelöscht :-({|=
Wenn man auf dem Low Level programmiern will, muß man schon ziemlich im Dattenblatt lesen, das machen leider die wenigsten :-(
Kennst Du schon diesen (https://www.roboternetz.de/wissen/index.php/Fallstricke_bei_der_C-Programmierung) Artikel ?
Ist sehr lesenswert, auch wenn der mal ganz einfache Fehler behandelt, die Du mit Sicherheit nicht mehr machst ;-)
Wir werden aber wirkilich ziemlich OT hier...
Gute Nacht
Gruß Sebastian
PS
ldi arbeitsregister,(1<<TOV1)
out TIFR,arbeitsregister
ups, das habe ich gerade erst gelesen(ich hab wohl was an den Augen)
genau, sowas dürfte bei TIFR = 0b00000100;
rauskommen ...
Das Problem bei Dir sind mangelnde C Kenntnisse, aber es kommt noch
Na ja - hoffentlich
Vielen Dank!!!
hier habe ichs jetzt eingebaut:
https://www.roboternetz.de/phpBB2/viewtopic.php?t=31867
Gruss
M.
radbruch
02.07.2007, 23:56
Ha, ich bin wieder im Topic, weil mir aufgefallen ist, dass bei meinen Programm die grüne StatusLED und die BackLEDs(unterschiedlich hell) weiterglimmen. Bei der StatusLED liegt es wohl an den internen Pullups, die müssen aus sein. Die BackLEDs liegen mit der Kathode an PD7, deshalb gehen die aus, wenn man diesen Ausgang setzt:
#include <avr/io.h>
#include <avr/interrupt.h>
unsigned int timer_startwert=65536-7812; // 8MHz/1024=7812,5
int main(void)
{
DDRB=0; // nicht benoetigte Ports auf Eingang setzen
PORTB=0; // und die Pullups aus, sonst "glimmt" die StatusLED gruen
DDRC=0;
PORTC=0;
DDRD=(1 << PD2); //rote StatusLED haengt an PD2(= Port D, Bit2)
DDRD|=(1 << PD7); // Kathoden der BackLEDs haengen auf PD7
PORTD=(1 << PD7); // high an PD7 schaltet die BackLEDs aus
/* Es folgt eine Einschaltverzögerung von ca. 1 Sekunde */
TCNT1=timer_startwert; // 16-Bit auf einmal laden?
TCCR1B |= 0b00000101; // Prescaller Timer1 auf 1024 setzen
while(!(TIFR & (1 <<TOV1) )); //Warten bis Überlauf Timer1
TCCR1B &= ~0b00000101; // Prescaller löschen bedeutet Timer1 stoppen
TIFR = (1 << TOV1); // Flag setzen bedeutet Flag wieder löschen
while(1) PORTD=(1 << PD7) | ((PINC & (1<<PC4)) >> 2); // eine Taste schaltet StatusLED aus
return(0);
}
Das heißt aber auch, wenn man die BackLEDs einschalten will, muss man zusätzlich zu PC0/PC1 noch PD7 als Ausgang definieren und ein Low ausgeben. Dann gehen auch D13/14 aus, deshalb funktionieren BackLEDs und Odometrie nicht zusammen. Oder sehe ich das falsch?
ich hab wohl was an den Augen
War ein [Edit] meinerseits O:)
Schöne Nacht wünsche ich euch auch
mic
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.