Forum: Mikrocontroller und Digitale Elektronik Frequenz messen (260 Hz)


von Horst (Gast)


Lesenswert?

Hallo zusammen,

ich möchte mit einem PIC12, den ich bei 1 Mhz laufen lasse ein 
Taktsignal ausmessen. Irgendwie schwankt mein Ergebnis aber gravierend, 
daher an euch die Frage, ob ihr wisst, woran das liegen kann.
Mein Signal hat eine Frequenz von ca. 264 Hz (Tsignal = 3,78 ms).
Ich messe, indem ich einen 16 bit Timer mit Ttimer = 7,99 µs pro 
Inkrement starte, mit

for(i=0; i<16; i++)
{
while(RA5);
while(!RA5);
}

16 Durchläufe abwarte, und dann meinen Timer auslese (inklusive 
eventuellen Overflows).

Nach den 16 Durchläufen sollte ich nun doch eigentlich einen Wert von 
ca. 7570 aus dem Timer lesen (16 * Tsignal / Ttimer), tatsächlich 
bekomme ich aber nur etwa die Hälfte und das Ergebnis schwankt obendrein 
wie gesagt gravierend. Was meint ihr dazu?

von Fuerst-Rene (Gast)


Lesenswert?

264 HZ kannst du mit Kopfhörern oder kleinem Lautspr. noch hören ohne 
verstärker. Damit weist du obs schwankt.
Gibts bei dem Proz auch ein ANSELA Register?
Der macht bei nichtabfrage einen Analogen Eingang draus.

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Horst schrieb:
> bekomme ich aber nur etwa die Hälfte und das Ergebnis schwankt obendrein
> wie gesagt gravierend. Was meint ihr dazu?

Wie sehr schwankt denn dein Ergebnis? Wenn es weniger als 1/16 der 
Frequenz ist, kann das daran liegen, dass du vor den Beginn deiner 
Mess-Schleife ein
1
while(RA5); while(!RA5);
setzen solltest, um einen definierten Startzeitpunkt für deine Messung 
zu erhalten.

von Krapao (Gast)


Lesenswert?

Es kann passieren, dass du irgendwo in die erste Periode einsteigst und 
dadurch zu knapp misst. Der Fehler davon ist worst-case (Signal bei 
Beginn der for-Schleife im letzten Zucken der Low-Halbperiode) 1/16-tel 
deiner Messfrequenz, also rund 16 Hz.

Bei dem halben Timerwert würde ich als erstes meine Initialisierung des 
Timers überprüfen, ob die angenommenen 7,99 µs auch stimmen.

von Horst (Gast)


Lesenswert?

Fuerst-Rene schrieb:
> 264 HZ kannst du mit Kopfhörern oder kleinem Lautspr. noch hören ohne
> verstärker. Damit weist du obs schwankt.
Nicht nötig, habe es mit Oszi überprüft :)

Fuerst-Rene schrieb:
> Gibts bei dem Proz auch ein ANSELA Register?
> Der macht bei nichtabfrage einen Analogen Eingang draus.
Ein ANSELA Register gibt es, aber es ist alles auf 0 für I/O gesetzt.

Markus W. schrieb:
> Wie sehr schwankt denn dein Ergebnis? Wenn es weniger als 1/16 der
> Frequenz ist, kann das daran liegen, dass du vor den Beginn deiner
> Mess-Schleife ein
while(RA5); while(!RA5);
>setzen solltest, um einen definierten Startzeitpunkt für deine Messung
> zu erhalten.
Das Ergebnis schwankt zwischen 2700-4000 und sogar darüber hinaus. An 
den Startzeitpunkt habe ich auch gedacht und es genau so gemacht, wie du 
beschrieben hast. Habe ich vergessen zu erwähnen.

Krapao schrieb:
> Bei dem halben Timerwert würde ich als erstes meine Initialisierung des
> Timers überprüfen, ob die angenommenen 7,99 µs auch stimmen.
Den Timer habe ich auch mit Oszi geprüft.

Vielen Dank für die Tips, leider klappt es immer noch nicht. Habt ihr 
noch eine Idee?

