本帖最后由 Milinker_XU 于 2016-1-12 21:48 编辑
我们在前几章遇到延时,通常的做法是直接写个延时函数,但这样延时的时间其实是非常不精确的。那么如何在MB系统中,做出精准的延时呢。这一章我们通过定时器中断的方法来实现。首先得清楚,这里的定时器,是硬件系统提供的一个稳定的计数源。当定时器启动时,通过累加或累减的方式,当定时器的存储值溢出时,定时器就产生一个使能信号,MB系统由此产生定时中断,响应该信号。 ◎紧接上一章的工程,在XPS中添加一个定时控制器。在弹出窗口中,将Only one Timer is present选中。关于IP的详细信息,xilinx公司在每个ip的窗口右上方的pdf文件来查看。 ◎将该定时器与MB系统连接,修改定时器名称为,此时timer_0挂到了axi4lite总线下。 ◎再添加一个中断控制器。该ip保持默认即可,将ip名称改为intc_0。同样,该ip自动添加到MB系统,通过axi4lite总线连接。 ◎在MB系统中,将MB系统的中断和中断控制器相连。 ◎在Ports端口中,为中断控制器添加中断信号源。点击intc_0下面的intr,单击即可。 ◎从弹出对话框中,设置中断源为timer_0。 ◎保存XPS文件后,点击Hardware->Generate Bitstream,产生bit文件。
◎启动SDK,新建个TIMER_INTR工程,选择Helloworld为模板,程序将在helloworld.c文件中编写。 ◎将helloworld.c文件改成intr.c文件(备注:也可以自己新建文件,然后搭建个MB软件系统,但通常我习惯直接建个helloworld模板在上面做修改)。 ◎初学者这时候就纠结了,做好了硬件平台,软件平台也搭建好了,那么如何写个定时器中断程序呢。这章我们来详细理解下各个头文件和BSP文件包的应用。
◎首先我们看看BSP包里面的头文件,在include文件夹下面,包含了一对乱起八糟的头文件。如下图所示。通常只有对具体的应用时,才查看对应的头文件。 ◎本章节中,我们采用定时器定时,当定时器到达指定时间时,产生中断,MB系统在响应改中断后,通知外设该干嘛。这里,我们以LED来做测试,当MB系统开起定时器中断,定时器计时达到1s时,中断控制器通知MB系统,MB系统响应后,告知LED灯闪烁一次。基本示意图如下所示。 ◎搞明白上面的流程图之后,我们需要的外设也就出来了,那么程序中所要用到的头文件也就清晰了。包括: #include "xparameters.h" MB参数:包含外设的地址、状态标志以及中断向量号等 #include "xgpio.h" 外设GPIO:IO初始化、如何往指定IO寄存器读写等、IO中断使能等 #include "xintc.h" 中断控制器:包括中断如何初始化、中断开始、中断枚举等 #include "xtmrctr.h" 定时器:定时器初始化、开始、启动、定时器状态函数等 #include "mb_interface.h" MB接口:MB接口同其他外设接口,包括硬件开中断、异常、启动指令缓存等 #include "platform.h" MB系统的指令、数据缓存使能,MB系统平台初始化,作用其实不大 ◎我们再定义几个文件。1.定义一个中断开启和设置的文件set_intc.c;2.定义一个中断响应文件,即中断处理程序文件handler_intc.c;3.包含各个文件中函数的头文件intc.h。
◎在set_intc.c文件中,对定时器0中断进行注册,开启中断并设置定时器开始计算值,产生中断信号。 #include "intc.h" //包含中断intc.h头文件 void set_intc(void) { //注册定时器0中断,中断处理函数到中断控制器,中断处理函数入口 XIntc_RegisterHandler(XPAR_INTC_0_BASEADDR, XPAR_INTC_0_TMRCTR_0_VEC_ID, (XInterruptHandler) timer_int_handler, (void *)XPAR_TIMER_0_BASEADDR); //开启MB系统中断使能 microblaze_enable_interrupts(); //启动所有中断寄存器控制器 XIntc_MasterEnable(XPAR_INTC_0_BASEADDR); //使能定时器0中断 XIntc_EnableIntr(XPAR_INTC_0_BASEADDR, XPAR_TIMER_0_INTERRUPT_MASK); //设置定时器,主频100Mhz,周期10ns,1s即1000000000/10=100000000 XTmrCtr_SetLoadReg(XPAR_TIMER_0_BASEADDR, 0, 100000000); //使能定时器0产生中断信号 XTmrCtr_EnableIntr(XPAR_TIMER_0_BASEADDR, 0); //设置定时器控制状态寄存器 XTmrCtr_SetControlStatusReg(XPAR_TIMER_0_BASEADDR, 0, XTC_CSR_ENABLE_TMR_MASK | XTC_CSR_ENABLE_INT_MASK | XTC_CSR_AUTO_RELOAD_MASK | XTC_CSR_DOWN_COUNT_MASK); } |
[/table] ◎中断处理函数中,读取定时器控制状态寄存器,判断是否有中断产生,如果有,则led灯移位一次。 /* * handler.c * * Created on: 2016-1-12 * Author: Administrator */ #include "intc.h" /************************** interrupt handler process****************************/ void timer_intc_handler(void * baseaddr_p) { unsigned int rcs; //读取定时器控制状态寄存器 rcs = XTmrCtr_GetControlStatusReg(XPAR_TIMER_0_BASEADDR,0); //判断有中断产生,若有,led左移一位 if(rcs & XTC_CSR_INT_OCCURED_MASK) // if interrupt is occurred { led<<=1; } //清除定时器控制状态寄存器 XTmrCtr_SetControlStatusReg(XPAR_TIMER_0_BASEADDR,0, rcs); } |
◎在intc.h中,做了函数和全局变量的声明,还包括所需头文件的声明。 /* * intc.h * * Created on: 2016-1-12 * Author: Administrator */ #ifndef INTC_H_ #define INTC_H_ #include "xparameters.h" #include "xgpio.h" #include "xintc.h" #include "xtmrctr.h" #include "mb_interface.h" #include "platform.h" extern unsigned int led; void set_timer_intc(void); void timer_intc_handler(void * baseaddr_p); #endif /* INTC_H_ */ |
◎主函数中,调用中断设置函数,定义了个全局变量led,led通过mis603开发板上的灯显示。可以看出,每秒led灯移位一次。寄存器初始值的改变,将会是led状态发送变化。 ◎这样,关于定时器中断的例子就到此结束了。中断是单片机系统中使用非常多的,在描述中断处理函数时,要确保函数处理简单,简洁,复杂的程序,可以在其他调用程序或主函数中进行。
|