Forum: Mikrocontroller und Digitale Elektronik STM32 Frequenz erzeugen, Fehler im Programm


von Skha (Gast)


Lesenswert?

Hallo, ich habe auf einem STM32F107VC ein Programm geschrieben um 
Protokolle auszugeben. Die Protokolle lassen sie bei einer von au?en 
angelegten Frequenz an einem GPIO über einen weiten Frequenzbereich 
ausgeben. Ich möchte diese Protokolle nun allerdings auch über einen 
internen Frequenzgenerator ausgeben lassen. Dummerweise kommt es dabei 
zu Fehlern. Vielleicht kann mir einer helfen.
Fehlerbeschreibung:
- Ausgabe funktioniert, auch mit Überläuften gut, bis zu einer Frequenz 
von ca. 1/1200µs. (Höhere Frequenzen sind auch kein Problem)
- Wird die Frequenz niedriger gewählt, wird die Protokollausgabe doppelt 
aufgerufen und zwar direckt nach der letzten Ausgabe. Bei weiterer 
gringer Frequenzerhöhung vervierfacht sich die Protokollanzahl auf ihr 
Maximum.
-Wird die Frequenz weiter heruntergesetzt kommt es nicht zu einer 
weiteren Erhöhung der Protokollanzahl, aber die Protokolle sind gestört 
(zeitliche Sprünge bei gewissen Frequenzen)


Die Idee ist, dass ich eine Frequenz in Form von einer 32-Bit Variablen 
einlese, die Überläufe in die Timererweiterung schreibe (alles was 
größer als 16 Bit ist)und diese Erweiterungen abarbeite. Sind alle 
Erweiterungen abgearbeitet wird der übrig bleibende 16-Bit Wert als 
neuer Startwert des Protokolls vorgegeben. Dieser Wert wird von einer 
anderen Funktion genutzt um das Protokoll auszugeben. Die Funktionen 
arbeiten alle ordnungsgemäs wenn man sie durch externe Interrupts 
aufruft. Der Fehler muss also in der Frequenzvorgabe liegen. Am Ende der 
Frequenzvorgabe wird noch der CaptureCompare Wert auf den neuen 
Startwert gelegt und das Spiel geht von vorn los.




1
    if(Simulation == SET)