von Krapao (Gast)


Lesenswert?

Sorry, mehr fällt mir zu dem gezeigten Code nicht ein.

von Michael R. (mexman) Benutzerseite


Lesenswert?

Hallo,

zeig doch mal den Assemblercode!


Gruss

Michael

von Horst (Gast)


Lesenswert?

Michael Roek schrieb:
> zeig doch mal den Assemblercode!
Von Assembler habe ich leider keine Ahnung und weiß nicht genau was du 
brauchst. Ich habe das projekt nun extra nochmal neu angelegt, nur mit 
den relevanten Funktionen. Unten ist nun der Assembler Code dazu. Ich 
habe nicht alles kopiert, was der Compiler ausgespuckt hat, ich hoffe 
die relevanten Sachen sind dabei. Wenn nicht, sag Bescheid, dann schicke 
ich nochmal alles...

Vorher nochmal Zusatzinfos: Ich habe es gerade mal anders herum 
ausprobiert: in einem gesamten Timer Durchlauf (ca. 520 ms) die I/O 
steps (ca. 3,7 ms) gezählt. Also
1
while(1)
2
{
3
while(RA5);
4
while(!RA5);
5
i++;
6
}
Dann in der ISR des Timers i abgefragt, und komischerweise liegt i statt 
der erwarteten 140 ca. bei 280, aber auch stark schwankend. Auffallend 
fand ich den Faktor 2 der in beiden Fällen Probleme macht.

