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?
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.
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.
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.
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?
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 |
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.
Sicher daß dein Signal ein sauberer Rechteck ist und keine Störungen (Peaks) enthält? Signalquelle? Schaltungsaufbau?
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
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?
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
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!
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.
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.
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 :)
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 :-)
> 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!
> Das Verfahren von Horst Jo, ne das "Schnell und kurz Auslesen, später Rechnen" meine ich. Beitrag "Re: Frequenz messen (260 Hz)"
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 | }
|
> 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.
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?
Yasin schrieb: > Wenn ich aber > 10000-60000 rechne kommt doch was anderes raus, oder? Richtig. Nämlich 15536.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.