2
    {
3
      //Auf ersten Durchlauf vorbereiten
4
      if(Flag_Erstdurchlauf_fertig == RESET)
5
      {
6
        //n_Zaehler_Protokolldaten = Protokolllaenge;
7
        Flag_Erstdurchlauf_fertig = SET;
8
        n_Tim4_Erweiterung_CC1 = 0;
9
        TIM_SetCompare1(TIM4, n_Timer4_Ausgabe_Startwert_pos);  //setze comparewert 1 auf gerade ermittelten Ausgabestartwert
10
      }
11
12
      //Frequenzvorgabe neu laden
13
      if(Test_Verriegelung == RESET    ) //erst wenn neuer Startimpuls freigegeben wurde und damit neuer Startwert festliegt
14
      {
15
        n_Tim4_Erweiterung_CC1 = n_Frequenzvorgabe >> 16;  //Timererweiterung für CC1 "Überläufe"
16
         Test_Verriegelung = SET;              //sperrt sich selbst bis neue Startimpulsauslösung stattgefunden hat
17
        n_Timer4_Ausgabe_Startwert_pos = (_Timer4_Ausgabe_Startwert_pos + n_Frequenzvorgabe); //Übergabe des Startwertes für Auslösung des neuen Protokollstarts
18
      }
19
20
      //32 Bit Erweiterung
21
      if(TIM_GetFlagStatus(TIM4, TIM_FLAG_CC1) == SET   &&     //Wenn Timer einmal durchgezählt hat (von CC1 bis CC1) "Überläufe"
22
         n_Tim4_Erweiterung_CC1 > 0             &&     //Wenn noch nicht alle "Überläufe" durchgeführt
23
         Test_Verriegelung == SET              )    //Aufruf erst wenn neue Frequenz vorgegeben wurde (if darüber)
24
      {
25
        n_Tim4_Erweiterung_CC1 --;
26
        TIM_ClearFlag(TIM4, TIM_FLAG_CC1);
27
28
      }
29
30
      //Freigabe für neues Protokoll (Pause abgeschlossen)
31
      if(n_Tim4_Erweiterung_CC1 == 0             &&  //Timererweiterung muss abgeschlossen sein
32
         n_Zaehler_Protokolldaten > (Protokolllaenge - 1) &&  //Protokoll muss vollständig durchsucht worden sein
33
         Flag_pos_Flanke_ausgegeben == SET         &&   //letzte Flankenausgabe muss abgeschlossen sein bevor neuer Starimpuls vorgegeben wird
34
         Flag_neg_Flanke_ausgegeben == SET )
35
36
      {
37
                ADC1_Konv_Wert = 5000;                  //Vorgabe eines Startimpulses (notwendig weil vorhandene Funktionen nur auf diesen Reagieren));
38
                Merker_High_Flanke = SET;                //Freigabe zur Auswertung des neuen Protokollstarts
39
        TIM_SetCompare1(TIM4, n_Timer4_Ausgabe_Startwert_pos);  //setze comparewert 1 auf gerade ermittelten Ausgabestartwert
40
        Interruptflag
41
        Test_Verriegelung = RESET;                //Freigabe: neue Frequenz darf vorgegeben werden (2. if-Bedingung)
42
        n_Tim4_Erweiterung_CC1 --;                //Nach Startwertübergabe weiter runter zaehlen um if-Bedingung ungültig zu machen.
43
44
45
      }



"Flag_pos_Flanke_ausgegeben" und Flag_neg_Flanke_ausgegeben" teilen mit 
dass das Protokoll vollständig ausgegeben wurde


"ADC1_Konv_Wert = 5000"  Gibt an dass eine Highflanke detektiert wurde, 
da das Programm bei externen Flanken die Pegel noch einmal auf ihre Höhe 
untersucht

"Merker_High_Flanke" lässt den Start einer Funktion zu, die den Wert 
"n_Timer4_Ausgabe_Startwert_pos" an ihre Entgültige Variable weiter 
gibt, die dann als Comparereferenz für die Ausgabe des Protokols dient.


Das ganze Programm läuft also im Polling-Verfahren, lediglich die 
Ausgabe des Protokols wird durch einen Interrupt aufgerufen. Tests haben 
gezeigt dass das es keine Zeitkritischen Momente gibt.

Weiterhin habe ich festgestellt, dass auch der Überlaufzähler im bereich 
der fehlerfreien Frequenzen bereits eingesetzt hat und arbeitet. Die 
letzte If-Bedingung löst jedoch im Fehlerfall zu oft aus und die If 
Bedingung des Überlaufzählers wird unregelmäsiger aufgerufen.

Die Protokollabstände die sich bei in dem von mir als fehlerfrei 
angegebenen Bereich einstellen stimmen mit den vorgegebenen Werten 
überein. Somit ist dieser Bereich wirklich der gewünschte und nicht etwa 
umgedreht.

Die Timer arbeiten mit 72 MHz. Ich hoffe ich habe jetzt nichts 
vergessen.


Gruß

von Schnurf (Gast)


Lesenswert?

Hallo,

Kannst Du uns bitte Dein Verständnis des Begriffs "Protokoll"
mitteilen?

Danke!

Schnurf

von Skha (Gast)


Lesenswert?

Manchaster Codierte Bitfolgen. Ich breche das ganze gerade auf eine 
Minimalfunktion herunger die einfach nur einen Bitwechsel zu bestimmten 
Zeitpunkten auslöst. Vielleicht finde ich doch noch etwas oder kann man 
ein ausführbares Projekt hier einfügen.

von Skha (Gast)


Lesenswert?

Die Main auf das minimale beschränkt sieht nun wie folgt aus. Ich gebe 
nur noch Flankenwechsel aus und nutze nur die IOs.
1
/* Includes ------------------------------------------------------------------*/
2
#include "stm32f10x.h"
3
4
5
/* Private function prototypes -----------------------------------------------*/
6
void RCC_Configuration(void);
7
void TIM_Configuration(void);    //Einstellung der Timer + Systick
8
void GPIO_Configuration(void);    //GPIO Pins definieren und aktivieren
9
10
11
12
  FlagStatus Merker_High_Flanke        = 0;      //Merker für Hauptprogramm, dass gerade eine High_Flanke erkannt wurde
13
14
15
  __IO uint32_t n_Anz_OF_T4_LF           = 0;
16
  __IO uint32_t n_Frequenzvorgabe        = 0;
17
  __IO uint32_t n_Tim4_Erweiterung_CC1   = 0;
18
  __IO uint32_t n_Anz_OF_T4              = 0;
19
20
21
  __IO uint16_t Bit32_MSB_Zaehler                = 0;
22
  __IO uint16_t n_Timer4_Ausgabe_Startwert_pos   = 0;    //Speichert Startzeitpunkt der Flanke 
23
  __IO uint16_t zaehler                          = 0;
24
25
26
  __IO FlagStatus Freq_High            = RESET;
27
  __IO FlagStatus Freq_Low             = RESET;
28
  __IO FlagStatus Freq_High_fast       = RESET;
29
  __IO FlagStatus Freq_Low_fast        = RESET;
30
  __IO FlagStatus Test_Verriegelung    = RESET;
31
32
33
34
  int main(void)
35
  {
36
   //Konfigurationen
37
    RCC_Configuration();
38
    GPIO_Configuration();
39
    TIM_Configuration();
40
41
   //Freigaben
42
    // Freigabe der Timer
43
    TIM_Cmd(TIM2, ENABLE);
44
    TIM_Cmd(TIM4, ENABLE);
45
46
47
    n_Frequenzvorgabe = 50000;
48
49
50
  while (1)
51
  {
52
53
54
//######################################################################################################
55
//######################## Frequenzeinstellungen #######################################################
56
57
    zaehler ++;
58
59
    if(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_11) == RESET && Freq_High == RESET)
60
    {
61
      n_Frequenzvorgabe = n_Frequenzvorgabe + 50;
62
      Freq_High = SET;
63
      zaehler = 0;
64
    }
65
66
    if(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_13) == RESET && Freq_Low == RESET )
67
    {
68
      n_Frequenzvorgabe = n_Frequenzvorgabe - 50;
69
      Freq_Low = SET;
70
      zaehler = 0;
71
    }
72
73
    if(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_14) == RESET && Freq_High_fast == RESET )
