4. 定时器中断应用
任务目标
使用Zynq PS端私有定时器(SCU Private Timer)产生周期性中断,在中断服务函数(ISR)中翻转MIO连接的LED,掌握定时器寄存器配置、中断控制器(GIC)初始化及中断处理流程。
硬件连接
LED接在PS端MIO引脚(本例使用MIO0,对应Zynq开发板LED0),高电平点亮。定时器中断频率设定为1Hz,便于肉眼观察LED翻转。
核心代码
// timer_led.c - Zynq PS定时器中断控制LED
#include "xil_io.h"
#include "xil_exception.h"
#include "xscugic.h"
#include "xscutimer.h"
#define TIMER_DEVICE_ID XPAR_XSCUTIMER_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_XSCUGIC_0_DEVICE_ID
#define TIMER_IRPT_INTR XPAR_SCUTIMER_INTR
#define LED_MIO_PIN 0
#define GPIO_DATA_REG 0xE000A000 // MIO引脚数据寄存器(SLCR已使能输出)
static XScuTimer TimerInstance;
static XScuGic IntcInstance;
static volatile int led_state = 0;
// 定时器中断服务函数:翻转LED
void Timer_ISR(void *CallbackRef) {
XScuTimer *TimerPtr = (XScuTimer *)CallbackRef;
if (XScuTimer_IsExpired(TimerPtr)) {
XScuTimer_ClearInterruptStatus(TimerPtr);
led_state = !led_state;
Xil_Out32(GPIO_DATA_REG, led_state ? 0x1 : 0x0); // MIO0输出
}
}
// 初始化MIO0为GPIO输出
static void MIO_LED_Init(void) {
// 设置MIO0为GPIO输出模式(SLCR寄存器)
Xil_Out32(0xF8000008, 0x0); // MIO_PIN_0: 选择GPIO功能
Xil_Out32(0xF8000700, 0x1); // GPIO_DIRM: MIO0输出
Xil_Out32(0xF8000714, 0x1); // GPIO_OEN: 使能输出
Xil_Out32(GPIO_DATA_REG, 0x0); // 初始LED灭
}
// 定时器中断初始化
static int Timer_Intc_Init(void) {
XScuGic_Config *IntcConfig;
XScuTimer_Config *TimerConfig;
// GIC初始化
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
XScuGic_CfgInitialize(&IntcInstance, IntcConfig, IntcConfig->CpuId);
// 定时器初始化
TimerConfig = XScuTimer_LookupConfig(TIMER_DEVICE_ID);
XScuTimer_CfgInitialize(&TimerInstance, TimerConfig, TimerConfig->BaseAddr);
// 设置定时器周期:CPU_1x_CLK(100MHz) / 1Hz = 100,000,000
XScuTimer_LoadTimer(&TimerInstance, 100000000);
XScuTimer_EnableAutoReload(&TimerInstance);
XScuTimer_Start(&TimerInstance);
// 连接中断并使能
XScuGic_Connect(&IntcInstance, TIMER_IRPT_INTR,
(Xil_ExceptionHandler)Timer_ISR, &TimerInstance);
XScuGic_Enable(&IntcInstance, TIMER_IRPT_INTR);
// 使能全局中断
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler, &IntcInstance);
Xil_ExceptionEnable();
return XST_SUCCESS;
}
int main(void) {
MIO_LED_Init();
Timer_Intc_Init();
while(1); // 等待中断
return 0;
}
运行与验证
- 工程配置:在Vivado中创建Zynq工程,使能PS端MIO0作为GPIO输出,导出硬件并启动SDK。
- 编译下载:在SDK中新建Application Project,将上述代码替换main.c,编译后下载到开发板运行。
- 验证方法:观察LED0是否以1Hz频率(每秒翻转一次)闪烁。若LED不亮或频率异常,检查:
- MIO0引脚是否被其他外设占用(SLCR配置需与Vivado中的MIO设置一致);
- 定时器预装载值是否正确(CPU_1x_CLK频率需与硬件配置一致,常见为100MHz);
- 中断号是否匹配(XPAR_SCUTIMER_INTR通常为29)。
预期结果:LED0以1秒为周期持续亮灭交替,程序不退出,无异常打印。