Forum: Mikrocontroller und Digitale Elektronik Frage zu delay (mit SysTick) für den STM32f4


von jogl (Gast)


Lesenswert?

Guten Tag,

ich habe eine delay Funktion mit dem SysTick von folgender Homepage.
http://patrickleyman.be/blog/stm32f407-delay-with-systick/

Damit habe ich folgendes Programm geschrieben:
1
uint32_t counter=0;
2
3
void init_LED(){
4
  //Anschalten der Taktversorgung für Port D
5
  RCC->AHB1ENR |= (1<<3);
6
  
7
  //Konfigurationsregister für den I/O-Port
8
  GPIOD->MODER |= (1<<24);
9
  GPIOD->MODER |= (1<<26);
10
}
11
12
void delay(int time){
13
  
14
  while(counter!=time){
15
  }
16
  
17
  counter=0;
18
}
19
20
void SysTick_Handler(void){
21
  counter++;
22
}
23
24
int main ()
25
{
26
  //Configure SysTick to generate an interrupt every millisecond 
27
  SysTick_Config(SystemCoreClock/1000);
28
  
29
  init_LED();
30
31
  do
32
  {
33
    GPIOD->BSRRL |= (1<<12);
34
    delay(6000);
35
    GPIOD->BSRRH |= (1<<12);
36
    delay(3000);
37
    
38
  }
39
  while (1);
40
}

Diese Funktion habe ich in zwei verschiedene Projekt eingebunden. In 
einem funktioniert sie und in der anderen ist die Wartezeit deutlich 
länger.

Das wird wohl an den Einstellungen für die SystemCoreClock liegen? Auf 
welchen Wert muss ich diese dann einstellen?

von Haas (Gast)


Lesenswert?

Du musst die Variable SystemCoreClock einfach auf den Wert stellen den 
dein Mikrocontroller als Takt hat.

Durch die Funktion:

SysTick_Config(SystemCoreClock/1000);

wird dann sichergestellt, dass der Systick 1ms ist.

Wird jetzt für SystemCoreClock ein andere Wert eingesetzt ist Systick 
nicht mehr 1ms. Deshalb funktioniert das ganze unterschiedlich in deinen 
zwei Projekten.

von aSma>> (Gast)


Lesenswert?

Servus,
deklariere den counter mit volatile davor.

mfg

von W.S. (Gast)


Lesenswert?

jogl schrieb:
> Damit habe ich folgendes Programm geschrieben:

Und ich sage dir: Es ist Murks.

Warum?
Weil zwei voneinande unabhängige Instanzen schreibend auf die gleiche 
Variable zugreifen. Darum.

Abgesehen davon kann dein ganzer µC während der Wartezeiten rein garnix 
Vernünftiges anderes machen, sondern trampelt die ganze Zeit stupide auf 
der Stelle.

Mein Rat: Arbeite mit Events. Hättest du zuvor dir die mittlerweile 
steinalte Lernbetty heruntergeladen und dort geschaut, wie man eine 
Systemuhr programmiert und wie man Verzögerungen (delayed events) 
benutzt, dann hättest du gewiß ein besseres Programm geschrieben.

W.S.

von Jim M. (turboj)


Lesenswert?

Ich sags nur ungern, aber sobald der Optimizer an ist wird aus dem 
delay() eine Endlosschleife. Die Variable ist nicth "volatile" 
deklariert.

W.S. schrieb:
> Weil zwei voneinande unabhängige Instanzen schreibend auf die gleiche
> Variable zugreifen. Darum.

In dem Falle Wurst. Das Schreiben in delay() ist atomar.

Sein größeres Problem ist die flasche Reihenfolge von "schreiben" und 
Warten im delay(). Deshalb hat er auch vom sonstigen Programmfluss 
abhängige Ergebnisse, da die Wartezeit vom letzten delay aus zählt. 
Spaß gibt es insbesondere wenn counter > time ist.

von jogl (Gast)


Lesenswert?

Danke für eure Hinweise. So wie ich das nun auffasse ist es mit dem 
volatile vor der Variable nicht getan und einen anderen Ansatz habe ich 
gerade nicht.

Hätte jemand bitte eine "saubere" Lösungsvariante für mich?

von holger (Gast)


Lesenswert?

Versuch das mal so:
1
volatile uint32_t counter=0;
2
3
void delay(uint_32t time){
4
  
5
  counter = time;
6
7
  while(counter){  }
8
}
9
10
void SysTick_Handler(void){
11
  if(counter) counter--;
12
}

von aSma>> (Gast)


Lesenswert?

Ja, oder irgendwie sowas in der Art:
1
uint32_t counter_ms;
2
3
void SysTick_Handler(void){
4
  counter_ms++;
5
}
6
7
void delay_ms(uint32_t ntime_ms){
8
  uint32_t cur_time_ms = counter_ms;
9
  while(counter_ms-cur_time_ms < ntime_ms)
10
    ;
11
}

Achtung nach ca. 50 Tagen hat man einen Überlauf vom counter_ms.

von Jens (Gast)


Lesenswert?

aSma>> schrieb:
> Achtung nach ca. 50 Tagen hat man einen Überlauf vom counter_ms.

History repeats itself:
http://www.cnet.com/news/windows-may-crash-after-49-7-days/