Hier jetzt der Assembler code:
1
1:                 #include"globals.h"
2
2:                   
3
3:                 
4
4:                 void Get_Speed(void)
5
5:                 {  
6
6:                   unsigned int time;
7
7:                   unsigned int overflow;
8
8:                   unsigned char i;
9
9:                   
10
10:                  while(RA5);
11
   789    2F8A     GOTO 0x78a
12
   78A    0020     MOVLB 0
13
   78B    1A8C     BTFSC 0xc, 0x5
14
   78C    2F8E     GOTO 0x78e
15
   78D    2F8F     GOTO 0x78f
16
   78E    2F8A     GOTO 0x78a
17
   78F    2F91     GOTO 0x791
18
11:                  while(!RA5);          //wait for toggle to high
19
   790    2F91     GOTO 0x791
20
   791    1E8C     BTFSS 0xc, 0x5
21
   792    2F94     GOTO 0x794
22
   793    2F95     GOTO 0x795
23
   794    2F91     GOTO 0x791
24
   795    2F96     GOTO 0x796
25
12:                  time = (TMR1H << 8) + TMR1L;  //Timer1 start time
26
   796    0816     MOVF 0x16, W
27
   797    00F6     MOVWF 0x76
28
   798    01F7     CLRF 0x77
29
   799    0817     MOVF 0x17, W
30
   79A    00F8     MOVWF 0x78
31
   79B    01F9     CLRF 0x79
32
   79C    0878     MOVF 0x78, W
33
   79D    00F9     MOVWF 0x79
34
   79E    01F8     CLRF 0x78
35
   79F    0876     MOVF 0x76, W
36
   7A0    0778     ADDWF 0x78, W
37
   7A1    00A2     MOVWF 0x22
38
   7A2    0877     MOVF 0x77, W
39
   7A3    3D79     ADDWFC 0x79, W
40
   7A4    00A3     MOVWF 0x23
41
13:                  overflow = timer1_overflow;    //Timer1 start overflow
42
   7A5    0828     MOVF 0x28, W
43
   7A6    01A1     CLRF 0x21
44
   7A7    07A1     ADDWF 0x21, F
45
   7A8    0827     MOVF 0x27, W
46
   7A9    01A0     CLRF 0x20
47
   7AA    07A0     ADDWF 0x20, F
48
14:                  for(i=0;i<16;i++)        //16 changes = 2 rotations (8 pole pairs)
49
   7AB    01A4     CLRF 0x24
50
   7AC    3010     MOVLW 0x10
51
   7AD    0224     SUBWF 0x24, W
52
   7AE    1C03     BTFSS 0x3, 0
53
   7AF    2FB1     GOTO 0x7b1
54
   7B0    2FB2     GOTO 0x7b2
55
   7B1    2FB5     GOTO 0x7b5
56
   7B2    2FCB     GOTO 0x7cb
57
   7B3    2FCB     GOTO 0x7cb
58
   7C0    3001     MOVLW 0x1
59
   7C1    00F6     MOVWF 0x76
60
   7C2    0876     MOVF 0x76, W
61
   7C3    07A4     ADDWF 0x24, F
62
   7C4    3010     MOVLW 0x10
63
   7C5    0224     SUBWF 0x24, W
64
   7C6    1C03     BTFSS 0x3, 0
65
   7C7    2FC9     GOTO 0x7c9
66
   7C8    2FCA     GOTO 0x7ca
67
   7C9    2FB5     GOTO 0x7b5
68
   7CA    2FCB     GOTO 0x7cb
69
15:                  {
70
16:                    while(RA5);    
71
   7B4    2FB5     GOTO 0x7b5
72
   7B5    1A8C     BTFSC 0xc, 0x5
73
   7B6    2FB8     GOTO 0x7b8
74
   7B7    2FB9     GOTO 0x7b9
75
   7B8    2FB5     GOTO 0x7b5
76
   7B9    2FBB     GOTO 0x7bb
77
17:                    while(!RA5);  
78
   7BA    2FBB     GOTO 0x7bb
79
   7BB    1E8C     BTFSS 0xc, 0x5
80
   7BC    2FBE     GOTO 0x7be
81
   7BD    2FBF     GOTO 0x7bf
82
   7BE    2FBB     GOTO 0x7bb
83
   7BF    2FC0     GOTO 0x7c0
84
18:                  }  
85
19:                
86
20:                  time = (TMR1H << 8) + TMR1L + 0xFFFFFFFF - time + ((timer1_overflow - overflow) * 65535);  // * 0.0000079 for time in sec. 
87
   7CB    0922     COMF 0x22, W
88
   7CC    00F6     MOVWF 0x76
89
   7CD    0923     COMF 0x23, W
90
   7CE    00F7     MOVWF 0x77
91
   7CF    0AF6     INCF 0x76, F
92
   7D0    1903     BTFSC 0x3, 0x2
93
   7D1    0AF7     INCF 0x77, F
94
   7D2    0920     COMF 0x20, W
95
   7D3    00F8     MOVWF 0x78
96
   7D4    0921     COMF 0x21, W
97
   7D5    00F9     MOVWF 0x79
98
   7D6    0AF8     INCF 0x78, F
99
   7D7    1903     BTFSC 0x3, 0x2
100
   7D8    0AF9     INCF 0x79, F
101
   7D9    0827     MOVF 0x27, W
102
   7DA    0778     ADDWF 0x78, W
103
   7DB    00F0     MOVWF 0x70
104
   7DC    0828     MOVF 0x28, W
105
   7DD    3D79     ADDWFC 0x79, W
106
   7DE    00F1     MOVWF 0x71
107
   7DF    30FF     MOVLW 0xff
108
   7E0    00F2     MOVWF 0x72
109
   7E1    30FF     MOVLW 0xff
110
   7E2    00F3     MOVWF 0x73
111
   7E3    3187     MOVLP 0x7
112
   7E4    2765     CALL 0x765
113
   7E5    3187     MOVLP 0x7
114
   7E6    0870     MOVF 0x70, W
115
   7E7    0020     MOVLB 0
116
   7E8    0716     ADDWF 0x16, W
117
   7E9    00FA     MOVWF 0x7a
118
   7EA    0871     MOVF 0x71, W
119
   7EB    3D17     ADDWFC 0x17, W
120
   7EC    00FB     MOVWF 0x7b
121
   7ED    0876     MOVF 0x76, W
122
   7EE    077A     ADDWF 0x7a, W
123
   7EF    00FC     MOVWF 0x7c
124
   7F0    0877     MOVF 0x77, W
125
   7F1    3D7B     ADDWFC 0x7b, W
126
   7F2    00FD     MOVWF 0x7d
127
   7F3    087C     MOVF 0x7c, W
128
   7F4    3EFF     ADDLW 0xff
129
   7F5    00A2     MOVWF 0x22
130
   7F6    30FF     MOVLW 0xff
131
   7F7    3D7D     ADDWFC 0x7d, W
132
   7F8    00A3     MOVWF 0x23
133
21:                
134
22:                
135
23:                  new_max_speed = time;    //16 Steps, 8 pole pairs -> 7.5/time 
136
   7F9    0823     MOVF 0x23, W
137
   7FA    01A6     CLRF 0x26
138
   7FB    07A6     ADDWF 0x26, F
139
   7FC    0822     MOVF 0x22, W
140
   7FD    01A5     CLRF 0x25
141
   7FE    07A5     ADDWF 0x25, F
142
24:                }
143
   7FF    0008     RETURN
