Forum: Mikrocontroller und Digitale Elektronik Reloadwertberechnung C167


von Niko (Gast)


Lesenswert?

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

von Jörg S. (joerg-s)


Lesenswert?

>Wie kommt man auf 9860,...
Timer startet bei 0x679F (26537) und läuft bis 0xFFFF (65535).
Von 0x679F bis 0xFFFF sind es 0x9860 (39008).

von TManiac (Gast)


Lesenswert?

>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 */

von Jam (Gast)


Lesenswert?

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

von Jörg S. (joerg-s)


Lesenswert?

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
}

von Jam (Gast)


Lesenswert?

wieso mal 2,5???

von Jam (Gast)


Lesenswert?

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;
}

von Jörg S. (joerg-s)


Lesenswert?

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.

von Jam (Gast)


Lesenswert?

axo. Das klingt plausiebel. Danke für die gute erläuterung.
aber muss die Bedingung (T3 < wait); nicht trotzdem (T3 < wait_us); 
lauten???

von Jam (Gast)


Lesenswert?

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;
}

von Jörg S. (joerg-s)


Lesenswert?

>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).

von Jam (Gast)


Lesenswert?

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

von Jörg S. (joerg-s)


Lesenswert?

>ich mein können diese auch größer sein??
Die Zeiten können i.d.R. auch immer größer sein.

von Jam (Gast)


Lesenswert?

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

von Jörg S. (joerg-s)


Lesenswert?

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

von Jörg S. (joerg-s)


Lesenswert?

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.

von Jam (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Jörg S. (joerg-s)


Lesenswert?

Was geht denn schon oder was nicht? Blinkt der Cursor schon? Wenn nicht 
müsste man wohl erst mal bei der initLCD(); anfangen.

von Jam (Gast)


Lesenswert?

Der Cursor blingt, es sind auch zwei zeilen sichtbar, es sieht so aus 
als ob mit der init alles in ordnung ist. ????

von Jam (Gast)


Angehängte Dateien:

Lesenswert?

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

von Jörg S. (joerg-s)


Lesenswert?

>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
}

von Jam (Gast)


Lesenswert?

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

von Jam (Gast)


Lesenswert?

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

von Jörg S. (joerg-s)


Lesenswert?

>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
}

von Jam (Gast)


Lesenswert?

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

von Jörg S. (joerg-s)


Lesenswert?

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

von Jam (Gast)


Lesenswert?

Axo hab ich mir fast gedacht. danke nochmal

von Jam (Gast)


Lesenswert?

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

von Jörg S. (joerg-s)


Lesenswert?

T2R vergessen?

von Jam (Gast)


Lesenswert?

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

von Jörg S. (joerg-s)


Lesenswert?

Sehe den Fehler auf anhieb jetzt nicht. Schau doch erst mal ob der Timer 
läuft.

von B. J. (bjue)


Lesenswert?

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.

von Jam (Gast)


Lesenswert?

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
}

von B. J. (bjue)


Lesenswert?

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.

von Jam (Gast)


Lesenswert?

Axo, bin jetzt einwenig schlauer.
danke

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
Noch kein Account? Hier anmelden.