Hi!
Hier mal mein Gesamtprogramm...
Ich habe noch nicht viel verändert, da ich mir über die Timer nicht ganz
im klaren bin.
Müsste ich die Timer Einstellungen in die while(g_run) Schleife
schreiben, damit sie erst beim Start anfangen zu zählen?
Und mach ich dann im Timeroverflow Interrupt eine Schleife die
Hochzählt?
#include <avr/io.h>
#include <inttypes.h>
#include <avr/delay.h> // definiert _delay_ms()
#include <avr/interrupt.h>
#include <util/delay.h> // aktuelle Version in util
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef F_CPU
#define F_CPU 3686400UL // Quarz mit 3.6864 Mhz ?? noch prüfen!!
#endif
#define true 1
#define false 0
// Funktion zum Entprellen
inline uint8_t debounce(volatile uint8_t *port, uint8_t pin)
{
if ( ! (*port & (1 << pin)) )
{
// Pin wurde auf Masse gezogen, 100ms warten
_delay_ms(100);
if ( *port & (1 << pin) )
{
// Anwender Zeit zum Loslassen des Tasters geben
_delay_ms(100);
return 1;
}
}
return 0;
};
//---------------- Global variables ------------------------
char g_run; // Variable zum Stoppen
int g_count; // Zähler
// ---------------------------------------------------------
// --------------- Interrupt zum Umschalten von g_run ------
ISR(INT0_vect)
{
// toggle
g_run = false;
}
// --------------- Interrupt bei Timeroverflow --------------
ISR(TIMER1_OVF_vect)
{
g_count = 0;
g_count++;
int main(void)
{
DDRD = 0x00; // Port D ist Eingang
PORTD = 0xFF; // interne Pullup-Widerstände aktiviert
DDRB = 0xFF; // Port B ist Ausgang
PORTB = 0x00;
EICRA |= (1<<ISC01); // Fallende Flanke löst Interrupt aus
EIMSK |= (1<<INT0);
TIMSK |= (1<<TOIE1); // Bei Überlauf des Datenregisters von Timer 1
wird Timer Overflow 1 Interruot ausgelöst
//Konfiguration von Timer 1
TCCR1A = 0x00; // Timer 1 ohne Outputpins und ohne PWM
TCCR1B |= (1<<CS12) | (1<<CS10); // CPU-Takt/ 1024
sei(); // Interrupts eingeschaltet
g_run = 1;
while( ! debounce(&PIND, PD0) ); //Wenn Taster an PIN PD0 gedrueckt
wird while verlassen.
while(g_run == 1)
{
int i;
long j;
i = rand() % 20; // Generierung der "Pulsbreite"
j = rand() % 20; // Generierung der Zeit zwischen zwei Pulsen
j = j * 60000; // Umrechnung in Millisekunden
_delay_ms(j); // Verzögerungszeit zwischen zwei Pulsen
PORTB |= (1<<PB0); // PB0 auf high
_delay_ms(i); // PB0 für 1-20 ms auf high
PORTB &= ~ (1<<PB0); // PB0 wieder auf low
PORTB |= (1<<PB1); // PB1 auf high
_delay_ms(10); // PB1 immer für 10 ms auf high
PORTB &= ~ (1<<PB1); // PB1 wieder auf low
};
cli(); // Interrupts ausgeschaltet
while(1);
return 0;
}
Danke für eure Hilfe...
> j = j * 60000; // Umrechnung in Millisekunden> _delay_ms(j); // Verzögerungszeit zwischen zwei Pulsen
Hatten wir das nicht schon mal? Die _delay_xx-Funktionen funktionieren
nur dann korrekt, wenn sie mit zur compile-Zeit bekannten Konstanten
Werten aufgerufen werden und sie sind in Abhängigkeit von der
CPU-Frequenz begrenzt!
> Und mach ich dann im Timeroverflow Interrupt eine Schleife die Hochzählt?
Zählschleifen haben in einer ISR eigentlich nichts verloren.
Was soll das Programm überhaupt machen? Warum postest Du sowas nicht in
Deinem originalen Thread? Dann müsste man sich jetzt nicht den anderen
Thread raussuchen um zu erfahren worum es eigentlich geht!
@ ghost
>Hier mal mein Gesamtprogramm...
Aha, es geht immer noch um die 1..20 min Verzögerung zur LED-Ansteuerung
>Und mach ich dann im Timeroverflow Interrupt eine Schleife die>Hochzählt?
Nö.
>#define true 1>#define false 0
Das kannst du dir sparen.
>// --------------- Interrupt bei Timeroverflow -------------->ISR(TIMER1_OVF_vect)>{> g_count = 0;> g_count++;
} fehlt hier
Die Initialisierung sieht mal gut aus. Dein Main läuft dann eigentlich
nur noch in einer Endlosschleife etwas so
while(1);
Die Schow findet im Interrupt statt.
// --------------- Interrupt bei Timeroverflow --------------
ISR(TIMER1_OVF_vect)
{
static uin16_t i, j;
static uin8_t state=0;
switch (state)
{
case 0: // start, get new random values
i = rand() % 20; // Generierung der "Pulsbreite"
j = rand() % 20; // Generierung der Zeit zwischen zwei Pulsen
j = j * 60000; // Umrechnung in Millisekunden
state = 1;
break;
case 1: // first delay
j--;
if (j==0) state =2;
break;
case 2: // first LED action
PORTB |= (1<<PB0); // PB0 auf high
state =3;
break;
case 3: // second delay
i--;
if (i==0) state =4;
break;
case 4: // second LED action
PORTB &= ~ (1<<PB0); // PB0 wieder auf low
PORTB |= (1<<PB1); // PB1 auf high
state =5;
i = 10;
break;
case 5: // second delay
i--;
if (i==0) state =6;
break;
case 6: // third LED action
PORTB &= ~ (1<<PB1); // PB1 wieder auf low
state =0;
break;
default: state = 0; // just in case ;-)
}
}
MfG
Falk
@ Jupp
>>> #define true 1>>> #define false 0>> Das kannst du dir sparen.>Nö.>#define TRUE 1>#define FALSE 0>könnte er sich sparen.
Warum muss ich da gerade wieder an eine griechische Stadt mit K und den
Auswurf von Exkrementen denken . . .?
MFG
Falk
>Ich hoffe du verstehst auch den Unterschied?
Ich denke schon.
Der Compiler scheint nur die zwei Zeilen net zu mögen:
static uin16_t i, j;
static uin8_t state=0;
main.c:53: error: expected '=', ',', ';', 'asm' or '__attribute__'
before 'i'
main.c:53: error: 'i' undeclared (first use in this function)
main.c:53: error: (Each undeclared identifier is reported only once
main.c:53: error: for each function it appears in.)
main.c:53: error: 'j' undeclared (first use in this function)
main.c:53: warning: left-hand operand of comma expression has no effect
main.c:53: warning: statement with no effect
main.c:56: error: 'state' undeclared (first use in this function
)
ghost wrote:
>>Ich hoffe du verstehst auch den Unterschied?>> Ich denke schon.>> Der Compiler scheint nur die zwei Zeilen net zu mögen:>> static uin16_t i, j;> static uin8_t state=0;>> main.c:53: error: expected '=', ',', ';', 'asm' or '__attribute__'> before 'i'
mach noch ein
#include <stdint.h>
ganz an den Anfang.
Der Compiler weiss nicht was ein uint16_t ist. stdint.h
enthält die dazu notwendigen Definitionen.
@ johnny.m
>Da fehlen ja auch zwei 't'! uin8_t und uin16_t findet er sicher auch mit>der stdint.h nicht...
Ich sach nur Licherkette. An alle Badesalz-Fans ;-)
MFG
Falk
So schaut jetzt main() aus:
int main(void)
{
DDRD = 0x00; // Port D ist Eingang
PORTD = 0xFF; // interne Pullup-Widerstände aktiviert
DDRB = 0xFF; // Port B ist Ausgang
PORTB = 0x00;
// ------- Einstellungen für Ext. Interrupt zum Stoppen des Programms
----
EICRA |= (1<<ISC01); // Fallende Flanke löst Interrupt aus
EIMSK |= (1<<INT0);
//
-----------------------------------------------------------------------
TIMSK1 |= (1<<TOIE1); // Bei Überlauf des Datenregisters von Timer 1
wird Timer Overflow 1 Interrupt ausgelöst
//Konfiguration von Timer 1
TCCR1A = 0x00; // Timer 1 ohne Outputpins und ohne PWM
TCCR1B |= (1<<CS12) | (1<<CS10); // 3,6864MHZ/ 1024 = 3600 Hz
sei(); // Interrupts eingeschaltet
g_run = 1;
while( ! debounce(&PIND, PD0) ); //Wenn Taster an PIN PD0 gedrueckt
wird, wird while verlassen
cli(); // Interrupts ausgeschaltet
while(1);
return 0;
}
Ich habe in switch mal i recht groß gemacht um ein Blinken zu sehen,
aber es tut sich nix. Hab ich in main noch nen groben Bock drin??
ghost wrote:
> So schaut jetzt main() aus:
...
>> sei(); // Interrupts eingeschaltet>> g_run = 1;>> while( ! debounce(&PIND, PD0) ); //Wenn Taster an PIN PD0 gedrueckt> wird, wird while verlassen>> cli(); // Interrupts ausgeschaltet>> while(1);> return 0;> }
Wenn du mittels cli() die Interrupts global ausschaltest, kannst
du lange warten, bis ein Overflow Interrupt durchkommt. Die
eigentliche Arbeit wird während
while(1)
;
im Hintergrund von einer ISR (Interrupt Service Routine) erledigt.
Die muss aber auch aufgerufen werden können! Das kann sie aber
nicht, wenn du mittels cli() die Interrupts sperrst.
@Falk
>Warum muss ich da gerade wieder an eine griechische Stadt mit K und den>Auswurf von Exkrementen denken . . .?
Keine Ahnung, vielleicht hast du ein Problem mit deiner Verdauung?
Wie auch immer, ich wollte es nur klarstellen, denn ich hasse
Halbwissen, welches du hier gezeigt hast. LOL
Also irgendwie funzt es net so wie ich will.
Das Programm soll nach 1- 20 Minuten einen Pin für ca 10 ms auf high
legen und dann wieder auf low. Sofort danach einen anderen Pin auf high
für ca 10 ms und dann wieder auf low. Und das ganze halt immer wieder
bis man stoppen will.
Und halt noch ne Stop-Taste, die aber schon funktioniert ( mit dem
externen interrupt).
Der Vorschlag von Falk ist ja ok, aber da muss ich doch irgendwie noch
meine Frequenz anpassen? Könnte da der Fehler liegen?
Regler wrote:
> Wie auch immer, ich wollte es nur klarstellen, denn ich hasse> Halbwissen, welches du hier gezeigt hast. LOL
Du meinst, solcherart wie du gerade zur Schau stellst? (Falls Regler
derselbe wie Yupp sein sollte.)
Guck dir mal <stdbool.h> von C99 an.
Tja, dann muß ich das wohl zurücknehmen.
Dennoch ist es schon bescheuert, dass einerseits in der von dir
genannten Datei
#define true 1
#define false 0
auftaucht, man aber andererseits ohne die Inkludierung dieser Datei
#define TRUE 1
#define FALSE 0
definiert wurde, wo auch immer. Frei nach dem Motto: doppelt gemoppelt
hält besser.
Regler wrote:
> auftaucht, man aber andererseits ohne die Inkludierung dieser Datei>> #define TRUE 1> #define FALSE 0>> definiert wurde, wo auch immer.
Wo denn? Bei mir nicht. Keine der avr-libc- oder GCC-Headerdateien
bringt das mit.
1
$ cat foo.c
2
#include <avr/io.h>
3
4
int
5
main(void)
6
{
7
return TRUE;
8
}
9
$ avr-gcc -mmcu=atmega1281 -c foo.c
10
foo.c: In function 'main':
11
foo.c:6: error: 'TRUE' undeclared (first use in this function)
12
foo.c:6: error: (Each undeclared identifier is reported only once
Hab des Programm jetzt so geschrieben:
#include <avr/io.h>
#include <inttypes.h>
#include <avr/delay.h> // definiert _delay_ms()
#include <avr/interrupt.h>
#include <util/delay.h> // aktuelle Version in util
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#ifndef F_CPU
#define F_CPU 3686400UL // Quarz mit 3.6864 Mhz ?? noch prüfen!!
#endif
#define true 1
#define false 0
// -------- Funktion zum Entprellen --------------------------
inline uint8_t debounce(volatile uint8_t *port, uint8_t pin)
{
if ( ! (*port & (1 << pin)) )
{
// Pin wurde auf Masse gezogen, 100ms warten
_delay_ms(100);
if ( *port & (1 << pin) )
{
// Anwender Zeit zum Loslassen des Tasters geben
_delay_ms(100);
return 1;
}
}
return 0;
};
//---------------- Global variables ------------------------
char g_run; // Variable zum Stoppen
// ---------------------------------------------------------
// --------------- Interrupt zum Umschalten von g_run ------
ISR(INT0_vect)
{
// toggle
g_run = false;
}
// --------------- Interrupt bei Timeroverflow --------------
ISR(TIMER1_OVF_vect)
{
static uint16_t i, j;
static uint8_t state=0;
switch (state)
{
case 0: // Start, Erzeugung der neuen Zufallszahlen
i = rand() % 20; // Generierung der "Pulsbreite"
j = rand() % 20; // Generierung der Zeit zwischen zwei Pulsen
j = j * 60000; // Umrechnung in Millisekunden
state = 1;
break;
case 1: // Erste Verzögerung: 1 - 20 Minuten
j--;
if (j==0) state =2;
break;
case 2:
PORTB |= (1<<PB0); // PB0 auf high
state =3;
break;
case 3: // Verzögerung 1 - 20 ms
i--;
if (i==0) state =4;
break;
case 4:
PORTB &= ~ (1<<PB0); // PB0 wieder auf low
PORTB |= (1<<PB1); // PB1 auf high
state =5;
i = 10;
break;
case 5: // 10ms Verzögerung
i--;
if (i==0) state =6;
break;
case 6:
PORTB &= ~ (1<<PB1); // PB1 wieder auf low
state =0;
break;
default: state = 0;
}
}
int main(void)
{
DDRD = 0x00; // Port D ist Eingang
PORTD = 0xFF; // interne Pullup-Widerstände aktiviert
DDRB = 0xFF; // Port B ist Ausgang
PORTB = 0xFC;
// ------- Einstellungen für Ext. Interrupt zum Stoppen des Programms
----
EICRA |= (1<<ISC01); // Fallende Flanke löst Interrupt aus
EIMSK |= (1<<INT0);
//
-----------------------------------------------------------------------
sei(); // Interrupts eingeschaltet
g_run = 1;
while( ! debounce(&PIND, PD0) ); //Wenn Taster an PIN PD0 gedrueckt
wird, wird while verlassen
while(g_run == 1)
{
TIMSK1 |= (1<<TOIE1); // Bei Überlauf des Datenregisters von Timer 1
wird Timer Overflow 1 Interrupt ausgelöst
//Konfiguration von Timer 1
TCCR1A = 0x00; // Timer 1 ohne Outputpins und ohne PWM
TCCR1B |= (1<<CS12) | (1<<CS10); // 3,6864MHZ/ 1024 = 3600 Hz
};
while(1);
return 0;
}
Jetzt sollte es doch eigentlich beim drücken des Tasters an Pin PD0
starten und solange durchlaufen bis ich den externen Interrupt durch
drücken des Tasters an PD2 auslöse.
Das ganze ist ein kleines Teil für meine BA und sollte mich eigentlich
nicht zu lange damit aufhalten ( auch wenn ich das Programmieren schon
interessant finde...)
Habe ich evtl. den Overflow Vektor falsch gewählt? Oder noch ein
Register falsch belegt?
ghost wrote:
> Habe ich evtl. den Overflow Vektor falsch gewählt? Oder noch ein> Register falsch belegt?
Schmeiss mal das ganze Gerödel mit deinen Tastern raus.
Da blickt doch keiner mehr durch.
Halte dich an das einfache Schema:
int main()
{
alles initialisieren
//
// Endlosschleife und den Timer Interrupt
// machen lassen
//
while(1)
;
}
Dazu packst du dann noch die ISR und alles was an globalen
Variablen dazugehört. Dann setzt du den Vorteiler für
den Timer mal auf 1 (*) und gehst mit dem Ganzen in den Simulator
zum durchdebuggen.
(*) 1 deswegen, damit du dir im Simulator keinen Wolf auf der
F10 Taste tippst um den Timerwert um 1 zu erhöhen.
@ ghost
Deine Programmierkenntnisse sind wohl schon ein wenig arg rostig, was?
int main(void)
{
DDRD = 0x00; // Port D ist Eingang
PORTD = 0xFF; // interne Pullup-Widerstände aktiviert
DDRB = 0xFF; // Port B ist Ausgang
PORTB = 0xFC;
// ------- Einstellungen für Ext. Interrupt zum Stoppen des Programms
----
EICRA |= (1<<ISC01); // Fallende Flanke löst Interrupt aus
EIMSK |= (1<<INT0);
//
TIMSK1 |= (1<<TOIE1); // Bei Überlauf des Datenregisters von Timer 1
wird Timer Overflow 1 Interrupt ausgelöst
//Konfiguration von Timer 1
TCCR1A = 0x00; // Timer 1 ohne Outputpins und ohne PWM
TCCR1B |= (1<<CS12) | (1<<CS10); // 3,6864MHZ/ 1024 = 3600 Hz
// sämtliche Konfiguration VOR das Aktivieren der Interrupts
-----------------------------------------------------------------------
sei(); // Interrupts eingeschaltet
g_run = 1;
while( ! debounce(&PIND, PD0) ); //Wenn Taster an PIN PD0 gedrueckt
wird, wird while verlassen
while(g_run == 1); // Endlosschleife, bis durch INT0 G_run false
wird, das Semikolon ist wichtig!
cli(); // alle Interrupts, aus, das wars
while(1); // bis zum Sant Nimmerleinstag
}
>Habe ich evtl. den Overflow Vektor falsch gewählt? Oder noch ein>Register falsch belegt?
Nur kleinere logische Schwächen ;-). Die Interrupts hast du nicht
wirklich kapiert, oder?
Ausserdem musst du noch die Multiplikatoren anpassen, bei ~3600 Hz
Timertakt ist deine Überlauf (=Interrupt)freqeunz 3600/256 ~14 Hz,
sprich 71ms. Das ist dein Zeitraster.
MfG
Falk
Hab mittlerweile das Programm nochmal neu geschrieben. Jetzt
funktioniert eigentlich alles so wie es soll. Nur mit dem externen
Interrupt klappt es net so gut.
Wenn in der ISR meine globale Variable g_run = 0 gesetzt wird, sollte
mein programm die while(g_run == 1) schleife verlassen und in die
while(1) schleife laufen. Dann dürfte aber eigentlich nichts mehr
passieren, oder? weil bei mir die testLEDs weiterhin blinken...
@ ghost
>Wenn in der ISR meine globale Variable g_run = 0 gesetzt wird, sollte>mein programm die while(g_run == 1) schleife verlassen und in die>while(1) schleife laufen. Dann dürfte aber eigentlich nichts mehr>passieren, oder?
Ja.
Aber erstzte mal
char g_run;
durch
volatile char g_run;
> weil bei mir die testLEDs weiterhin blinken...
Dann wird dein Interrupt nicht ausgeführt. Hast du deinen 2. Taster,
welcher den Interrupt auslösen soll auch and PD2 angeschlossen?.
MFG
Falk
hab das mit volatile grad selber bei AVR freaks gefunden...
jetzt klappt es. volatile heißt also, dass der wert global also auch in
main geändert wird oder? dacht immer das macht eine globale variable
sowieso??
ghost wrote:
> volatile heißt also, dass der wert global also auch in> main geändert wird oder? dacht immer das macht eine globale variable> sowieso?Das macht eine globale Variable immer, ja.
`volatile' besagt, dass der Compiler den Code so schreiben muss, dass
an einem sogenannten sequence point der Inhalt der Variablen auch
tatsächlich dem Ergebnis entsprechend der abstrakten Maschine
entsprechen soll. In freier Übersetzung bedeutet das etwa so viel
wie, dass er jegliche Zugriffsoptimierung auf derartige Variablen
sein lassen soll.