中断在裸机开发中是非常重要的一项学习内容,之前学习过STM32的中断实
   现,是参考正点原子的代码,通过库函数的方式实现的,为了进一步深度理解
   其中的道理,此次通过天嵌的TQ210开发板实现中断方式。
   	   具体功能为,LED正常闪烁,当按键被按下的时候,通过串口打印信息,提
   示按键被按下,此过程不影响LED正常闪烁。
       中断执行过程具体如下图:

天嵌开发板 TQ210 S5PV210 中断方式按键实现

   	    根据示意图,可知道当有中断请求时,首先进行保护现场,然后跳到中断处理函数,执行中断处理函数当中的程序,最后进行恢复现场,程序继续运行。
   	    通过查询开发板原理图得知,按键连接的为外部中断XEINT0,连接的芯片引脚为GPH0,具体细节如下图。

天嵌开发板 TQ210 S5PV210 中断方式按键实现

天嵌开发板 TQ210 S5PV210 中断方式按键实现
知道了硬件连接就可以进行代码编写了,具体流程如下:

  1. 配置GPH0引脚为为外部中断模式
  2. 配置中断触发方式(此处设置为下降沿触发)
  3. 中断屏蔽配置
  4. 使能外部中断
    通过以上流程中断基本已经完成初始化准备工作。
    其中提到了中断屏蔽,此处引用百度百科进行简单的介绍下:

什么叫屏蔽中断?允许中断?怎样实现?
按照是否可以被屏蔽,可将中断分为两大类:不可屏蔽中断(又叫非屏蔽中断)和可屏蔽中断。不可屏蔽中断源一旦提出请求,CPU必须无条件响应,而对可屏蔽中断源的请求,CPU可以响应,也可以不响应。CPU一般设置两根中断请求输入线:可屏蔽中断请求INTR(Interrupt Require)和不可屏蔽中断请求NMI(NonMaskable Interrupt)。对于可屏蔽中断,除了受本身的屏蔽位控制外,还都要受一个总的控制,即CPU标志寄存器中的中断允许标志位IF(Interrupt Flag)的控制,IF位为1,可以得到CPU的响应,否则,得不到响应。IF位可以由用户控制,指令STI或Turbo c的Enable()函数,将IF位置1(开中断),指令CLI或Turbo_c 的Disable()函数,将IF位清0(关中断)。

此外,还需配置中断向量表、优先级、控制等具体配置过程中涉及的中断控制器如下图所示:
天嵌开发板 TQ210 S5PV210 中断方式按键实现
具体程序文件由key.h、key.c main.c start.S等文件组成,具体目录结构如下图:
天嵌开发板 TQ210 S5PV210 中断方式按键实现
gpio.h 内容如下图

#ifndef _ASM_ARCH_GPIO_H
#define _ASM_ARCH_GPIO_H

struct s5pc1xx_gpio_bank{
        unsigned int con;
        unsigned int dat;
        unsigned int pull;
        unsigned int drv;
        unsigned int pdn_con;
        unsigned int pdn_pull;
        unsigned char res1[8];  
};
struct s5pv210_gpio{
        struct s5pc1xx_gpio_bank gpio_a0;
        struct s5pc1xx_gpio_bank gpio_a1;
        struct s5pc1xx_gpio_bank gpio_b;
        struct s5pc1xx_gpio_bank gpio_c0;
        struct s5pc1xx_gpio_bank gpio_c1;
        struct s5pc1xx_gpio_bank gpio_d0;
        struct s5pc1xx_gpio_bank gpio_d1;
        struct s5pc1xx_gpio_bank gpio_e0;
        struct s5pc1xx_gpio_bank gpio_e1;
        struct s5pc1xx_gpio_bank gpio_f0;
        struct s5pc1xx_gpio_bank gpio_f1;
        struct s5pc1xx_gpio_bank gpio_f2;
        struct s5pc1xx_gpio_bank gpio_f3;
        struct s5pc1xx_gpio_bank gpio_g0;
        struct s5pc1xx_gpio_bank gpio_g1;
        struct s5pc1xx_gpio_bank gpio_g2;
        struct s5pc1xx_gpio_bank gpio_g3;
        struct s5pc1xx_gpio_bank gpio_i;
        struct s5pc1xx_gpio_bank gpio_j0;
        struct s5pc1xx_gpio_bank gpio_j1;
        struct s5pc1xx_gpio_bank gpio_j2;
        struct s5pc1xx_gpio_bank gpio_j3;
        struct s5pc1xx_gpio_bank gpio_j4;
};
#define S5PV210_GPIO_BASE (0xE0200000)

struct s5pv210_gph_bank{
        unsigned int con;
        unsigned int dat;
        unsigned int pull;
        unsigned int drv;
};
#define S5PV210_GPH0_BASE (0xE0200C00)  //GPH0 基地址

#endif 

uart.h内容如下图


#ifndef UART_H
#define UART_H

struct s5pv2xx_uart
{

        unsigned int   ulcon;
        unsigned int   ucon;
        unsigned int   ufcon;
        unsigned int   umcon;
        unsigned int   utrstat;
        unsigned int   uerstat;
        unsigned int   ufstat;
        unsigned int   umstat;
        unsigned char  utxh;
        unsigned char  resl[3];
        unsigned char  urxh;
        unsigned char  res2[3];
        unsigned int   ubrdiv;
        unsigned short udivslot;
        unsigned char  res3[2];
        unsigned char  res4[0x3d0];
};

#define S5PV210_UART_BASE (0xE2900000)
void uart_init(void);
void myputc(char c); 
void myputs(const char *str);
#endif