144
---  C:\Daten\gepr\forum\Init.c  -----------------------------------------------------------------
145
1:                 #include "globals.h"
146
2:                 
147
3:                 void Init(void)
148
4:                 {  
149
5:                   TRISA = 0b11101110;
150
   732    30EE     MOVLW 0xee
151
   733    0021     MOVLB 0x1
152
   734    008C     MOVWF 0xc
153
6:                   ANSELA = 0x00;
154
   735    0023     MOVLB 0x3
155
   736    018C     CLRF 0xc
156
7:                 
157
8:                   INTCONbits.PEIE = 1;        
158
   737    170B     BSF 0xb, 0x6
159
9:                   INTCONbits.GIE = 1;  
160
   738    178B     BSF 0xb, 0x7
161
10:                  
162
11:                  OSCCON = 0b01101000;    //bit7: PLL,  bit6-3: 4 MHz internal Clock,  bit2: not implemented, bit1-0 Dont care cause __CONFIG(INTOSC_ON);
163
   739    3068     MOVLW 0x68
164
   73A    0021     MOVLB 0x1
165
   73B    0099     MOVWF 0x19
166
12:                
167
13:                  timer1_overflow = 0;
168
   73C    0020     MOVLB 0
169
   73D    01A7     CLRF 0x27
170
   73E    01A8     CLRF 0x28
171
14:                  PIE1bits.TMR1IE = 1;      //Timer1 Overflow Enable
172
   73F    0021     MOVLB 0x1
173
   740    1411     BSF 0x11, 0
174
15:                  T1CON |= 0b00110000;      //Prescaler: 1:8
175
   741    3030     MOVLW 0x30
176
   742    00F0     MOVWF 0x70
177
   743    0870     MOVF 0x70, W
178
   744    0020     MOVLB 0
179
   745    0498     IORWF 0x18, F
180
16:                  TMR1H = 0;            //Set Timer1 value
181
   746    0197     CLRF 0x17
182
17:                  TMR1L = 0;            //Set Timer1 value
183
   747    0196     CLRF 0x16
184
18:                  T1CONbits.TMR1ON = 1;      //Timer1 start  
185
   748    1418     BSF 0x18, 0
186
19:                }
187
   749    0008     RETURN
188
189
:                 #include "globals.h"
190
2:                 
191
3:                 __CONFIG(FOSC_INTOSC & WDTE_OFF);
192
4:                 __CONFIG(LVP_OFF & BORV_25 & STVREN_ON & PLLEN_ON);          
193
5:                       
194
6:                 unsigned int timer1_overflow = 0;  
195
7:                 
196
8:                 void main(void)
197
9:                 {
198
10:                  Init();  
199
   74A    3187     MOVLP 0x7
200
   74B    2732     CALL 0x732
201
   74C    3187     MOVLP 0x7
202
   74D    2F4E     GOTO 0x74e
203
11:                  while(1)
204
   762    2F4E     GOTO 0x74e
205
12:                  {
206
13:                    Get_Speed();
207
   74E    3187     MOVLP 0x7
208
   74F    2789     CALL 0x789
209
   750    3187     MOVLP 0x7
210
14:                    if(new_max_speed > 4000)
211
   751    300F     MOVLW 0xf
212
   752    0020     MOVLB 0
213
   753    0226     SUBWF 0x26, W
214
   754    30A1     MOVLW 0xa1
215
   755    1903     BTFSC 0x3, 0x2
216
   756    0225     SUBWF 0x25, W
217
   757    1C03     BTFSS 0x3, 0
218
   758    2F5A     GOTO 0x75a
219
   759    2F5B     GOTO 0x75b
220
   75A    2F5E     GOTO 0x75e
221
15:                      LATA4 = 1;
222
   75B    0022     MOVLB 0x2
223
   75C    160C     BSF 0xc, 0x4
224
   75D    2F4E     GOTO 0x74e
225
16:                    else
226
17:                      LATA4 = 0;
227
   75E    0022     MOVLB 0x2
228
   75F    120C     BCF 0xc, 0x4
229
   760    2F4E     GOTO 0x74e
230
   761    2F4E     GOTO 0x74e
231
18:                
232
19:                  }        
233
20:                }
234
   763    3180     MOVLP 0

