Forum: Compiler & IDEs Timer1 lässt sich nicht auf 0 stellen


von Manfred Schreier (Gast)


Lesenswert?

Hi,

Ich hab den Atmega32. Ich wollte mir eine/zwei Funktionen schreiben, die 
mir es erlauben die WCET und die BCET einer funktion oder eines 
Codesegments zu bestimmen.

Hier der Code:
1
void ETE_start(void){
2
// set the counter value to 0
3
  TCNT1L = 0; // set the low part to 0
4
  TCNT1H = 0;  // set the high part to 0
5
  USART_Transmit(TCNT1L);
6
  USART_Transmit(TCNT1H);
7
// set the prescaler s. Table 48 Datasheet
8
// 0,5µs= 1/(F_CPU/8)
9
  TCCR1B|=(1<<CS11);
10
}
11
12
13
void ETE_stop(void){
14
  uint16_t temp=0;  //auxiliary variable
15
// combine TCNT1L and TCNT1H
16
  temp=TCNT1L; //save the lower part
17
  temp|=(TCNT1H<<8); // save the higher part to the right place
18
  USART_Transmit_uint16(&temp);
19
// evaluate if it was a BCET or a WCET
20
  if (temp<BCET){
21
    BCET=temp;      // save the new BCET to the global variable
22
  }else if(temp>WCET){
23
    WCET=temp;      // save the new WCET to the global variable
24
  }  
25
  TCCR1B&=~(1<<CS11);
26
}

Leider hab ich festgestellt (mit den USART Ausgaben) das TCNT nicht auf 
0 gesetzt wird, warum ?

kann mir jemand helfen?

von Patrick B. (p51d)


Lesenswert?

Den Timer würde ich bei ETE_stop als erstes stoppen, ansonsten stimmen 
dann die Register nicht mehr genau.

Wie sieht denn die USART_Transmitt Funktion aus?? Im obigen Code 
scheints korrekt zu sein.

Gruss

von Michael D. (etzen_michi)


Lesenswert?

Was passiert wenn du nur einen auf 0 und den anderen auf 1 schreibst?

Welche Werte werden angezeigt?

Bin mir grad nicht sicher über die Reihenfolge, aber was passiert wenn 
du zuerst H dann L schreibst?

von Karl H. (kbuchegg)


Lesenswert?

Michael D. schrieb:

> Bin mir grad nicht sicher über die Reihenfolge, aber was passiert wenn
> du zuerst H dann L schreibst?


Geht mir genauso. Daher überlasse ich sowas dem Compiler. Der weiß das 
nämlich

Anstelle von ...
1
void ETE_start(void){
2
// set the counter value to 0
3
  TCNT1L = 0; // set the low part to 0
4
  TCNT1H = 0;  // set the high part to 0
5
6
...
7
8
void ETE_stop(void){
9
  uint16_t temp=0;  //auxiliary variable
10
// combine TCNT1L and TCNT1H
11
  temp=TCNT1L; //save the lower part
12
  temp|=(TCNT1H<<8); // save the higher part to the right place
13
...

... dann eben
1
void ETE_start(void){
2
// set the counter value to 0
3
  TCNT1 = 0;
4
5
...
6
7
void ETE_stop(void){
8
  uint16_t temp = TCNT1;
9
...

Hat 2 Vorteile
* zum einen brauch ich mir nicht merken, wie rum es nun korrekt ist
* zum zweiten erspar ich mir das rumhampeln mit Bytes zusammensetzen
  bzw. auseinanderpfriemeln

In C ist eben weniger oft mehr :-)
Lass den Compiler für dich arbeiten!

von Karl H. (kbuchegg)


Lesenswert?

>   USART_Transmit_uint16(&temp);

Bist du dir da ganz sicher, dass du hier eine Adresse übergeben musst?
Ungewöhnlich, da es an dieser Stelle nichts bringt einen Pointer auf 
einen uint16_t zu übergeben. Da ein Pointer sicher nicht kleiner sein 
wird, als ein uint16_t, verkompliziert das nur die Funktion, weil sie 
über einen Pointer auf den Wert zugreifen muss. Das bringt also weder 
geschwindigkeitsmässig etwas, noch ist es notwendig.

von Manfred Schreier (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Anstelle von ...void ETE_start(void){
> // set the counter value to 0
>   TCNT1L = 0; // set the low part to 0
>   TCNT1H = 0;  // set the high part to 0
>
> ...
>
> void ETE_stop(void){
>   uint16_t temp=0;  //auxiliary variable
> // combine TCNT1L and TCNT1H
>   temp=TCNT1L; //save the lower part
>   temp|=(TCNT1H<<8); // save the higher part to the right place
> ...
>
> ... dann eben
> void ETE_start(void){
> // set the counter value to 0
>   TCNT1 = 0;
>
> ...
>
> void ETE_stop(void){
>   uint16_t temp = TCNT1;
> ...

Danke für die antwort

--> war es aber nicht

von Krapao (Gast)


Lesenswert?

> Leider hab ich festgestellt (mit den USART Ausgaben) das TCNT nicht auf
> 0 gesetzt wird, warum ?

Es kann überhaupt nur in diesen Ausgaben aus ETE_start() festgestellt 
werden:

>  USART_Transmit(TCNT1L);
>  USART_Transmit(TCNT1H);

wenn Timer1 nicht läuft, d.h. wenn z.B. zuvor ETE_stop() gelaufen ist 
und damit der Timertakt abgeschaltet wurde.

Wenn im sonstigen nicht gezeigten Programm der Timertakt angeschaltet 
wurde oder ein anderer Timertakt als CS11 abgeschaltet wurde, ist eine 
Ausgabe von TCNT1 = 0 in ETE_start() Zufall.

In ETE_stop() mit

>   USART_Transmit_uint16(&temp);

ist es Zufall, wenn eine 0 für die Kopie des TCNT1 übermittelt wird.

>   TCCR1B&=~(1<<CS11);

Am Ende von ETE_stop halte ich für eine logischen Unschönheit. Ich würde 
diese Anweisung am Anfang der Funktion machen, um den Timerzähler vor 
der Kopie an temp einzufrieren.

Insgesamt würde ich mehr Debugausgaben einbauen, um zu sehen welche 
Funktion am Ausgeben ist und in welcher Reihenfolge die Funktionen 
aufgerufen werden. Den restlichen Quellcode würde ich auf Einstellungen 
des Timertakts scannen.

von Karl H. (kbuchegg)


Lesenswert?

Manfred Schreier schrieb:

> Danke für die antwort
>
> --> war es aber nicht


Was ist mit der USART_Transmit_uint16 Sache?
Nur weil der Compiler das compiliert (und eine Warnung bringt) heißt das 
nicht, dass es korrekt ist!
Kein vernünftiger Programmierer würde diese Funktion die Signatur

void USART_Transmit_uint16( uint16_t * value )

verpassen.

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.