Hallo, also ich habe einige Zeitschleifen geschrieben, nur passiert nichts wenn sie aufgerufen werden... also nie wieder. Hab ich da irgentwie eine Endlosschleife gebaut? Oder Funktioniert das mit dem _asm ... _endasm so nicht? Ich verstehe nicht warum es so nicht funktioniert. Ich benutze MPLAB mit dem C18 Compiler. Hier die 3 Verzögerungen, vom Takt her habe ich 4MHz das erstmal fest gelegt, da es zur Zeit nur diesen Aufbau gibt. void DelayUs(unsigned int x); void DelayMs(unsigned int x); void DelayS(unsigned int x); void DelayUs(unsigned int x) { // 4MHz -> 1 Zyklus = 1us! while(x>0) { x--; _asm NOP _endasm } } void DelayMs(unsigned int x) { int i,j; for(i=0;i<x;i++) { for(j=0;j<4;j++) DelayUs(250); } } void DelayS(unsigned int x) { int i,j; for(i=0;i<x;i++) { for(j=0;j<4;j++) DelayMs(250); } } Dann habe ich noch ein kleines Testprogramm, das eine LED an Port-A blinken lassen soll. #include <p18f458.h> #pragma config OSC=EC, PWRT=ON, WDT=OFF // Hier stehen die Zeitfunktionen von oben zwischen. void main(void) { TRISA = 0; while(1) { PORTAbits.RA0 = 1; DelayS(1); PORTAbits.RA0 = 0; DelayS(1); } }
#pragma config OSC=EC... Hast du auch einen externen Taktgenerator dran?
Pascal schrieb: > Hallo, > > also ich habe einige Zeitschleifen geschrieben, nur passiert nichts wenn > sie aufgerufen werden... also nie wieder. > Hab ich da irgentwie eine Endlosschleife gebaut? > Oder Funktioniert das mit dem _asm ... _endasm so nicht? > Ich verstehe nicht warum es so nicht funktioniert. Funktioniert es in echter Hardware nicht, oder im Simulator nicht, oder in beiden nicht? > void DelayUs(unsigned int x) > { > // 4MHz -> 1 Zyklus = 1us! > while(x>0) > { > x--; > _asm NOP _endasm Du führst ja nicht nur NOP aus, sondern auch x--, das braucht auch noch ein paar Zyklen.
Mach mal die Verzögerung kürzer, denn dein DelayUs dauert sicher deutlich länger als eine Mikrosekunde. Nicht nur der nop frisst Zeit, x-- braucht auch und das x>0 will ausgewertet werden. Dazu kommt der Aufruf und die Rückkehr aus dem Unterprogramm. Selbst ohne das irgendwas auf dem Stack gesichert wird, und das wird es ganz bestimmt, würde ein CALL und ein RETURN schon 4 Zyklen brauchen. Ich schätze ein DelayUs(1) mal auf mindestens 30 Zyklen = 30 µs. Betrachte mal den erzeugten Assemblercode. Uwe
... while (x>0) ist immer wahr, wenn x eine unsigned int ist... Kleine Ursache, große wirkung! Gruß, R.
Sorry, zu schnell geantwortet: Das geschriebene stimmt natürlich nur, wenn da stehen würde "while (x>=0)" ... steht da aber nicht, muß also ander Ursache haben ... Gruß, R.
Versuchs mal so:
1 | void main(void) |
2 | {
|
3 | ADCON0=0; //AD-Wandler aus |
4 | ADCON1=0x0F; //Alle Analogeingänge auf digital |
5 | CMCON=0x07; //Komparatoren aus |
6 | |
7 | TRISA = 0; |
8 | while(1) |
9 | {
|
10 | PORTAbits.RA0 = 1; |
11 | DelayS(1); |
12 | PORTAbits.RA0 = 0; |
13 | DelayS(1); |
14 | }
|
15 | }
|
Und wie oben schon gesagt wurde, werden deine
Delays länger sein als erwartet.
>Oder Funktioniert das mit dem _asm ... _endasm so nicht?
Doch, das geht so.
Ja hab einen externen Takt angeschlossen. Es funktioniert in der Hardware nicht, wie man simuliert hab ich noch nicht rausgefunden. Ok, in Asm sieht das ganze schon etwas anders aus. Also die Us Funktion zumindest: void DelayUs(unsigned int x) 0008 CFD9 MOVFF 0xfd9, 0xfe6 // 2 Zyklen 000A FFE6 NOP 000C CFE1 MOVFF 0xfe1, 0xfd9 // 2 Zyklen 000E FFD9 NOP 27: { 28: // 4MHz -> 1 Zyklus = 1us! 29: while(x>0) 0010 50D9 MOVF 0xfd9, W, ACCESS // 1 Zyklus 0012 0FFD ADDLW 0xfd // 1 Zyklus 0014 6EE9 MOVWF 0xfe9, ACCESS // 1 Zyklus 0016 0EFF MOVLW 0xff // 1 Zyklus 0018 20DA ADDWFC 0xfda, W, ACCESS // 1 Zyklus 001A 6EEA MOVWF 0xfea, ACCESS // 1 Zyklus 001C 0E00 MOVLW 0 // 1 Zyklus 001E 80D8 BSF 0xfd8, 0, ACCESS // 1 Zyklus 0020 54EE SUBFWB 0xfee, W, ACCESS 0022 0E00 MOVLW 0 // 1 Zyklus 0024 54ED SUBFWB 0xfed, W, ACCESS 0026 E207 BC 0x36 0034 D7ED BRA 0x10 // 1 Zyklus 30: { 31: x--; 0028 0EFD MOVLW 0xfd // 1 Zyklus 002A 06DB DECF 0xfdb, F, ACCESS // 1-2 Zyklus 002C 0EFE MOVLW 0xfe // 1 Zyklus 002E E201 BC 0x32 // 1 Zyklus 0030 06DB DECF 0xfdb, F, ACCESS // 1-2 Zyklus 32: _asm NOP _endasm 0032 0000 NOP // 1 Zyklus 33: } 34: } 0036 52E5 MOVF 0xfe5, F, ACCESS // 1 Zyklus 0038 CFE7 MOVFF 0xfe7, 0xfd9 // 2 Zyklus 003A FFD9 NOP 003C 0012 RETURN 0 // 2 Zyklus so gob über den Daumen insgesamt 27 Zyklen... anstatt 1 wie gedacht. Bei den anderen Funktionen für Ms und S, ist das dann genauso, das heisst es wird "etwas" länger dauern... wenn ich dann noch die for() Schleifen in Asm übersetzt sehe, wird mir klar warum nichts passiert, es dauert einfach zu lange... Hm, ok hab jetzt versucht eine Us Funktion in Asm zu schreiben, mit dem Schluss das das woll nichts wird, weil der Aufruf und der Rücksprung bei 4Mhz schon länger wie 1us dauert. Gibts nicht irgentwo eine Art Bibiotek die fertige Zeitfunktionen hat, die auch ohne größere Schwierigkeiten in MPLAB zum laufen gebraucht werden können?
Hat dein PIC einen freien Timer, oder eine Real Time Clock? Warum realisierst du die Wartefunktion nicht mit einer Interrupt Funktion? etwa so:
1 | static volatile unsigned int s_v_u16_counter=0; |
2 | |
3 | void wait_ms (unsigned int u16_wait_cnt) |
4 | {
|
5 | s_v_u16_counter = u16_wait_cnt; |
6 | |
7 | while (s_v_u16_counter > 0) |
8 | {
|
9 | _asm{"nop"}; |
10 | }
|
11 | }
|
und dann in der Timer ISR
1 | void isr_timer_overflow (void) |
2 | {
|
3 | reset_overflow_flag(); // Makro |
4 | if (s_v_u16_counter > 0) |
5 | {
|
6 | s_v_u16_counter--; |
7 | }
|
8 | }
|
Die "Wartezeit" wird dann ueber den Timer Counter Wert bestimmt. So bekommt man allerdings keine Genauigkeit im us Bereich hin. Aber für ms und s reicht es. Gruß
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.