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
>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
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.
>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??
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.
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:
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:
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.??
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.