ZYNQ-实现GPIO的中断控制

简介: ZYNQ-实现GPIO的中断控制

学习内容


实现对GPIO的中断控制程序,实现按键按下使得led等闪亮一次,并结合前文的IIC工程,实现按键控制iic的数据采集。

开发环境


vivado 18.3

SDK

PYNQ-Z2

中断初始化的设置


对于熟悉ARM和32开发的人来说,中断的概念对其并不陌生。下面我给出按键在32开发时候的初始化的流程:

按键中断编程步骤分析:

  1. 使能相应的时钟
  2. 配置GPIO管脚为中断功能
  3. 设置中断优先级
  4. 使能相应的中断
  5. 实现中断服务程序

然后我给出ZYNQ的中断初始化的设置流程:

  1. 初始化CPU异常功能
  2. 初始化中断控制器
  3. 向CPU注册异常处理回调函数
  4. 向中断控制器中对应的中断ID和中断控制器相连接
  5. 设置中断的类型
  6. 设置中断的回调函数(用户自己设置)
  7. 使能对应引脚的中断
  8. 使能中断控制器
  9. 使能异常处理功能

对比纯arm开发和zynq的开发,我们可以大致看出,两者在中断初始化的过程中有很多相似的地方。 因为zynq的功能比较多,比较复杂,在开发的时的配置过程也相对麻烦。

对应初始化过程中的每一步,我们可以找到对应的函数进行调用,具体过程如下:

image.png

硬件平台搭建


新建工程初始化我们需要用到了GPIO的资源引脚,具体的工程可以参考ZYNQ-利用PS引脚实现EMIO GPIO的驱动

这里只给出搭建后的结果:

(这里只进行设计了gpio可以实现对应按键控制灯闪烁)

image.png

SDK软件部分


新建工程后,在main中添加中断初始化代码:

#define SCUGIC_0_ID XPAR_PS7_SCUGIC_0_DEVICE_ID
#define GPIO_INTR_ID 52
#define SW_BANK_ID 2
static XScuGic GicPs;
static XScuGic_Config *XScuGic_Cfg;
int setupinterrupt(){
  int status;
  //初始化异常处理
  Xil_ExceptionInit();
  //初始化中断控制器
  XScuGic_Cfg = XScuGic_LookupConfig(SCUGIC_0_ID);
  status = XScuGic_CfgInitialize(&GicPs,XScuGic_Cfg,XScuGic_Cfg->CpuBaseAddress);
  if( status != XST_SUCCESS){
      return XST_FAILURE;
  }
  //CPU中断异常注册
  Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&GicPs);
  //链接中断信号
  status = XScuGic_Connect(&GicPs,GPIO_INTR_ID,(Xil_InterruptHandler)XGpioPs_IntrHandler,&GpioPs);
  if( status != XST_SUCCESS){
        return XST_FAILURE;
  }
  //中断类型设置
  XGpioPs_SetIntrType(&GpioPs,SW_BANK_ID,0xffffffff,0xffffffff,0x00);
  //设置中断回调函数
  XGpioPs_SetCallbackHandler(&GpioPs,(void *) &GpioPs, IntrHandler);
  //打开gpio中断
  XGpioPs_IntrEnable(&GpioPs,SW_BANK_ID,1<<(BTN1-54));
  XScuGic_Enable(&GicPs,GPIO_INTR_ID);
  Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
  return XST_SUCCESS;
}

对于部分参数的查找进行简单说明,具体函数的使用,可以参考system.mss中进行查找:

GPIO_INTR_ID :中断配置时,要对中断ID进行设置,否则对应不上配置的中断

image.png

image.png

SW_BANK_ID

因为我们BANK0和BANK1对应的是MIO的管脚是54个,我们声明的管脚在BANK 2,所以我们就设置的BANK ID为2

image.png

按键控制led


