Forum: Mikrocontroller und Digitale Elektronik Anfängerfrage Timer/Counter


von Michel (Gast)


Lesenswert?

Hallo zusammen,

ich möchte gerne ein GSM-Modem ansteuern. Sprich ein anderes Modem 
anrufen.
Wenn nach einer bestimmten Zeit das Modem nicht antwortet will ich eine 
andere Nummer wählen.

ATD+xxxxxxxx;
bspw. 10 sek warten!
Wenn keine Antwort, neue Nummer wählen!

Ich verwende eine Arduino Mega Board: ATmega2560 mit 16MHz.
Counter und Timer bereiten mir noch etwas Kopfzerbrechen und ich steig 
nicht so richtig durch und weiß nicht so richtig, wie ich das angehen 
soll. Muss man das mit Interrupts machen?
Gruß
Michel

von antwort (Gast)


Lesenswert?

machs doch so:

for( int i = 0; i<10; i++)
_delay_ms( 1000 );

von Michel (Gast)


Lesenswert?

Hallo,
Danke für die Antwort. Wie reagiere dann aber, wenn eine Antwort kommt?

von Falk B. (falk)


Lesenswert?

@  Michel (Gast)

>Danke für die Antwort. Wie reagiere dann aber, wenn eine Antwort kommt?

Indem man eben NICHT 10x 1000ms wartet, sondern eher 10.000 mal 1ms. 
Etwa so.

1
for( int i = 0; i<10000; i++) {
2
    _delay_ms(1);
3
    if(UART_RXC) {
4
        // Antwort, weiter gehts
5
        break;
6
    }
7
}

Siehe Multitasking

MfG
Falk

von Sebastian (Gast)


Lesenswert?

Hi!

Also wenn du einen Timer starten willst, hab ich hier mal was für dich:
1
#include <avr/interrupt.h>
2
//#include <avr/math.h>
3
4
5
#define MCU_FREQ 16000000
6
#define SAMPLINGRATEHZ 300
7
#define PRESCALER 8
8
//1 Tick = 16e6 / 8 Prescaler => 2.000.000 Ticks pro Sekunde => 2.000.000/HERTZ = TimerTicks 
9
//(entspricht bei 300Hz 6666 Ticks = 0x1A0B) => Timer Offset muss auf 0xFFFF-0x1A0B gestellt werden
10
// damit alle 0x1A0B Ticks ein Overflow entsteht
11
12
int timer1Offset = 0xFFFF - (MCU_FREQ/(PRESCALER*SAMPLINGRATEHZ));
13
14
void setup()
15
{  
16
  //Configure Timer 1
17
  PRR &= ~(1<<PRTIM1); //disable Power Reduction Timer 1 (PRTIM1); 
18
  TCCR1A = 0x00; //Normal Mode
19
  TCNT1 = timer1Offset; //Setz den Timer auf den Startwert.
20
  
21
  
22
  if (1== PRESCALER) TCCR1B =    0b0000001; //Normal mode with prescaler 1
23
  if (8== PRESCALER) TCCR1B =    0b0000010; //Normal mode with prescaler 8
24
  if (64== PRESCALER) TCCR1B =   0b0000011; //Normal mode with prescaler 64
25
  if (256== PRESCALER) TCCR1B =  0b0000100; //Normal mode with prescaler 256
26
  if (1024== PRESCALER) TCCR1B = 0b0000101; //Normal mode with prescaler 1024
27
28
  TIMSK1 |= (1<<0); //Enable Overflow Interrupt
29
  sei(); //set_interrupts(), nicht sicher, ob man das auch noch braucht
30
  
31
}
32
33
34
//diese Funktion wird aufgerufen, wenn der Timer überlauft (TCNT1 == 0xFFFF)
35
ISR (TIMER1_OVF_vect)
36
{ 
37
   // ändere die wählnummer hier
38
39
  //reset des Timers auf den Startwert
40
  TCNT1 = timer1Offset;
41
}

