本实验利用Plus1 7021自带的定时计数器介绍基本编程方法,涉及到中断使用, Plus17021系统提供4个通用的16位计数定时器timer0到timer3; 每个计数定时器都支持计数到预设值时产生相应的中断信号。
对应系统分配的中断号如下表所示
| 中断号 |
Timer0 | 151 |
Timer1 | 152 |
Timer2 | 153 |
Timer3 | 154 |
对应的32位寄存器详细介绍,请参考我们提供的文档QAC628_regfile.pdf, 如下
这里简单介绍相关寄存器的含义,如下表所示:
| 控制寄存器 | 计数预值控制器 | 计数时钟预处理控制器 | 计数值控制器 |
Timer0 | timer0_ctrl bit[31:16] :保留 bit[15:14] :计数时钟选择 0: 系统时钟(default) 1: STC 90KHZ 时钟 bit13 :操作方式 0:单次操作(default) 1:重复操作 bit12 : 保留 bit11 :开关控制 0:关闭计数器 1:启动计数器 bit[10:0] :保留 | timer0_reload bit[31:16] :保留 bit[15:0] : 16位计数预值设置
|
| timer0_cnt bit[31:16] :保留 bit[15:0] : 16位计数值
|
timer1 | timer1_ctrl bit[31:16] :保留 bit[15:14] :计数时钟选择 0: 系统时钟(default) 1: STC 90KHZ 时钟 bit13 :操作方式 0:单次操作(default) 1:重复操作 bit12 : 保留 bit11 :开关控制 0:关闭计数器 1:启动计数器 bit[10:0] :保留 | timer1_reload bit[31:16] :保留 bit[15:0] : 16位计数预值设置
|
| timer1_cnt bit[31:16] :保留 bit[15:0] : 16位计数值
|
timer2 | timer2_ctrl bit[31:6] :保留 bit[5:2] :计数时钟选择 0: 系统时钟(default) 1: STC 90KHZ 时钟 bit1 :操作方式 0:单次操作(default) 1:重复操作 bit1 : 保留 bit0 :开关控制 0:关闭计数器 1:启动计数器 | timer2_reload bit[31:16] :保留 bit[15:0] : 16位计数预值设置
| timer2_pres_val bit[31:16] :保留 bit[15:0] : 16位计数时钟预值设置
| timer2_cnt bit[31:16] :保留 bit[15:0] : 16位计数值
|
timer3 | timer3_ctrl bit[31:6] :保留 bit[5:2] :计数时钟选择 0: 系统时钟(default) 1: STC 90KHZ 时钟 bit1 :操作方式 0:单次操作(default) 1:重复操作 bit1 : 保留 bit0 :开关控制 0:关闭计数器 1:启动计数器 | timer3_reload bit[31:16] :保留 bit[15:0] : 16位计数预值设置
| timer3_pres_val bit[31:16] :保留 bit[15:0] : 16位计数时钟预值设置
| timer3_cnt bit[31:16] :保留 bit[15:0] : 16位计数值
|
安装目录 \SP7021\workspace\sp7021\include 文件夹下的regmap_q628.h定义了这四个寄存器,如下图红色:
regmap_q628.h
struct stc_regs {
unsigned int stc_15_0; // 12.0
unsigned int stc_31_16; // 12.1
unsigned int stc_64; // 12.2
unsigned int stc_divisor; // 12.3
unsigned int rtc_15_0; // 12.4
unsigned int rtc_23_16; // 12.5
unsigned int rtc_divisor; // 12.6
unsigned int stc_config; // 12.7
unsigned int timer0_ctrl; // 12.8
unsigned int timer0_cnt; // 12.9
unsigned int timer1_ctrl; // 12.10
unsigned int timer1_cnt; // 12.11
unsigned int timerw_ctrl; // 12.12
unsigned int timerw_cnt; // 12.13
unsigned int stc_47_32; // 12.14
unsigned int stc_63_48; // 12.15
unsigned int timer2_ctl; // 12.16
unsigned int timer2_pres_val;// 12.17
unsigned int timer2_reload; // 12.18
unsigned int timer2_cnt; // 12.19
unsigned int timer3_ctl; // 12.20
unsigned int timer3_pres_val;// 12.21
unsigned int timer3_reload; // 12.22
unsigned int timer3_cnt; // 12.23
unsigned int stcl_0; // 12.24
unsigned int stcl_1; // 12.25
unsigned int stcl_2; // 12.26
unsigned int atc_0; // 12.27
unsigned int atc_1; // 12.28
unsigned int atc_2; // 12.29
unsigned int timer0_reload; // 12.30
unsigned int timer1_reload; // 12.31
};
#define STC_REG ((volatile struct stc_regs *)RF_GRP(12, 0))
定时器控制实验需要如下3个文件,如下:
1) 安装目录 \SP7021\workspace\sp7021\ 文件夹下的main.c
2) 安装目录 \SP7021\workspace\sp7021\testapi\util 文件夹下的timer.c
3) 安装目录 \SP7021\workspace\sp7021\ include\util文件夹下的timer.h
main.c
int main(void)
{
printf("Build @%s, %s\n", __DATE__, __TIME__);
hw_init();
sys_init();
timer_test_init();/*interrupt test api */
sp_interrupt_setup(); /* interrupt manager module init */
while(1);
}
首先时系统及硬件初始化:hw_init();sys_init();
然后时调用timer.c中定义的计数定时器初始化函数timer_test_init();
最后调用系统中断管理函数sp_interrupt_setup();
上面的4个函数只有timer_test_init()是由用户根据应用需求编写,其它都是系统提供。
timer_test_init() 的函数体实现在timer.c中,负责计数定时器timer3进行初始化工作,包含计数时钟的选择,定时值设置,定时器中断配置及对应的中断处理函数操作。
timer.c
#include "common_all.h"
#include "cache.h"
#include "sp_interrupt.h"
#define TIMER3_TICKS (90 - 1) /* 1s */
#define TIMER3_CONFIG_STC (1 << 2) /* src: stc */
#define TIMER3_RELOAD (1 << 1) /* timer3 auto reload */
#define TIMER3_RUN (1 << 0) /* timer3 run */
#define TIMER3_STOP (0 << 0) /* timer3 stop */
#define TIMER3_INT (154)
static unsigned int g_repeat_cnt = 0;
void timer3_interrupt_control_mask(int enable)
static void timer3_isr_cfg()
void timer3_callback(void)
void timer_test_init()
timer.c提供实现定时器控制实验的4个方法函数及宏定义,分别讲解如下:
void timer3_interrupt_control_mask(int enable)
{
if (enable != 0) {
/* enable timer3 interrupt */
hal_interrupt_unmask(TIMER3_INT);
} else {
hal_interrupt_mask(TIMER3_INT);
}
}
用来控制计数定时器3中断的开与关;enable为0时关闭中断,为1时开启中断
static void timer3_isr_cfg()
{
printf("[CFG] Timer3\n");
STC_REG->timer3_ctl = TIMER3_CONFIG_STC | TIMER3_RELOAD;
STC_REG->timer3_pres_val = 999;
STC_REG->timer3_reload = TIMER3_TICKS;
STC_REG->timer3_cnt = TIMER3_TICKS;
hal_interrupt_configure(TIMER3_INT, 0, 1);
timer3_interrupt_control_mask(1);
STC_REG->timer3_ctl |= TIMER3_RUN;
}
实现计数定时器每1秒产生1次中断,相关配置工作如下:
1) STC_REG->timer3_ctl = TIMER3_CONFIG_STC | TIMER3_RELOAD;
计时钟选择STC 90KHZ 时钟;操作方式为重复操作
2) STC_REG->timer3_pres_val = 999;
计数时钟预处理设置为999,表示每收到1000个STC 90KHZ时钟,timer3 才计数1次;
3) STC_REG->timer3_reload = TIMER3_TICKS;
计数预值设置为89, 表示timer3 计数90次后,重新开始计数
4) STC_REG->timer3_cnt = TIMER3_TICKS;
计数初值设置为89,因为计数器是 UP to DOWN 的方式,即从初值计数到0完成1次操作;
5) hal_interrupt_configure(TIMER3_INT, 0, 1);
这是系统提供的中断设置函数,共有3个参数需要设置,如下:
void hal_interrupt_configure(int vector, int level, int up)
int vector :中断号,系统分配指定,每个定时器都有自己专门的中断号:
time0的中断号是151
time1的中断号是152
time2的中断号是153
time3的中断号是154
int level :中断信号触发方式
0:边沿触发
1:电平触发
int up :中断信号极性方式
0:负极性(负边沿或负电平)
1:正极性(正边沿或正电平)
6) timer3_interrupt_control_mask(1);
开启计数定时器3中断
7) STC_REG->timer3_ctl |= TIMER3_RUN;
启动计数定时器3,计数开始
void timer3_callback(void)
{
printf("@Timer3[%d]\n", ++g_repeat_cnt);
}
是对应的中断处理函数操作,将中断的次数显示在IDE 环境的Terminal窗口,如图所示。
void timer_test_init()
{
static interrupt_operation timer3_opt;
memcpy(timer3_opt.dev_name, "Timer3", strlen("Timer3"));
timer3_opt.vector = TIMER3_INT;
timer3_opt.device_config = timer3_isr_cfg;
timer3_opt.interrupt_handler = timer3_callback;
interrupt_register(&timer3_opt);
}
是中断初始化操作,完成中断函数的注册,包含上面定义的3个函数的调用
timer.h
#ifndef __TIMER_H__
#define __TIMER_H__
void timer_test_init();
#endif // __TIMER_H__
timer.c 中的函数被其它文件中的函数调用时,需要在timer.h中申明
在Plus1 IDE环境中compile后,下载到平台运行,在terminal窗口看到如下信息
Add Comment