定时器 0
原理图
工作模式 0
配置定时器 0:
- 工作模式 0,16 位自动重装定时器;
- 时钟源来自内部系统时钟 / 12
- 允许其在计数溢出之后请求中断;
- 每次 T0 中断,反转一次 P1.1 的输出电平。
main.c 文件:
/**
* Interrupt Registers Definition
*/
sfr IE = 0xA8; /* Interrupt Enable Register */
/**
* Interrupt Registers Bits Definition
*/
/** IE */
#define GLOBAL_IE_EA (0x80)
#define T0_IE_ET0 (0x02)
/**
* Timer 0 Registers Definition
*/
sfr TCON = 0x88; /* Timer 0 & Timer 1 Control Register */
sfr TMOD = 0x89; /* Timer 0 & Timer 1 Working Mode */
sfr TL0 = 0x8A; /* Timer 0 Counter Low Register */
sfr TH0 = 0x8C; /* Timer 0 Counter High Register */
sfr AUXR = 0x8E; /* Auxiliary Register */
/**
* Timer 0 Registers Bits Definition
*/
/** TCON */
#define T0_TCON_TF0 (0x20) /* Timer 0 - Overflow Flag */
#define T0_TCON_TR0 (0x10) /* Timer 0 - Run Control */
/** TMOD */
#define T0_TMOD_GATE (0x08) /* Timer 0 - Gate Control */
#define T0_TMOD_CT (0x04) /* Timer 0 - Counter or Timer Selection */
#define T0_TMOD_M1 (0x02) /* Timer 0 - Mode Selection Bit 1 */
#define T0_TMOD_M0 (0x01) /* Timer 0 - Mode Selection Bit 0 */
/** AUXR */
#define T0_AUXR_T0x12 (0x80) /* Timer 0 - Speed Control */
/**
* Port 1 Registers Definition
*/
sfr P1 = 0x90; /* Port 1 Register */
sbit LED = P1^1;
void main() {
TMOD &= ~T0_TMOD_GATE;
TMOD &= ~T0_TMOD_CT; // T0 acts as a timer
TMOD &= ~(T0_TMOD_M1 | T0_TMOD_M0); // Mode 0: 16-bit auto-reload
TH0 = (65536 - 10000) >> 8; // 8 MSB
TL0 = (65536 - 10000) & 0xFF; // 8 LSB
// AUXR |= T0_AUXR_T0x12; // T0's clock source is divided by 1
TCON &= ~T0_TCON_TF0; // Clear T0 overflow flag
TCON |= T0_TCON_TR0; // T0 run
IE |= T0_IE_ET0; // Enable T0 overflow interrupt request
IE |= GLOBAL_IE_EA; // Enable global interrupt
while(1) {}
}
void Timer0InterruptService() interrupt 1 {
LED = !LED;
}
使用 STC-ISP 下载程序,频率设为 12.000 MHz:
注意:虽然 STC-ISP 提示下载失败!但是,我发现单片机仍然按照我的设想执行程序,这里可能是 STC-ISP 有问题。
对 T0 的时钟源进行 12 分频(AUXR &= ~T0_AUXR_T0x12;
),测量 P1.1 输出:
注意:虽然在原理图中,我给单片机的电源符号是 5V,但是在实际测试中,我使用的是 USB 转串口模块上提供的 3.3V(实测没有 3.3V),这并不妨碍单片机正常运行。
不对 T0 的时钟源进行分频(AUXR |= T0_AUXR_T0x12;
),测量 P1.1 输出:
模块化处理
把所有的代码写在一个 main.c 文件是非常不好的习惯,我们需要将上例中的定时器 2 模块化处理:
- 将 1 ~ 35 行提取到 stc15w204s.h 头文件中;
- 将 47 ~ 59 行封装成函数,在 timer0.c 文件中实现,在 timer0.h 头文件中声明。
工程结构:
stc15w204s.h 头文件:
- 声明有关定时器 0 的特殊功能寄存器;
- 声明有关定时器 0 的特殊功能寄存器的位掩码;
- 以及其他。
#ifndef __STC15W204S_H
#define __STC15W204S_H
/**
* Interrupt Registers Definition
*/
sfr IE = 0xA8; /* Interrupt Enable Register */
/**
* Interrupt Registers Bits Definition
*/
/** IE */
#define GLOBAL_IE_EA (0x80)
#define T0_IE_ET0 (0x02) /* Timer 0 interrupt enable */
/**
* Timer 0 Registers Definition
*/
sfr TCON = 0x88; /* Timer 0 & Timer 1 Control Register */
sfr TMOD = 0x89; /* Timer 0 & Timer 1 Working Mode */
sfr TL0 = 0x8A; /* Timer 0 Counter Low Register */
sfr TH0 = 0x8C; /* Timer 0 Counter High Register */
sfr AUXR = 0x8E; /* Auxiliary Register */
/**
* Timer 0 Registers Bits Definition
*/
/** TCON */
#define T0_TCON_TF0 (0x20) /* Timer 0 - Overflow Flag */
#define T0_TCON_TR0 (0x10) /* Timer 0 - Run Control */
/** TMOD */
#define T0_TMOD_GATE (0x08) /* Timer 0 - Gate Control */
#define T0_TMOD_CT (0x04) /* Timer 0 - Counter or Timer Selection */
#define T0_TMOD_M1 (0x02) /* Timer 0 - Mode Selection Bit 1 */
#define T0_TMOD_M0 (0x01) /* Timer 0 - Mode Selection Bit 0 */
/** AUXR */
#define T0_AUXR_T0x12 (0x80) /* Timer 0 - Speed Control */
/**
* Port 1 Registers Definition
*/
sfr P1 = 0x90; /* Port 1 Register */
typedef enum {
FALSE = 0,
TRUE = !FALSE
} boolean;
#define enableInterrupts(enable) if(enable) { \
IE |= GLOBAL_IE_EA; \
} else { \
IE &= ~GLOBAL_IE_EA; \
}
#endif
timer0.h 头文件:
#ifndef __STC15W204S_TIMER_0_H
#define __STC15W204S_TIMER_0_H
#include "stc15w204s.h"
typedef enum {
TIMER0_PRESCALER_DIVIDED_BY_1 = 1,
TIMER0_PRESCALER_DIVIDED_BY_12 = 12
} Timer0Prescaler;
typedef enum {
TIMER0_COUNTER_MODE_0 = ((unsigned char)0x00),
TIMER0_COUNTER_MODE_1 = ((unsigned char)0x01),
TIMER0_COUNTER_MODE_2 = ((unsigned char)0x02),
TIMER0_COUNTER_MODE_3 = ((unsigned char)0x03)
} Timer0CounterMode;
typedef struct {
void (*asTimer)(boolean);
void (*setCounterMode)(Timer0CounterMode);
void (*set8BitCounter)(unsigned char);
void (*set16BitCounter)(unsigned int);
void (*setPrescaler)(Timer0Prescaler);
void (*start)(boolean);
void (*enableInterrupt)(boolean);
} Timer0;
extern Timer0 timer0;
/**
* First call to this function to initialize
* the <code>timer0</code> variable.
*/
void Timer0Constructor();
#endif
timer2.c 文件:
#include "timer0.h"
Timer0 timer0;
/**
* If true, timer 0 acts as timer,
* otherwise it acts as counter.
*/
static void asTimer(boolean isTimer) {
if(isTimer) {
TMOD &= ~T0_TMOD_CT;
} else {
TMOD |= T0_TMOD_CT;
}
}
/**
* Set the counter mode of the timer 0.
*/
static void setCounterMode(Timer0CounterMode mode) {
switch(mode) {
case TIMER0_COUNTER_MODE_0:
TMOD &= ~(T0_TMOD_M1 | T0_TMOD_M0);
break;
case TIMER0_COUNTER_MODE_1:
TMOD &= ~T0_TMOD_M1;
TMOD |= T0_TMOD_M0;
break;
case TIMER0_COUNTER_MODE_2:
TMOD |= T0_TMOD_M1;
TMOD &= ~T0_TMOD_M0;
break;
case TIMER0_COUNTER_MODE_3:
TMOD |= (T0_TMOD_M1 | T0_TMOD_M0);
break;
}
}
/**
* Set the initial value of the counter
* or the timer 0, This only for mode 2.
*/
static void set8BitCounter(unsigned char counter) {
TH0 = counter;
TL0 = TH0;
}
/**
* Set the initial value of the counter
* or the timer 0.
*/
static void set16BitCounter(unsigned int counter) {
TH0 = (counter) >> 8;
TL0 = (counter) & 0xff;
}
/**
* Set the prescaler of the timer 0.
*/
static void setPrescaler(Timer0Prescaler prescaler) {
switch(prescaler) {
case TIMER0_PRESCALER_DIVIDED_BY_1:
AUXR |= T0_AUXR_T0x12;
break;
case TIMER0_PRESCALER_DIVIDED_BY_12:
AUXR &= ~T0_AUXR_T0x12;
break;
}
}
/**
* If true, start the timer 0 to run,
* othewise, stop.
*/
static void start(boolean start) {
if(start) {
TCON |= T0_TCON_TR0;
} else {
TCON &= ~T0_TCON_TR0;
}
}
/**
* If true, enable timer 0 overflow
* interrupt request, othewise, disable.
*/
static void enableInterrupt(boolean enable) {
if (enable) {
IE |= T0_IE_ET0;
} else {
IE &= ~T0_IE_ET0;
}
}
/**
* First call to this function to initialize
* the <code>timer0</code> variable.
*/
void Timer0Constructor() {
timer0.asTimer = &asTimer;
timer0.setCounterMode = &setCounterMode;
timer0.set8BitCounter = &set8BitCounter;
timer0.set16BitCounter = &set16BitCounter;
timer0.setPrescaler = &setPrescaler;
timer0.start = &start;
timer0.enableInterrupt = &enableInterrupt;
}
将定时器 0 的功能模块化处理之后,main.c 文件如下:
/**
* STC15W204S-35I SOP16
* Timer 0 - Mode 0: 16 bit, auto-reload
*/
#include "timer0.h"
sbit LED = P1^1;
void main() {
Timer0Constructor();
timer0.asTimer(TRUE);
timer0.setCounterMode(TIMER0_COUNTER_MODE_0);
timer0.setPrescaler(TIMER0_PRESCALER_DIVIDED_BY_1);
// timer0.set8BitCounter(256 - 100);
timer0.set16BitCounter(65536 - 10000);
timer0.start(TRUE);
timer0.enableInterrupt(TRUE);
enableInterrupts(TRUE);
while(1) {}
}
void timer0InterruptService() interrupt 1 {
LED = !LED;
}