Timer2 is another timer/counter of 8051 architecture. Timer2 has four modes of operation.
1. Normal Timer mode
T2 = External clock source input pin / Clock output pin form Timer2
Now I am going to describe you how to write a driver routine to so that firmware layer can use it.
Its very simple to organize whole concept with minimal set of functions.
[Here is the detailed code for Timer2 library]
[timer2.h]
#ifndef __TIMER_2_H__
#define __TIMER_2_H__
#include <ioat89c55wd.h>
#define TIMER2_REG_LOW TL2
#define TIMER2_REG_HIGH TH2
#define Timer2_SetRegister(val) \
{ \
TL2 = (unsigned char) val; \
TH2 = (unsigned char) (val >> 8); \
}
#define TIMER2_CAPREG_LOW RCAP2L
#define TIMER2_CAPREG_HIGH RCAP2H
#define Timer2_SetRelod(val) \
{ \
RCAP2L = (unsigned char) val; \
RCAP2H = (unsigned char) (val >> 8); \
}
#define Timer2_Run() T2CON_bit.TR2 = timer2_on
#define Timer2_Stop() T2CON_bit.TR2 = timer2_off
#define Timer2_SetState(timer2_states) T2CON_bit.TR2 = timer2_states
#define Timer2_SetExtClock(timer2_clktype) T2MOD_bit.T2OE = timer2_clktype
typedef union {
unsigned int value;
struct {
unsigned char low;
unsigned char high;
};
} t_timer2_register;
typedef enum {
timer2_dir_up = 0,
timer2_dir_dn = 1
} timer2_dir;
typedef enum {
timer2_clktype_input = 0,
timer2_clktype_output = 1
} timer2_clktype;
enum timer2_clk_src {
timer2_clk_internal = 0,
timer2_clk_external = 1
};
typedef enum {
timer2_off = 0,
timer2_on = 1
} timer2_states;
typedef enum {
timer2_mode_normal = 0, // Normal mode
timer2_mode_capture = 1, // Capture mode
timer2_mode_reload = 2, // Auto Reload mode
timer2_mode_baudgen = 3 // Baud Rate Generator mode
} timer2_mode;
struct t_timer2_callbacks {
void (*pfnOverflow) (t_timer2_register *);
void (*pfnExternal) (t_timer2_register *);
};
void Timer2_Init(timer2_mode,enum timer2_clk_src);
void Timer2_RegCallbacks(struct t_timer2_callbacks *);
void Timer2_UnregCallbacks();
#endif
[Timer2.c]
#include "timer2.h"
static struct t_timer2_callbacks *p_timer2_callbacks;
static t_timer2_register timer2_counter;
#pragma vector=0x2B
__interrupt void timer2_interrupt_handler(void) {
if(T2CON_bit.TF2 == 1) {
timer2_counter.high = TIMER2_REG_HIGH;
timer2_counter.low = TIMER2_REG_LOW;
p_timer2_callbacks->pfnOverflow(&timer2_counter);
}
if(T2CON_bit.EXF2 == 1) {
timer2_counter.high = TIMER2_CAPREG_HIGH;
timer2_counter.low = TIMER2_CAPREG_LOW;
p_timer2_callbacks->pfnExternal(&timer2_counter);
T2CON_bit.EXF2 = 0;
}
}
void Timer2_Init(timer2_mode mode,enum timer2_clk_src clk_src) {
switch(mode) {
case timer2_mode_normal:
T2CON = 0x00 << 4;
T2CON_bit.EXEN2 = 0;
T2CON_bit.CP_RL2 = 1;
break;
case timer2_mode_capture:
T2CON = 0x00 << 4;
T2CON_bit.EXEN2 = 1;
T2CON_bit.CP_RL2 = 1;
break;
case timer2_mode_reload:
T2CON = 0x00 << 4;
T2CON_bit.EXEN2 = 1;
T2CON_bit.CP_RL2 = 0;
break;
case timer2_mode_baudgen:
T2CON = 0x03 << 4;
break;
}
T2CON_bit.C_T2 = clk_src;
T2MOD_bit.DCEN = 1;
}
void Timer2_RegCallbacks(struct t_timer2_callbacks *pCallbacks) {
IE_bit.ET2 = 1;
p_timer2_callbacks = pCallbacks;
}
void Timer2_UnregCallbacks() {
IE_bit.ET2 = 0;
}
[Timer2 mode: Normal]
int main( void )
{
Timer2_Init(timer2_mode_normal,timer2_clk_internal);
Timer2_SetRegister(0x0000);
Timer2_RegCallbacks(&timer2_callbacks);
IE_bit.EA = 1; // Enable global interrupt
Timer2_Run();
while(1) { /* User codes will go here */ }
//return 0;
}
[Timer2 mode: Capture]
int main( void )
{
Timer2_Init(timer2_mode_capture,timer2_clk_internal);
Timer2_SetRegister(0x0000);
Timer2_RegCallbacks(&timer2_callbacks);
IE_bit.EA = 1; // Enable global interrupt
Timer2_Run();
while(1) { /* User codes will go here */ }
//return 0;
}
[Timer2 mode: Auto-Reload]
int main( void )
{
Timer2_Init(timer2_mode_reload,timer2_clk_internal);
Timer2_SetRegister(0xFF00);
Timer2_SetRelod(0xFF00);
Timer2_RegCallbacks(&timer2_callbacks);
IE_bit.EA = 1; // Enable global interrupt
Timer2_Run();
while(1) { /* User codes will go here */ }
//return 0;
}
[Timer2 mode: BaudRate Genetrator]
int main( void )
{
Timer2_SetExtClock(timer2_clktype_output);
Timer2_Init(timer2_mode_baudgen,timer2_clk_internal);
Timer2_SetRelod(0xFF00);
Timer2_RegCallbacks(&timer2_callbacks);
IE_bit.EA = 1; // Enable global interrupt
Timer2_Run();
while(1) { /* User codes will go here */ }
//return 0;
}
Now I will show a complete main.c file which should look like
#include <timer_0_1.h>
#include <timer2.h>
#include <ioat89c55wd.h>
unsigned int capval;
void Timer2Ovrflow(t_timer2_register *);
void Timer2External(t_timer2_register *);
static struct t_timer2_callbacks timer2_callbacks = {
.pfnOverflow = Timer2Ovrflow,
.pfnExternal = Timer2External
};
int main( void )
{
Timer2_Init(timer2_mode_capture,timer2_clk_internal);
Timer2_SetRegister(0x0000);
Timer2_RegCallbacks(&timer2_callbacks);
IE_bit.EA = 1; // Enable global interrupt
Timer2_Run();
while(1) { /* User codes will go here */ }
//return 0;
}
void Timer2Ovrflow(t_timer2_register *p_timer2_register) {
Timer2_SetRegister(0x0000);
P0 = P0 ^ 0x01; // Toggle to show action on P0.0
}
void Timer2External(t_timer2_register *p_timer2_register) {
capval = p_timer2_register->value;
P0 = P0 ^ 0x02; // Toggle to show action on P0.1
}
N.B: Thanks for reading my article. I will update more this article latter. Requesting for your suggestions. Serial port is coming soon.
1. Normal Timer mode
2. Capture mode
3. Auto-Reload mode
4. Baud Rate Generator mode
Timer2 has a T2CON register which controls the basic operating parameters of it. T2MOD is another register which controls counting direction and a I/O port alternate function for Timer2. Now we are going to dig into Timer2 architecture.
[Modes Selection Table]
Following table shows bit status for each operating mode.
[Modes Selection Table]
Following table shows bit status for each operating mode.
RCLK + TCLK
|
CP / RL2
|
TR2
|
EXEN2
|
Mode
|
0
|
1
|
1
|
0
|
16 bit normal
|
0
|
0
|
1
|
X
|
16 bit auto-reload |
0
|
1
|
1
|
1
|
16 bit capture |
1
|
X
|
1
|
X | baud rate generator |
X
|
X
|
0
|
X
|
off
|
[T2CON Register]
T2CON register is used to control Timer2 and for selecting operating modes. It also reflects various interrupt events. Details are shown in the following table.
T2CON register is used to control Timer2 and for selecting operating modes. It also reflects various interrupt events. Details are shown in the following table.
[T2MOD Register]
T2MOD register controls clock input or output from Timer2. In auto-reload mode counting direction can also be changed by using following register.
[Interrupt vector addresses]
Both Timer2 overflow (TF2) and Timer2 External (EXF2) vector at the same address at 002BH. We can distinguish them by checking bits in the T2CON register.
Now I will show 4 block diagrams for Timer2 operating modes. Before that I will discuss some symbolic text used to describe block diagrams.
T2 = External clock source input pin / Clock output pin form Timer2
T2EX = External pin for controlling Timer2 module. These pins actually used for general purpose interrupt
C/T2 = Counter / Timer operation control bit
TR2 = Timer run control bit
TH2 = Timer register high byte
TL2 = Timer register low byte
TF2 = Timer overflow event detection bit
TR2 = Timer run control bit
TH2 = Timer register high byte
TL2 = Timer register low byte
TF2 = Timer overflow event detection bit
EXF2 = Timer external event detection bit
[Normal Mode Block Diagram]
[Capture Mode Block Diagram]
[Auto-Reload Mode Block Diagram]
[BaudRate Generator Mode Block Diagram]
Its very simple to organize whole concept with minimal set of functions.
[Here is the detailed code for Timer2 library]
[timer2.h]
#ifndef __TIMER_2_H__
#define __TIMER_2_H__
#include <ioat89c55wd.h>
#define TIMER2_REG_LOW TL2
#define TIMER2_REG_HIGH TH2
#define Timer2_SetRegister(val) \
{ \
TL2 = (unsigned char) val; \
TH2 = (unsigned char) (val >> 8); \
}
#define TIMER2_CAPREG_LOW RCAP2L
#define TIMER2_CAPREG_HIGH RCAP2H
#define Timer2_SetRelod(val) \
{ \
RCAP2L = (unsigned char) val; \
RCAP2H = (unsigned char) (val >> 8); \
}
#define Timer2_Run() T2CON_bit.TR2 = timer2_on
#define Timer2_Stop() T2CON_bit.TR2 = timer2_off
#define Timer2_SetState(timer2_states) T2CON_bit.TR2 = timer2_states
#define Timer2_SetExtClock(timer2_clktype) T2MOD_bit.T2OE = timer2_clktype
typedef union {
unsigned int value;
struct {
unsigned char low;
unsigned char high;
};
} t_timer2_register;
typedef enum {
timer2_dir_up = 0,
timer2_dir_dn = 1
} timer2_dir;
typedef enum {
timer2_clktype_input = 0,
timer2_clktype_output = 1
} timer2_clktype;
enum timer2_clk_src {
timer2_clk_internal = 0,
timer2_clk_external = 1
};
typedef enum {
timer2_off = 0,
timer2_on = 1
} timer2_states;
typedef enum {
timer2_mode_normal = 0, // Normal mode
timer2_mode_capture = 1, // Capture mode
timer2_mode_reload = 2, // Auto Reload mode
timer2_mode_baudgen = 3 // Baud Rate Generator mode
} timer2_mode;
struct t_timer2_callbacks {
void (*pfnOverflow) (t_timer2_register *);
void (*pfnExternal) (t_timer2_register *);
};
void Timer2_Init(timer2_mode,enum timer2_clk_src);
void Timer2_RegCallbacks(struct t_timer2_callbacks *);
void Timer2_UnregCallbacks();
#endif
[Timer2.c]
#include "timer2.h"
static struct t_timer2_callbacks *p_timer2_callbacks;
static t_timer2_register timer2_counter;
#pragma vector=0x2B
__interrupt void timer2_interrupt_handler(void) {
if(T2CON_bit.TF2 == 1) {
timer2_counter.high = TIMER2_REG_HIGH;
timer2_counter.low = TIMER2_REG_LOW;
p_timer2_callbacks->pfnOverflow(&timer2_counter);
}
if(T2CON_bit.EXF2 == 1) {
timer2_counter.high = TIMER2_CAPREG_HIGH;
timer2_counter.low = TIMER2_CAPREG_LOW;
p_timer2_callbacks->pfnExternal(&timer2_counter);
T2CON_bit.EXF2 = 0;
}
}
void Timer2_Init(timer2_mode mode,enum timer2_clk_src clk_src) {
switch(mode) {
case timer2_mode_normal:
T2CON = 0x00 << 4;
T2CON_bit.EXEN2 = 0;
T2CON_bit.CP_RL2 = 1;
break;
case timer2_mode_capture:
T2CON = 0x00 << 4;
T2CON_bit.EXEN2 = 1;
T2CON_bit.CP_RL2 = 1;
break;
case timer2_mode_reload:
T2CON = 0x00 << 4;
T2CON_bit.EXEN2 = 1;
T2CON_bit.CP_RL2 = 0;
break;
case timer2_mode_baudgen:
T2CON = 0x03 << 4;
break;
}
T2CON_bit.C_T2 = clk_src;
T2MOD_bit.DCEN = 1;
}
void Timer2_RegCallbacks(struct t_timer2_callbacks *pCallbacks) {
IE_bit.ET2 = 1;
p_timer2_callbacks = pCallbacks;
}
void Timer2_UnregCallbacks() {
IE_bit.ET2 = 0;
}
[Timer2 mode: Normal]
int main( void )
{
Timer2_Init(timer2_mode_normal,timer2_clk_internal);
Timer2_SetRegister(0x0000);
Timer2_RegCallbacks(&timer2_callbacks);
IE_bit.EA = 1; // Enable global interrupt
Timer2_Run();
while(1) { /* User codes will go here */ }
//return 0;
}
[Timer2 mode: Capture]
int main( void )
{
Timer2_Init(timer2_mode_capture,timer2_clk_internal);
Timer2_SetRegister(0x0000);
Timer2_RegCallbacks(&timer2_callbacks);
IE_bit.EA = 1; // Enable global interrupt
Timer2_Run();
while(1) { /* User codes will go here */ }
//return 0;
}
[Timer2 mode: Auto-Reload]
int main( void )
{
Timer2_Init(timer2_mode_reload,timer2_clk_internal);
Timer2_SetRegister(0xFF00);
Timer2_SetRelod(0xFF00);
Timer2_RegCallbacks(&timer2_callbacks);
IE_bit.EA = 1; // Enable global interrupt
Timer2_Run();
while(1) { /* User codes will go here */ }
//return 0;
}
[Timer2 mode: BaudRate Genetrator]
int main( void )
{
Timer2_SetExtClock(timer2_clktype_output);
Timer2_Init(timer2_mode_baudgen,timer2_clk_internal);
Timer2_SetRelod(0xFF00);
Timer2_RegCallbacks(&timer2_callbacks);
IE_bit.EA = 1; // Enable global interrupt
Timer2_Run();
while(1) { /* User codes will go here */ }
//return 0;
}
Now I will show a complete main.c file which should look like
#include <timer_0_1.h>
#include <timer2.h>
#include <ioat89c55wd.h>
unsigned int capval;
void Timer2Ovrflow(t_timer2_register *);
void Timer2External(t_timer2_register *);
static struct t_timer2_callbacks timer2_callbacks = {
.pfnOverflow = Timer2Ovrflow,
.pfnExternal = Timer2External
};
int main( void )
{
Timer2_Init(timer2_mode_capture,timer2_clk_internal);
Timer2_SetRegister(0x0000);
Timer2_RegCallbacks(&timer2_callbacks);
IE_bit.EA = 1; // Enable global interrupt
Timer2_Run();
while(1) { /* User codes will go here */ }
//return 0;
}
void Timer2Ovrflow(t_timer2_register *p_timer2_register) {
Timer2_SetRegister(0x0000);
P0 = P0 ^ 0x01; // Toggle to show action on P0.0
}
void Timer2External(t_timer2_register *p_timer2_register) {
capval = p_timer2_register->value;
P0 = P0 ^ 0x02; // Toggle to show action on P0.1
}
N.B: Thanks for reading my article. I will update more this article latter. Requesting for your suggestions. Serial port is coming soon.






No comments:
Post a Comment