本次实验主要演示EMIO 的GPIO读取功能
本文在 vivado2018.3版本上 演示, 其他版本请自行研究
(备注 此章节内容适用于 Smart ZYNQ SP和SL 版的板子,如果是Smart ZYNQ 标准版请看对应板子目录)
硬件介绍
先看原理图,由原理图可以看出板子上接了两个按键,并且默认是通过上拉电阻上拉到3.3V的,也就是当按键没有按下的时候 按键KEY 的信号脚是3.3V ,当按键按下后,该信号脚被拉低到GND也就是0V 同样也能看出 两个按键分别连接到了 FPGA芯片的J20和K21管脚上
![](http://www.hellofpga.com/wp-content/uploads/2023/04/image-20.png)
为了演示两个按键的功能,这里再引入两个指示灯,指示灯之前3节的例子里测试过,将LED的驱动脚拉高,指示灯亮,拉低指示灯熄灭,指示灯分别接在主芯片的P20和P21脚
![](http://www.hellofpga.com/wp-content/uploads/2023/04/image-21.png)
工程创建
完整的工程创建图文教程前面已经详细图文描写了,可以参考前面的工程,这里仅仅增加关键步骤。 详细过程可以参考 Smart ZYNQ(SP&SL 版) 工程七 用ZYNQ的PS点亮连接到PL端的LED灯EMIO 方式
器件名称选择 XC7Z020CLG484-1
在BLOCK DESIGN 中搜索并添加一个ZYNQ模块
在ZYNQ 设置界面,设置 DDR MT41K256M16RE-125的型号 和位宽16bit
![](http://www.hellofpga.com/wp-content/uploads/2023/01/image-92.png)
添加4个EMIO ,其中两个用来驱动LED灯,另两个用来读取按键KEY的信息
![](http://www.hellofpga.com/wp-content/uploads/2022/11/image-19.png)
对GPIO make external,并且连接AXI的时钟(AXI默认开启的,这里用不到AXI,也可以去设置里关闭AXI功能,就不需要连接了)
![](http://www.hellofpga.com/wp-content/uploads/2022/11/image-21.png)
之后 点选Create HDL Wrapper
![](http://www.hellofpga.com/wp-content/uploads/2022/11/image-22.png)
之后创建和添加约束文件:
可以在图文界面里设置管脚定义
![](http://www.hellofpga.com/wp-content/uploads/2023/01/image-97-1024x566.png)
也可以在约束文件里添加管脚定义的描述
set_property PACKAGE_PIN P20 [get_ports {GPIO_0_0_tri_io[3]}] set_property PACKAGE_PIN P21 [get_ports {GPIO_0_0_tri_io[2]}] set_property PACKAGE_PIN K21 [get_ports {GPIO_0_0_tri_io[1]}] set_property PACKAGE_PIN J20 [get_ports {GPIO_0_0_tri_io[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {GPIO_0_0_tri_io[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {GPIO_0_0_tri_io[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {GPIO_0_0_tri_io[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {GPIO_0_0_tri_io[0]}]
之后对程序进行正常的编译综合,并且导出 Export Hardware (勾选 include bitstream)供SDK加载
![](http://www.hellofpga.com/wp-content/uploads/2022/11/image-24.png)
![](http://www.hellofpga.com/wp-content/uploads/2022/11/image-25.png)
程序设计:
建立一个名为KEY_TEST空的工程,并且添加main.c 添加如下代码:
#include "xparameters.h" #include "xgpiops.h" #include "xstatus.h" #include "xplatform_info.h" #include "xscutimer.h" #include "Xscugic.h" #define LED2 57 #define LED1 56 #define KEY2 55 #define KEY1 54 #define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID XGpioPs Gpio; void Gpio_Init(void){ XGpioPs_Config *ConfigPtr; ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID); XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr); XGpioPs_SetDirectionPin(&Gpio, LED1, 1); XGpioPs_SetOutputEnablePin(&Gpio, LED1, 1); XGpioPs_WritePin(&Gpio, LED1, 1); XGpioPs_SetDirectionPin(&Gpio, LED2, 1); XGpioPs_SetOutputEnablePin(&Gpio, LED2, 1); XGpioPs_WritePin(&Gpio, LED2, 1); XGpioPs_SetDirectionPin(&Gpio, KEY1, 0); XGpioPs_SetDirectionPin(&Gpio, KEY2, 0); } int main(void) { Gpio_Init(); while(1){ if(XGpioPs_ReadPin(&Gpio, KEY1)==0){ XGpioPs_WritePin(&Gpio, LED1, 1); XGpioPs_WritePin(&Gpio, LED2, 0); } else if(XGpioPs_ReadPin(&Gpio, KEY2)==0){ XGpioPs_WritePin(&Gpio, LED1, 0); XGpioPs_WritePin(&Gpio, LED2, 1); } } return 0; }
程序很简单, Gpio_Init是对4个GPIO进行初始化, 因为EMIO 是从54的管脚号开始的,所以根据原先VIVADO 的管脚约束来看,两个按键应该对应54和55,两个LED灯对应56和57
#define LED2 57 #define LED1 56 #define KEY2 55 #define KEY1 54
XGpioPs_SetDirectionPin(&Gpio, KEY1, 0); 最后的0代表输入,XGpioPs_WritePin(&Gpio, LED1, 1);像 这个最后的1就代表输出。
主程序也非常简单, 对GPIO初始化之后 就开始循环查看按键状态,当按键1按下时LED1亮,LED2熄灭, 当按键2按下时LED2亮LED1熄灭(上电后两个灯默认都亮)
程序仅作演示,实际项目中需要对按键增加按键消抖程序,否则按下瞬间会反复触发程序代码
以下是完整工程(仅供学习参考)