74
    {
75
      n_Frequenzvorgabe = n_Frequenzvorgabe + 1000;
76
      Freq_High_fast = SET;
77
      zaehler = 0;
78
    }
79
80
    if(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_12) == RESET && Freq_Low_fast == RESET )
81
    {
82
      n_Frequenzvorgabe = n_Frequenzvorgabe - 1000;
83
      Freq_Low_fast = SET;
84
      zaehler = 0;
85
    }
86
87
88
    if(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_11) == SET && zaehler > 20)
89
    {Freq_High = RESET;}
90
91
    if(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_13) == SET && zaehler > 20)
92
    {Freq_Low = RESET;}
93
94
    if(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_14) == SET && zaehler > 20)
95
    {Freq_High_fast = RESET;}
96
97
    if(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_12) == SET && zaehler > 20)
98
    {Freq_Low_fast = RESET;}
99
100
101
102
103
//######################################################################################################
104
//######################## Frequenzumsetzung  #######################################################
105
106
107
108
      //Frequenzvorgabe neu laden
109
      if(  Test_Verriegelung == RESET  )          //erst wenn neuer Impuls freigegeben wurde und damit neuer Startwert festliegt
110
      {
111
        n_Tim4_Erweiterung_CC1 = n_Frequenzvorgabe >> 16;  //Timererweiterung für CC1 "Überläufe"
112
        Test_Verriegelung = SET;              //sperrt sich selbst bis neue Startimpulsauslösung stattgefunden hat
113
        n_Timer4_Ausgabe_Startwert_pos = (n_Timer4_Ausgabe_Startwert_pos + n_Frequenzvorgabe); //Übergabe des Startwertes für Flankenauslösung 
114
      }
115
116
      //32 Bit Erweiterung
117
      if(TIM_GetFlagStatus(TIM4, TIM_FLAG_CC1) == SET   &&     //Wenn Timer einmal durchgezählt hat (von CC1 bis CC1) "Überläufe"
118
         n_Tim4_Erweiterung_CC1 > 0             &&     //Wenn noch nicht alle "Überläufe" durchgeführt
119
         Test_Verriegelung == SET              )    //Aufruf erst wenn neue Frequenz vorgegeben wurde (if darüber)
120
      {
121
        TIM_ClearFlag(TIM4, TIM_FLAG_CC1);
122
        n_Tim4_Erweiterung_CC1 --;
123
124
      }
125
126
      //Freigabe für neues Protokoll (Pause abgeschlossen)
127
      if(n_Tim4_Erweiterung_CC1 == 0   &&  GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_15) == SET)  //Testknopf eingefügt um Ausgabe zu unterbrechen
128
      {
129
        TIM_ClearFlag(TIM4, TIM_FLAG_CC1);            //reset Interruptflag
130
        Merker_High_Flanke = SET;                //Freigabe zur Auswertung des neuen Protokollstarts
131
        TIM_SetCompare1(TIM4, n_Timer4_Ausgabe_Startwert_pos);  //setze comparewert 1 auf gerade ermittelten Ausgabestartwert
132
        Test_Verriegelung = RESET;                //Freigabe: neue Frequenz darf vorgegeben werden (2. if-Bedingung)
133
        n_Tim4_Erweiterung_CC1 --;                //Nach Startwertübergabe weiter runter zaehlen um if-Bedingung ungültig zu machen.
134
      }
135
136
137
      //######################################################################################################
138
      //######################## Ausgabe der Flanken #######################################################
139
140
141
        if(Merker_High_Flanke == SET)
142
        {
143
144
          TIM_SetCompare2(TIM4, n_Timer4_Ausgabe_Startwert_pos);  //setze comparewert 1 auf gerade ermittelten Ausgabestartwert
145
146
          while(TIM_GetFlagStatus(TIM4, TIM_FLAG_CC2) == RESET);
147
          TIM_ClearFlag(TIM4, TIM_FLAG_CC2);
148
149
150
          ///Bitwechsel nach jedem Durchlauf
151
          if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == RESET)
152
          {
153
            GPIO_WriteBit(GPIOB, GPIO_Pin_1, Bit_SET);
154
          }
155
          else
156
          {
157
            GPIO_WriteBit(GPIOB, GPIO_Pin_1, Bit_RESET);
158
          }
159
160
161
          Merker_High_Flanke = RESET;
162
        }
163
      }
164
  }

von Skha (Gast)


Lesenswert?

Hm ok einer der Fehler liegt darin dass ich den Überlauf um eins höher 
zählen muss als er wirklich ist, da ich sonst keine volle 2^16 Bit Runde 
im Timer bekomme....

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.