#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xgpiops.h"
#include "xparameters.h"
#include "xscugic.h"
#define GPIO_ID XPAR_PS7_GPIO_0_DEVICE_ID
#define SCUGIC_0_ID XPAR_PS7_SCUGIC_0_DEVICE_ID
#define GPIO_INTR_ID 52
#define SW_BANK_ID 2
#define LED0 54
#define LED1 55
#define BTN1 56
static XGpioPs GpioPs;
static XGpioPs_Config *XGpioPs_Cfg;
static XScuGic GicPs;
static XScuGic_Config *XScuGic_Cfg;
int initGpio();
int setupinterrupt();
void IntrHandler(void *CallBack,u32 Bank,u32 status);
int main()
{
  init_platform();
    initGpio();
    print("Hello World\n\r");
    setupinterrupt();
    while(1)
    {
      XGpioPs_WritePin(&GpioPs,LED0,0);
      XGpioPs_WritePin(&GpioPs,LED1,0);
      usleep(1000);
    }
    cleanup_platform();
    return 0;
}
int initGpio(){
  int status;
  XGpioPs_Cfg = XGpioPs_LookupConfig(GPIO_ID);
  status = XGpioPs_CfgInitialize(&GpioPs,XGpioPs_Cfg,XGpioPs_Cfg->BaseAddr);
  if( status != XST_SUCCESS){
    return XST_FAILURE;
  }
  XGpioPs_SetDirectionPin(&GpioPs,LED0,0x01);
  XGpioPs_SetOutputEnablePin(&GpioPs,LED0,0x01);
  XGpioPs_SetDirectionPin(&GpioPs,LED1,0x01);
  XGpioPs_SetOutputEnablePin(&GpioPs,LED1,0x01);
  XGpioPs_SetDirectionPin(&GpioPs,BTN1,0x00);
  XGpioPs_SetOutputEnablePin(&GpioPs,BTN1,0x00);
}
int setupinterrupt(){
  int status;
  //初始化异常处理
  Xil_ExceptionInit();
  //初始化中断控制器
  XScuGic_Cfg = XScuGic_LookupConfig(SCUGIC_0_ID);
  status = XScuGic_CfgInitialize(&GicPs,XScuGic_Cfg,XScuGic_Cfg->CpuBaseAddress);
  if( status != XST_SUCCESS){
      return XST_FAILURE;
  }
  //CPU中断异常注册
  Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&GicPs);
  //链接中断信号
  status = XScuGic_Connect(&GicPs,GPIO_INTR_ID,(Xil_InterruptHandler)XGpioPs_IntrHandler,&GpioPs);
  if( status != XST_SUCCESS){
        return XST_FAILURE;
  }
  //中断类型设置
  XGpioPs_SetIntrType(&GpioPs,SW_BANK_ID,0xffffffff,0xffffffff,0x00);
  //设置中断回调函数
  XGpioPs_SetCallbackHandler(&GpioPs,(void *) &GpioPs, IntrHandler);
  //打开gpio中断
  XGpioPs_IntrEnable(&GpioPs,SW_BANK_ID,1<<(BTN1-54));
  XScuGic_Enable(&GicPs,GPIO_INTR_ID);
  Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
  return XST_SUCCESS;
}
void IntrHandler(void *CallBack,u32 Bank,u32 status){
  XGpioPs *GPIO_ptr;
  u32 read_val;
  GPIO_ptr = (XGpioPs *)CallBack;
  if(XGpioPs_ReadPin(GPIO_ptr,BTN1) == 1)
  {
    XGpioPs_WritePin(GPIO_ptr,LED0,1);
    XGpioPs_WritePin(GPIO_ptr,LED1,1);
    printf("%d\n",XGpioPs_ReadPin(&GpioPs,BTN1));
    usleep(1000000);
  }
}

按键控制数据采集


/*
 * helloworld.c: simple test application
 *
 * This application configures UART 16550 to baud rate 9600.
 * PS7 UART (Zynq) is not initialized by this application, since
 * bootrom/bsp configures it to baud rate 115200
 *
 * ------------------------------------------------
 * | UART TYPE   BAUD RATE                        |
 * ------------------------------------------------
 *   uartns550   9600
 *   uartlite    Configurable only in HW design
 *   ps7_uart    115200 (configured by bootrom/bsp)
 */
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xgpiops.h"
#include "xiicps.h"
#include "xparameters.h"
#include "xscugic.h"
#define GPIO_ID XPAR_PS7_GPIO_0_DEVICE_ID
#define SCUGIC_0_ID XPAR_PS7_SCUGIC_0_DEVICE_ID
#define I2C_0_DEVICE_ID XPAR_PS7_I2C_0_DEVICE_ID
#define I2C_0_CLK 100000
#define IIC_0_SALV_ADDR 0x23 //定义器件在IIC总线中的从地址,根据ALT  ADDRESS地址引脚不同修改
                              //ALT  ADDRESS引脚接地时地址为0x23
