PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ATmega32: IRQ-Programmierung



Leverator
26.02.2007, 10:19
Hallo Profies,

kann mir jemand einen guten Einstieg in die IRQ-Programmierung von ATmega32-uCn geben? Ich steige bei der Atmel-Dokumentation nicht so recht durch.

Wie ich vorgehen möchte:
1. Einen Timer konfigurieren, als IRQ-Quelle definieren und starten.

2. Eine InterruptServiceRoutine definieren und verwenden können.

Danke und Gruß,
Lev

Pascal
26.02.2007, 10:25
Schau mal hier oder auf www.mikrocontroller.net im wiki. Da findest du auf jeden Fall was dazu.

bL1nK
26.02.2007, 10:42
also was du machen solltest ist die interrupts mal einschalten. sprich den globalen interrupbt mit sei() und dann noch den spezifischen zb den overflow-interrupt vom timer.

und dann einfach die interrupt-routine in deinen quelltext mit rein hängen.

sprich
ISR(interrupt_vektor)
{
interrupt-routine
}

die interrupt-namen sind in den headerdatein von avr definiert, z.b. beim atmega8 die iom8.h da steht zb für timer-overflow SIG_OVERFLOW0...

Leverator
27.02.2007, 07:46
Wau, Ihr seid ja schnell dabei. :)
Vielen Dank für die Hinweise. Eine Frage noch: Muß die IRQ-Routine ISR heißen, oder kann die jeden anderen Namen tragen? Wo finde ich da mehr zu?

[Edit:] Ich möchte wissen, wie man das in C macht.


Danke und Gruß,
Lev

coCo
27.02.2007, 10:21
Hi,
Pascal hat dir nen Link gegeben wo es schön beschrieben wird:
www.microcontroller.net
Such da in der linken Spalte nach AVR-GCC TUtorial

MfG

bL1nK
27.02.2007, 11:59
Wau, Ihr seid ja schnell dabei. :)
Vielen Dank für die Hinweise. Eine Frage noch: Muß die IRQ-Routine ISR heißen, oder kann die jeden anderen Namen tragen? Wo finde ich da mehr zu?

[Edit:] Ich möchte wissen, wie man das in C macht.


Danke und Gruß,
Lev

ja, ISR(vektor) ist hier sozusagen sowas wie der funktionsname und vektor ist der parameter welcher interrupt gemeint ist. aber durch substitution kannst es auch in günther umbenennen :P das ist dann dir überlassen.

Leverator
01.03.2007, 18:18
Ja hallo,

vielen Dank für die interessanten Tipps.
Damit wir hier nicht so virtuell in den Äther diskutieren, hier mal etwas Code an dem ich gerade arbeite.




#ifndef _stepMotorClass_
#define _stepMotorClass_

#include <util/delay.h>
#include <avr/io.h>

class ClStepMotor {
private:
uint8_t stepNo;
int8_t direction; // +1 / -1
uint16_t wait;

public:
ClStepMotor();
void setMotorStep(void);
void setWait(uint16_t*);
void setDirection(int8_t*);
void setMotorOff(void);

};


#endif // stepMotorClass


Und hier die ClStepMotor.cpp:



#include <util/delay.h>
#include <avr/io.h>

#include "ClStepMotor.h"


ClStepMotor::ClStepMotor() {
// Den Schrittmotortreiber aktivieren. => Port D Bit 4 & 5 auf eins schalten
DDRD |= (1<<PD4 | 1<<PD5); // Die Bits 4 und 5 auf Ausgang setzen.
PORTD |= (1<<PD4 | 1<<PD5); // Die beiden Bits auf 1 setzen: High-Ausgang

// Die Steuerleitungen fuer den Schrittmotortreiber aktivieren => Port B Bit 0 und 1, Port C Bit 6 und 7
DDRB |= (1<<PB0 | 1<<PB1); // Port B aktivieren
DDRC |= (1<<PC6 | 1<<PC7); // Port C aktivieren

wait = 80;
stepNo = 0;
direction = 1;
}


void ClStepMotor::setWait(uint16_t *w) {
wait = *w;
}

void ClStepMotor::setDirection( int8_t *d ) {
direction = *d;
}


void ClStepMotor::setMotorStep(void) {
uint8_t valPrtB = 0;
uint8_t valPrtC = 0;
uint16_t w = wait;

stepNo += direction;

if( stepNo > 7 ) { // auch 2'er-Komplementzahlen (negative) sind usigned größer als 7 :)
if ( direction > 0 )
stepNo = 0;

if ( direction < 0 )
stepNo = 7;
}

switch( stepNo ) {

case 0: valPrtB = 1<<PB0; // 10-10
valPrtC = 1<<PC6;
break;

case 1: valPrtB = 1<<PB0; // 10-00
valPrtC = 0<<PC6;
break;

case 2: valPrtB = 1<<PB0; // 10-01
valPrtC = 1<<PC7;
break;

case 3: valPrtB = 0<<PB0; // 00-01
valPrtC = 1<<PC7;
break;

case 4: valPrtB = 1<<PB1; // 01-01
valPrtC = 1<<PC7;
break;

case 5: valPrtB = 1<<PB1; // 01-00
valPrtC = 0<<PC7;
break;

case 6: valPrtB = 1<<PB1; // 01-10
valPrtC = 1<<PC6;
break;

case 7: valPrtB = 0<<PB1; // 00-10
valPrtC = 1<<PC6;
break;

default: stepNo = 0;
break;
}

PORTB = (PORTB & !(1<<PB0 | 1<<PB1) ) | valPrtB; // Clear out old values and then set the new ones.
PORTC = (PORTC & !(1<<PC6 | 1<<PC7) ) | valPrtC;

while ( w-- )
_delay_us(1);
}

void ClStepMotor::setMotorOff(void) {
PORTB = (PORTB & !(1<<PB0 | 1<<PB1) ); // Clear out old values.
PORTC = (PORTC & !(1<<PC6 | 1<<PC7) );
}


Wie Ihr sehen könnt, programmiere ich gerne in C++. Das bringt mir die Vorteile, daß ich einmal geschriebenen Code wirklich einfach wiederverwenden kann. Aber in diesem Fall wird in der Prozedur motorStep() eine delay-Routine aufgerufen. Das ist natürlich nicht gut, und diese möchte ich gerne gegen die ISR ersetzen.

Ansonten: Was haltet Ihr von meinem Code?


Gruß,
Lev

Leverator
04.03.2007, 17:25
Moin zusammen,

ich habe die IRQ-Routine nun eingebaut.

Dazu musste ich meine Klasse global definieren und konnte sie dann einfach auch in der ISR verwenden.

Bei jedem Interrupt wird nun der Schrittmotor um einen Schritt weiter gedreht (Halb-Schritt).

Das hat auch alles wunderbar funktioniert, bis ich auf die Idee kam, den Vorteiler statt auf 1024 auf 1 zu stellen. Daraufhin konnte mein Schrittmotortreiber (L293) den Impulsen nicht mehr recht folgen und fing zu qualmen an.

Tolle Sache das.

Auf jeden Fall Danke an Euch für Eure guten Tipps bisher.

Gruß,
Lev