目录
一般来说ZYNQ可以有三种方式实现流水灯:MIO,EMIO,AXI GPIO。但是由于赛灵思的ZYNQ开发板MIO资源没有LED,所以实现流水灯只能EMIO或者AXI GPIO。这里使用AXI GPIO实现流水灯,为了更多的使用板子资源,在流水灯的基础上增加了按键,中断,定时器,串口等功能可以实现流水灯的方向的切换,精准定时等功能。同时也会给出AXI GPIO和EMIO实现流水灯的代码。
创建一个工程,添加ZYNQ IP核

点击自动连线

完成后双击打开,配置EMIO


配置EMIO位宽为2

然后添加AXI GPIO

点击自动连线

左边全勾上,接口选择led

然后点击ZYNQ核上的GPIO,刚刚才配置的,设置将引脚扩展处来,为后面PL分配引脚做准备。

然后删除USB端口,不然后面会报错
然后验证当前设计,出现如下弹窗,说明设计结果正确。

在 Sources 窗口中,选中 Design Sources 下的 .bd文件生成HDL 模块

然后进行分析与综合

分配引脚为刚刚我们设置的两个EMIO

按键原理图

设置按键引脚和电源值

保存引脚约束文件

然后生成字节流,因为用到了PL部分

将硬件导出

启动vitis进入软件编程部分

