Hallo. Ich bin noch totaler Anfänger und habe noch nie wirklich was mit Interrupts gemacht. Für mein nächstes Projekt brauche ich einen Timer (für eine Uhr). Die Frequenz des Timers ist erstmal egal. Ich möchte nur zB. das auf meiner Anzeige von 0 - 9 regelmäßig durchgezählt wird (bestens natürlich in 1Hz). Wie muss ich meinen Code ändern dass das irgendwie was werden kann? Ich nutze den NC30 für den m16c von Renesas. #include <stdio.h> #include "sfr62.h" // Taktfrequenz MainClock #define CLOCK_FREQ 16000000L #define OS_TICKS_PER_SEC 4000 /* Set the number of ticks in one second */ // Timer B5 Interrupt Level: Timer Counter #define TB5_INTLVL 1 void TimerInit(void); void Delay(int k); void Anzeige(int Ziffer, int Zahl); // ------------------------------------------------------------------- void main() { TimerInit(); // Timer initialisieren. // Hier möchte ich dann das zB. die Funktion Anzeige von 0 bis 9 hochzählt } // ------------------------------------------------------------------ void TimerInit(void) { tb5ic = 0; // IR reset und disable Ints tb5s = 0; // Timer stop tb5mr = 0x80; // f/32, Timer Mode tb5 = CLOCK_FREQ 32 OS_TICKS_PER_SEC - 1; tb5ic = TB5_INTLVL; // Int freigeben tb5s = 1; // Timer start }
Hat niemand einen Tipp am frühen morgen? :-) Also ich brauch eigentlich nur irgendeine Variable die dann hochzählt Gruß Christian
Hallo Christian, ich arbeite beruflich mit dem 16C80. Also, du willst erstmal eine Variable hochzählen: es funktioniert grundsätzlich mit einem Interrupt. Lade das tb5-Register mit einem Wert, starte den Timer und er zählt dann runter, bei 0x00 wird ein Interrupt ausgelöst, danach wird die Interrupt Service Routine abgearbeitet (hier steht deine Variable). Bei diesem Ausdruck tb5 = CLOCK_FREQ 32 OS_TICKS_PER_SEC - 1 würde ich vorschlagen, dass du Klammern setzt(sehr unübersichtlich). Also, ich würde folgendes Vorschlagen: void TimerInit(void) { tb5mr = 0x80; // f/32, Timer Mode tb5 = CLOCK_FREQ 32 OS_TICKS_PER_SEC - 1; tb5ic = 0x09; // Interrupt-Priorität festlegen, IR aktivieren tb5s = 1; // Timer start } tb5_isr() //Deine Interrupt Service Routine { Deine_Variable++; // fürs Erste } void main () { TimerInit() } P.S. Meiner Meinung nach ist dieser Controller eine schlechte Wahl für einen Anfänger.
mh also ich habe das soweit geändert und getestet. Folgender Code Funktioniert immer noch nicht, warum weiß ich auch nicht. double TimerVar = 0; void TimerInit(void); void Delay(int k); void Anzeige(int Ziffer, int Zahl); // ------------------------------------------------------------------------ ------------ // ------------------------------------------------------------------------ ------------ void main() { pd2 = 0xFF; // p2.0 - p2.7 output bzw. A0 - bis A7 pd9 = 0xff; pd5 = 0x00; /* p50 output */ p2_0 = 0x00; // enable p2_1 = 0x00; p5_0=0xff; TimerInit(); while(1) { if(TimerVar >= 1)Anzeige(2,8); } } // ------------------------------------------------------------------------ ------------ // ------------------------------------------------------------------------ ------------ void TimerInit(void) { tb5mr = 0x80; // f/32, Timer Mode tb5 = (CLOCK_FREQ 32 OS_TICKS_PER_SEC); tb5ic = 0x09; // Interrupt-Priorität festlegen, IR aktivieren tb5s = 1; // Timer start } // ------------------------------------------------------------------------ ------------ tb5_isr() //Deine Interrupt Service Routine { TimerVar++; // fürs Erste } // ------------------------------------------------------------------------ ------------
Hallo Christian, es wäre hilfreich, wenn du den ganzen Quellcode eingefügt hättest und schreib mal, welche Werkzeuge(Compiler IDE, Emulator...) du einsetzt. Ich arbeite mit: C-Compiler nc308 v.5.10 Release 1, Assembler as308 für m16c80, Linker ln308 für m16c80. Also ich gehe von den selben Voraussetzungen aus: Wichtig für die Interrupt Service Routine(ISR) ist, dass du sie dem Compiler bekannt machst und zwar in der Datei sect308.inc. Diese sieht dann folgendermaßen aus: ;--------------------------------------------------------------- ; variable vector section ;--------------------------------------------------------------- .section vector ; variable vector table .org VECTOR_ADR .lword dummy_int ; .org (VECTOR_ADR +32) .lword dummy_int ; DMA0 (software int 8) .lword dummy_int ; DMA1 (software int 9) .lword dummy_int ; DMA2 (software int 10) .lword dummy_int ; DMA3 (software int 11) .lword dummy_int ; TIMER A0 (software int 12) .lword dummy_int ; TIMER A1 (software int 13) .lword dummy_int ; TIMER A2 (software int 14) .lword dummy_int ; TIMER A3 (software int 15) .lword dummy_int ; TIMER A4 (software int 16) .lword dummy_int ; uart0 trance (software int 17) .lword dummy_int ; uart0 receive (software int 18) .lword dummy_int ; uart1 trance (software int 19) .lword dummy_int ; uart1 receive (software int 20) .lword dummy_int ; TIMER B0 (software int 21) .lword dummy_int ; TIMER B1 (software int 22) .lword dummy_int ; TIMER B2 (software int 23) .lword dummy_int ; TIMER B3 (software int 24) .lword dummy_int ; TIMER B4 (software int 25) .lword dummy_int ; INT5 (software int 26) .lword dummy_int ; INT4 (software int 27) .lword dummy_int ; INT3 (software int 28) .lword dummy_int ; INT2 (software int 29) .lword dummy_int ; INT1 (software int 30) .lword dummy_int ; INT0 (software int 31) .lword dummy_int ; TIMER B5 (software int 32) .glb _uart2_isr .lword _uart2_isr ; uart2 trance/NACK (software int 33) .lword dummy_int ; uart2 receive/ACK (software int 34) .lword dummy_int ; uart3 trance/NACK (software int 35) .lword dummy_int ; uart3 receive/ACK (software int 36) .lword dummy_int ; uart4 trance/NACK (software int 37) .lword dummy_int ; uart4 receive/ACK (software int 38) .lword dummy_int ; uart2 bus collision (software int 9) .lword dummy_int ; uart3 bus collision (software int 40) .lword dummy_int ; uart4 bus collision (software int 41) .lword dummy_int ; A-D Convert (software int 42) .lword dummy_int ; input key (software int 43) ; from vector XX to vector YY is used MR30 hier habe ich eine ISR für den UART2. In deine ISR kommt das, was du, nach dem dein Timer ein Interrupt ausgelöst hat, ausgeführt haben willst. Also, wenn ich das richtig verstanden habe, führt die Funktion "Anzeige(2,8)" irgendetwas, was angezeigt wird. ------------------------------------------------------------------------ ------------ unsigned long TimerVar = 0; void TimerInit(void); void Delay(int ); void Anzeige(int , int ); // ------------------------------------------------------------------------ ------------ // ------------------------------------------------------------------------ ------------ void main() { pd2 = 0xFF; // p2.0 - p2.7 output bzw. A0 - bis A7 pd9 = 0xff; pd5 = 0x00; /* p50 output */ p2_0 = 0; // enable p2_1 = 0; p5_0=1; TimerInit(); tb5s = 1; // Timer start while(1) { } }//main zu Ende // ------------------------------------------------------------------------ ------------ // ------------------------------------------------------------------------ ------------ void TimerInit(void) { tb5mr = 0x80; // f/32, Timer Mode tb5 = (CLOCK_FREQ 32 OS_TICKS_PER_SEC); tb5ic = 0x09; // Interrupt-Priorität festlegen, IR aktivieren } //---------------------------------------------------------------------- -------------- tb5_isr() //Deine Interrupt Service Routine { TimerVar++; if(TimerVar >= 1) { Anzeige(2,8); } } //---------------------------------------------------------------------- -------------- Zweitens sollte deine Zählvariable TimerVar je nach Größe der Schleife "unsigned char, unsigned int oder unsigned long" sein und nicht double. Mit dem Klammern habe ich folgendes gemeint: ((CLOCK_FREQ / 32) / OS_TICKS_PER_SEC) oder (CLOCK_FREQ / (32 / OS_TICKS_PER_SEC)) -> Es ist ein großer Unterschied. Grüße 'Andy
Hallo Andy, vielen Dank für deine Hilfe. Das mit der *.inc Datei wusste ich noch gar nicht. Ich nutze auch den NC30 5.x für den m16c62P. Meine sect30.inc habe ich nun so editiert: ;--------------------------------------------------------------- ; variable vector section ;--------------------------------------------------------------- .section vector ; variable vector table .org VECTOR_ADR .lword dummy_int ; vector 0 (BRK) .org (VECTOR_ADR +44) .lword dummy_int ; DMA0 (for user) .lword dummy_int ; DMA1 2 (for user) ;.glb _keyint .lword dummy_int ; input key (for user) .lword dummy_int ; AD Convert (for user) .org (VECTOR_ADR +68) .lword dummy_int ; uart0 trance (for user) .lword dummy_int ; uart0 receive (for user) .lword 0FF900h ; uart1 trance (for user) .lword 0FF900h ; uart1 receive (for use .lword dummy_int ; TIMER A0 (for user) .lword dummy_int ; TIMER A1 (for user) .lword dummy_int ; TIMER A2 (for user) .lword dummy_int ; TIMER A3 (for user) .lword dummy_int ; TIMER A4 (for user) (vector 25) .glb _tb0_isr .lword _tb0_isr ; TIMER B0 (for user) (vector 26) .lword dummy_int ; TIMER B1 (for user) (vector 27) .lword dummy_int ; TIMER B2 (for user) (vector 28) .lword dummy_int ; INT0 (for user) (vector 29) .lword dummy_int ; INT1 (for user) (vector 30) .lword dummy_int ; INT2 (for user) (vector 31) .lword dummy_int ; vector 32 (for user or MR30) .lword dummy_int ; vector 33 (for user or MR30) .lword dummy_int ; vector 34 (for user or MR30) .lword dummy_int ; vector 35 (for user or MR30) .lword dummy_int ; vector 36 (for user or MR30) .lword dummy_int ; vector 37 (for user or MR30) .lword dummy_int ; vector 38 (for user or MR30) .lword dummy_int ; vector 39 (for user or MR30) .lword dummy_int ; vector 40 (for user or MR30) .lword dummy_int ; vector 41 (for user or MR30) .lword dummy_int ; vector 42 (for user or MR30) .lword dummy_int ; vector 43 (for user or MR30) .lword dummy_int ; vector 44 (for user or MR30) .lword dummy_int ; vector 45 (for user or MR30) .lword dummy_int ; vector 46 (for user or MR30) .lword dummy_int ; vector 47 (for user or MR30) ; to vector 63 from vector 32 is used MR30 - Ist es egal ob ich _funktion_isr schreibe oder funktion_isr ? Mein C Code sieht nun wie folgt aus. Ich habe quasi deinen Vorschlag übernommen. Und ja Anzeige(int,int) ist eine Funktion die eine Zahl auf einer von vier Ziffern auf einer Siebensegmentanzeige ausgibt (funktioniert). #include <stdio.h> #include "sfr62.h" // Taktfrequenz MainClock #define CLOCK_FREQ 16000000L #define OS_TICKS_PER_SEC 4000 /* Set the number of ticks in one second */ unsigned long TimerVar = 0; void TimerInit(void); void Delay(int k); void Anzeige(int Ziffer, int Zahl); // ------------------------------------------------------------------- void main() { pd2 = 0xff; // p2.0 - p2.7 output bzw. A0 - bis A7 pd9 = 0xff; pd5 = 0x00; /* p50 output */ p2_0 = 0x00; // enable p2_1 = 0x00; p5_0=0xff; TimerInit(); tb0s = 1; // Timer start while(1) { //if(TimerVar >= 0)Anzeige(2,8); } } // ------------------------------------------------------------------- void TimerInit(void) { tb0mr = 0x80; // f/32, Timer Mode tb0 = (CLOCK_FREQ 32 OS_TICKS_PER_SEC); tb0ic = 0x09; // Interrupt-Priorität festlegen, IR aktivieren } // ------------------------------------------------------------------- tb0_isr() //Deine Interrupt Service Routine { TimerVar++; if(TimerVar >= 1) { Anzeige(2,8); } } // ------------------------------------------------------------------- Ist es eigentlich egal ob ich für diesen Zweck Timer A0 nehme oder zB. B0 ? Leider ist auch dieser Code ohne jeglichen Effekt. Ich hoffe du/ihr kannst/könnt mir noch weiter helfen :-) Gruß Christian
Hallo Christian, also, erstmal zu deinen Fragen: - Der Eintrag in der sect308.inc muß für jeden Interrupt drin sein und muß mit einem "_"(Unterstrich) beginnen, weil die ganze Datei in Assembler geschrieben wurde. In deiner C-Routine schreibst du den Namen ohne "_". Alle Namen sind frei wählbar. Z.B. in sect308.inc: _interrupt_dma0, in C-Routine: interrupt_dma0 usw. Lies mal dazu das Manual für C-Language. -In deiner C-Routine mußt du noch folgendes einfügen: " #pragma INTERRUPT dein_interrupt_name ". -Und was am aller wichtigsten ist, mußt du bevor du einen Interrupt ausführen kannst, das Interrupt enable flag (I flag) in deiner C-Routine setzen, mit: asm( "fset I"); // alle Interrupts aktivieren sonst sind alle Interrupts deaktiviert. -Ob du für diesen Zweck Timer A oder B nimmst, ist egal, Timer A hat halt mehr Funktionen. Ich habe in der Datei meinen Quellcode eingefügt, der hat bei mir funktioniert. Grüße 'Andy
hallo christian! ich habe schon ne weile auf einem m16c62 programmiert. hier ist mein timer code für einen 16mhz-quarz: //********************************************************************** * // Routine für eine Pause von time µs m.H. des Hardware-Timers A0 //********************************************************************** * void delay_us(int time) { ta0ic = 0x00; // Timer A0 erst einmal deaktivieren ta0mr = 0x40; // Timer A0 in Timer-Mode und F_CPU wird durch 8 geteilt -> 2Mhz ta0 = 2*time; // Set up Timer A0 Reload Register for 1 usec interval interrupt // -> zählt bis 2*time -> 2*time / 2Mhz = 1µs*time ta0s = 1; // Timer A0 count start flag aktiviert while (ir_ta0ic != 1); // wait for timer to run out -> solange noch nicht fertig gezählt, // noch kein interrupt-request, also tu nichts // -> ir_ta0ic ist das interrupt request bit vom ta0ic s.o. ta0s = 0; // Timer stoppen } gruß danyo
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.