von W.S. (Gast)


Lesenswert?

jogl schrieb:
> Hätte jemand bitte eine "saubere" Lösungsvariante für mich?

Kannst du lesen? Insbesondere meinen obigen Beitrag?

W.S.

von wikinger (Gast)


Lesenswert?

holger schrieb:
> Versuch das mal so:

Ich habe in einem anderen Beitrag folgenden Code von dir gefunden:
1
/**
2
  ******************************************************************************
3
  * @file    main.c
4
  */ 
5
6
/* Includes ------------------------------------------------------------------*/
7
#include <stdint.h>
8
9
#include "misc.h"
10
#include "stm32f4xx.h"
11
#include "stm32f4xx_gpio.h"
12
#include "stm32f4xx_rcc.h"
13
#include "stm32f4xx_tim.h"
14
15
#include "leds.h"
16
17
void Delay1ms(uint32_t nCount);
18
volatile uint32_t delay1ms;
19
20
/**
21
  * @brief  Main program
22
  */
23
int main(void)
24
{
25
  // Discovery Board LEDs
26
  LEDs_Init();
27
  SysTick_Config(SystemCoreClock/1000);
28
29
  while (1)
30
  {
31
    LED_ORANGE_ON;
32
    Delay1ms(100);
33
    LED_ORANGE_OFF;
34
    Delay1ms(300);
35
  }
36
}
37
38
/**
39
  * @brief  This function handles SysTick Handler.
40
  * @param  None
41
  * @retval None
42
  */
43
void SysTick_Handler(void)
44
{
45
 if(delay1ms) delay1ms--;
46
}
47
48
/**
49
  * @brief  Delay Function.
50
  * @param  nCount:specifies the Delay time length.
51
  * @retval None
52
  */
53
void Delay1ms(uint32_t nCount)
54
{
55
  delay1ms = nCount;
56
  while(delay1ms);
57
}

Was ich hierbei noch nicht verstehe ist, was du mit dieser Funktion 
machst:
SysTick_Config(SystemCoreClock/1000);

Welchen Wert hat mein SystemCoreClock? Ich gehe mal davon aus, dass sind 
die 168MHz beim STM32F4. Wie kommt man dann aber darauf, dass er jede 
Millisekunde in den Systick_Handler geht?

von Haas (Gast)


Lesenswert?

Der SysTickTimer funktioniert wie ein Upcounter (Hochzähler).

Er läuft bei den STM32 mit Systemtakt und zählt bis zu einem vom User 
vorgegebenen Wert. Dieser Wert kann unter anderem über die Funktion: 
SysTick_Config(SystemCoreClock/1000); eingestellt werden (oder z.B. 
direkt über Register).

Wenn ich die 168 MHz (SystemCoreClock) durch 1000 teile, bekomme ich 
168000 heraus. Es wird also bis zu diesem Wert gezählt und dann ein 
Interrupt ausgelöst. Um die 168000 Ereignisse mit einem Takt von 168 MHz 
zu zählen benötigt der Mikrocontroller:

168000 / 168 MHz = 1 ms

Gruß

von lolo (Gast)


Lesenswert?

Jim M. schrieb:
> Ich sags nur ungern, aber sobald der Optimizer an ist wird aus dem
> delay() eine Endlosschleife. Die Variable ist nicth "volatile"
> deklariert.

Wieso muss man die Variable hier als volatile deklarieren?

Ich kenne die Definition von volatile: Solch eine Variable kann ihren 
Wert ständig ändern.

Aber kann dies auch nicht eine normale Variable? Und warum benötigt man 
dies hier überhaupt?

von W.S. (Gast)


Lesenswert?

lolo schrieb:
> Wieso muss man die Variable hier als volatile deklarieren?

Dieses Attribut "volatile" weist den Compiler darauf hin, daß die damit 
bezeichnete Variable auch von einer anderen Instanz als der Funktion, 
die er grad am Übersetzen ist, verändert werden kann und er deshalb 
diese Variable für jede Verwendung neu laden muß und sie nicht 
wegoptimieren darf. Klaro?

Aber das Lesen bzw. Zuhören scheint den hier aufschlagenden 
Hilfesuchenden nicht in die Wiege gelegt zu sein. Begreift mal das 
Prinzip des Arbeitens mit Events und verzögerten Events. Man muß in main 
nicht wirklich auf dem SysTick direkt herumtrampeln, sowas macht man mit 
einer programminternen Uhr, die auf dem Systick beruht, selbigen aber so 
gut es geht kapselt und einem entsprechende Events generiert.

W.S.

von Lernbetty (Gast)


Lesenswert?

>ie auf dem Systick beruht, selbigen aber so
>ut es geht kapselt und einem entsprechende Events generiert.

Halt so, wie bei der Lernbetty

von lolo (Gast)


Lesenswert?

W.S. schrieb:
> Dieses Attribut "volatile" weist den Compiler darauf hin, daß die damit
> bezeichnete Variable auch von einer anderen Instanz als der Funktion,
> die er grad am Übersetzen ist, verändert werden kann und er deshalb
> diese Variable für jede Verwendung neu laden muß und sie nicht
> wegoptimieren darf. Klaro?

Und diese andere Instanz ist das Interrupt?

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.