Feng HanXiu
Articles9
Tags0
Categories0

Archive

2024开源蓝桥系列(五):定时器与中断概念

2024开源蓝桥系列(五):定时器与中断概念

定时器与中断

一、 初步认知

什么是定时器?什么是中断?

1.定时器就是单片机里的一个“计时工具”,它就像一个自动计时的秒表。你可以设定它倒数或计数,时间一到就提醒你。这就好比你设置手机闹钟,当时间到了,手机就响起闹钟一样。

定时器的作用

  • 定时提醒:比如设定每1秒亮一下LED灯。
  • 精确延时:让某些操作延迟一会儿再执行。
  • 控制周期任务:比如定时读取传感器数据。

例子:假如你想让一个小风扇每隔2秒转动一下,就可以用定时器来实现。设定好2秒的时间,当时间一到,定时器就会提醒单片机“时间到了,该转动风扇了”。

2.中断可以理解为一种“紧急通知”机制。当单片机在忙着执行程序时,如果突然有一个更紧急的事情发生(就像你正在玩游戏,突然电话响了),中断会打断当前的程序,先去处理这个紧急事件。

中断的作用

  • 快速响应紧急情况:比如有人按下按钮,单片机立即停止当前工作,先去处理按钮的事情。
  • 节省时间:只有在需要时才执行某个操作,而不是一直轮询等待事件发生。

例子:假如你做了一个门铃系统,当有人按门铃时,中断就会打断单片机正在做的其他事情,让它立刻去响铃。这比单片机一直盯着按钮看有没有被按下要高效得多。

二、 定时器原理

1. 配置定时器:

  • 选择定时器模块(如 Timer0、Timer1)。
  • 设置预分频器(调整计数速度)。
  • 设定初始值(从哪个数开始计数)。

2. 启动定时器:

  • 启动后,定时器根据系统时钟和预分频器设置开始自动计数

3. 定时器计数:

  • 计数器从初始值开始递增
  • 当计数器达到最大值(如 255 或 65535)时,溢出

4. 触发溢出事件:

  • 溢出时,定时器自动生成中断信号。
  • 执行中断服务程序(ISR)来处理特定任务。

三、 如何使用定时器

1. 从STC工具中生成需要的定时器:

  • 选择定时周期。
  • 设置预分频器

2. 复制到程序中:

  • 定义到main()函数之前。

3. while(1)之前调用初始化函数:

  • 调用后定时器就启动了,会定时触发中断执行中断服务函数中的内容。

四、 示例代码

1. 从STC工具中生成的定时器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void Timer0_Isr(void) interrupt 1
{

}

void Timer0_Init(void) //1000微秒@12.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
}

2. 具体使用案例(定时切换数码管显示界面,数码管部分代码与上一节相同):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include <STC15F2K60S2.H>
#include <intrins.h>

unsigned char code SMG[10] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90}; // 共阳极数码管段码表
// 0 1 2 3 4 5 6 7 8 9

/* 数码管动态显示 */

void Delay1ms() //@12.000MHz
{
unsigned char i, j;

i = 12;
j = 169;
do
{
while (--j);
} while (--i);
}

void delay_ms(int x)
{
while(x--)
{
Delay1ms();
}
}

void slect_138_573(unsigned char channel, unsigned char dat)
{
/* 选择通道并且输入数据 */
P0 = 0x00; /* 将原来P0口中的数据清0 */
P0 = dat; /* 这里用P0而不用其他端口是因为我们操作LED、数码管、继电器、蜂鸣器都是对P0进行操作 */
switch(channel) /* 选择通道 */
{
case 4: /* 使Y4输出低电平0,也就是操作LED */
P2 = (P2 & 0x1f) | 0x80; /* (P2 & 0x1f)就是将前3位清0,再操作前3位。将0x80转为2进制1000 0000,这里只看前3位100就是Y4 */
break;
case 5: /* 使Y5输出低电平0,也就是操作继电器和蜂鸣器 */
P2 = (P2 & 0x1f) | 0xa0;
break;
case 6: /* 使Y6输出低电平0,也就是操作8个数码管 */
P2 = (P2 & 0x1f) | 0xc0;
break;
case 7: /* 使Y7输出低电平0,也就是操作8个数码管中的1个数码管显示值 */
P2 = (P2 & 0x1f) | 0xe0;
break;
case 0: /* 关闭所有通道 */
P2 = (P2 & 0x1f) | 0x00;
break;
}
P2 = (P2 & 0x1f) | 0x00; /* 使用后,关闭所有通道 */
}

void SMG_Display_Bit(unsigned char pos, unsigned char value)
{
slect_138_573(6, 0x01 << pos - 1);
slect_138_573(7, value);
delay_ms(2);
// delay_ms(50); // 延时太长数码管就做不到动态显示

// 消影
slect_138_573(6, 0x01 << pos - 1);
slect_138_573(7, 0xff);
}

void System_init(void)
{
slect_138_573(4, 0xff);
slect_138_573(5, 0x00);
}
/***********************************定时器部分**************************************/
unsigned int t_1s;//定时1s标志位
unsigned int t_4s;//定时4s标志位
unsigned char time;//时钟数据0~9 每秒加一
unsigned char mode;//显示模式

void Timer0_Isr(void) interrupt 1
{
if(++t_1s >= 1000)
{
t_1s = 0;
time += 1;
if(time == 10)
time = 0;
}
if(++t_4s >= 4000)
{
t_4s = 0;
mode ^= 1;
}
}

void Timer0_Init(void) //1毫秒@12.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
EA = 1;
}



void main(void)
{
System_init();
Timer0_Init();//定时器初始化
while(1)
{
switch(mode)
{
case 0:
SMG_Display_Bit(1, SMG[0]);
SMG_Display_Bit(2, SMG[0]);
SMG_Display_Bit(3, SMG[0]);
SMG_Display_Bit(4, SMG[0]);
SMG_Display_Bit(5, SMG[0]);
SMG_Display_Bit(6, SMG[0]);
SMG_Display_Bit(7, SMG[0]);
SMG_Display_Bit(8, SMG[0]);
break;
case 1:
SMG_Display_Bit(1, SMG[1]);
SMG_Display_Bit(2, SMG[2]);
SMG_Display_Bit(3, SMG[3]);
SMG_Display_Bit(4, SMG[4]);
SMG_Display_Bit(5, SMG[5]);
SMG_Display_Bit(6, SMG[6]);
SMG_Display_Bit(7, SMG[7]);
SMG_Display_Bit(8, SMG[8]);
break;
default:
break;
}
}
}
/***********************************定时器部分**************************************/

Author:Feng HanXiu
Link:http://example.com/2024/11/26/2024%E5%BC%80%E6%BA%90%E8%93%9D%E6%A1%A5%E7%B3%BB%E5%88%97%EF%BC%88%E4%BA%94%EF%BC%89%EF%BC%9A%E5%AE%9A%E6%97%B6%E5%99%A8%E4%B8%8E%E4%B8%AD%E6%96%AD%E6%A6%82%E5%BF%B5/
版权声明:本博客采用由开源协会搭建