外观
定时器中断实验
电路分析
简易万用表项目使用CH32V208RBT6作为主控芯片,具有一个高级定时器、一个32位通用定时器以及三个16位通用定时器。
注
高级定时器1挂载在APB2总线上,其他通用定时器挂载在APB1总线上,这一点主要注意。
功能实现
创建工程
- 点击左上方文件、选择新建,选择新建MounRiver工程;
- 对工程进行修改,修改完成后点击“完成”按键,系统会自动生成好工程;
- 创建直接的工程库文件夹,分别创建头文件与源文件;
- 对工程库路径进行包含;
代码实现
- 包含头文件,在头文件中包含ch32相关的头文件,方便对相关库函数进行调用;
C
#ifndef MYLIB_INC_POWERSWITCH_H_
#define MYLIB_INC_POWERSWITCH_H_
#include "ch32v20x.h"
#include "debug.h"
#endif /* MYLIB_INC_POWERSWITCH_H_ */
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
- 在源文件中创建两个函数,用于实现定时器2初始化功能与定时器2中断服务函数;相关中断服务函数在启动文件中有进行声明,这里找到对应的函数名进行使用即可。
- 初始化定时器函数
- 使能定时器时钟;
- 设置定时器初始化结构体参数,包括定时器周期、预分频器、时钟分配、计数模式等;这里需要注意TIM2、3、4这些时钟源是来自APB1总线上的,根据时钟树说明,当APB1总线不分频时,定时器时钟与总线时钟一致,若APB1总线为4/8/16这些分频,定时器会在此基础上*2。(此时系统时钟为96Mhz,且APB1总线2分频,定时器时钟应该还是96Mhz,(5000*9600)/96Mhz=0.5s)。
- 使能定时器中断;
- 定时器中断优先级设置;
- 使能定时器;
C
/*
* 函数内容:初始化定时器2
* 函数参数:无
* 返回值:无
*/
void Init_TIM2(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //定时器参数结构体
NVIC_InitTypeDef NVIC_InitStructure; //中断参数结构体
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能TIM2时钟
TIM_TimeBaseStructure.TIM_Period = 4999; //定时器周期值。
TIM_TimeBaseStructure.TIM_Prescaler =9599; //定时器预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频因子
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM计数模式,向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); //使能TIM2中断,允许更新中断
//初始化TIM NVIC,设置中断优先级分组
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM2中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //设置抢占优先级0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //设置响应优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能通道1中断
NVIC_Init(&NVIC_InitStructure); //初始化NVIC
TIM_Cmd(TIM2, ENABLE); //TIM2使能
}
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
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
- 定时器中断服务函数:
中断服务函数中实现的功能非常简单,定时器是0.5s进入一次中断,这里每次进入中断服务函数,就翻转一次LED灯,使LED灯每隔1s进行闪烁。
在tim.c中将之前编写好的驱动代码包含进来;
在中断服务函数中不断检测事件是否到来,若到来,则清除该事件,并使用一个静态标志位对LED灯进行记录翻转。
C
/*
* 函数内容:定时器2中断服务函数
* 函数参数:无
* 返回值:无
*/
void TIM2_IRQHandler(void)
{
static uint8_t i = 0;
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) //检查TIM2中断是否发生。
{
TIM_ClearITPendingBit(TIM2,TIM_IT_Update); //清除TIM2的中断挂起位。
if(i == 0){
Open_LED();
i = 1;
}else {
Close_LED();
i = 0;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
代码编写完成后,对定时器初始化函数进行声明,同时需要对定时器中断服务函数进行声明;这里的中断服务函数声明加入了属性描述(attribute__());这可以使其进行硬件/软件压栈,提升中断响应速度。
在主函数中对函数进行调用,这里定时器2初始化完成后,会每隔0.5s触发中断自动进入中断服务函数中去翻转LED灯,注意长按开关机需要包含进来,否则松手就断电了。
C
#include "debug.h"
#include "led.h"
#include "powerswitch.h"
#include "tim.h"
/* Global typedef */
/* Global define */
/* Global Variable */
/*********************************************************************
* @fn main
*
* @brief Main program.
*
* @return none
*/
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
SystemCoreClockUpdate();
Delay_Init();
Init_Power_Con_GPIO();
Init_LED_GPIO();
Init_TIM2();
while(1)
{
Scanf_Power_Key();
}
}
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
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
TIP
当长按开机时,LED灯进行闪烁。
源码&USB下载工具等软件,均在gitee资料中