PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : INT0 funktioniert nicht



Dämmi
02.06.2013, 20:21
Hallo,

ich bin gerade dabei ein kleines Programm für eine Ladeschaltung zu Programmieren. Ich benutze einen Atmega8. Im Allgmeinen ist das Programm wie folgt aufgebaut:

Ich benutze 2 Timer. Timer1 für die PWM generierung der LED. Einmal steuern der Helligkeit und einmal Ein und Aus schalten in abhängigkeit des ADUs. Außerdem ereuge ich durch zwei hochzählende Variablen Takte als abaufsteuerung des restlichen Programms

Timer0 soll den µC aus dem Idle Mode wecken.

Das alles funktioniert auch schön und gut. Allerdings möchte ich auch das der µC durch INT0 geweckt wird durch eine Positive Flanke. Leider funktioniert es nicht wirklich. Er springt glaub ich in die ISR rein allerdings hab ich da wohl nicht sauber Programmiert. Kann mir da einer helfen? Wäre super hab mir schon total den kopf zerbrochen....

Ich bedanke mich schon einmal für die Hilfe.

Gruß Jonas

Hier der Code:


#define F_CPU 1000000UL //CPU takt auf 1MHz#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include <avr/interrupt.h>
#include "ADC.h"


#define Uladeschluss 1014
#define UladeschlussLED Uladeschluss-0
#define UladeschlussR 914
#define Uladeunter 814
#define UladeunterLED Uladeunter+0
#define UladeunterR 914
#define adupwmmin Uladeunter
#define adupwmmax Uladeschluss
#define helligkeit 5 //10 ist maximum


#define devidedeltaU (((UladeschlussLED)-(UladeunterLED))/100)


#define ledddr DDRD
#define ledPort PORTD
#define ledG PD7
#define ADC_ONddr DDRB
#define ADC_ONPort PORTB
#define ADC_ON PB0
#define ladeddr DDRD
#define ladeport PORTD
#define ladeschlussS PD3
#define ladeschlussR PD4
#define ladeunterS PD5
#define ladeunterR PD6
#define ladeschlussRelais PD0
#define ladeunterRelais PD1
#define DynOn PD2
#define Relaisddr DDRD
#define RelaisPort PORTD
#define RelaisPins PIND


volatile unsigned char timerz=0;
volatile unsigned char timerpwm = 0;
volatile unsigned short adupwm;
volatile unsigned short takt1 = 0;
volatile unsigned short takt2 = 0;
volatile unsigned char status1 = 0;
volatile unsigned short adu, adu1, adu2;


ISR(INT0_vect)
{
GICR &= ~(1<<INT0); //INT0 aus
MCUCR &= ~(1<<SE);
timerz=0;
timerpwm=0;
takt1=0;
takt2=0;
TCCR0 |= (1<<CS01); //Timer0 ein mit prescler 8
TCCR1B = 0; //Timer1 aus
}


ISR(TIMER0_OVF_vect)
{
takt1++;
takt2++;
timerz++;
if(timerz <= helligkeit)
{
if (adupwm < timerpwm)
{
ledPort &= ~(1<<ledG);
}
else
{
ledPort |= (1<<ledG);
}
if (timerpwm>=100)
{
timerpwm=0;
}
}
else
{
ledPort &= ~(1<<ledG);
}

if(timerz==10)
{
timerz=0;
timerpwm++;
}
}


ISR(TIMER1_OVF_vect)
{
MCUCR &= ~(1<<SE);
GICR &= ~(1<<INT0); //INT0 aus
timerz=0;
timerpwm=0;
takt1=0;
takt2=0;
TCCR0 |= (1<<CS01); //Timer0 ein mit prescler 8
TCCR1B = 0; //Timer1 aus
}


void impuls(volatile uint8_t *port, uint8_t pin);


