版本:Vivado2020.2(Vitis)
任务:使用 GPIO 中断实现按键 (PL端) KEY控制 (PS端) LED亮灭翻转
目录
一、介绍
ZYNQ 的 GPIO 中断功能允许 PS 端通过硬件中断快速响应GPIO引脚的电平变化(如按键按下、传感器触发等),无需轮询,适合实时性要求高的场景。ZYNQ GPIO支持以下中断触发方式:(通常推荐边沿触发)
-
边沿触发:上升沿(
RISING
)、下降沿(FALLING
)、双边沿(BOTH
)。 -
电平触发:高电平(
LEVEL_HIGH
)、低电平(LEVEL_LOW
)。
二、硬件设计
(1)ZYNQ 的配置不再赘述,如Bank电压、UART串口配置(用于debug)、去掉未使用端口等等。其次PL端KEY用了1个EMIO管脚,设置EMIO位宽为1。
(2)最后整体 bd 设计部分如图所示:设计检查、Generate Output Products、 Create HDL Wrapper、管脚约束、Gnerate Bitstream、Export Hardware(包含比特流文件)、启动Vitis
三、软件设计
#include "stdio.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xil_exception.h"
#include "xgpiops.h"
#include "xscugic.h"
#include "sleep.h"
//===========================自定义宏===========================//
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID //宏定义器件ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID //宏定义中断控制器(GIC)ID
#define GPIO_INTERRUPT_ID XPAR_XGPIOPS_0_INTR //宏定义GPIO中断号
#define MIO_LED 7 //宏定义LED管脚(PS端LED,根据开发板LED引脚设值,这里对应GPIO MIO 7)
#define EMIO_KEY 54 //宏定义KEY管脚(PL端KEY,根据EMIO管脚分配设值,这里对应GPIO 54)
//===========================实例化===========================//
XGpioPs Gpio; //GPIO驱动实例
XScuGic Intc; //中断控制器驱动实例
//===========================函数变量声明===========================//
static void Gpio_Init(); //GPIO初始化
static void IntrHandler(); //中断处理函数
static void Setup_Intr_System(XScuGic *GicInstancePtr, XGpioPs *Gpio, u16 GpioIntrId); //建立中断系统
static u32 key_value;
int main()
{
xil_printf("GPIO Interrupt Test \r\n");
Gpio_Init();
Setup_Intr_System(&Intc,&Gpio,GPIO_INTERRUPT_ID);
while(1)
return 0;
}
//===========================中断处理函数===========================//
void IntrHandler()
{
//屏蔽按键中断
XGpioPs_IntrDisablePin(&Gpio, EMIO_KEY);
//按键消抖延时20ns(不消抖会反复中断)
usleep(20000);
//延时后键值高电平说明有效(按下为1)
if( XGpioPs_ReadPin(&Gpio, EMIO_KEY) == 1 ) //读取键值
{
//debug打印字符串
xil_printf("Interrupt detected! \n\r");
//翻转数据并写入LED
key_value = ~key_value;
XGpioPs_WritePin(&Gpio, MIO_LED, key_value);
}
//清除EMIO_KEY中断状态(不清除会一直触发中断,导致死循环)
XGpioPs_IntrClearPin(&Gpio, EMIO_KEY);
//重新使能按键中断
XGpioPs_IntrEnablePin(&Gpio, EMIO_KEY);
}
//===========================GPIO初始化函数===========================//
void Gpio_Init()
{
//定义GPIO配置信息(指针类型)
XGpioPs_Config * ConfigPtr;
//根据器件ID,查找GPIO配置信息
ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
//初始化器件驱动
XGpioPs_CfgInitialize(&Gpio, ConfigPtr, ConfigPtr->BaseAddr);
//GPIO方向设置(0输入/1输出)
XGpioPs_SetDirectionPin(&Gpio, MIO_LED, 1);
XGpioPs_SetDirectionPin(&Gpio, EMIO_KEY, 0);
//设置输出使能(1使能)
XGpioPs_SetOutputEnablePin(&Gpio, MIO_LED, 1);
}
//===========================建立中断系统===========================//
/* 建立中断系统,使能EMIO_KEY按键的上升沿产生中断
* @param GicInstancePtr 是一个指向 XScuGic 驱动实例的指针
* @param Gpio 是一个指向连接到中断的 GPIO 驱动实例的指针
* @param GpioIntrId 是 Gpio中断控制器ID
*/
void Setup_Intr_System(XScuGic *GicInstancePtr, XGpioPs *Gpio, u16 GpioIntrId)
{
//定义中断控制器配置信息(指针类型)
XScuGic_Config * IntcConfig;
//根据中断控制器ID,查找GIC配置信息(Generic Interrupt Controller(通用)中断控制器)
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
//初始化中断控制器驱动
XScuGic_CfgInitialize(GicInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress);
//设置并打开中断异常处理功能
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
GicInstancePtr);
Xil_ExceptionEnable();
//为GPIO中断设置中断处理函数(IntrHandler为自己编写的中断函数)
XScuGic_Connect(GicInstancePtr, GpioIntrId,
(Xil_ExceptionHandler)IntrHandler,
(void *)&Gpio);
//使能处理器中断
Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
//使能来自GPIO器件的中断
XScuGic_Enable(GicInstancePtr, GpioIntrId);
//设置GPIO引脚的中断类型(设置EMIO_KEY引脚上升沿时中断)
XGpioPs_SetIntrTypePin(Gpio, EMIO_KEY, XGPIOPS_IRQ_TYPE_EDGE_RISING);
//使能来自GPIO引脚的中断
XGpioPs_IntrEnablePin(Gpio, EMIO_KEY);
}
四、效果
上板启动串口发送测试信息,之后每当按一次按键时,串口发送中断debug信息,同时LED灯状态翻转一次。