von Karl H. (kbuchegg)


Lesenswert?

Horst schrieb:
> Michael Roek schrieb:
>> zeig doch mal den Assemblercode!
> Von Assembler habe ich leider keine Ahnung und weiß nicht genau was du
> brauchst.

Das dürfte auch eine Fehlinformation gewesen sein. Da du in C 
programmierst, sollten wir erst mal das Naheliegenste kontrollieren: Du 
hast einen Fehler im C-Programm. Und dazu braucht man das C-Programm.
Und zwar nicht nur einen winzigen Ausschnitt, sondern komplett.

von Udo S. (urschmitt)


Lesenswert?

Sicher daß dein Signal ein sauberer Rechteck ist und keine Störungen 
(Peaks) enthält?

Signalquelle?
Schaltungsaufbau?

von Michael R. (mexman) Benutzerseite


Lesenswert?

Hallo Horst,

> 11:                  while(!RA5);          //wait for toggle to high
>    790    2F91     GOTO 0x791
>    791    1E8C     BTFSS 0xc, 0x5
>    792    2F94     GOTO 0x794
>    793    2F95     GOTO 0x795
>    794    2F91     GOTO 0x791
>    795    2F96     GOTO 0x796

ich habe ersty spaeter Zeit, mal in Ruhe  ueber die Initalisierung zu 
gehen, aber hier oben z.B: ist schon erkennbar, dass je nachdem zu 
welchem Zeitpunkt  Dein Eingangssignal den Zustand wechselt (vor Zeile 
791 oder danach) einige Codezeilen mehr oder weniger ausgefuehrt werden.
Dennoch duefte das bei der Takt- und der EIngangsfrequenz nicht so 
erheblich sein wie Du das beschreibst. Ich schaue spaeter nochmal 
rein....




@Karl-Heinz: Beim Assemblercode steht ka das C-Programm dabei

Gruss

Michael