int main(void)
{
//extern ref.. ADC0 als Eingang, rechts Ausrichtung
ADMUX = 0;
//ADU Einstellung:Einzelwandlung, 128 Teilung, keine Interrupts
ADCSRA = 0;
ADCSRA |= (1 << ADPS2)|(1 << ADPS1)|(1 << ADPS0);

//Timer0 Teiler
TCCR0 = 0;
TCCR0 |= (1<<CS01); //prescaler auf 8 2ms pro Überlauf bei 1MHz
//Timer0 Interrupt einschalten
TIMSK = 0;
TIMSK |= (1 << TOIE0);

//Timer1 Teiler
TCCR1B = 0;
TCCR1B |= (1<<CS12)|(1<<CS10); //prescaler auf 1024 alle 61sec ein Überlauf bei 1MHz
//Timer1 Interrupt einschalten
TIMSK |= (1<<TOIE1);

//Extern Interrupt
MCUCR |= (1<<ISC01)|(1<<ISC00); //INT0 auf steigende Flanke (1<<ISC01)|(1<<ISC00)

// Den Pin, an den die LED angeschlossen ist, als Ausgang setzen
ledddr = 0;
ladeddr = 0;
ADC_ONddr = 0;
Relaisddr = 0;

ledddr |= (1 << ledG);
ladeddr |= (1 << ladeunterR)|(1<<ladeunterS)|(1<<ladeschlussS)|(1<<ladeschlussR); //Als Ausgang
ADC_ONddr |= (1<<ADC_ON);

RelaisPort |= (1<<ladeschlussRelais)|(1<<ladeunterRelais); //Eingänge setzen

sei();


/*
do //Ersten ADU wert einlesen
{
timerz=0;
ledPort &= ~(1<<ledG);

if (takt1>489) //takt1 wird vom zähler gezählt, d.h. warten
{
if (!(status1 & (1<<0))) //wenn noch nicht in schleife
{
ADCSRA |= (1<<ADEN); //Einschalten des ADU
ADC_ONPort |= (1<<ADC_ON); //Einschalten ADC_ON um Spannungsteiler vom ADC auf Masse zu legen
status1 |= (1<<0);
}

if (takt1>=500 && !(status1 & (1<<1))) //Erste AD Wandlung danach eine Zweite
{ //beide werden verglichen ob sie auf bis zu
adu1 = getADC(); //10 stellen ähnlich sind wenn ja
status1 |= (1<<1); //weiter mit arbeiten
}

if (takt1>=510)
{
adu2 = getADC();

if ((adu1<=(adu2+5)) && (adu1 >=(adu2-5)))
{
adu=adu2;
}


if (adu<=UladeunterLED) //Kontrolle ob ladeunter- oder Ladeüberspannung
{ //erreicht wurde und dadrauf die grenzen für das
adupwm=0; //blinken der LED setzen
}
else
{
if (adu >= UladeschlussLED)
{
adupwm=100;
}
else
{
adupwm=((adu-UladeunterLED)/devidedeltaU);
}
}

ADCSRA &= ~(1<<ADEN); //Auschalten des ADU
ADC_ONPort &= ~(1<<ADC_ON);
status1 &= ~(1<<0);
status1 &= ~(1<<1);
}
}
} while (takt1<=513);

takt1=0;
*/
while (1) //Hauptschleife
{
if (takt1>489) //takt1 wird vom zähler gezählt, d.h. warten
{
if (!(status1 & (1<<0))) //wenn noch nicht in schleife
{
ADCSRA |= (1<<ADEN); //Einschalten des ADU
ADC_ONPort |= (1<<ADC_ON); //Einschalten ADC_ON um Spannungsteiler vom ADC auf Masse zu legen
status1 |= (1<<0);
}

if (takt1>=500 && !(status1 & (1<<1))) //Erste AD Wandlung danach eine Zweite
{ //beide werden verglichen ob sie auf bis zu
adu1 = getADC(); //10 stellen ähnlich sind wenn ja
status1 |= (1<<1); //weiter mit arbeiten
}

if (takt1>=510)
{
adu2 = getADC();

if ((adu1<=(adu2+5)) && (adu1 >=(adu2-5)))
{
adu=adu2;
}


if (adu<=UladeunterLED) //Kontrolle ob ladeunter- oder Ladeüberspannung
{ //erreicht wurde und dadrauf die grenzen für das
adupwm=0; //blinken der LED setzen
}
else
{
if (adu >= UladeschlussLED)
{
adupwm=100;
}
else
{
adupwm=((adu-UladeunterLED)/devidedeltaU);
}
}

ADCSRA &= ~(1<<ADEN); //Auschalten des ADU
ADC_ONPort &= ~(1<<ADC_ON);
takt1=0;
status1 &= ~(1<<0);
status1 &= ~(1<<1);

//Kontrolle ob Ladeunter- oder Ladeüberspannung erreicht wurde dann Kontrolle ob Relais
//schon geschaltet haben sonst selber schalten
if ((adu > Uladeschluss) && !(RelaisPins & (1<<ladeschlussRelais)))
{
ladeport |= (1<<ladeschlussS);
}else ladeport &= ~(1<<ladeschlussS);

if ((adu < UladeschlussR) && (RelaisPins & (1<<ladeschlussRelais)))
{
ladeport |= (1<<ladeschlussR);
}else ladeport &= ~(1<<ladeschlussR);

if ((adu < Uladeunter) && !(RelaisPins & (1<<ladeunterRelais)))
{
ladeport |= (1<<ladeunterS);
}else ladeport &= ~(1<<ladeunterS);

if ((adu > UladeunterR) && (RelaisPins & (1<<ladeunterRelais)))
{
ladeport |= (1<<ladeunterR);
}else ladeport &= ~(1<<ladeunterR);
}
}

takt2=0;

if (!(RelaisPins & (1<<DynOn)))
{
do //Nichts tun nur Timer0 läuft daher LED blinkt
{
} while (takt2<=2100 && !(RelaisPins & (1<<DynOn)));

TCCR0 = 0; //Timer0 aus
TCCR1B |= (1<<CS12)|(1<<CS10); //Timer1 ein
ledPort &= ~(1<<ledG); //LED aus
GICR |= (1<<INT0); //INT0 ein
MCUCR |= (1<<SE); //Sleep Modus ein
}

}
}

