Xilinx ZYNQ 7000+Vivado2015.2系列(十四)按键中断控制LED亮灭
前面我们介绍了按键中断,其实我们稍作修改就可以用按键控制LED了。
做个小实验,两个按键分别控制两个led亮灭。
板子:zc702。
硬件部分
添加zynq核:
勾选串口用于打印信息,勾选EMIO,我们控制两个led,所以需要2bit
PL 到PS的中断勾选上:
PL时钟什么的都用不到,我们用的按键不需要时钟,EMIO属于PS。
再添加一个concat IP用于合并两路按键信号:
最后连接完的系统:
In0,In1和GPIO_0需要自己右键make external
。
生成顶层文件。
添加约束文件:
在顶层模块找到相应的信号名称,将SW0,SW1连接到SW5,SW7;将GPIO[1:0]连接到两个led:
#GPIO PMOD1
set_property PACKAGE_PIN E15 [get_ports {gpio_0_tri_io[0]}]
set_property IOSTANDARD LVCMOS25 [get_ports {gpio_0_tri_io[0]}]
set_property PACKAGE_PIN D15 [get_ports {gpio_0_tri_io[1]}]
set_property IOSTANDARD LVCMOS25 [get_ports {gpio_0_tri_io[1]}]
#SW5 SW7
set_property PACKAGE_PIN G19 [get_ports {SW0[0]}]
set_property IOSTANDARD LVCMOS25 [get_ports {SW0[0]}]
set_property PACKAGE_PIN F19 [get_ports {SW1[0]}]
set_property IOSTANDARD LVCMOS25 [get_ports {SW1[0]}]
生成bit文件。打开SDK。
软件部分
原理就是产生中断后在中断处理程序里完成控制led的操作。
#include <stdio.h>
#include "xscugic.h"
#include "xil_exception.h"
#include "xgpiops.h"
#include "sleep.h"
#define SW1_INT_ID 61
#define SW2_INT_ID 62
#define INTC_DEVICE_ID XPAR_PS7_SCUGIC_0_DEVICE_ID
static XScuGic INTCInst;
static void SW_intr_Handler(void *param);
static int IntcInitFunction(u16 DeviceId);
static int cnt1=0,cnt2=0;
static void SW_intr_Handler(void *param){
int sw_id = (int)param;
XGpioPs psGpioInstancePtr;
XGpioPs_Config* GpioConfigPtr;
int xStatus;
//-- EMIO的初始化
GpioConfigPtr = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID);
xStatus = XGpioPs_CfgInitialize(&psGpioInstancePtr,GpioConfigPtr,
GpioConfigPtr->BaseAddr);
if(sw_id==1){
cnt1++;
XGpioPs_SetDirectionPin(&psGpioInstancePtr, 54,1);
XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, 54,1);
if(cnt1%2){
XGpioPs_WritePin(&psGpioInstancePtr, 54, 1);//EMIO的第0位输出1
}else{
XGpioPs_WritePin(&psGpioInstancePtr, 54, 0);
}
XGpioPs_IntrClearPin(&psGpioInstancePtr, 54);
}
if(sw_id==2){
cnt2++;
XGpioPs_SetDirectionPin(&psGpioInstancePtr, 55,1);
XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, 55,1);
if(cnt2%2){
XGpioPs_WritePin(&psGpioInstancePtr, 55, 1);//EMIO的第1位输出0
}
else{
XGpioPs_WritePin(&psGpioInstancePtr, 55, 0);
}
XGpioPs_IntrClearPin(&psGpioInstancePtr, 55);
}
printf("led %d on\n\r",sw_id);
}
int IntcInitFunction(u16 DeviceId){
XScuGic_Config *IntcConfig;
int status;
// Interrupt controller initialisation
IntcConfig = XScuGic_LookupConfig(DeviceId);
status = XScuGic_CfgInitialize(&INTCInst, IntcConfig,
IntcConfig->CpuBaseAddress);
if(status != XST_SUCCESS) return XST_FAILURE;
// Call to interrupt setup
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
&INTCInst);
Xil_ExceptionEnable();
// Connect SW1~SW3 interrupt to handler
status = XScuGic_Connect(&INTCInst,
SW1_INT_ID,
(Xil_ExceptionHandler)SW_intr_Handler,
(void *)1);
if(status != XST_SUCCESS) return XST_FAILURE;
status = XScuGic_Connect(&INTCInst,
SW2_INT_ID,
(Xil_ExceptionHandler)SW_intr_Handler,
(void *)2);
if(status != XST_SUCCESS) return XST_FAILURE;
// Enable SW1~SW3 interrupts in the controller
XScuGic_Enable(&INTCInst, SW1_INT_ID);
XScuGic_Enable(&INTCInst, SW2_INT_ID);
return XST_SUCCESS;
}
int main(void){
printf("key interrupt control leds\n\r");
IntcInitFunction(INTC_DEVICE_ID);
while(1);
return 0;
}
定义使用GIC需要的两个结构体:XScuGic XScuGic\_Config
初始化GIC:XScuGic\_LookupConfig XScuGic\_CfgInitialize
Xil\_ExceptionRegisterHandler //在ARM里注册中断异常
Xil\_ExceptionEnable //异常使能
XScuGic\_Connect //连接到自定义中断处理函数
XScuGic\_Enable //GIC使能
自定义异常处理函数SW\_intr\_Handler()
里:
传进来的参数表明当前是哪个按键按下;
定义使用GPIO需要的两个结构体:XGpioPs XGpioPs\_Config
EMIO初始化:XGpioPs\_LookupConfig XGpioPs\_CfgInitialize
XGpioPs\_SetDirectionPin //设置GPIO是输入还是输出,1表示输出
XGpioPs\_SetOutputEnablePin //GPIO输出使能
XGpioPs\_WritePin //向pin脚写数据
XGpioPs\_IntrClearPin //废弃这个pin