von Horst (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Und dazu braucht man das C-Programm.
> Und zwar nicht nur einen winzigen Ausschnitt, sondern komplett.

Wird gemacht :)
1
#include "globals.h"
2
3
__CONFIG(FOSC_INTOSC & WDTE_OFF);
4
__CONFIG(LVP_OFF & BORV_25 & STVREN_ON & PLLEN_ON);          
5
unsigned int timer1_overflow = 0;  
6
7
void main(void)
8
{
9
  Init();  
10
  while(1)
11
  {
12
    Get_Speed();
13
    if(new_max_speed > 4000)
14
      LATA4 = 1;
15
    else
16
      LATA4 = 0;
17
  }        
18
}
19
20
///////////////////////////////////////INIT/////////////////////
21
#include "globals.h"
22
void Init(void)
23
{  
24
  TRISA = 0b11101110;
25
  ANSELA = 0x00;
26
27
  INTCONbits.PEIE = 1;        
28
  INTCONbits.GIE = 1;  
29
  
30
  OSCCON = 0b01101000;    
31
  timer1_overflow = 0;
32
  PIE1bits.TMR1IE = 1;      //Timer1 Overflow Enable
33
  T1CON |= 0b00110000;      //Prescaler: 1:8
34
  TMR1H = 0;          //Set Timer1 value
35
  TMR1L = 0;          //Set Timer1 value
36
  T1CONbits.TMR1ON = 1;      //Timer1 start  
37
}
38
39
/////////////////////////////GET_SPEED///////////////////
40
#include"globals.h"
41
void Get_Speed(void)
42
{  
43
  unsigned int time;
44
  unsigned int overflow;
45
  unsigned char i;
46
  
47
  while(RA5);
48
  while(!RA5);          //wait for toggle to high
49
  time = (TMR1H << 8) + TMR1L;  //Timer1 start time
50
  overflow = timer1_overflow;    //Timer1 start overflow
51
  for(i=0;i<16;i++)        //16 changes = 2 rotations (8 pole pairs)
52
  {
53
    while(RA5);    
54
    while(!RA5);  
55
  }  
56
57
  time = (TMR1H << 8) + TMR1L + 0xFFFFFFFF - time + ((timer1_overflow - overflow) * 65535);  
58
59
  new_max_speed = time;    //16 Steps, 8 pole pairs -> 7.5/time 
60
}
61
///////////////////////GLOBALS.H/////////////////////////////////
62
63
64
#include <htc.h>
65
#include "defines.h"
66
67
static void interrupt ISR(void);
68
void Init(void);
69
void Get_Speed(void);
70
71
unsigned int timer1_overflow;
72
73
unsigned int new_max_speed;

Udo Schmitt schrieb:
> Sicher daß dein Signal ein sauberer Rechteck ist und keine Störungen
> (Peaks) enthält?
>
> Signalquelle?
> Schaltungsaufbau?

von Michael R. (mexman) Benutzerseite


Lesenswert?

Hallo Horst,

Kannst Du das denn nicht erst mal im  Simulator laufen lassen und sehen 
was passiert?
Oder besser im Emulator?
Dort ein paar Breakpoints setzen und den Programmzaehler 
beobachten....Gruss

Michael

von Horst (Gast)


Lesenswert?

Udo Schmitt schrieb:
> Sicher daß dein Signal ein sauberer Rechteck ist und keine Störungen
> (Peaks) enthält?
>
> Signalquelle?
> Schaltungsaufbau?

Es ist leider kein sauberes Rechtecksignal, sondern was ganz eigenes. 
Die ansteigende Flanke "zittert" etwas. Und gerade habe ich mal einen 
I/O toggeln lassen mit jeder Flanke, die erkannt wird, und siehe da, die 
Hysterese von meinem Pin ist zu klein. Der schaltet bevor er endgültig 
High geht nochmal ganz kurz auf Low. Konnte ich erst sehen, als ich ganz 
nah herangezoomt habe. Damit dürfte das Problem wohl gegessen sein :)
Vielen vielen Dank an euch alle!

@ Michael Roek
Das ist natürlich auch interessant. Dann muss ich mal sehen, wie genau 
es am ende wird und abklären, wie genau ich es brauche. Wenn es zu 
ungenau ist, komme ich hier nochmal darauf zurück. Vorerst brauchst du 
dir also keine weitere Mühe machen.

Nochmal vielen Dank an alle!

von (prx) A. K. (prx)


Lesenswert?

Horst schrieb:

>   while(RA5);
>   while(!RA5);          //wait for toggle to high
>   time = (TMR1H << 8) + TMR1L;  //Timer1 start time

Zwischen den kritischen Zeilen nur auslesen und in Variablen speichern. 
Zusammenrechnen kannst du sie später.

von Horst (Gast)


Lesenswert?

Michael Roek schrieb:
> Kannst Du das denn nicht erst mal im  Simulator laufen lassen und sehen
> was passiert?

Das wäre wegen dem sehr eigentümlichen Eingangssignal nicht so sinnig 
gewesen. Habe ich vergessen gleich zu erwähnen, tut mir leid.

von Horst (Gast)


Lesenswert?

A. K. schrieb:
> Zwischen den kritischen Zeilen nur auslesen und in Variablen speichern.
> Zusammenrechnen kannst du sie später.

Danke für den Tipp, wird umprogrammiert :)