#define GPIO_INTR_ID 52
#define SW_BANK_ID 2
#define LED0 54
#define LED1 55
#define BTN1 56
//声明结构体
static XGpioPs GpioPs;
static XGpioPs_Config *XGpioPs_Cfg;
static XScuGic GicPs;
static XScuGic_Config *XScuGic_Cfg;
// XIicPs* iicps;
static XIicPs iicps;
static XIicPs_Config * iicpscfgtr;
int status;
  double out=0;
  unsigned short tmp;
    unsigned char Cmdon = 0x01;
  unsigned char Cmdlight = 0x10;
  char temp[2];
int initGpio();
int setupinterrupt();
//初始化 iic
int InitIic(XIicPs *iips,XIicPs_Config *iiccfg);
void IntrHandler(void *CallBack,u32 Bank,u32 status);
int main()
{
  init_platform();
    initGpio();
    setupinterrupt();
    status=InitIic(&iicps,iicpscfgtr);
  if(status !=XST_SUCCESS){
    return XST_FAILURE;
  }
  //初始化
  status = XIicPs_MasterSendPolled(&iicps,&Cmdon,1,IIC_0_SALV_ADDR);
  if(status !=XST_SUCCESS){
    return XST_FAILURE;
  }
    usleep(10000);//延时10ms
    printf("init iic successful!\n");
    while(1)
    {
      XGpioPs_WritePin(&GpioPs,LED0,0);
      XGpioPs_WritePin(&GpioPs,LED1,0);
      usleep(1000);
    }
    cleanup_platform();
    return 0;
}
int initGpio(){
  int status;
  XGpioPs_Cfg = XGpioPs_LookupConfig(GPIO_ID);
  status = XGpioPs_CfgInitialize(&GpioPs,XGpioPs_Cfg,XGpioPs_Cfg->BaseAddr);
  if( status != XST_SUCCESS){
    return XST_FAILURE;
  }
  XGpioPs_SetDirectionPin(&GpioPs,LED0,0x01);
  XGpioPs_SetOutputEnablePin(&GpioPs,LED0,0x01);
  XGpioPs_SetDirectionPin(&GpioPs,LED1,0x01);
  XGpioPs_SetOutputEnablePin(&GpioPs,LED1,0x01);
  XGpioPs_SetDirectionPin(&GpioPs,BTN1,0x00);
  XGpioPs_SetOutputEnablePin(&GpioPs,BTN1,0x00);
}
int InitIic(XIicPs *iips,XIicPs_Config * iiccfg){
  int status;
  iiccfg = XIicPs_LookupConfig(I2C_0_DEVICE_ID);
  status = XIicPs_CfgInitialize(iips,iiccfg,iiccfg->BaseAddress);
  if(status !=XST_SUCCESS){
    return XST_FAILURE;
  }
  status = XIicPs_SelfTest(iips);
      if (status != XST_SUCCESS) {
        return XST_FAILURE;
      }
  status = XIicPs_SetSClk(iips,I2C_0_CLK);
  if(status !=XST_SUCCESS){
    return XST_FAILURE;
  }
  return 0;
}
int setupinterrupt(){
  int status;
  //初始化异常处理
  Xil_ExceptionInit();
  //初始化中断控制器
  XScuGic_Cfg = XScuGic_LookupConfig(SCUGIC_0_ID);
  status = XScuGic_CfgInitialize(&GicPs,XScuGic_Cfg,XScuGic_Cfg->CpuBaseAddress);
  if( status != XST_SUCCESS){
      return XST_FAILURE;
  }
  //CPU中断异常注册
  Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&GicPs);
  //链接中断信号
  status = XScuGic_Connect(&GicPs,GPIO_INTR_ID,(Xil_InterruptHandler)XGpioPs_IntrHandler,&GpioPs);
  if( status != XST_SUCCESS){
        return XST_FAILURE;
  }
  //中断类型设置
  XGpioPs_SetIntrType(&GpioPs,SW_BANK_ID,0xffffffff,0xffffffff,0x00);
  //设置中断回调函数
  XGpioPs_SetCallbackHandler(&GpioPs,(void *) &GpioPs, IntrHandler);
  //打开gpio中断
  XGpioPs_IntrEnable(&GpioPs,SW_BANK_ID,1<<(BTN1-54));
  XScuGic_Enable(&GicPs,GPIO_INTR_ID);
  Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
  return XST_SUCCESS;
}
void IntrHandler(void *CallBack,u32 Bank,u32 status){
  XGpioPs *GPIO_ptr;
  u32 read_val;
  GPIO_ptr = (XGpioPs *)CallBack;
  if(XGpioPs_ReadPin(GPIO_ptr,BTN1) == 1)
  {
        XGpioPs_WritePin(&GpioPs,LED0,1);
        status = XIicPs_MasterSendPolled(&iicps,&Cmdon,1,IIC_0_SALV_ADDR);
          if(status !=XST_SUCCESS){
           return XST_FAILURE;
          }
        status = XIicPs_MasterSendPolled(&iicps,&Cmdlight,1,IIC_0_SALV_ADDR);
        if(status !=XST_SUCCESS){
              return XST_FAILURE;
          }
        usleep(180000);//延时180ms
        status = XIicPs_MasterRecvPolled(&iicps,&temp,2,IIC_0_SALV_ADDR);
        //串口检测结果
        tmp = (temp[0]<<8)| temp[1];
        out = tmp/1.2;
        printf("light intensity : %.1f lx\n",out);
        usleep(1000000);
  }
}

