PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Timerproblem



schorsch_76
06.04.2012, 11:42
Hallo zusammen!

Momentan erzeugen meine 3 Timer konstant IRQs. Das funktioniert auch im CTC Mode.

Das Problem: Jetzt möchte ich aber in der ISR des Timer1 den Timer0 bzw Timer 2 starten. Diese sollen "Singleshot" Timer sein. Bisher habe ich diese am Anfang vor der while(1) Schleife Prescale etc initialisiert. um jetzt den Timer zu starten, setze ich jetzt in der Timer1 ISR



OCR0A = x-1; TIMSK0 |= (1 << OCIE0A);


Die Timer0 ISR macht ihre Aktion und soll dann sich selbst wieder stoppen mit



TIMSK0 &= ~(1 << OCIE0A);


Geht das prinzipell oder ist das unmöglich dass der Atmega168 in einer TimerISR einen anderen Timer startet? Bzw seine "eigenen" IRQ register beschreibt?

Der Atmega168 läuft mit 16 MHz.

Hier ist mein Code:


#include <stdlib.h>
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>

#include "i2cmaster.h"
#include "uart.h"

// -----------------------------------------------------
// defines for better readability
// -----------------------------------------------------

// Leds
#define led_alive_on() (PORTC |= (1<<PC0))
#define led_alive_off() (PORTC &= ~(1<<PC0))

// timer
#define start_timer0(x) { OCR0A = x-1; TIMSK0 |= (1 << OCIE0A);}
#define start_timer2(x) { OCR2A = x-1; TIMSK2 |= (1 << OCIE2A);}

#define stop_timer0() (TIMSK0 &= ~(1 << OCIE0A))
#define stop_timer2() (TIMSK2 &= ~(1 << OCIE2A))

// EEPROMs
#define EEPROM_SERVO_1 0b01010000
#define EEPROM_SERVO_2 0b01010001

// Baud rate
#define UART_BAUD_RATE 38400

// -----------------------------------------------------
// global variables
// - communication of IRQ routines with main loop
// - communication if pin change irqs with impuls generation
// -----------------------------------------------------

// status of live led
volatile bool b_live_led = false;
volatile uint16_t gi_cnt = 0;

// -----------------------------------------------------
// io handling
// -----------------------------------------------------
void init_io()
{
DDRB = 0b00000000; // All inputs
DDRC = 0b11111111; // All outputs
DDRD = 0b11111000; // mixed in-/outputs

PORTB = 0b11111001; // set inputs to high
PORTC = 0b00000000; // set outputs to low
PORTD = 0b00000111; // set inputs to high
}

// -----------------------------------------------------
// Timer handling
// -----------------------------------------------------
void init_timer(void)
{
// prescalefactor settings is equal at timer 0 and 1. Timer 2 is different
// ((16.000.000 MHz / 64) = 250 kHz Prescaleclock;

// ----------------------------
// Timer 1
// ----------------------------
TCCR1A = 0; // CTC Mode
TCCR1B = ((1<<WGM12) | (1<<CS01) | (1<<CS00)); // prescale factor 64
OCR1A = 2500-1;
TIMSK1 |= (1 << OCIE1A);

// ----------------------------
// Timer 0
// ----------------------------
TCCR0A = 0; // CTC Mode
TCCR0B = ((1<<WGM12) | (1<<CS11) | (1<<CS10)); // prescale factor 64

// ----------------------------
// Timer 2
// ----------------------------
TCCR2A = 0; // CTC Mode
TCCR2B = ((1<<WGM12) | (1<<CS22)); // prescale factor 64
}

// Timer ISR
ISR(TIMER1_COMPA_vect)
{
// Debug
if (++gi_cnt > 100)
{
led_alive_on();
start_timer0(250);
gi_cnt = 0;
}
}

// set servo output off for servo 1
ISR(TIMER0_COMPA_vect)
{
led_alive_off();
stop_timer0();

#if 0
// regular ISR
// set output off for servo 1
servo1_off();
stop_timer0();
#endif
}

ISR(TIMER2_COMPA_vect)
{
led_alive_off();
stop_timer0();
return;

#if 0
// regular ISR
// set output off for servo 2
servo2_off();
stop_timer2();
#endif
}

// -----------------------------------------------------
// main loop
// - handle modes
// - handle i2c storage, save and read
// -----------------------------------------------------

int main(void)
{
// io port directions
init_io();

// init timer at 1ms rate
init_timer();

// init the uart library
uart_init(UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU));

// allow all interrupts
sei();

// endless loop
while(1)
{
// check mode switch
static uint8_t s_old_mode_switch_status = 0;
static uint8_t s_new_mode_switch_status = 0;

s_new_mode_switch_status = is_mode_switch_on();
if (s_new_mode_switch_status && !s_old_mode_switch_status)
{
gb_mode++;
if (gb_mode > MODE_REPLAY)
gb_mode = MODE_DIRECT;
}
s_old_mode_switch_status = s_new_mode_switch_status;

// mode direct
if (gb_mode == MODE_DIRECT)
{
// leds
led_mode_direct_on();
led_mode_capture_off();
led_mode_replay_off();

// only display active led for debug purpose
}

// mode capture
else if (gb_mode == MODE_CAPTURE)
{
// leds
led_mode_direct_off();
led_mode_capture_on();
led_mode_replay_off();
}

// mode replay
else if (gb_mode == MODE_REPLAY)
{
// leds
led_mode_direct_off();
led_mode_capture_off();
led_mode_replay_on();
}
}
}


Gruß
Georg

Kampi
06.04.2012, 11:51
Hi,

also generell kannst du in einer ISR alles machen was du willst. Bei der ISR passiert ja nichts anderes als das ein Interruptbit gesetzt wird und dadurch springt der Programmzähler zu einer Vektoradresse die für diese Interruptquelle deffiniert ist und an dieser Vektoradresse steht dann ein Sprungbefehl zu der Startadresse deiner eigentlichen ISR wo dann der Code steht.
Klar kannst du dann in einer ISR einen anderen Timer starten oder den Timer der die ISR verändert hat "bearbeiten".
Die Timer kannst du generell immer "bearbeiten". Das ist nicht so das die dann keine Änderungen zulassen :)
Nur eventuell treten diese Änderungen dann nicht sofort in Kraft.
Und du kannst in einer Timer-ISR auch den Timer stoppen der diese ISR ausgelöst hat (z.B. wenn du einen Puls messen willst machst du das auch so. Bei der steigenden Flanke wird eine ISR abgearbeitet wo ein Timer gestartet wird und bei einer fallenden Flanke wird der Timer gestoppt und dann hast du die Zeit wie lange der Impuls High war).

schorsch_76
06.04.2012, 18:10
Danke Daniel!