In diesem Beispiel wird der Timeroverflow 300 mal/sekunde aufgerufen.

Um auf einmal in 10 Sek. zu kommen müsstest du dein timer1Offset so 
berechnen:

0xFFFF - ((MCU_FREQ/PRESCALER) * 10), was aber nicht geht weil selbst 
bei Prescaler 1024 kommst du beim Klammernterm auf 156250, was keine 
16bit Zahl mehr ist!

Daher kannst du nur zb. 0xFFFF - ((MCU_FREQ/PRESCALER) * 2) ausrechnen, 
also bei 1024 Prescaler 0xFFFF - 0x7A12 = 0x85ED.

Dann wird die Interruptroutine alle 2 Sekunden aufgerufen.
Die musst du dann so ändern, dass der Code nur jedes 5te mal ausgeführt 
wird:
1
int i = 0;
2
ISR (TIMER1_OVF_vect)
3
{ 
4
   i++;
5
   if (i>5) 
6
   {   
7
      // ändere die wählnummer hier
8
      i=0;
9
   }
10
11
  //reset des Timers auf den Startwert
12
  TCNT1 = timer1Offset;
13
}

Ich hoffe das war verständlich und v.a. dass ich mich nicht verrechnet 
hab.
Bitte zu bedenken, dass ich selbst auch noch Anfänger bin es geht sicher 
noch besser/schöner, aber so sollte es funktionern.

Viel Glück!

von Sebastian (Gast)


Lesenswert?

achja, wenn eine Antwort kommt sowohl TCNT1 = timer1Offset setzen als 
auch i=0;

von Michel (Gast)


Lesenswert?

Hallo,
vielen Dank für die Antworten. Ich habs nun mal probiert, aber es klappt 
noch nicht so richtig. Also im Grunde will ich eine Nummer anrufen und 
wenn die/der nach 15 Sekunden ran geht, die Verbindung beenden und eine 
andere Nummer wählen.

Ich hab also zwei Nummern, die abwechselnd anrufen will, bis jemand ran 
geht, bzw. durch Auflegen bemerkbar macht, dass er da ist. Ich erhalte 
dann vom Modem die Antwort BUSY. Mit gsm_ans = 1 springe ich in 
gsm_antwort()und warte/werte die Antwort des Modems ab/aus. Wenn nicht 
BUSY detektiert wurde soll der Anruf nach 15 min mit ATH beendet und das 
Ganze von vorne beginnen. Wenn das Modem nach ATD+xxxxx; sendet erhöhe 
ich init_step um eins.

Ich habs nun mal mit einer Nummer versucht und es klappt nicht 
richtig...Ich seh den Fehler nicht...zum Haare raufen!

Es wäre wirklich nett wenn mir jemand weiterhelfen könnte. VG


  do
    if ( gsm_ans == 0 )
    {

      if ( init_step == 0 )
      {
        uarts( "ATD" );

        uarts( number1 );

        uarts( ";" );

        gsm_ans = 1;
      }


      if ( init_step == 1 )
      {

        for( int i = 0; i<15000; i++)
        {
             _delay_ms(1);

          if( busy == 1 )
          {
             break;
          }
        }


        if( busy == 1 )
        {
          uarts("BUSY detektiert");
          busy = 0;
        }

        else
        {
          uarts( "ATH" );
          init_step = 0;
        }

        gsm_ans = 1;

      }

    }

    else
    gsm_antwort();

  while( init_step <= 1 );

von glop (Gast)


Lesenswert?

wie soll der in der for-Schleife denn wissen, wann busy==1 ist?????

von Michel (Gast)


Lesenswert?

Hallo glop!
Mir scheint als würde das Programm gar nicht aus der Schleife bei busy 
== 1 springen. Ich hab nun auch einmal noch gsm_answer = 1 in die 
Schleife gepackt, ohne Erfolg.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.