von Udo S. (urschmitt)


Lesenswert?

Horst schrieb:
> Es ist leider kein sauberes Rechtecksignal, sondern was ganz eigenes.
> Die ansteigende Flanke "zittert" etwas. Und gerade habe ich mal einen
> I/O toggeln lassen mit jeder Flanke, die erkannt wird, und siehe da, die
> Hysterese von meinem Pin ist zu klein. Der schaltet bevor er endgültig
> High geht nochmal ganz kurz auf Low. Konnte ich erst sehen, als ich ganz
> nah herangezoomt habe. Damit dürfte das Problem wohl gegessen sein :)
> Vielen vielen Dank an euch alle!

Schön, dann habe ich heute wenigstens einmal was nützliches gemacht.
Kann ich jetzt wenigstens mit einem guten Gefühl hier an meinem Sch... 
weitermachen :-)

von Krapao (Gast)


Lesenswert?

>   time = (TMR1H << 8) + TMR1L;  //Timer1 start time

Das ist auf dem PIC12 kein atomarer Zugriff. Siehe die Hinweisbox dazu 
im Datenblatt.

Um das sauber zu machen, darf während des Auslesens des 16-Bit Registers 
kein Timerinterrupt kommen. Also diesen lokal sperren! Das Verfahren von 
Horst vermindert die Chance, dass TMR1H und TMR1L asynchron gelesen 
werden, vorkommen kann es trotzdem.

> TMR1H und TMR1L vs. timer1_overflow

Gleiches Problem nur seltener. Zusätzlich solltest du dem Compiler 
mitteilen, dass timer1_overflow volatile ist.

> unsigned int time;
> time = (TMR1H << 8) + TMR1L + 0xFFFFFFFF - time + ((timer1_overflow -
>        overflow) * 65535);

Wieviele Bit hat unsigned int auf dem PIC12?

Deine Teilausdrücke ((timer1_overflow - overflow) * 65535) und 
0xFFFFFFFF in der Formel sind mir suspekt. Sobald timer1_overflow - 
overflow ungleich 0 ist, bekommst du abenteuerliche Werte.

Die 65535 selbst sind IMHO auch fischig. Ein Overflow heisst, dass 2^16 
= 65536 Timerschritte vergangen sind!

von Krapao (Gast)


Lesenswert?

> Das Verfahren von Horst

Jo, ne das "Schnell und kurz Auslesen, später Rechnen" meine ich.
Beitrag "Re: Frequenz messen (260 Hz)"

von Yasin (Gast)


Lesenswert?

Krapao schrieb:
> Das ist auf dem PIC12 kein atomarer Zugriff. Siehe die Hinweisbox dazu
> im Datenblatt.
Ich weiß leider nicht welche Hinweisbox du genau meinst aber ich habe es 
jetzt gemacht, wie ihr empfohlen habt. Zuerst auslesen, dann berechnen, 
und außerdem vor dem auslesen den Timer gestoppt.


Krapao schrieb:
> Wieviele Bit hat unsigned int auf dem PIC12?
16

