Arbeiten mit Timern

Erstellen von Rechtecksignalen

Mit der ISR des Timers kann ein kontinuierliches Rechtecksignal an einem Portpin er­zeugt werden. Die minimale bzw. maximale Frequenz hängt von der Betriebsart des Timers ab. Die Taktfrequenz des Timers errechnet sich wie folgt:

PCLK = CCLK/2 = OSCCLK/(DIVM *4)

Mit der Betriebsart 2 des Timers kann eine maximale Frequenz von 200 kHz, mit Be­triebs­art 1 des Timers kann eine minimale Frequenz von 28 Hz bei Verwendung des RC-Oscillator erreicht werden.

Erstellen sie eine Rechteckspannung von ti/T = 0.5 und einer Frequenz von 1 kHz. Der Reloadwert für den Timer beträgt somit 0.5 ms/PCLK = 0.5 ms/0.2712 µs = 1843. Dieser Wert kann nur mit den Betriebsarten 1 und 2 verarbeitet werden. Verwenden sie für dieses Beispiel die Betriebsart 2. In der ISR des Timers soll der Zustand des Portpins P2.0 invertiert werden. Der Reloadwert ist in der Variablen „uiTime“ abgespeichert (siehe Listing 47, ). Die Initialisierung des Timers und das Setzen der ersten Timer­wer­te werden in der Funktion „v_ InitTimer0()“ vorgenommen (siehe , ƒ). Der Reload­wert für den Timer 0 wird am Anfang der ISR durchgeführt (siehe ). Das Toggeln des Ausgangssignals wird erst danach durchgeführt (siehe ).

Projektname

Verzeichnis

Verwendete Sourcemodule

Test_TimRec

Test_TimerRectangle

Test_Timer0Rectangle.c

 

..\Library

PortConfig.c

Tabelle 53  Projekt Test_TimRec

 

 

 

 

 

 

 

 

ƒ

ƒ

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

#include <REG932.H>

#include <PortConfig.H>

 

sbit btClk = P2^0;

unsigned int uiTime = 0xF8CC;

 

void v_InitTimer0(void)

{

  TMOD = 0x01;

 

  TH0 = uiTime/256;

  TL0 = (unsigned char) uiTime;

  TF0 = 0;

  ET0 = 1;

}

 

void main(void)

{

  v_PortConfig(Port2, Pin0 | Pin1 | Pin2, PushPull);

  v_InitTimer0();

  TR0 = 1;

  EA = 1;

  while(1);

}

 

void v_Timer0Int(void) interrupt 1

{

  TH0 = uiTime/256;

  TL0 = (unsigned char) uiTime;

  btClk = !btClk;

}

Listing 47  Inhalt von Test_Timer0Rectangle.c

Abbildung 46 enthält das Signal vom Portpin btClk (P2.0). Die geringfügige Abweichung von der 1 kHz-Frequenz ergibt sich aus der Toleranz des RC-Oscillators.

Abbildung 46  Timer 0, Betriebsart 1, 1kHz

Erstellen sie ein Projekt, bei dem mit Hilfe des Inkrementalgebers die Frequenz ein­stell­bar ist.

Projektname

Verzeichnis

Verwendete Sourcemodule

Test_TrimFreq

Test_TrimFreq

Test_TrimFreq.c

 

..\Library

PortConfig.c, Encoder_Lib.c

Tabelle 54  Projekt Test_TrimFreq

 

 

 

 

 

 

 

 

ƒ

ƒ

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

#include <REG932.H>

#include <Encoder_Lib.h>

#include <PortConfig.H>

 

sbit btClk = P2^2;

unsigned int uiTime = 0xF8D2; // 1 kHz beim RC-Oscillator

void v_InitTimer0(void)

{

  TMOD = 0x01;

  TH0 = uiTime/256;

  TL0 = (unsigned char) uiTime;

  TF0 = 0;

  ET0 = 1;

}

 

void main(void)

{

  v_InitEncoder();

  v_PortConfig(Port2, Pin0 | Pin1 | Pin2, PushPull);

  v_InitTimer0();

  TR0 = 1;

  EA = 1;

  while(1)

  {

    while (cValue == 0); // Warten bis Encoder gedreht wurde

    if (cValue > 0 & uiTime < 0xFFFF)

      uiTime++;

    else if (uiTime > 0)

      uiTime--;

    cValue = 0;

  }

}

 

void v_Timer0Int(void) interrupt 1