这里工程的建立就不说了,具体的可以参考前面的
主要是初始化LED和设置LED的输入输出方向
- int led_init(void)
- {
- int Status;
- //初始化GPIO
- Status = XGpio_Initialize(&Axi_Gpio, GPIO_DEVICE_ID);
- if (Status != XST_SUCCESS) //判断是否初始化成功
- {
- return XST_FAILURE;
- }
- //设置GPIO输入/输出模型 0:输出 1:输入
- XGpio_SetDataDirection(&Axi_Gpio, led_channel, 0x00);
- return XST_SUCCESS;
- }
主要是初始化Key和设置Key的输入输出方向
-
- int key_init(void)
- {
- int Status;
- //查找器件的ID,查找器件的配置信息
- ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
- if (ConfigPtr == NULL)
- {
- return XST_FAILURE;
- }
- //初始化GPIO驱动
- Status = XGpioPs_CfgInitialize(&Key_Gpio, ConfigPtr,ConfigPtr->BaseAddr);
- if (Status != XST_SUCCESS) //判断是否初始化成功
- {
- return XST_FAILURE;
- }
-
- //设置输出使能(最后一个参数:0表示关闭使能,1表示打开)
- XGpioPs_SetOutputEnablePin(&Key_Gpio, EMIO_KEY0, 1);
- XGpioPs_SetOutputEnablePin(&Key_Gpio, EMIO_KEY1, 1);
-
-
- //把GPIO的方向设置为输入(最后一个参数:0表示输入,1表示输出)
- XGpioPs_SetDirectionPin(&Key_Gpio, EMIO_KEY0, 0);
- XGpioPs_SetDirectionPin(&Key_Gpio, EMIO_KEY1, 0);
- return XST_SUCCESS;
-
- }
初始化定时器并且设置定时器的周期和模式。定时器周期计算主要是要主要私有定时器的时钟频率为CPU工作频率的一半。
- int timer_init(void)
- {
- int Status;
- //私有定时器初始化
- XScuTimer_Config *timer_cfg_ptr;
- timer_cfg_ptr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);
- if (timer_cfg_ptr == NULL)
- {
- return XST_FAILURE;
- }
- Status = XScuTimer_CfgInitialize(&Timer, timer_cfg_ptr,timer_cfg_ptr->BaseAddr);
- if (Status != XST_SUCCESS) //判断是否初始化成功
- {
- return XST_FAILURE;
- }
-
- XScuTimer_LoadTimer(&Timer, TIMER_LOAD_VALUE); // 加载计数周期
- XScuTimer_EnableAutoReload(&Timer); // 设置自动装载模式
- return XST_SUCCESS;
- }
中断处理固定模式:
①初始化中断控制器
②初始化CPU异常功能、向CPU注册异常处理回调函数、使能异常处理功能
③使能中断控制器、设置中断的类型、使能对应引脚的中断
④设置中断的回调函数(用户自己设置)
- int interrupt_init()
- {
- int Status;
- //初始化中断控制器
- XScuGic_Config *gic_cfg; //中断控制器配置信息
- gic_cfg = XScuGic_LookupConfig(INTC_DEVICE_ID);
- if (gic_cfg == NULL)
- {
- return XST_FAILURE;
- }
- Status = XScuGic_CfgInitialize(&Intc,gic_cfg,gic_cfg->CpuBaseAddress);
- if (Status != XST_SUCCESS) //判断是否初始化成功
- {
- return XST_FAILURE;
- }
- //初始化异常处理
- Xil_ExceptionInit();
- //CPU中断异常注册
- Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&Intc);
- //使能处理器中断
- Xil_ExceptionEnable();;
-
- //设置定时器中断: timer_intr_handler 中断处理函数
- XScuGic_Connect(&Intc, TIMER_IRPT_INTR,(Xil_ExceptionHandler)timer_intr_handler, &Timer);
-
-
- XScuGic_Enable(&Intc,TIMER_IRPT_INTR);//使能 GIC 中的定时器中断
- XScuTimer_EnableInterrupt(&Timer); //使能定时器中断
-
- return XST_SUCCESS;
- }
EMIO代码:
- #include "stdio.h"
- #include "xparameters.h"
- #include "xgpiops.h"
- #include "sleep.h"
-
- #define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
-
- //EMIO引脚从54开始算起
- #define EMIO_LED0 54
- #define EMIO_LED1 55
- #define EMIO_LED2 56
- #define EMIO_LED3 57
-
- #define EMIO_KEY0 58
- #define EMIO_KEY1 59
- int key_scan();
- XGpioPs_Config * ConfigPtr;
- XGpioPs Gpio; /* The driver instance for GPIO Device. */
-
- int main()
- {
- int key_value;
-
- //查找器件的ID,查找器件的配置信息
- ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
- //初始化GPIO驱动
- XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr);
-
- //LED:
- //把GPIO的方向设置为输出(最后一个参数:0表示输入,1表示输出)
- XGpioPs_SetDirectionPin(&Gpio, EMIO_LED0, 1);
- XGpioPs_SetDirectionPin(&Gpio, EMIO_LED1, 1);
- XGpioPs_SetDirectionPin(&Gpio, EMIO_LED2, 1);
- XGpioPs_SetDirectionPin(&Gpio, EMIO_LED3, 1);
-
- //设置输出使能(最后一个参数:0表示关闭使能,1表示打开)
- XGpioPs_SetOutputEnablePin(&Gpio, EMIO_LED0, 1);
- XGpioPs_SetOutputEnablePin(&Gpio, EMIO_LED1, 1);
- XGpioPs_SetOutputEnablePin(&Gpio, EMIO_LED2, 1);
- XGpioPs_SetOutputEnablePin(&Gpio, EMIO_LED3, 1);
-
-
- //KEY:
- //把GPIO的方向设置为输入(最后一个参数:0表示输入,1表示输出)
- XGpioPs_SetDirectionPin(&Gpio, EMIO_KEY0, 0);
- XGpioPs_SetDirectionPin(&Gpio, EMIO_KEY1, 0);
-
- while(1)
- {
- key_value = key_scan();
- if(key_value ==1)
- {
- //将按键的状态写入LED
- XGpioPs_WritePin(&Gpio, EMIO_LED1,1);
-
- }
- else if(key_value ==2)
- {
-
- XGpioPs_WritePin(&Gpio, EMIO_LED1,0);
-
- }
- }
- return 0;
- }
-
-
- int key_scan()
- {
- int val=0;
- if(XGpioPs_ReadPin(&Gpio, EMIO_KEY0) == 1)
- val = 1;
- if(XGpioPs_ReadPin(&Gpio, EMIO_KEY1) == 1)
- val = 2;
-
- return val;
- }
AXI GPIO代码:
- #include "xparameters.h"
- #include "xgpiops.h"
- #include "xscugic.h"
- #include "xil_exception.h"
- #include "xplatform_info.h"
- #include
- #include "xgpio.h"
- #include "xscutimer.h"
- #include "xil_exception.h"
-
- #define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID //GPIO ID
- #define TIMER_DEVICE_ID XPAR_XSCUTIMER_0_DEVICE_ID //定时器 ID
-
- #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID //中断控制器 ID
- #define TIMER_IRPT_INTR XPAR_SCUTIMER_INTR //定时器中断 ID
-
-
- static XScuGic Intc; //中断驱动程序实例
- static XScuTimer Timer; //定时器驱动程序实例
- #define TIMER_LOAD_VALUE 0x1EFE920 //定时器装载值 100ms中断 1EFE920
-
- //EMIO KEY
- static XGpioPs Key_Gpio; //gpio ps 驱动实例
- static XGpioPs_Config * ConfigPtr;
- #define EMIO_KEY0 54
- #define EMIO_KEY1 55
-
- //AXI GPIO
- #define led_channel 1 //LED灯引脚
- static XGpio Axi_Gpio; //GPIO设备的驱动实例
-
- static int key_val,key_down,key_up,key_old; //按键处理
- static int delay_cnt=0; //用于精准延时
-
- int led_init(void)
- {
- int Status;
- //初始化GPIO
- Status = XGpio_Initialize(&Axi_Gpio, GPIO_DEVICE_ID);
- if (Status != XST_SUCCESS) //判断是否初始化成功
- {
- return XST_FAILURE;
- }
- //设置GPIO输入/输出模型 0:输出 1:输入
- XGpio_SetDataDirection(&Axi_Gpio, led_channel, 0x00);
- return XST_SUCCESS;
- }
-
- int key_init(void)
- {
- int Status;
- //查找器件的ID,查找器件的配置信息
- ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
- if (ConfigPtr == NULL)
- {
- return XST_FAILURE;
- }
- //初始化GPIO驱动
- Status = XGpioPs_CfgInitialize(&Key_Gpio, ConfigPtr,ConfigPtr->BaseAddr);
- if (Status != XST_SUCCESS) //判断是否初始化成功
- {
- return XST_FAILURE;
- }
-
- //设置输出使能(最后一个参数:0表示关闭使能,1表示打开)
- XGpioPs_SetOutputEnablePin(&Key_Gpio, EMIO_KEY0, 1);
- XGpioPs_SetOutputEnablePin(&Key_Gpio, EMIO_KEY1, 1);
-
-
- //把GPIO的方向设置为输入(最后一个参数:0表示输入,1表示输出)
- XGpioPs_SetDirectionPin(&Key_Gpio, EMIO_KEY0, 0);
- XGpioPs_SetDirectionPin(&Key_Gpio, EMIO_KEY1, 0);
- return XST_SUCCESS;
-
- }
-
-
- int key_scan()
- {
- int val=0;
- if(XGpioPs_ReadPin(&Key_Gpio, EMIO_KEY0) == 1)
- val = 1;
- if(XGpioPs_ReadPin(&Key_Gpio, EMIO_KEY1) == 1)
- val = 2;
- return val;
- }
-
-
- //中断处理函数 100ms
- void timer_intr_handler(void *CallBackRef)
- {
- XScuTimer *timer_ptr = (XScuTimer *) CallBackRef;
-
- delay_cnt += 1;
-
- //处理按键
- key_val = key_scan();
- key_down = key_val & (key_old^key_val);
- key_up = ~key_val & (key_old^key_val);
- key_old = key_val;
-
- //清除定时器中断标志
- XScuTimer_ClearInterruptStatus(timer_ptr);
- }
-
- int interrupt_init()
- {
- int Status;
- //初始化中断控制器
- XScuGic_Config *gic_cfg; //中断控制器配置信息
- gic_cfg = XScuGic_LookupConfig(INTC_DEVICE_ID);
- if (gic_cfg == NULL)
- {
- return XST_FAILURE;
- }
- Status = XScuGic_CfgInitialize(&Intc,gic_cfg,gic_cfg->CpuBaseAddress);
- if (Status != XST_SUCCESS) //判断是否初始化成功
- {
- return XST_FAILURE;
- }
- //初始化异常处理
- Xil_ExceptionInit();
- //CPU中断异常注册
- Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&Intc);
- //使能处理器中断
- Xil_ExceptionEnable();;
-
- //设置定时器中断: timer_intr_handler 中断处理函数
- XScuGic_Connect(&Intc, TIMER_IRPT_INTR,(Xil_ExceptionHandler)timer_intr_handler, &Timer);
-
-
- XScuGic_Enable(&Intc,TIMER_IRPT_INTR);//使能 GIC 中的定时器中断
- XScuTimer_EnableInterrupt(&Timer); //使能定时器中断
-
- return XST_SUCCESS;
- }
-
- int timer_init(void)
- {
- int Status;
- //私有定时器初始化
- XScuTimer_Config *timer_cfg_ptr;
- timer_cfg_ptr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);
- if (timer_cfg_ptr == NULL)
- {
- return XST_FAILURE;
- }
- Status = XScuTimer_CfgInitialize(&Timer, timer_cfg_ptr,timer_cfg_ptr->BaseAddr);
- if (Status != XST_SUCCESS) //判断是否初始化成功
- {
- return XST_FAILURE;
- }
-
- XScuTimer_LoadTimer(&Timer, TIMER_LOAD_VALUE); // 加载计数周期
- XScuTimer_EnableAutoReload(&Timer); // 设置自动装载模式
- return XST_SUCCESS;
- }
-
- int main(void)
- {
- xil_printf("My test!\r\n");
-
- //led初始化
- int Status,key;
- int lval = 0x1,rval = 0x1;
- Status = led_init();
- if (Status != XST_SUCCESS)
- {
- xil_printf("LEDs init failed!\r\n");
- }
-
- //key初始化
- Status = key_init();
- if (Status != XST_SUCCESS)
- {
- xil_printf("Key init failed!\r\n");
- }
-
- //定时器初始化
- Status = timer_init();
- if (Status != XST_SUCCESS)
- {
- xil_printf("timer init failed!\r\n");
- }
- //中断初始化
- Status = interrupt_init(); //一定要先定时器初始化后再中断初始化
- if (Status != XST_SUCCESS)
- {
- xil_printf("interrupt init failed!\r\n");
- }
-
- XScuTimer_Start(&Timer); //启动定时器
-
- while(1)
- {
- if(key_down ==1) //右移
- {
- key = 1;
- }
- else if(key_down ==2)
- {
- key = 2;
- }
-
- if(key == 1)
- {
- if(delay_cnt >= 10) //1s
- {
- //将按键的状态写入LED
- XGpio_DiscreteWrite(&Axi_Gpio, led_channel, rval);
- rval = rval >>1;
- if(rval < 0x1)
- {
- rval = 0x8;
- }
- delay_cnt = 0;
- }
- }
- else if(key == 2)
- {
- if(delay_cnt >= 10)
- {
- //将按键的状态写入LED
- XGpio_DiscreteWrite(&Axi_Gpio, led_channel, lval);
- lval = lval <<1;
- if(lval > 0x8)
- {
- lval = 0x1;
- }
- delay_cnt = 0;
- }
- }
- }
-
- return 0;
- }
-