Die Code Zeile ist dir zu Recht suspekt, da stimmt auch was nicht. Für 
alle, die es interessier, seht ihr nochmal die gesamte Funktion. Zuerst 
habe ich die "zittrigen" Flanken versucht per Software zu kompensieren, 
indem ich sie einfach mit einem delay "überspringe". Dadurch wurde es 
zwar deutlich besser, aber irgendwie hatte ich trotzdem noch starke 
Schwankungen, obwohl die Flanken so eigentlich sehr schön erkannt 
werden. Nunja, nun hat erstmal ein 470pF Kerko geholfen. Das ist mir 
allerdings sehr unlieb, weil bei höheren Frequenzen (die später noch 
auftreten werden) das Signal zu stark geglättet werden könnte und ich 
irgendwann nur noch "High" erkenne. Falls also jemand noch eine Idee 
hat, wie ich das Problem per Software in den Griff bekomme...
Das 0xFFFFFFFF ist mein maximaler Timer Wert. Kann ich das auch 
eleganter machen?
1
void Get_Speed(void)
2
{  
3
  unsigned int timer_steps;
4
  unsigned int overflow_old;
5
  unsigned int overflow_new;
6
  unsigned char i;
7
  unsigned char timerl;
8
  unsigned char timerh;
9
  
10
  while(RA5);
11
  while(!RA5);    
12
  T1CONbits.TMR1ON = 0;
13
        timerl = TMR1L;
14
  timerh = TMR1H;  
15
  overflow_old = timer1_overflow;        
16
  T1CONbits.TMR1ON = 1;            
17
  timer_steps = (timerh << 8) + timerl;
18
  for(i=0;i<16;i++)              
19
  {
20
    __delay_us(200);    //gegen "zittrige" Flanken
21
    while(RA5);  
22
    __delay_us(200);      
23
    while(!RA5);      
24
  }  
25
  T1CONbits.TMR1ON = 0;            
26
  timerl = TMR1L;
27
  timerh = TMR1H;
28
  overflow_new = timer1_overflow;
29
  T1CONbits.TMR1ON = 1;              
30
31
  if(overflow_new - overflow_old) //mehr als 1 Overflow ist nicht möglich
32
  timer_steps = (timerh << 8) + timerl + 0xFFFFFFFF - timer_steps;  //neuer Wert plus Differenz des alten Wertes bis zum Überlauf
33
  else 
34
  timer_steps = (timerh << 8) + timerl - timer_steps;        //neuer Wert minus alter Wert
35
}

von Karl H. (kbuchegg)


Lesenswert?

> if(overflow_new - overflow_old) //mehr als 1 Overflow ist nicht möglich

Wenn du unsigned und alles in 16 Bit rechnest, brauchst du diesen 1 
Overflow überhaupt nicht berücksichtigen. Durch die Definition des 
unsigned-Rechenhandlings kommt trotzdem immer das richtige raus, wenn du 
einfach nur Ende - Anfang rechnest.

von Yasin (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Wenn du unsigned und alles in 16 Bit rechnest, brauchst du diesen 1
> Overflow überhaupt nicht berücksichtigen. Durch die Definition des
> unsigned-Rechenhandlings kommt trotzdem immer das richtige raus, wenn du
> einfach nur Ende - Anfang rechnest.

Achso? Aber wenn ich zum Beispiel bei 60000 starte, einen Überlauf habe, 
und bei 10000 stoppe. Dann hatte ich ja 15535 Schritte. Wenn ich aber 
10000-60000 rechne kommt doch was anderes raus, oder?

von Christian G. (christian_g83)


Lesenswert?

Yasin schrieb:

> Wenn ich aber
> 10000-60000 rechne kommt doch was anderes raus, oder?

Richtig. Nämlich 15536.

von Karl H. (kbuchegg)


Lesenswert?

Yasin schrieb:

> Achso? Aber wenn ich zum Beispiel bei 60000 starte, einen Überlauf habe,
> und bei 10000 stoppe. Dann hatte ich ja 15535 Schritte.

15536.
Auch der Schritt von 65535 nach 0 ist ein Schritt

> Wenn ich aber
> 10000-60000 rechne kommt doch was anderes raus, oder?

Hast du das schon mal nachgerechnet?
Was kommt den raus?


Aber du hast recht. Ich muss mich präzisieren:

Ausgangssituation: 16 Bit Timer, der seinen vollen Wertebereich 
durchzählt, sowie die Annahme, dass die komplette Berechnung in 16-Bit 
unsigned Arithmetik durchgeführt wird.

Solange es nur 1 Überlauf geben kann UND der Endwert kleiner als der 
Startwert ist, braucht dieser 1 Überlauf nicht berücksichtigt werden.
De facto läuft das darauf hinaus, das der Timer vom Start der 
Messperiode bis zum Ende derselben nicht mehr als maximal 65535 Ticks 
machen darf. Ist dieser Fall gegeben, dann können die Überläufe komplett 
ignoriert werden.
Ein Einbeziehen eines eventuellen Überlaufs würde alles nur 
komplizierter machen und durch das Aufblähen auf 32 Bit Arithmetik auch 
verlangsamen.

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.