运行效果


image.png

目录
相关文章
|
传感器 开发工具 C语言
EXTI外部中断介绍(内置1.中断系统+2.中断执行流程+3.STM32中断+4.NVIC基本结构+5.NVIC优先级分组+6.EXTI简介+7.EXTI基本结构...)
EXTI外部中断介绍(内置1.中断系统+2.中断执行流程+3.STM32中断+4.NVIC基本结构+5.NVIC优先级分组+6.EXTI简介+7.EXTI基本结构...)
340 0
EXTI外部中断介绍(内置1.中断系统+2.中断执行流程+3.STM32中断+4.NVIC基本结构+5.NVIC优先级分组+6.EXTI简介+7.EXTI基本结构...)
|
6月前
|
机器人 异构计算 SoC
实例2:树莓派GPIO控制外部LED灯闪烁
本文是一个关于使用树莓派GPIO控制外部LED灯闪烁的实验教程,介绍了树莓派的基本概念、GPIO接口的使用、RPi.GPIO库的基本操作,以及通过Python编程实现LED灯周期性闪烁的详细步骤和代码示例。
182 1
实例2:树莓派GPIO控制外部LED灯闪烁
|
9月前
|
C语言 芯片
LED 底层原理 和 GPIO引脚、寄存器操作
LED 底层原理 和 GPIO引脚、寄存器操作
LED 底层原理 和 GPIO引脚、寄存器操作
|
存储 开发工具 芯片
ZYNQ-UART串口中断测试
ZYNQ-UART串口中断测试
846 0
ZYNQ-UART串口中断测试
|
9月前
|
Linux API 开发者
设备树知识小全(九):GPIO、时钟、pinmux连接
设备树知识小全(九):GPIO、时钟、pinmux连接
416 0
STM32使用寄存器通过控制GPIO点亮一盏灯
STM32使用寄存器通过控制GPIO点亮一盏灯
122 0
STM32使用寄存器通过控制GPIO点亮一盏灯
【STM32】通用定时器TIM2-TIM5中断配置方式+继电器控制
【STM32】通用定时器TIM2-TIM5中断配置方式+继电器控制
486 0
STM32学习笔记(2) 使用外部中断控制按键
NVIC_IRQChannel ​​​​:对于RCT6来说,它的中断源如上图所示,在stm32f103.h中已经配置好寄存器,直接调用即可,下图中,RCT6主要用的是STM32F103X_HD的中断源
273 0
|
安全 开发工具 Perl
ZYNQ-定时器中断使用
ZYNQ-定时器中断使用
374 0
ZYNQ-定时器中断使用
|
编译器
STM32的HAL库开发系列 - GPIO中断/外部中断EXTI
STM32的HAL库开发系列 - GPIO中断/外部中断EXTI
713 0