PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Code: Globale Boolvariable mit INT0 Interrupt auf Tiny13 set



ExXeQtor
30.10.2010, 17:46
Hallo Community,

ich brauche hilfe für ein projekt, für das ich nur noch eine Funktion implementieren muss und es dann echt geschafft habe- aber die bereitet mir momentan probleme:

Ich möchte über einen hardwareentprellten taster und dem INT0 Interrupt
bestimmen, ob der µC die Funtion "signal_event" in der mainschleife
ausführt oder nicht. Zum wechseln ob ja oder nein, dachte ich an die
if-bedingungen im ISR und eine globale boolvariable.
Bei meinem Code wird über den INT0 immer nur der zweite teil der
ifbedingung ausgeführt, das heißt die bool ändert sich nicht.

Könnt ihr mir sagen, was ich falsch mache? Sehr viel mehr code passt
nicht rein, bin momentan bei ca 88%.



#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/power.h>
#include <avr/sleep.h>

#define F_CPU 9.6E6
#include <util/delay.h>

#define CLOCK_PRESCALER 256
#define TIMER_PRESCALER 1024

#define TIMER_PERIOD (256 / (F_CPU / CLOCK_PRESCALER / TIMER_PRESCALER))

#define MEDIAN ( 1 * 60) /* 10 minutes */

static uint16_t countdown;
static volatile bool timer_expired;
volatile bool on;


ISR(TIM0_OVF_vect)
{
if (--countdown == 0) {
TCCR0B = 0; /* turn off timer */
timer_expired = true;
clock_prescale_set(clock_div_1);
}
}

ISR(INT0_vect)
{
if (on)
{
on = false;

PORTB |= (1<<PB4); // LED 2*flashing: Off
_delay_ms(20);
PORTB &= ~(1<<PB4);
_delay_ms(20);
PORTB |= (1<<PB4);
_delay_ms(20);
PORTB &= ~(1<<PB4);
_delay_ms(20);
}
else if (!on)
{
on = true;

PORTB |= (1<<PB4); // LED 1*flashing: On
_delay_ms(20);
PORTB &= ~(1<<PB4);
_delay_ms(20);
}
}

static void starttimer(uint16_t timeout)
{
countdown = timeout;
TCNT0 = 0;
timer_expired = false;
clock_prescale_set(clock_div_256);
TCCR0B = _BV(CS02) | _BV(CS00); /* start timer with prescaler 1024 */
}

static void ioinit(void)
{
TIMSK0 = _BV(TOIE0);
GIMSK |= (1<<INT0);
MCUCR |= (1<<ISC01); // Falling edge
MCUCR &= ~(1<<ISC00); // INT0 detection

sei();
DDRB = _BV(4); /* connection for LED or something else */
}

static void signal_event(void)
{
PORTB |= _BV(4);
_delay_ms(1000);
PORTB &= ~_BV(4);
}

int
main(void)
{
ioinit();

for (;;) {
int r = rand();
uint16_t timeout = (unsigned)r % (unsigned)(2 * MEDIAN / TIMER_PERIOD) + 1;

starttimer(timeout);
do
{
sleep_mode();
}
while (!timer_expired);

if (on)
signal_event();
}
}



Beste Grüße[/code]

Slein
30.10.2010, 18:39
Nur ein Schuss ins Blaue, aber probiers mal so:


ISR(INT0_vect)
{
if (on) {
on = false;
...
} else {
on = true;
...
}
}

Wer weiß, wie der Compiler das else if wirklich evaluiert und was dann passiert wenn du die Bedingung im ersten Teil veränderst...

ExXeQtor
30.10.2010, 19:16
danke, ändert aber leider nichts. :/

021aet04
30.10.2010, 19:33
Ich habe es im AVR Studio getestet (mit und ohne Änderung). Ohne Änderung hat es nicht funktioniert (hat "on" und "!on" ausgeführt).
Mit der Änderung hat es aber funktioniert.

Da ich keinen Tiny13 habe kann ich es nur im Simulator testen.

Hast du es im Simulator getestet oder auf dem µC?

MfG Hannes

ExXeQtor
30.10.2010, 19:43
auf dem µC, mit dem simulator habe ich keine erfahrung...
was meinst du mit änderung? die änderung der booleschen in der if/else schleife?

Slein
30.10.2010, 20:27
Die ISR macht komische Dinge im Simulator...

Hab die bools mal durch uint8 ersetzt und den Wechsel mit nem xor realisiert.
Zumindest im Simulator tuts jetzt in der ISR.


#include <stdlib.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/power.h>
#include <avr/sleep.h>

#define F_CPU 9.6E6
#include <util/delay.h>

#define CLOCK_PRESCALER 256
#define TIMER_PRESCALER 1024

#define TIMER_PERIOD (256 / (F_CPU / CLOCK_PRESCALER / TIMER_PRESCALER))

#define MEDIAN ( 1 * 60) /* 10 minutes */

volatile uint16_t countdown;
volatile uint8_t timer_expired;
volatile uint8_t on;


ISR(TIM0_OVF_vect)
{
if (--countdown == 0) {
TCCR0B = 0; /* turn off timer */
timer_expired = 0x01;
clock_prescale_set(clock_div_1);
}
}

