文章目录
- 一、实验分析
- 二、RCC章节:找到外设基地址并使能外设控制器时钟源
- 1. RCC
- 2. GICC和GICD
- 3. TIM3
- 三、TIM3章节
- (一)CR1寄存器
- (二)DIER寄存器
- (三)SR寄存器
- (四)PSC寄存器
- (五)ARR寄存器
- 四、GIC章节
- (一)查看TIM3中断的中断号
- (二)GICD
- 1. GICD_CTLR
- 2. GICD_ISENABLERx
- 3. GICD_ICPENDRx
- 4. GICD_IPRIORITYRx
- 5. GICD_ITARGETSRx
- (三)GICC
- 1. GICC_CTRL
- 2. GICC_PMR
- 3. GICC_IAR
- 4. GICC_EOIR
- 五、代码实现
- 六、通过定时器实现按键消抖
一、实验分析
通过定时器TIM3的计数功能,产生一个定时器中断,将中断信号转发给GIC;
GIC控制器接收到中断信号后,将其转发给指定的CPU进行处理。
其中,RCC为TIM3提供时钟源。
- 注:此时定时器只用于计数功能,并不需要再产生PWM方波,因此无需再配置捕获比较寄存器,仅配置自动重装载寄存器即可。
二、RCC章节:找到外设基地址并使能外设控制器时钟源
1. RCC
RCC挂在AHB4总线,基地址0x50000000
2. GICC和GICD
GICC和GICD挂在Cortex-A7核内部总线,无需开发人员手动使能时钟源
GICC基地址0xA0022000
GICD基地址0xA0021000
3. TIM3
TIM3挂在APB1总线上,需要手动使能时钟源
TIM3基地址0x40001000
三、TIM3章节
当发生更新事件时会置位更新中断标志位,
因此需要设置相关的寄存器使能该标志位,在处理完中断后需要清除该标志位
(一)CR1寄存器
ARPE:使能自动重载寄存器的缓冲区
CMS:设置对齐模式,选择边沿对齐
DIR:计数方向,此处选择向下计数
CRN:计数器使能位
(二)DIER寄存器
此处将UIE位置1,使能更新中断
(三)SR寄存器
UIF:
读1,说明中断挂起,即中断发生了。
写0,清除中断标志位。
(四)PSC寄存器
分频寄存器,
注意,该寄存器是16位寄存器,因此分频值可设置为0~65535,即可以设置为1~65536分频
(五)ARR寄存器
自动重载寄存器
此处使用TIM3为一个16位的寄存器,因此其可装载的数值范围为0~65535
四、GIC章节
(一)查看TIM3中断的中断号
(二)GICD
1. GICD_CTLR
使能GROUP0
2. GICD_ISENABLERx
使能中断号。
TIM3中断号是61,ISENABLER每个寄存器设置32个中断,
61/32=1…29
因此设置GICD_ISENABLER[1]的第29位为1,使能
3. GICD_ICPENDRx
写1,清除终端挂起标志位
4. GICD_IPRIORITYRx
设置中断权限
每个寄存器管理4个中断号,
61/4=15…1
因此需要设置GICD_IPRIOROTYR[15]的第8*1+3位
5. GICD_ITARGETSRx
设置中断分配给哪个CPU,每个寄存器管理4个中断号
61/4=15…1
因此需要设置GICD_ITAGETS[15]的第8*1位
(三)GICC
1. GICC_CTRL
使能GROUP0
2. GICC_PMR
设置权限掩码
3. GICC_IAR
4. GICC_EOIR
五、代码实现
实现一个5s中断
tim.c
void tim3_IT_init(void){
//时钟源使能
RCC_APB1->tim3_en=1;
//PSC寄存器设置分频值为10000 未分频是209MHz,分频209000就是1000Hz
TIM3->PSC=20900-1; //分频后时钟为1MHz
TIM3->ARR=10000; //计数值为1000,此时就是1S
TIM3->CR1.ARPE=1;//预加载寄存器使用缓冲区
TIM3->CR1.DIR=1;//向下计数
TIM3->CR1.CMS=0;//边沿
TIM3->DIER |= 0x1<<0; //使能更新中断
TIM3->CR1.CEN=1;//使能定时器
}
gic.c
void gic_tim3_init(void){
//使能GICD中断号
GICD->ISENABLER[1] |= (0x1<<29); //使能GICD中断号9 61/32=1...29
//设置优先级
GICD->IPRIORITYR[15] &= ~(0xf<<11);
GICD->IPRIORITYR[15] |= (0x5<<11); //设置优先级 61/4=15...1
//分配CPU
GICD->ITARGETSR[15] &= ~(0x3<<8);
GICD->ITARGETSR[15] |= (0x1<<8); //设置中断给CPU0 61/4=15...1
GICD->CTRL |= (0x1<<0); //使能GICD组0
//配置GICC
GICC->PMR |= 0x1f<<3; //31
GICC->CTLR|= 0x1<<0; //使能GICC
}
do_irq.c
static unsigned int count = 0;
void do_irq(void)
{
int irqnum=0;
irqnum = GICC->IAR & 0x1ff;
switch(irqnum){
case 61: //tim3中断
count++;
if(count==5){
printf("interrupt 5s\n");
count=0;
}
TIM3->SR &= ~(0x1<<0);//清除中断标志位
GICD->ICPENDR[1] |=(1<<29); //61/32=1 61%32=29
break;
}
GICC->EOIR = irqnum;
}
六、通过定时器实现按键消抖
tim3.c
void tim3_xiaodou_init(void){
//时钟源使能
RCC_APB1->tim3_en=1;
//PSC寄存器设置分频值为10000 未分频是209MHz,分频209000就是1000Hz
TIM3->PSC=209-1; //分频后时钟为1MHz
TIM3->ARR=10000; //计数值为1000,此时就是1ms
TIM3->CR1.ARPE=1;//预加载寄存器使用缓冲区
TIM3->CR1.DIR=1;//向下计数
TIM3->CR1.CMS=0;//边沿
TIM3->DIER |= 0x1<<0; //使能更新中断
TIM3->CR1.CEN=1;//使能定时器
}
gic.c
void gic_tim3_init(void){
//使能GICD中断号
GICD->ISENABLER[1] |= (0x1<<29); //使能GICD中断号9 61/32=1...29
//设置优先级
GICD->IPRIORITYR[15] &= ~(0xf<<11);
GICD->IPRIORITYR[15] |= (0x5<<11); //设置优先级 61/4=15...1
//分配CPU
GICD->ITARGETSR[15] &= ~(0x3<<8);
GICD->ITARGETSR[15] |= (0x1<<8); //设置中断给CPU0 61/4=15...1
GICD->CTRL |= (0x1<<0); //使能GICD组0
//配置GICC
GICC->PMR |= 0x1f<<3; //31
GICC->CTLR|= 0x1<<0; //使能GICC
}
do_irq.c
void do_irq(void)
{
int irqnum=0;
irqnum = GICC->IAR & 0x1ff;
switch(irqnum){
case 61: //tim3中断
if(!gpio_read(GPIOF,KEY1_PORT)){
printf("key1 down!\n");
}
if(!gpio_read(GPIOF,KEY2_PORT)){
printf("key2 down!\n");
}
if(!gpio_read(GPIOF,KEY3_PORT)){
printf("key3 down!\n");
}
TIM3->SR &= ~(0x1<<0);//清除中断标志位
GICD->ICPENDR[1] |=(1<<29); //61/32=1 61%32=29
TIM3->CR1.CEN=0;//关闭定时器
break;
case 97: //KEY2
tim3_xiaodou_init();
EXTI->FPR1.event7=1; //清除EXTI中断
GICD->ICPENDR[3] |= (1<<1);//清除GICD中断
break;
case 98:
tim3_xiaodou_init();
EXTI->FPR1.event8=1; //清除EXTI中断
GICD->ICPENDR[3] |= (1<<2);//清除GICD中断
break;
case 99: //KEY1
tim3_xiaodou_init();
EXTI->FPR1.event9=1; //清除EXTI中断
GICD->ICPENDR[3] |= (1<<3);//清除GICD中断
break;
}
GICC->EOIR = irqnum;
}