{

  TH0 = uiTime/256;

  TL0 = (unsigned char) uiTime;

  btClk = !btClk;

}

Listing 48  Inhalt von Test_Timer0Rectangle.c

Erweitern sie das Projekt so, dass der Reloadwert für den Timer 1 auf der 7-Seg­ment-Anzeige aus­ge­ge­ben wird. Um die Ausgabe zu realisieren, müssen die Sourcemo­du­le „I2C_Lib.c“ und „SAA1064_Lib.c“ mit in das Projekt aufgenommen werden (siehe Tabelle 55, Abschnitt „Verwendete Sourcemodule“). Um die Funktionen im Source­mo­dul „Test_TrimFreq.c“ bekannt zu machen, müssen die H-Files inkludiert werden (siehe Listing 49, und ). Die Initialisierung des I²C-Busses erfolgt in der Funktion „v_InitI2C()“ (siehe ƒ). Um den SAA1064 zu initialisieren, muss zuerst die allgemeine Interruptsperre aufgehoben werden (siehe ). Die Umrechnung des Reloadwertes und die Ausgabe erfolgt am Anfang der while-Schleife (siehe ).

Projektname

Verzeichnis

Verwendete Sourcemodule

Test_TrimFreq

Test_TrimFreq

Test_TrimFreq.c

 

..\Library

PortConfig.c, Encoder_Lib.c, I2C_Lib.c, SAA1064_Lib.c

Tabelle 55  Projekt Test_TrimFreq (erweitert)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ƒ

 

 

 

 

 

 

 

 

#include <REG932.H>

#include <Encoder_Lib.h>

#include <I2C_LIB.H>

#include <SAA1064_LIB.h>

#include <PortConfig.H>

 

sbit btClk = P2^2;

unsigned int uiTime = 0xF8D2; // 1 kHz beim RC-Oscillator

void v_InitTimer0(void)

{

  TMOD = 0x01;

  TH0 = uiTime/256;

  TL0 = (unsigned char) uiTime;

  TF0 = 0;

  ET0 = 1;

}

 

void main(void)

{

  v_InitI2C();

  v_InitEncoder();

  v_PortConfig(Port2, Pin0 | Pin1 | Pin2, PushPull);

  v_InitTimer0();

  TR0 = 1;

  EA = 1;

  v_InitSAA1064(DYNAMIC_MODE);

  while(1)

  {

    Slave.DataLen = 0;   

    Slave.Adr = 0x70;      // Adresse SAA1064   

    v_SetNextI2CVal(1);    // Subadresse auf 1 (Daten-Byte)

    v_ConvVal(uiTime/0x1000); // Umrechung des Reloadwertes (MSB)

    v_ConvVal((uiTime & 0xF00)/0x100);

    v_ConvVal((uiTime & 0xF0)/0x10);

    v_ConvVal(uiTime & 0x0F); // Umrechung des Reloadwertes (LSB)

    v_StartI2CandWait();

    while (cValue == 0); // Warten bis Encoder gedreht wurde

    if (cValue > 0 & uiTime < 0xFFFF)

      uiTime++;

    else if (uiTime > 0)

      uiTime--;

    cValue = 0;

  }

}

 

void v_Timer0Int(void) interrupt 1

{

  TH0 = uiTime/256;

  TL0 = (unsigned char) uiTime;

  btClk = !btClk;

}

Listing 49  Inhalt von Test_TrimFreq.c

Konfigurieren der Timer mit Hilfe von Libraryfunktionen

Da die beiden Timer 0 und 1 über die SFR TMOD und TAMOD konfiguriert werden, ist es sinnvoll, diese mit Hilfe von Funktionen zu initialisieren. Die Funktionen übernehmen das nötige Ausmaskieren und Setzen der jeweiligen Bits in den SFR. Damit der Übergabewert an die Initialisierungsfunktion nicht in einem HEX-Wert geschrieben werden muss, sind für die einzelnen Betriebsarten des Timers enum-Aufzählungstypen im H-File definiert (siehe Listing 50, und ). Für jeden der beiden Timer ist eine eigene Funktion zur Ini­tia­li­sie­rung des Timers erstellt worden (siehe ƒ, ). Die Definitionen in den enum-Aufzählungstypen sind so gelegt worden, dass alle zulässigen Kombinationen in einem Byte abgespeichert werden können. Dadurch ist der Programmcode klein.

 

 

 

ƒ

