Forum: Mikrocontroller und Digitale Elektronik asynchroner Timer2 im AVR


von Owen S. (senmeis)


Lesenswert?

Hi,

ich möchte eine Zeichenkette über UART im Atmega169 alle 5 Sekunde 
senden lassen. Dazwischen wechselt der Controller in den Schlaf Modus. 
Ein 32.768kHz Quarz wird für Timer2 eingesetzt und der interne RC 
Oszillator wird als Systemtakt verwendet.

Das Problem ist, statt 5s wird diese Zeichenkette alle 2s geschickt. 
Woran kann das liegen?
1
extern char gPowerSaveTimer;    // external Counter from "RTC.c"
2
char PowerSaveTimeout = 5;
3
char PowerSave = FALSE;     
4
5
int main( void )
6
{
7
  char str[] = "12345";
8
  
9
  clock_init_8MHz();
10
  USART_Init(103); // 9600bps by 8MHz
11
  RTC_init();
12
  
13
  __enable_interrupt();
14
15
  for(;;) // main loop
16
  {
17
    if (!PowerSave)
18
    {
19
        uart_put_string(str);   
20
        PowerSave = TRUE;   // enter sleep mode
21
        gPowerSaveTimer = 0;
22
    }
23
      
24
    else 
25
    {
26
      SMCR = (3<<SM0) | (1<<SE);      // Enable Power-save mode
27
      __sleep();                      // Go to sleep
28
    }            
29
    SMCR = 0;                       // Just woke, disable sleep
30
  }
31
}
32
33
void clock_init_8MHz(void)
34
{
35
  CLKPR = (1<<CLKPCE);        // set Clock Prescaler Change Enable
36
    
37
  // set prescaler = 8, Inter RC 8Mhz / 1 = 8Mhz
38
  CLKPR = 0; 
39
}
40
41
void Delay(unsigned int millisec)
42
{
43
    int i;
44
    
45
    while (millisec--)
46
        for (i=0; i<125; i++);
47
}
48
49
void USART_Init(unsigned int baudrate)
50
{
51
    // Set baud rate
52
    UBRR0H = (unsigned char)(baudrate>>8);
53
    UBRR0L = (unsigned char)baudrate;
54
55
    // Enable 2x speed
56
    UCSR0A = (1<<U2X0);
57
58
    // Enable receiver and transmitter
59
    UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(0<<RXCIE0)|(0<<UDRIE0);
60
61
    // Async. mode, 8N1
62
    UCSR0C = (0<<UMSEL0)|(0<<UPM00)|(0<<USBS0)|(3<<UCSZ00)|(0<<UCPOL0);
63
}
64
65
void Usart_Tx(char data)
66
{
67
  UCSR0A = UCSR0A;               // clear TXC0 !!!  
68
  UDR0 = data;
69
  while (!(UCSR0A & (1<<TXC0)));
70
}
71
72
void uart_put_string (char *data_string)
73
{
74
    while(*data_string) Usart_Tx(*(data_string++));
75
}
76
77
/******************************************************************************
78
*
79
*   Function name:  RTC_init
80
*
81
*   returns:        none
82
*
83
*   parameters:     none
84
*
85
*   Purpose:        Start Timer/Counter2 in asynchronous operation using a
86
*                   32.768kHz crystal.
87
*
88
*******************************************************************************/
89
void RTC_init(void)
90
{
91
    Delay(1000);            // wait for 1 sec to let the Xtal stabilize after a power-on,
92
93
    __disable_interrupt();  // disabel global interrupt
94
95
    cbi(TIMSK2, TOIE2);             // disable OCIE2A and TOIE2
96
97
    ASSR = (1<<AS2);        // select asynchronous operation of Timer2
98
99
    TCNT2 = 0;              // clear TCNT2A
100
    TCCR2A |= (1<<CS22) | (1<<CS20);             // select precaler: 32.768 kHz / 128 = 1 sec between each overflow
101
    
102
    while((ASSR & (0x01 | 0x04)));       // wait for TCN2UB and TCR2UB to be cleared
103
104
    TIFR2 = 0xFF;           // clear interrupt-flags
105
    sbi(TIMSK2, TOIE2);     // enable Timer2 overflow interrupt
106
107
    OCR2A = 200;    // set timer2 compare value
108
    
109
    __enable_interrupt();                 // enable global interrupt
110
}
111
112
/******************************************************************************
113
*
114
*   Timer/Counter2 Overflow Interrupt Routine
115
*
116
*   Purpose: Increment the real-time clock
117
*            The interrupt occurs once a second (running from the 32kHz crystal)
118
*
119
*******************************************************************************/
120
#pragma vector = TIMER2_OVF_vect
121
__interrupt void TIMER2_OVF_interrupt(void)
122
{
123
  gPowerSaveTimer++;
124
  if (gPowerSaveTimer >= PowerSaveTimeout)
125
  {
126
    gPowerSaveTimer = 0;
127
    PowerSave = FALSE;
128
  }
129
}

Gruss
Owen

von Peter D. (peda)


Lesenswert?

Im asynchronen Modus brauchts ne Flanke des 32kHz Taktes, damit Werte 
übernommen werden, z.B. das Löschen des Interruptflags.
Dafür gibt es allerdings kein Busy-Bit.
Daher wacht er wieder auf und Du bekommst mehrere Interrupts.
Als Lösung kann man ein Dummy-Write auf TCCR2A machen und warten, bis 
TCR2UB wieder gelöscht ist.


Peter

von (prx) A. K. (prx)


Lesenswert?

Ein letztes Mal schreib ich dir das noch, aber dann nicht mehr, 
versprochen: Wenn TCCR2A nach setzen von AS2 per Definition Schrott ist, 
dann ergibt
  TCCR2A |= (1<<CS22) | (1<<CS20);
schlicht und einfach keinen Sinn.

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.