Hallo Zusammen, ich habe folgendes Probem: ich muss bei einem Beispiel mit einem C167 den Reloadwert berechnen: Die Aufgabenstellung lautet wie folgt: "Mit einem an Port P2.0-P2.8 angeschlossenen LED Balken ist ein Lauflicht zu generieren.........Das T3 Register wird mit einem Anfangswert programmiert, sodass die Periode (Anfangswert bis Maximalwert) den geforderten 250ms entspricht. Nach einem Überlauf würde T3 bei 0x0000 weiterzählen Mir ist das gesamte Beispiel klar, bis auf die Berechnung von T3; also vom Reloadwert. Ich habe zwar die Lösung hierzu, aber ich verstehe nicht wie man darauf kommt. ....... void main (void) { i=0; DP2=0x00ff; /* Port P2.0-P2.8 -> Ausgang */ P2=0x0000; /* Dunkelschaltung der LEDs */ T3CON=0x0004; /* Pre-Scaler=128 -> Periode=420ms */ T2CON=0x0027; /* Reload Mode bei jedem Flankenwechsel von T3OTL */ T3=0x679F; /* =0xFFFF-0x9860; 0x9860 == 250ms */ T2=0x679F; /* Reload Wert fuer T3 */ T3IC=0x0047; /* IE=1; ILVL=1; GLVL=3 */ IEN=1; /* globale Interruptfreigabe im PSW */ T3R=1; /* startet den Timer 3 */ while(1){ /* Endlosschleife */ _idle_(); } Wie kommt man auf 9860,...wie kann ich mir das berechnen. Könnt ihr mir da vl. weiterhelfen? Mfg Niko
>Wie kommt man auf 9860,...
Timer startet bei 0x679F (26537) und läuft bis 0xFFFF (65535).
Von 0x679F bis 0xFFFF sind es 0x9860 (39008).
>T3CON=0x0004; /* Pre-Scaler=128 -> Periode=420ms */ das macht 0,0064ms pro Takt des T3. Also braucht man für 250ms ca 39008 (=0x9860) Takte. Das mit dem Aufwärtszählen hat Jörg ja schon erklärt. Steht auch bei dir selber: >T3=0x679F; /* =0xFFFF-0x9860; 0x9860 == 250ms */
Hi Ich programmiere mit dem Keil compiler den C167 un versuche grade ein Display zu implementieren. Dazu brauche ich auch einpaar delays die ich mit hilfe des timers T3 realisieren will. Allerdings weiß ich nicht ganz genau ab ich das LCD falsch initialisiere oder den Timer3. Will nur eine Warteschleife von 50us erreichen. Der Teiler ist auf 16 gesetzt und somit ergibt sich eine Timer Periode von 0,4us bei 40MHz. kann mam den Timer so in den code Implementieren??? main() { //Init eines LCD// chip=44780 2x16 //Funktion set// DP2 = 0x54FF; //0101 0100 1111 1111 LCDRS = 0; LCDRW = 0; P2 = 0x38; waitT(125); //<-----aufruf der Timerfunktion (unten)????? T3R =0; //Timer aus; //display on/off control P2 = 0x0F; waitT(125); T3R =0; //Display clear P2 = 0x01; waitT(125); T3R =0 ; //Entry mode P2 = 0x07; waitT(65536); // test A auf LCD Ausgeben LCDRW=1; wait2(); T3R =0; P2 = 0x41; // hex A } void waitT(wait) ??????Timer funktion??????????????? { T3 = wait; T3CON = 0x081; //Txi=16, Txm = ohne Gade, TxUD = down T3IC = 0x44; //ILVL =1, T3IE = 1 T3R = 1; //Timer3 ein } danke
So könnte was draus werden (ungetestet):
1 | void waitT_us(wait_us) |
2 | {
|
3 | wait_us = wait_us*2.5; // us in Timerwert umrechnen |
4 | |
5 | T3CON = 0x0001; // Teiler 16 = 2,5MHz = 0,4µs Cnt |
6 | T3 = 0; // Timer loeschen |
7 | T3R = 1; // Timer3 ein |
8 | |
9 | // Warten
|
10 | while(T3 < wait); |
11 | |
12 | // Timer Stop
|
13 | T3R = 0; |
14 | }
|
wenn ich mich nicht irre muß es doch wait_us in deiner init??? heißen oder?? (T3 < wait_us); <---vorher nur wait????? sonst kein vergleichswert??? // Timer Stop T3R = 0; }
Die wait Funktion wird jetzt direkt mit µs Werten gefüttert, d.h. der µs Wert muss in Timer-Werte umgerechnet werden. Der kleinste Wert der der Funktion übergeben werden kann sind 1. µs. Für eine µs ist die Rechnung: 1 Timer Count sind 2,5MHz/1 = 400ns 1µs/400ns = 2,5 D.h. der Übergabewert muss immer mit 2,5 multipliziert werden um auf den korrekten Timer Wert zu kommen. Für ein delay von 50µs ist der Aufruf jetzt also
1 | waitT_us(50); |
Kannst die Umrechnung natülich auch weglassen, dann musst da halt vorher immer umrechnen.
axo. Das klingt plausiebel. Danke für die gute erläuterung. aber muss die Bedingung (T3 < wait); nicht trotzdem (T3 < wait_us); lauten???
nachtrag zu oben: ist nicht 2,5MHz/1 = Hz??? 1/Hz ergiebt doch sec???? demnach müßte doch die umrechnung in sec so lauten: void waitT(wait_us) { wait_us = wait_us / 2.5e^6; // nicht mal* sondern 2.5e^6 für MHz<---????? T3CON = 0x0001; // Teiler 16 = 2,5MHz = 0,4µs Cnt T3 = 0; // Timer loeschen T3R = 1; // Timer3 ein // Warten while(T3 < wait_us); // <----????? // Timer Stop T3R = 0; }
>aber muss die Bedingung (T3 < wait); nicht trotzdem (T3 < wait_us); >lauten??? Ja, das wäre besser :) >nachtrag zu oben: ist nicht 2,5MHz/1 = Hz??? Muss natürlich 1/2,5MHz heissen. >1/Hz ergiebt doch sec???? Ja, die Periodendauer wird berechnet. Die Rechnung ist ansonsten richtig. Die hast du doch auch schon gemacht, sonst wärst du ja nicht auf den Wert "125" für 50µs gekommen. Genau diese Umrechnung habe ich in die Funktion gepackt (50µs*2,5 = 125).
Super Jörg danke für die hilfe, das display läuft zwar trozdemnoch nicht, aber mit dem timern bin ich jetzt einwenig weitergekommen. vieleicht kennst du dich auch mit display´s aus. Muss ich eigentlich die angegebenen zeiten z.B. bei der init von LCD´s einhalten, ich mein können diese auch größer sein??
>ich mein können diese auch größer sein??
Die Zeiten können i.d.R. auch immer größer sein.
Hallo wollte gerne wissen ob der Timer auch würklich bis zur gewünschten Zahl hochzählt. Wenn ich z.B. 50 übergebe sollte dann w mit hilfe der while schleife bis 125(wait*2.5) hochgezählt werden? w dient nur als kontrolle, will gucken ob der timer wie ich es mir denke läuft. mit printf(); gucke ich welchen wert wait & w hat. kann man das eigentlich so machen?? oder zählt der timer schneller als w inkrementiert(w++) wird?? mein terminal zeigt mir nämlich für wait = 125; und für w einen wert von 99 an; waitT(50); waitT(int wait) { int w =0; wait = wait*2.5; <----------=125, richtig T3CON = 0x0001; // Teiler 16 = 2,5MHz = 0,4µs Cnt T3 = 0; // Timer loeschen T3R = 1; // Timer3 ein // Warten while(T3 < wait) <----- läuft nur 99 durch, als ob wait = wait*2;??? { w++; } printf("wait = %i\n", wait);<----kann man das so ausgeben printf("w = %i\n", w); wait =0; T3R = 0; } danke
>Hallo wollte gerne wissen ob der Timer auch würklich bis zur gewünschten >Zahl hochzählt. Wenn er das nicht machen würde, würde das Programm hängen bleiben. Die while Schleife wird ja nur abgebrochen wenn der Timer den Wert auch erreicht hat. Edit: >kann man das eigentlich so machen?? oder zählt der timer schneller als w >inkrementiert(w++) wird?? Kommt darauf an wie der Timer eingestellt ist. In diesem Fall zählt der Timer schneller. >mein terminal zeigt mir nämlich für wait = 125; und für w einen wert von >99 an; Der Timer zählt in Hardware, während die CPU noch andere Dinge machen muss und nicht so schnell nachkommt.
Zum Verständis: Bei dem Timer stellst du einfach nur einen Takt ein und lässt in loslaufen. Der Timer zählt mit jedem Takt EXAKT ein Bit hoch. Es lässt sich also genau berechnen wie lange er braucht bis er einen bestimmten Wert (in dem Fall 125) erreicht hat. Bei dem Ausdruck
1 | while(T3 < wait) w++; |
Schaut die CPU nach ob im Register T3 des Timers schon der Wert 125 überschritten wurde, wenn nicht, wird w um eins erhöht. Das Inkrementieren von w lässt sich aber nicht so schön berechnen. Die CPU muss etliche Operationen ausführen bis der Wert inkrementiert wurde (wesentlich länger als 1 Takt). Da der Timer recht schnell läuft, ist es in diesem Fall so das die CPU langsamer inkrementiert als der Timer.
axo. Ich verzweifle nur grad an der write to LCD routine die ich grade implementieren will. Also hängt das wohl nicht am timing bei der initLCD(). im Datenblatt steht: RS R/W H L Data Write operation (MPU writes data into DR) RS R/W D7....D3....D0 (Implementiert in Port2, D7-D0 liegen auf P7-P0) Hinten im Datenblat sind die Timings zum schreiben dargestellt. Im Quellcode habe ich das so realisiert: void main () { char Z =0x41; init_serial1(); printf("hallo\n"); initLCD(); LCDE =0; waitT(90); writeLCD(Z); } void writeLCD(char zeichen) { putchar(zeichen); // test A auf LCD Ausgeben, zeichen = 0x41 LCDRS = 1; LCDRW= 0; waitT(50); LCDE =1; waitT(50); P2 = zeichen; //A ins LCD Ram schreiben waitT(50); LCDE =0; waitT(196); } Weiß jemand was ich dort falsch mache??? Die timings habe ich extro was gröser gewählt.
Was geht denn schon oder was nicht? Blinkt der Cursor schon? Wenn nicht müsste man wohl erst mal bei der initLCD(); anfangen.
Der Cursor blingt, es sind auch zwei zeilen sichtbar, es sieht so aus als ob mit der init alles in ordnung ist. ????
Der Cursor blingt, es sind auch zwei zeilen sichtbar, es sieht so aus als ob mit der init alles in ordnung ist. ???? Nachtrag: LCD-Display(Pinbelegung, c167cs, phycore_167HS/E) P2.0 - 2.7 Out Daten/LCD P2.10 Out RS P2.12 Out R/W P2.14 Out E
>P2.0 - 2.7 Out Daten/LCD >P2.10 Out RS >P2.12 Out R/W >P2.14 Out E Dann schreiben dir deine Daten evt. die Steuerleitungen kaputt. Vielleicht geht es damit:
1 | writeLCDString("Hallo Welt"); |
2 | |
3 | |
4 | void writeLCDString (char* string) |
5 | {
|
6 | LCDRS = 1; |
7 | LCDRW= 0; |
8 | waitT(50); |
9 | |
10 | while(*string!= '\0') |
11 | {
|
12 | LCDE =1; |
13 | waitT(50); |
14 | |
15 | // P2.0 bis 2.7 auf 0 und dann Daten setzen
|
16 | P2 = (P2 & 0xFF00) | *string; |
17 | waitT(50); |
18 | |
19 | LCDE =0; |
20 | waitT(196); |
21 | |
22 | data_string++; |
23 | }
|
24 | }
|
jörg, dein code hat auf anhieb, bis auf das, daß hallo sozusagen in einer endlosschleife im Lcd nacheinander ausgegeben wird, geklappt. Ich glaube das liegt dadran das man das display nach einer ausgabe, wieder löschen und den cursor wieder in starposition bringen müss. Werd mal einwenig rumspielen. Danke
Hi hab mit dem display einwenig rumgespielt, es klappt soweit alles bis auf, das ich nicht so weiteres auf die zweite zeile schreiben kann?? geht das durch setzten eines bit´s in irgend einem reg, was ich noch nicht gefunden habe?? oder muß man das mit dem adresscounter(AC) machen Datenblatt: Set DDRAM Address: 0 0 1 AC6 AC5 AC5....AC0 // set adress in DDRAM Line 1: 00 - 0F, Line 2: 40 - 4F. Hab versucht die erste line bzw Line 1 stelle 0x40 zu beschreiben aber ich schreibe immer wieder auf die erste line. weiß einer wie ich den cursor in die line 2 bewegen kann?? Danke
>oder muß man das mit dem adresscounter(AC) machen Genau da mit, ja. >Hab versucht die erste line bzw Line 1 stelle 0x40 zu beschreiben aber >ich schreibe immer wieder auf die erste line. Source code? Daran denken das du dafür auf "Instruction" (LCDRS = 0;) umschalten musst. So ungefähr sollte es laufen:
1 | setLineLCD(1); // Zeile 1 Position 1 |
2 | |
3 | setLineLCD(2); // Zeile 2 Position 1 |
4 | |
5 | |
6 | #define CMD_DDRAM_ADDR 0x80
|
7 | |
8 | void setLineLCD (unsigned char line) |
9 | {
|
10 | unsigned char data; |
11 | |
12 | LCDRS = 0; // Instruction |
13 | LCDRW= 0; |
14 | waitT(50); |
15 | |
16 | LCDE =1; |
17 | waitT(50); |
18 | |
19 | data = CMD_DDRAM_ADDR; |
20 | |
21 | if(line == 2) |
22 | data += 0x40; |
23 | |
24 | // P2.0 bis 2.7 auf 0 und dann Daten setzen
|
25 | P2 = (P2 & 0xFF00) | data; |
26 | waitT(50); |
27 | |
28 | LCDE =0; |
29 | waitT(196); |
30 | }
|
Jörg ich muß dich korregieren nicht "So ungefähr sollte es laufen", sondern es läuft so. Danke noch ne formale frage. Wieso verwendet man diese schreibweise???? P2 = (P2 & 0xFF00) | data; und nicht einfach: P2 = 0x80; Wegen der schnelligkeit(hardware) oder um die anderen Pins(pegel) nicht zu beiflussen????
>Wieso verwendet man diese schreibweise???? >P2 = (P2 & 0xFF00) | data; >und nicht einfach: >P2 = 0x80; Weil P2 = 0x80 identisch mit P2 = 0x0080 wäre. Da du an P2 aber auch an den oberen Pins was hängen hast überscheibst du dir die sonst.
keil uV3 c167cs-L40M // 40MHz Hallo, bin wieder mit den timern am kämpfen. Diesmal mit dem timer2. Er Soll nach jedem überlauf, einen Interrupt auslösen und der timer2 soll von null wieder starten. hab das so versucht: main() { init_timer2(); IEN = 1; T2IR = 1; T2IE = 1; while (1) } ....... ....... ....... } } void init_timer2 (void) { // Teiler = 1024(takt 39.0625k), Betriebsart(timer ohne Gate), Laufkontrolle(aus), Zähllichtung(up), Mode Zählrichtung(TxUD abhängig) T2CON = 0x0007; T2 =0x0000; // startwert timer2 } void AbPos(void) interrupt 0x22 // timer2 interrupt { const char SternPos[] = {"*1,$"}; putchar('a'); // test ausgaben THolding_R = SternPos[0]; // UART schreiben THolding_R = SternPos[1]; THoldin_R = SternPos[2]; THolding_R = SternPos[3]; } die funtionen wurden natürlich Deklariert. Komischer weise wird die Interrupt Routine nicht aufgerufen, desshalb denke ich, das der timer entweder nicht zählt. hat einer ein tipp waran es liegen könnte?? danke
Hi Jörg, hast vollkommen recht, T2R = 1; <--- hab ich jetzt gesetzt. main() { init_timer2(); IEN = 1; T2IR = 1; T2IE = 1; T2R =1; aber der interrupt will immer noch nicht auslösen.??
Sehe den Fehler auf anhieb jetzt nicht. Schau doch erst mal ob der Timer läuft.
Vergessen Interruptlevel zu vergeben? Wie im Thread weiter oben T3IC=0x0047; /* IE=1; ILVL=1; GLVL=3 */ muss das natürlich in ähnlicher Weise auch für Timer 2 gemacht werden, sonst gibt es keine Interuptauslösung.
hallo Jörg und Jue, Jue danke für den tipp, kann den allerdings diese woche nicht mehr testen. Was ich mich aber frage, muß ich den Interrupt priorisieren?? Es ist doch nur dann notwenig zu priorisieren wenn interrupts zur gleichen Zeit ausgelöst werden können?? ob der timer läuft oder nicht, wollte ich durch nen putchar('a'); in der Interruptroutine testen. Passiert aber nichts?? void AbPos(void) interrupt 0x22 // timer2 interrupt { const char SternPos[] = {"*1,$"}; putchar('a'); // test ausgaben }
Jam wrote: > Was ich mich aber frage, muß ich den Interrupt priorisieren?? Ja! > Es ist doch nur dann notwenig zu priorisieren wenn interrupts zur > gleichen Zeit ausgelöst werden können?? Standardmäßig läuft die Hauptschleife mit Priorität 0 und kann nur von einem Interrupt unterbrochen werden, der einen höheren Level hat. Ein Interrupt Level 0 wird also nie die Hauptschleife mit ebenfalls Level 0 unterbrechen können! Wenn zwei Interrupts mit gleichem Interrupt Priority Level eintreffen, gewinnt der Interrupt mit den höheren Group Level.
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.