enum enTimerMode {MODE0 =0, MODE1, MODE2, MODE3, MODE6 = 0x12};

enum enTimerFunc {TIMER = 0, COUNTER = 4, GATE_OFF = 0,

                  GATE_ON = 8, PWM_OFF = 0, PWM_ON = 0x20};

 

// Funktionsdeklaration

void v_InitTimer0(unsigned char ucMode);

void v_InitTimer1(unsigned char ucMode);

Listing 50  Inhalt von TestTimerLib.h

Am Anfang der Initialisierung des Timers werden zuerst alle Bits in den SFR TMOD und AUXR1 auf „0“ gesetzt (siehe Listing 51, ). Als nächstes wird überprüft, ob der Timer in der Betriebsart 6 (Mode 6) arbeiten soll (siehe ). Ist dies der Fall, wird das jeweilige Bit im SFR TAMOD gesetzt (siehe ƒ). In dieser Programmverzweigung wird auch überprüft, ob das PWM-Signal aktiviert werden soll (siehe ). Ist dies der Fall wird das jeweilige Bit im SFR AUXR1 gesetzt. Trifft die Betriebsart 6 nicht zu, wird das jeweilige Bit im SFR TAMOD gelöscht (siehe ). In der letzten Zeile (siehe ) wird die Betriebsart in das TMOD-Register geschrieben.

 

 

 

 

 

 

 

ƒ

 

 

 

 

 

 

 

 

ƒ

 

 

 

 

 

#include <REG932.H>

#include <TimerLibrary.h>

 

void v_InitTimer0(unsigned char ucMode)

{

  // Einstellung der Betriebsart

  TMOD  = TMOD  & 0xF0;

  AUXR1 = AUXR1 & 0xEF; // Externen PWM-Ausgang abschalten

  if ((ucMode & MODE6) == MODE6) // Ueberpruefung auf Betriebsart

  {                              // 6 (PWM)

    TAMOD = TAMOD | 0x01;

    if ((ucMode & PWM_ON) == PWM_ON)

      AUXR1 = AUXR1 | 0x10;

    ucMode = ucMode & 0x0F;  // MODE6-Codierung und PWM-Info ausb.

  }

  else

    TAMOD = TAMOD & 0xFE;

  TMOD  = TMOD | ucMode;

}

 

void v_InitTimer1(unsigned char ucMode)

{

  // Einstellung der Betriebsart

  TMOD  = TMOD  & 0x0F;

  AUXR1 = AUXR1 & 0xDF; // Externen PWM-Ausgang abschalten

  if ((ucMode & MODE6) == MODE6) // Ueberpruefung auf Betriebsart  

  {                              // 6 (PWM)

    TAMOD = TAMOD | 0x10;

    if ((ucMode & PWM_ON) == PWM_ON)

      AUXR1 = AUXR1 | 0x20;

    ucMode = ucMode & 0x0F;  // MODE6-Codierung und PWM-Info ausb.

  }

  else

    TAMOD = TAMOD & 0xEF;

  TMOD  = TMOD | (ucMode * 16);

}

Listing 51  Inhalt von TestTimerLib.c

Erstellen sie nun das Projekt aus Tabelle 56, das die Funktionen „v_InitTimer0()“ und „v_InitTimer1()“ aus­tes­tet. Timer 0 soll in der Betriebsart 2 als Counter (siehe Listing 52, ) und Timer 2 in Betriebsart 6 als Timer mit aktiver PWM laufen (siehe ). Um die Aufzählungstypen MODE2, MODE6, ... verwenden zu können, muss das H-File Timerlibrary.h über die #include-Anweisung eingebunden werden (siehe ƒ).

Projektname

Verzeichnis

Verwendete Sourcemodule

Test_TimerLib

Test_TimerLib

Test_TimerLib.c

 

..\Library

PortConfig.c, TimerLibrary.c

Tabelle 56  Projekt Test_TimerLib

 

ƒ

 

 

 

 

 

 

#include <REG932.H>

#include <TimerLibrary.h>

#include <PortConfig.H>

 

void main(void)

{

  v_InitTimer0(MODE2 | COUNTER);

  v_InitTimer1(MODE6 | TIMER | PWM_ON);

  v_PortConfig(Port0, Pin7, PushPull);

  TH1 = 0xF0;

  P0 = 0xFF;

  TR1 = 1;

  while(1);

}

Listing 52  Inhalt von TestTimerLib.c