Archiv verlassen und diese Seite im Standarddesign anzeigen : Kein Interrupt nach Reset/Neustart
Cheffe Boss
07.08.2013, 21:30
Guten Tag,
ich habe mit meinem mini-Programm ein Problem.
Jedes mal nach dem Neustarten oder Reseten des Kontrollers wird die Interrupt-Funktion ausgeführt und erst dann das Hauptprogramm.
Nun habe ich schon gelesen ,dass man in Assembler die erste Speicheradresse überspringen muss, um das zu unterbinden.
Aber ich finde nichts ,wie ich sowas in "C" machen kann.
Kann mir vlt. jemand helfen?
Vielen Dank!
/*
* Ampel.c
*
* Created: 07.08.2013 10:36:06
* Author: en
*/
#define F_CPU 1600000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
// eigene Bezeichnungen
#define rot PC0
#define gelb PC1
#define gruen PC2
#define ein 1
#define aus 0
//volatile unsigned char _taster=1;
ISR (INT1_vect)
{
_delay_ms(80);
PORTC |= (1 << PC4);
_delay_ms(1000);
PORTC &=~(1<<PC4);
}
void rot_schalten(unsigned int i)
{
if (i==ein){PORTC |= (1 << rot);} // Setzen
else {PORTC &= ~(1 << rot);} // Rücksetzen
//_delay_ms(1000);
};
void gelb_schalten(unsigned int i)
{
if (i==ein){PORTC |= (1 << gelb);} // Setzen
else {PORTC &= ~(1 << gelb);} // Rücksetzen
//_delay_ms(1000);
};
void gruen_schalten(unsigned int i)
{
if (i==ein){PORTC |= (1 << gruen);} // Setzen
else {PORTC &= ~(1 << gruen);} // Rücksetzen
//_delay_ms(1000);
};
int main(void)
{ cli();
GICR |= (1 << INT1);
MCUCR |= (1 << ISC11);
//PORT A als Ausgang
PORTC = 0x00;
DDRA = 0xFF;
//PORT C als Ausgang
PORTC = 0x00;
DDRC = 0xFF;
//PORT D als Eingang
DDRD = 1<<PD3;
PORTD = 1<<PD3;
SREG |= (1<<7);
while(1)
{
rot_schalten(ein);
_delay_ms(1000);
gelb_schalten(ein);
_delay_ms(600);
rot_schalten(aus);
gelb_schalten(aus);
gruen_schalten(ein);
_delay_ms(1000);
gruen_schalten(aus);
gelb_schalten(ein);
_delay_ms(600);
gelb_schalten(aus);
}
}
Hi,
die Speicherorganisation übernimmt der Linker beim Compilieren automatisch, Du musst also nicht wie in Assembler selber den Interrupt-Adressbereich überspringen.
Bist Du sicher, dass der Interrupt wirklich vor main() aufgerufen wird und nicht erst vor dem Sprung in Deine Hauptschleife (while(1){...})?
Denn mit
DDRD = 1<<PD3;
PORTD = 1<<PD3;
löst Du den Interrupt vor der Hauptschleife manuell aus.
Gruß,
askazo
Cheffe Boss
08.08.2013, 11:48
Habe mich falsch ausgedrückt.Natürlich wird es in "main()" ,aber noch vor der schleife ausgeführt.
Nur verstehe ich nicht wie ich mit
DDRD = 1<<PD3;
PORTD = 1<<PD3;
Interrupt auslöse?
Der ist doch auf abfallende Flanke eingestellt.Sprich gegen Masse.
Und wenn das doch der Fall ist und ich löse ihn tatsächlich selber aus.Wie mache ich das denn korrekt?
Könntest die Programmzeilen richtig stellen?!
Riesen Dank!
Du wechselst mit
DDRD = 1<<PD3; von einem offenen Eingang (floating) zu einem definierten Low-Pegel, was schon als fallende Flanke erkannt wird. Das Interrupt-Flag wird auch gesetzt, wenn das I-Bit nicht aktiviert ist. Sobald dieses dann aktiviert wird, wird der Interrupt ausgeführt.
Am besten konfigurierst Du zuerst den Port und aktivierst dann den externen Interrupt. Also
DDRD = 1<<PD3;
PORTD = 1<<PD3;
MCUCR |= 1<<ISC11;
GICR |= 1<<INT1;
GIFR |= 1<<INTF1;
sei();
Somit wird der Interrupt erst scharf geschaltet, wenn der PD3 schon einen definierten High-Pegel hat.
Sicherheitshalber habe ich mit der vorletzten Zeile das Interrupt-Flag ausdrücklich gelöscht.
Gruß,
askazo
Cheffe Boss
08.08.2013, 17:02
Was soll ich sagen..
Das war die Lösung!Einfach die Plätze tauschen...
Erst Eingänge setzten ,dann interrups definieren.
Vielen Dank!!
-----------------------------------------
Ganz andere frage:
Macht es Sinn die "Delay`s" aus dem Programm rauszunehmen und stattdessen Timer zu verwenden?
Und wenn ja, könnte mir jemand ein "Stoß" bzw Tipp geben wie ich das am besten mache?
Also kein Code,sondern so ein kleines Flussdiagramm.
Nach meinem derzeitigen Plan, brächte ich mindestens drei Timer...für rot ,gelb,grün..
robo_tom_24
08.08.2013, 20:26
Wieso machst du ds eigentlich mit einer Interrupt routine?
Klar, Timer sind besser, bei delays rechnet die CPU andauernd, bei Timern nicht da dies ein externes Modul am die ist und unabhängig von der cpu läuft. Am besten eine Timer machen, der alle 100ms einen Interrupt auslöst, diese Interrupts mit einer static variable mitzählen und je nach Zählerstand handeln (nach 10x100ms => 1s Rot aus, Gelb ein; nach 16x100ms => 1.6s Gelb aus, usw), wenn man dann einmal durch ist mit dem Ampelprogramm Variable zurücksetzten und das Spiel beginnt von neuem ;)
Cheffe Boss
12.08.2013, 20:04
Hallo geehrte Freunde der "C"-Sprache!
Nun habe ich etwas weiter gemacht.Ich bin auf Timer umgestiegen!
Soweit funktioniert es auch grundsätzlich!Ein Problem habe ich aber...
Ich schaffe es nicht zuverlässig den Taster abzufragen..
Nun habe ich schon in fast jede zweite Code-Zeile die Abfrage reingepackt...kein erfolg..Es funktioniert einfach unzuverlässig.
Prinzip ist schnell erklärt:Es wird immer die Funktion schalten_ohne(); ausgeführt.bis der Taster PB3 gedrückt wird!dann soll in der nächsten Rot-Phase für Autos, grün für Fußgänger angehen.
Was mache ich falsch?muss ich tatsächlich auf interrupt für Taster ausweichen(wie in der ersten Version vom Code)?Gibt es vlt doch eine andere Lösung?
/*
* Ampel_mit_Timer.c
*
* Created: 10.08.2013 10:05:38
* Author: Gerrus
*/
#define F_CPU 4000000UL //Takt auf 4Mhz festlegen
#include <avr/io.h>
#include <avr/interrupt.h> //Include fürs INterrupt
// eigene Bezeichnungen
#define rot PC0
#define gelb PC1
#define gruen PC2
#define rotf PC4
#define gruenf PC5
#define ein 1
#define aus 0
volatile int sec,igr;
void rotf_schalten(unsigned int i)
{
if (i==ein){PORTC |= (1 << rotf);} // Setzen
else {PORTC &= ~(1 << rotf);} // Rücksetzen
};
void gruenf_schalten(unsigned int i)
{
if (i==ein){PORTC |= (1 << gruenf);} // Setzen
else {PORTC &= ~(1 << gruenf);} // Rücksetzen
};
void rot_schalten(unsigned int i)
{
if (i==ein){PORTC |= (1 << rot);} // Setzen
else {PORTC &= ~(1 << rot);} // Rücksetzen
};
void gelb_schalten(unsigned int i)
{
if (i==ein){PORTC |= (1 << gelb);} // Setzen
else {PORTC &= ~(1 << gelb);} // Rücksetzen
};
void gruen_schalten(unsigned int i)
{
if (i==ein){PORTC |= (1 << gruen);} // Setzen
else {PORTC &= ~(1 << gruen);} // Rücksetzen
//_delay_ms(1000);
};
void schalten_ohne (void)
{
if (!(PIND &(1<<PD3)))
{
sec=1;
}
if (igr==0)
{
rot_schalten(ein);
}
if (!(PIND &(1<<PD3)))
{
sec=1;
}
if (igr==76)
{
gelb_schalten(ein);
}
if (!(PIND &(1<<PD3)))
{
sec=1;
}
if (igr==107)
{
rot_schalten(aus);
gelb_schalten(aus);
gruen_schalten(ein);
}
if (!(PIND &(1<<PD3)))
{
sec=1;
}
if (igr==183)
{
gruen_schalten(aus);
gelb_schalten(ein);
}
if (!(PIND &(1<<PD3)))
{
sec=1;
}
if (igr==213)
{
gelb_schalten(aus);
igr=0;
}
}
void schalten_mit (void)
{
if (!(PIND &(1<<PD3)))
{
sec=1;
}
if (igr==0)
{
rot_schalten(ein);
rotf_schalten(ein);
}
if (igr==15)
{
rotf_schalten(aus);
gruenf_schalten(ein);
}
if (igr==61)
{
gruenf_schalten(aus);
rotf_schalten(ein);
}
if (igr==76)
{
gelb_schalten(ein);
}
if (igr==107)
{
rot_schalten(aus);
gelb_schalten(aus);
gruen_schalten(ein);
}
if (igr==183)
{
gruen_schalten(aus);
gelb_schalten(ein);
}
if (igr==213)
{
rotf_schalten(aus);
gelb_schalten(aus);
igr=0;
sec=0;
}
}
ISR (TIMER0_OVF_vect) // Die Funktion die beim Overflow aufgerufen wird
{
igr ++;
if (!(PIND &(1<<PD3)))
{
sec=1;
}
}
int main(void)
{
//PORT C als Ausgang
PORTC = 0x00;
DDRC = 0xFF;
//PORT D als Eingang
DDRD = 0<<PD3;
PORTD = 1<<PD3;
TCCR0 |= (1<<CS02)|(1<<CS00); //Einstellen Von Preteiler 1/1024. Datasheet Seite 85
TIMSK |= (1<<TOIE0); //Interrupt auslösen beim Overflow Datasheet Seite 85
TCNT0 = 0; //den timer selber reseten.Eine Null reinschreiben
sei(); //Interruos aktivieren
while(1)
{
if (!(PIND &(1<<PD3)))
{
sec=1;
}
if (sec==0)
{
schalten_ohne(); //Ampelschaltung ohne fussgaenger
}
if (!(PIND &(1<<PD3)))
{
sec=1;
}
if (sec==1)
{
schalten_mit(); //Ampelschaltung mit fussgaenger
}
}
}
P.S: Bin über jede Art von Tips dankbar!!Vlt verfolge ich komplett verkehrten weg?vlt geht es einfacher,stabiler,besser?
Vielen Dank!
Hallo,
ich lange über deinen Code gesessen und möchte dazu folgendes beitragen
Viel Text mit hoffentlikch einer Lösung ganz am Ende.
Deine Tastenabfrage kannst Du so schreiben, da brauchst Du keine Klammern, weil nur eine Anweisung folgt
if (!(PIND &(1<<PD3))) sec=1;
Diese Abfrage kommt eigentlich nur einmal in deine Interrupt Funktion, alle abderen identischen Abfragen kannst Du rausnehmen, die geben dann keinen Sinn.
Wenn die Taste betätigt wird, setzt Du ja im Interrupt dann die Variable "sec" auf 1. Diese bleibt nun solange auf 1 bis sie vom Hauptprogramm wieder auf 0 gesetzt wird.
Dies passiert bei Dir NUR in der Funktion schalten_mit bei dem Zählerstand 213 also nach einem kompletten Durchlauf mit Fussgänger. Das sieht soweit okay aus.
Ich weis jetzt nicht wie oft dein Interrupt ausgelöst wird, anhand deiner Zahlenwerte anscheinend nicht sonderlich häufig. Da könnte es mit der eben genannten Methode "nur im Interrupt" problematisch werden, also lass das vorerst mal so, das tut keinem ja weh, obwohl nicht schön.
Du könntest noch den Int Aufruf schneller machen, z.B. 10 mal schneller und deine Zeitwertabfragen auch entsprechend mit 10 multiplizieren.
Dann reicht die Tastenabfrage nur im Interrupt sicherlich aus.
Idee, aber wieder verworfen....
Könnte es sein, das an deinem Pin wo die Taste dran ist kein Widerstand nach Plus dran ist, dann bekommt er zwar eine schöne Null wenn Du die Taste drückst, aber wenn Du sie losläst hängt der Pin irgendwie inder Luft.
Gibt aber auch keinen Sinn, da der High Pegel bei Dir nie ausgewertet wird.
etwas übersichtliche ist folgende Vorgehensweise:
while(1)
{
if (sec==0) schalten_ohne(); //Ampelschaltung ohne fussgaenger
else schalten_mit(); //Ampelschaltung mit fussgaenger
switch(igr) /* den Zeitwert auswerten */
{
case 0 : rot_schalten(ein);
break; /* fertig, sprige hinter die switsch Anweisung */
case 76 : gelb_schalten(ein);
break;
case 107 : rot_schalten(aus);
gelb_schalten(aus);
gruen_schalten(ein);
break;
case 183 : gruen_schalten(aus);
gelb_schalten(ein);
break;
case 213 : gelb_schalten(aus);
igr=0;
break;
} /* ende switch */
} /* ende while */
Was fällt mir noch ein:
Ist dein Taster defekt und gibt schlechten Kontakt ?
ich davon tonnenweise rumliegen.....
dann hab ich ein ein Read Modify Write Problem gedacht, kenne ich von den PICs von Microchip her.
Port lesen Bit ändern und zurück schreiben. Dein Taster ist aber auf einem anderen Port als deine LEDs, also eher unwahrscheinlich.
Letzte Idee:
Die Variable sec wird im Interrupt gesetzt,
du hast sie als int definiert, könnte also sein, dass sie 2 Bytes belegt
Wenn nun im Hauptprogramm der Wert gesetzt wird und ein Interrupt während der Verarbeitung
der beiden Bytes auftritt, könnte das schief gehen.
Um das zu verhindern versuche mal folgendes:
Sperre die Interrupts während Du den Wert sec auf Null setzt.
Atomaren Code erzeugen nennt man das wohl, also so:
cli(); // sperre alle Interrupts
sec = 0; // setzen den Wert
sei(); //Interrupts aktivieren
vielleicht konnte ich Dir irgendwie weiterhelfen
viel Spass noch wünscht Dir
Siro
Cheffe Boss
14.08.2013, 11:42
Hallo Siro!
Vielen Dank für deine Tips!
Ich bin mi meinem Programm immer noch nicht erfolgreich.
Wie ich inzwischen raus gefunden habe,reicht die Abfrage in dem Timer-Interupt komplett aus.Denn,ich lasse jetzt ein Port setzen und damit eine extra LED (zur Kontrolle) aufleuchten.Das blöde ist,schein bar wird die Variable "sec" entwider nicht gesetzt (obwohl im gleich "IF"-Strang) oder wird wieder zurückgesetzt ,wie auch immer...
Leider kriege ich das auch nicht mit dem Debuggen in Atmel Studio raus..
bin so bischen schon am lust zuverlieren weiter zumachen...
zB : wenn ich Rücksetzten von "sec" rausnehme aus dem Code ,dann wird "sec" richtig gesetzt(also wenn ich den Taster drücke) und danach läuft wirklich immer die Funktion "schalten_mit"..aber wenn ich die "sec" am ende der Funktion "schalten_mit" wieder auf null setze ,dann funktioniert nichts mehr..
ich will jetzt nochmals die "IF"`s auf switch umschreiben,aber viel hoffnung, dass es was bringt,ausser übersicht, habe ich nicht.
es müssen doch zu hauf programme sein ,die ständig auf tasteneingabe warten und trotzdem etwas machen?!Sind die alle über INT0 (1) gemacht?Kann doch nicht sein.
Ich habe wirklich das Gefühl ,dass die "sec" aus versehen immer überschrieben wird.
Das ist wirklich merkwürdig was da anscheined passiert.
Kann es eine Überlappung von Stack und Variablen geben ?
Ich habe mit den AVR's noch nicht gearbeitet aber man kann sicher so einiges in der Entwicklungsumgebeung umstellen, oder es gibt einen Linker FIle....
Wenn Du der Meinung bist, dass sich ein Speicher überschreibt:
Mach doch mal ein paar unnütze Variablen vor den momentanen, um Speicher zu verschwenden....
Das Problem ist, dass die Compiler unbenutzen meist wegoptimieren, meist reicht das volatile davor.
volatile char dummy[20]; /* reserviere 20 Bytes für Muell */
dann deine wirklicehn Variablen
volatile int sec,igr;
dadurch verschieben sich die Speicherstellen deiner Variablen
Dann schaust Du wie sich das Programm dadurch verhält.
und ganz wichtig: NIE aufgeben ;) jeder Fehler ist zu finden
HeXPloreR
14.08.2013, 12:58
Hallo,
hast Du Software- oder Hardware-Entprellung am Taster? Für die Hardware Entprellung einen Keramikkondensator (etwa 20p - 100p ) parallel zum Taster schalten.
Das entprellt den Taster damit der Interrupt nicht mehrfach undefiniert ausgelöst wird.
Das schont die eigenen Nerven und erspart merkwürdige Effekte die man oft nicht so einfach aufspürt.
Hallo HeXPloreR,
er wertet in der Software nur das Low Signal aus.
Erst wenn sein gesamter Ampelablauf durch ist, wird die Variable err wieder auf 0 gesetzt. Prellen sollte da eigentlich keine Rolle spielen.
Aber Kondi kann nie schaden, 100nF geht auch.
Falls Speicherproblem: Tipps:
Ich weis nicht wie der Compiler seine Variablen ablegt, manche machen es sortiert nach Namen, oder man kann das sogar einstellen.
Vertausche mal die Variablen indem Du ihn andere Namen gibst oder die Reihenfolge veränderst wie sie definiert sind.
Nenn die einfach mal a_sec und probiere oder das nächste mal z_sec. Wenn der Compiler die dann Namentlich im Speicher sortiert landen sie
in andere Reihenfolge im Speicher und wenn es ein Speicherüberlappungsproblem ist wird sich das Programm dann auch anders verhalten.
Im .MAP File, falls dieser erzeugt wird, kann man nachschauen wo der Compiler die Variablen abgelegt hat.
Der Stack muss eingestellt sein, aber bei deinem Miniprogramm sollte das vermutlich voreingestellt sein.
Der Heap (Halde) wird nicht benötigt solange Du keine dynamische Speicherverwaltung benutzt. Hast Du ja nicht.
Ändere mal dein err zu einem char, nicht int, somit belegt die Variable nur noch 1 Byte.
Hast Du das mit dem sti() cli() ausprobiert ?
Cheffe Boss
14.08.2013, 19:24
Ich habe sowohl hardware-als auch software den taster versucht zuentprellen.daran liegt es nicht.
Das muss einfach an dem Programm liegen.
@Siro
ich habe versuch die "sec" umzubenennen und auch die Interrups vorrübergehend zuverbieten,kein erfolg.
Ich werde das Programm neu schreiben.Aber von hinten aufgerollt.Sprich:Erst "sec" setzen und dann immer weiteren Code zufügen.und diesmal will ich das hochzählen aus zwei variablen auslagern und diese auch im interrupt nullen.
ca so:
Interruptfunktion{
i_ohne++; (wenn >=255-> i_ohne =0;)
i_mit++; (wenn i_mit >=255 -> i_mit =0;)
wenn taster PD3 dann sec=1;
}
main()
{
if sec=1 dann
switch(i_mit)
case 12:
case23:
usw
...
case 234: sec= 0;
if sec=0 dann
switch (i_ohne)
case 12:
case 23:
usw
der derzeitige Code sieht so aus:
/*
* Ampel_mit_Timer.c
*
* Created: 10.08.2013 10:05:38
* Author: Gerrus
*/
//#define F_CPU 16000000UL //Takt auf 4Mhz festlegen
#include <avr/io.h>
#include <avr/interrupt.h> //Include fьrs INterrupt
// eigene Bezeichnungen
#define rot PC0
#define gelb PC1
#define gruen PC2
#define rotf PC4
#define gruenf PC5
#define ein 1
#define aus 0
volatile int igr;
volatile unsigned m_sec;
void rotf_schalten(unsigned int i)
{
if (i==ein){PORTC |= (1 << rotf);} // Setzen
else {PORTC &= ~(1 << rotf);} // Rьcksetzen
};
void gruenf_schalten(unsigned int i)
{
if (i==ein){PORTC |= (1 << gruenf);} // Setzen
else {PORTC &= ~(1 << gruenf);} // Rьcksetzen
};
void rot_schalten(unsigned int i)
{
if (i==ein){PORTC |= (1 << rot);} // Setzen
else {PORTC &= ~(1 << rot);} // Rьcksetzen
};
void gelb_schalten(unsigned int i)
{
if (i==ein){PORTC |= (1 << gelb);} // Setzen
else {PORTC &= ~(1 << gelb);} // Rьcksetzen
};
void gruen_schalten(unsigned int i)
{
if (i==ein){PORTC |= (1 << gruen);} // Setzen
else {PORTC &= ~(1 << gruen);} // Rьcksetzen
//_delay_ms(1000);
};
void schalten_ohne (void)
{
while(1)
{
if (igr==0)
{
rot_schalten(ein);
}
if (igr==76)
{
gelb_schalten(ein);
}
if (igr==107)
{
rot_schalten(aus);
gelb_schalten(aus);
gruen_schalten(ein);
}
if (igr==183)
{
gruen_schalten(aus);
gelb_schalten(ein);
rotf_schalten(aus);
}
if (igr==213)
{
gelb_schalten(aus);
igr=0;
}
break;
}
}
void schalten_mit (void)
{
while (1)
{
if (igr==0)
{
rot_schalten(ein);
rotf_schalten(ein);
}
if (igr==15)
{
rotf_schalten(aus);
gruenf_schalten(ein);
}
if (igr==61)
{
gruenf_schalten(aus);
rotf_schalten(ein);
}
if (igr==76)
{
gelb_schalten(ein);
}
if (igr==107)
{
rot_schalten(aus);
gelb_schalten(aus);
gruen_schalten(ein);
}
if (igr==183)
{
gruen_schalten(aus);
gelb_schalten(ein);
}
if (igr==213)
{
m_sec=0;
rotf_schalten(aus);
gelb_schalten(aus);
igr=0;
}
break;
}
}
ISR (TIMER0_OVF_vect) // Die Funktion die beim Overflow aufgerufen wird
{
int temp;
temp=PIND;
if ((temp &(1<<PD3)))
{
m_sec = 1; // setzen den Wert
}
igr ++;
}
int main(void)
{
//PORT C als Ausgang
PORTC = 0x00;
DDRC = 0xFF;
//PORT D als Eingang
DDRD = 0<<PD3;
PORTD = 1<<PD3;
TCCR0 |= (1<<CS02)|(1<<CS00); //Einstellen Von Preteiler 1/1024. Datasheet Seite 85
TIMSK |= (1<<TOIE0); //Interrupt auslцsen beim Overflow Datasheet Seite 85
TCNT0 = 0; //den timer selber reseten.Eine Null reinschreiben
sei(); //Interruos aktivieren
while(1)
{
switch(m_sec)
{
case 0:
schalten_ohne();
break;
case 1:
schalten_mit();
break;
}
}
}
und es funktioniert NUR wenn ich den Taster dauerhaft gedrückt halte.dann geht das.Los lasse,dann geht er wieder in Phase ohne Fussgänger-Ampel.wieder gedrückt halte,wieder mit Fussgänger.
Ich weiss nicht warum das Programm die variable "sec" immer wieder auf null setzt ,bevor die Funktion schalten_mit eintritt...
Ich melde mich,sobald ich das neue Programm fertig habe
Nabend,
die while schleifen in den beiden schalten_mit schalten_ohne und den break am Ende benötigst Du nicht,
da die Funktionen vom Hauptprogramm immer wieder aus der Schleife aufgerufen werden.
Ich bin gespannt....
Cheffe Boss
14.08.2013, 20:57
Nabend,
die while schleifen in den beiden schalten_mit schalten_ohne und den break am Ende benötigst Du nicht,
da die Funktionen vom Hauptprogramm immer wieder aus der Schleife aufgerufen werden.
Ich bin gespannt....
ich weiss, das ist alles schon wegen des verzweifelns entstanden:)
wollte damit ganz sicher gehen ,dass if anweisungen ausgeführt werden bevor die variable zurückgesetzt wird:)
SChönen Abend noch!
P.S: Ich sehe grad i-in der Version habe ich gar keine Rücksetzung der variable..wie gesagt bin zur Zeit sehr viel am rum rumprobieren
die letzte Abfrage würde ich sicherheitshalber mit >= abfragen.
if (igr>=213) denn wenn das Programm mal etwas länger braucht könnte der Zähler evtl. schon auf 214 stehen, was passiert dann eigentlich ?
Ich vermute dann stehen deine Lampen eine ganze Weil lang still bis die Variable bis auf 65535 hochgezählt hat und dann auf 0 springt.
Ich würde diese Abfrage sogar direkt in die Interrupt Routine packen.
if (igr < 213) igr++; else igr = 0;
dann kann das erst garnicht passieren und die Variable wird nur noch im Interrupt geändert.
klärt aber immer noch nicht dein Problem :(
Cheffe Boss
16.08.2013, 22:13
Das habe ich zur Zeit.
Funktioniert auch soweit ganz gut.
/*
* timer_von_null.c
*
* Created: 14.08.2013 17:14:16
* Author: Gerrus
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
// eigene Bezeichnungen
#define rot PC0
#define gelb PC1
#define gruen PC2
#define rotf PC4
#define gruenf PC5
#define ein 1
#define aus 0
volatile unsigned char zaehler=0,timer_mit=0,timer_ohne=0,temp=0,temp2=0;
ISR (TIMER0_OVF_vect) // Die Funktion die beim Overflow aufgerufen wird
{
if ((~PIND &(1<<PD3))) //Prüfen ob Taster gedrückt wurde.Taster ist gegen Ground gezogen
{
if ((~PINC&(1<<gruenf)))
{
rotf_schalten(ein); // Fussgänger Rot auf rot stellen.vorher war signal aus.
}
zaehler=1; //Zähler für Tasterzustand auf eins -Taster wurde betätigt.
}
if (timer_ohne < 214) timer_ohne++; else timer_ohne=0; //Variable um auf Sekunden zukommen.Eine Sekunde gleich 15,15 Ticks.beim erreichgen von 213,wieder auf null.
}
void rotf_schalten(unsigned int i) //Fussgänger Rot
{
if (i==ein){PORTC |= (1 << rotf);} // Setzen
else {PORTC &= ~(1 << rotf);} // Rьcksetzen
};
void gruenf_schalten(unsigned int i) //FUssgänger Grün
{
if (i==ein){PORTC |= (1 << gruenf);} // Setzen
else {PORTC &= ~(1 << gruenf);} // Rьcksetzen
};
void rot_schalten(unsigned int i) //Auto Rot
{
if (i==ein){PORTC |= (1 << rot);} // Setzen
else {PORTC &= ~(1 << rot);} // Rьcksetzen
};
void gelb_schalten(unsigned int i) //Auto Gelb
{
if (i==ein){PORTC |= (1 << gelb);} // Setzen
else {PORTC &= ~(1 << gelb);} // Rьcksetzen
};
void gruen_schalten(unsigned int i) //Auto Grün
{
if (i==ein){PORTC |= (1 << gruen);} // Setzen
else {PORTC &= ~(1 << gruen);} // Rьcksetzen
}
void schalten (void) //Hauptfunktion um Ampel zuschalten
{
if (timer_ohne==0) //Sekunde 0
{
rot_schalten(ein);
}
if (timer_ohne==15&&zaehler==1) //Sekunde 1 aber nur wenn Taster gedrückt wurde
{
rotf_schalten(aus);
gruenf_schalten(ein);
}
if (timer_ohne==61&&zaehler==1) //Sekunde 4 aber nur wenn Taster gedrückt wurde
{
gruenf_schalten(aus);
rotf_schalten(ein); //WICHTIG!!!
zaehler=2; //Zähler wird auf Zwei gesetzt damit man nicht durcheinander kommt beim rücksetzen später
}
if (timer_ohne==70&&zaehler==2) //Sekunde 4,6 Schaltet Fussgängerrot aus ,ABER nur wenn schon eine Phase durchgelaufen
{
rotf_schalten(aus);
}
if (timer_ohne==76) // Sekunde 5
{
gelb_schalten(ein);
}
if (timer_ohne==107) //Sekunde 7
{
rot_schalten(aus);
gelb_schalten(aus);
gruen_schalten(ein);
}
if (timer_ohne==183) //Sekunde 12,2
{
gruen_schalten(aus);
gelb_schalten(ein);
//rotf_schalten(aus);
}
if (timer_ohne==213) //Letzter Schaltvorgang Sekunde 14
{
gelb_schalten(aus);
if (zaehler==2)
{
zaehler=0; //Wird nur resetet wenn Fussgängerphase schon durchgelaufen ist
}
}
}
/*void schalten_mit (void)
{
if (timer_mit==0)
{
rot_schalten(ein);
rotf_schalten(ein);
}
if (timer_mit==15)
{
rotf_schalten(aus);
gruenf_schalten(ein);
}
if (timer_mit==61)
{
gruenf_schalten(aus);
rotf_schalten(ein);
}
if (timer_mit==76)
{
gelb_schalten(ein);
}
if (timer_mit==107)
{
rot_schalten(aus);
gelb_schalten(aus);
gruen_schalten(ein);
}
if (timer_mit==183)
{
gruen_schalten(aus);
gelb_schalten(ein);
}
if (timer_mit==213)
{
rotf_schalten(aus);
gelb_schalten(aus);
zaehler=0;
}
}
*/
int main(void)
{
//PORT C als Ausgang
PORTC = 0x00;
DDRC = 0xFF;
//PORT D als Eingang
DDRD = 0<<PD3;
PORTD = 1<<PD3;
TCCR0 |= (1<<CS02)|(1<<CS00); //Einstellen Von Preteiler 1/1024. Datasheet Seite 85
TIMSK |= (1<<TOIE0); //Interrupt auslцsen beim Overflow Datasheet Seite 85
TCNT0 = 0; //den timer selber reseten. Eine Null reinschreiben
sei(); //Interrups aktivieren
while(1)
{
schalten(); //Hauptschleife
}
}
Als nächstes will ich das ganze auf eine Kreuzung portieren.Sprich das ganze noch einmal aber mit verknüpfung zu einander.
Außerdem stelle ich grade fest,dass ich noch eine Sperre für Rot_fuss einbauen muss,sobald gruen_fuss leuchtet.Quasi ein BUG entdeckt.Mein erster!!!!*freu* :-D (siehe EDIT)
In Planung ist auch das ganze in Hardware umzusetzen,mit Batterie Einspeisung.Bin schon am ausschau halten nach ampel gehäuse.vlt einen dicken Kugelschreiber oder ähnliches.
Hier nochmal ein kleiner Plan,falls jemand auf die schnelle ausprobieren möchte.(Widerstände vor den LEDs ,in Höhe von 330 Ohm , fehlen auf der Zeichnung. Diese müssen unbedingt aber in die reele Schaltung rein)
26236
Nicht desto trotz,wenn jemand etwas zu verbessern oder zu optimieren weiss,immer her damit!
Vielen Dank und viel Erfolg!
EDIT: Einfache IF-Anweisung hat den "BUG" behoben.
if ((~PINC&(1<<gruenf)))
{
rotf_schalten(ein); // Fussgänger Rot auf rot stellen.vorher war signal aus.
}
P.S: Hat evtl. jemand weitere deutsche Foren für Programmieren in C für ATMEL? (ausser microkontroller.net,da sind ja nur "profis"... )
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.