ISR(INT0_vect)
{
on ^= 0x01;
if (on) {
PORTB |= (1<<PB4); // LED 2*flashing: Off
_delay_ms(20);
PORTB &= ~(1<<PB4);
_delay_ms(20);
PORTB |= (1<<PB4);
_delay_ms(20);
PORTB &= ~(1<<PB4);
_delay_ms(20);
} else {
PORTB |= (1<<PB4); // LED 1*flashing: On
_delay_ms(20);
PORTB &= ~(1<<PB4);
_delay_ms(20);
}
}

static void starttimer(uint16_t timeout)
{
countdown = timeout;
TCNT0 = 0;
timer_expired = 0x00;
clock_prescale_set(clock_div_256);
TCCR0B = _BV(CS02) | _BV(CS00); /* start timer with prescaler 1024 */
}

static void ioinit(void)
{
TIMSK0 = _BV(TOIE0);
GIMSK |= (1<<INT0);
//MCUCR |= (1<<ISC01); // Falling edge
//MCUCR &= ~(1<<ISC00); // INT0 detection
MCUCR = 0x02;

on = 0x00;

sei();
DDRB = _BV(4); /* connection for LED or something else */
}

static void signal_event(void)
{
PORTB |= _BV(4);
_delay_ms(1000);
PORTB &= ~_BV(4);
}

int
main(void)
{
ioinit();

while(1) {
int r = rand();
uint16_t timeout = (unsigned)r % (unsigned)(2 * MEDIAN / TIMER_PERIOD) + 1;

starttimer(timeout);
do
{
sleep_mode();
}
while (!timer_expired);

if (on) {
signal_event();
}
}
}

ExXeQtor
30.10.2010, 21:13
ich muss zugeben, ich verstehe nicht so ganz, was da im code jetzt passiert.. ^^
ich will ja einen wechsel innerhalb der if/else bedingungen. also wenn on an war, dann soll es danach aus sein und andersrum.
dein wechsel kommt ja vor der schleife!
Ich habe die wechsel wie bei meinem boolbeispiel dann wieder hineingetan - und es funktioniert auch nicht :(

ist doch verhext...

ExXeQtor
30.10.2010, 21:41
Ist doch merkwürdig.. wenn ich die funktion so verändere:


ISR(INT0_vect)
{
if (on)
{
PORTB |= (1<<PB4); // LED 1*flashing: Off
_delay_ms(2);
PORTB &= ~(1<<PB4);
_delay_ms(10);

on = 0;
if (!on)
{
PORTB |= (1<<PB4);
_delay_ms(2);
PORTB &= ~(1<<PB4);
_delay_ms(2);
}
}
else
{
PORTB |= (1<<PB4); // LED 2*flashing: On
_delay_ms(2);
PORTB &= ~(1<<PB4);
_delay_ms(2);
PORTB |= (1<<PB4);
_delay_ms(2);
PORTB &= ~(1<<PB4);
_delay_ms(10);

on = 1;
if (on)
{
PORTB |= (1<<PB4);
_delay_ms(2);
PORTB &= ~(1<<PB4);
_delay_ms(2);
}
}
}

zeigt sich, dass die variable in der schleife definitiv geändert wird (wenn ich mit on=0 initialisiere, wird die else schleife aufgerufen und es blinkt dreimal). Danach wird sie anscheinend wieder zurückgesetzt!
Woran liegt das? Was habe ich da nicht begriffen?

Slein
30.10.2010, 22:05
Zu deinem code:
...
on = 0;
if (!on)
...
und
...
on = 1;
if (on)
...
Beide if werden auf diese Weise immer zutreffen :-s

Zu meinem code:
Ein uint8_t ist ein byte und das kann man fast genauso testen wie ein bool.
Wenn es null ist treffen Vergleiche nicht zu (false), wenn es größer ist treffen Vergleiche zu (true). Man kann also wie bei bool 'if (on)' verwenden, muß nur auf 0 oder 1 setzen statt false und true.

In der ISR mach das 'on ^= 0x01;' den Wechsel genauso wie du es im if else beabsichtigst, nur kann der compiler im Vergleich dahinter keinen Blödsinn mehr veranstalten wie wenn du on zwischendurch setzt.
XOR:
0^0 ist 0
1^0 ist 1
0^1 ist 1
1^1 ist 0
Wenn on 1 ist und mit ner 1 xored, wird es 0, aus true wird false.
Wenn on 0 ist und mit ner 1 xored, wird es 1, aus false wird true.

Ausgeschrieben wirds evtl. deutlicher:
on = on ^ 0x01;

Slein
30.10.2010, 22:33
Scheißding...

Probier mal den Code aus deinem ersten Post, aber stell im Projekt mal die Optimierung von -Os auf -O3.
Sonst passieren in der ISR nur komische Sachen. ](*,)

ExXeQtor
30.10.2010, 23:10
Danke für die Hilfe!
habs. schuld war unter anderem eine doofe entprellung - die ich von einem pollinboard nachgemacht habe. leider ist die aber für meine anwendung nicht die richtige gewesen, wie ich dann mit meinem (leider analog-)oszi gesehen habe...
also, läuft! Besten Dank!