关键的是key.h 其中的地址一定要正确

#ifndef KEY_H
#define KEY_H

#define pEXECPTION_IRQ  (*(volatile unsigned int*)(0xD0037400+0X18))

#define EXT_INT_0_CON   (*(volatile unsigned int*)(0xE0200E00)) //外部中断0 控制寄存器
#define EXT_INT_0_MASK  (*(volatile unsigned int*)(0xE0200F00)) //外部中断0 mask(屏蔽控制)寄存器
#define EXT_INT_0_PEND  (*(volatile unsigned int*)(0xE0200F40)) //外部中断0 pend 阻塞 挂起控制器

#define VIC0INTENABLE   (*(volatile unsigned int*)(0xF2000010))//VICO  中断使能控制器
#define VIC0ADDRESS     (*(volatile unsigned int*)(0xF2000F00))//VICO  中断地址控制器
#define VIC0VECTADDR0   (*(volatile unsigned int*)(0xF2000100))//VICO  地址O清除寄存器


void key_init(void);
void irq_init(void);
void key1_handler(void);
void irp_c_handler(void);

#endif

key.c文件内容如下图:

#include "cpu_io.h"
#include "gpio.h"
#include "key.h"
#include "uart.h"

extern void asm_irq(void);
void irq_init()
{
        pEXECPTION_IRQ=(unsigned int )asm_irq;
}
void irq_c_handler(void)
{
          void  (*handler)(void)=0x0;
          myputs("in irq c handler....\n");
          handler =(void (*) (void)) VIC0ADDRESS;
          if(handler) handler();

}
void key1_handler(void)
{
        myputs("key1 down!!!\n");
        EXT_INT_0_PEND |= (0x1<<0);
        VIC0ADDRESS=0X0;
}
void key_init(void)
{
        struct s5pv210_gph_bank *gph0_base=(struct s5pv210_gph_bank*) S5PV210_GPH0_BASE;
        unsigned int var;
    
        /**外部引脚进行功能选择,EINT***/
        var =readl(&gph0_base->con);
        var|=0xf<<0; //功能选择 0xf 表示配置GPHO引脚为外部中断0
        writel(var,&gph0_base->con);
        /****配置ENIT功能***************/
        EXT_INT_0_CON &= ~(0X7<<0); //低三位清零 为以后配置中断触发方式做准备
        EXT_INT_0_CON |=(0x2<<0);   //低三位配置为010 即为下降沿触发方式
    
        EXT_INT_0_MASK &= ~(0x1<<0);//使能中断屏蔽
        /*****配置主中断控制器**********/
        VIC0INTENABLE |= (0X1<<0);  //使能中断
        VIC0VECTADDR0=(unsigned int)key1_handler;
}

uart.c 文件内容如下图:

#include "cpu_io.h"
#include "uart.h"
#include "gpio.h"
void uart_init(void)
{
        struct s5pv210_gpio *gpio_base=(struct s5pv210_gpio *)S5PV210_GPIO_BASE;
        struct s5pv2xx_uart *uart_base=(struct s5pv2xx_uart *)S5PV210_UART_BASE;
        unsigned int var;
        var=readl(&gpio_base->gpio_a0.con);
        var &= ~(0xff<<0);
        var |=  (0x22<<0);
        writel(var,&gpio_base->gpio_a0.con);
        _REG(&uart_base->ulcon)=0x3; //8 bit 1stop non-even
        _REG(&uart_base->ucon) =0x5; //
        _REG(&uart_base->ubrdiv)=35;
        _REG(&uart_base->udivslot)=0x80;
    
}
void myputc(char c)
{
    
        struct s5pv2xx_uart *uart_base=(struct s5pv2xx_uart *)S5PV210_UART_BASE;
         //判断缓冲区是否为空,再发送数据
        while(!(_REG(&uart_base->utrstat)&(0x1<<2)));   
        _REG(&uart_base->utxh)=c;


}
void myputs(const char *str)
{
        while(*str)
        {   
                myputc(*str);
                str++;
        }   
}

main.c函数内容比较少 ,完成闪烁LED和初始化工作:

//main.c 
#include "led.h"
#include "cpu_io.h"
#include "uart.h"
#include "key.h"
static void mydelay()
{
        volatile unsigned int i=0xfffff;
        while(i--);

}
void led_test()
{

      led_init();
      while(1)
      {   
         led_blink(1);
         mydelay();
         led_blink(0);
         mydelay();
      }   
}

int main()
{
        irq_init();
        uart_init();
        key_init();
        myputs("hello world!\n");
        led_test();
        return 0;
}

start.S内容如下 ,主要完成中断跳转和保护现场等;


.global _start
.global main
.global irq_c_handler
.global asm_irq
_start :
     bl   main
loop:
     b loop

irq_handler:
        stmfd sp!,{r0-r3,lr}
        bl    irq_c_handler
        ldmfd sp!,{r0-r3,lr}
        subs  pc,lr,#4
asm_irq:
        b irq_handler
.end

最后还需要注意的是,下载的时候应该选择SD卡下载,不要选择Dram下载。以上内容仅供参考,如有问题还请指出。

相关文章:

  • 2022-12-23
  • 2021-07-09
  • 2022-01-25
  • 2021-12-18
  • 2021-11-16
  • 2021-06-22
  • 2021-08-17
  • 2021-10-27
猜你喜欢
  • 2021-11-20
  • 2021-06-21
  • 2021-10-28
  • 2021-10-18
  • 2021-07-05
  • 2022-12-23
相关资源
相似解决方案