PICture
02.06.2013, 20:45
Hallo!

Ich bin ASMan und kenne "Cäh" gar nicht. Ich habe das Problem beim PIC per Verbinden des INT0 Pins mit anderem Pin gelöst: https://www.roboternetz.de/community/threads/26098-Tips-Tricks?p=559630&viewfull=1#post559630 . ;)

MagicWSmoke
02.06.2013, 21:16
Nur weil Du SE im MCUCR setzt, schläft da noch lange nix, das würde erst nach dem Opcode SLEEP passieren. Unter C gibt's für die Powermodes 'ne Lib, verwende am Besten die Lib.

Dämmi
02.06.2013, 21:28
Oh total überlesen im Datenblat...

Aber das erklärt doch noch nicht warum er den Code in der INT0 ISR nicht ausführt. Er soll ja eigentlich genau das machen was auch beim Timer1 passiert und mit dem Timer1 geht es....

PICture
02.06.2013, 21:51
Sorry, aber ich mache nur das minimalste, was ich brauche. ;)

MagicWSmoke
02.06.2013, 21:57
Da im Sleep der Hauptcode des uC nicht weiter ausgeführt wird, dürfte sich der tatsächliche Ablauf vom gedachten Ablauf doch deutlich unterscheiden. Damit ist natürlich möglich, dass der INT0 an anderer Stelle disabled wird. Bring doch erst mal Deinen Code so in Ordnung, dass er vom Powermode her so klappt, wie gedacht.
Es macht keinen Sinn sich über das wie und warum eines anderen Fehlers Gedanken zu machen, wenn der offensichtlichste Fehler noch nicht behoben ist.
Ob der INT0 dann später tatsächlich anspricht, lässt sich durch Wacklen eines Pins in der ISR testen.

Dämmi
02.06.2013, 22:06
OK sehr vielen dank werde ich morgen mal machen. Werde einfach überall da wo ich vorher das se Bit gesetzt habe die Funktionen:

set_sleep_mode(SLEEP_MODE_IDLE);
sleep_mode();

nutzen. In den beiden ISR werde ich auch das löschen des SE Bits entfernen.

Mich würde aber schon einmal interessieren wo ich im Datenblatt die so genannte SLEEP instruction finde.
Weiß das jemand?

PICture
02.06.2013, 22:21
Normaleweise befindet sich der "sleep" Befehl in "Instruction Set Summary" vom Datenblatt (DB).

MagicWSmoke
02.06.2013, 22:25
SLEEP ist wie schon geschrieben ein Opcode, Du könntest den per Inline Assembler einfügen, oder eben die entsprechenden Funktionen der Lib verwenden, die das alles für Dich machen.

Dämmi
02.06.2013, 22:35
OK nun weiß ich was du da mit Opcode meintest. Fehler ist nun auch weg hat Wunderbar geklappt. Noch einmal vielen vielen Dank