一. 实验任务
通过PS的按键对led进行控制,按下按键led灯亮,不按则灭
二. 实验操作
2.1 了解PS
PS(Programming System),是ZYNQ开发板上区别于FPGA(PL)的另一部分。二者可进行数据交互,相互配合以达到更好的目的。
笔者自己画的草图,画工不好,大家见谅,给大家附上一张来自Vivado的专业图片。
我们接下来深入看看PS的框架。
我们可以看到,它具有的东西非常之多。但不要紧,我们逐步了解即可。
1.PS的核心:APU,它的核心之核心就是ARM Cortex - A9 CPU.
2.I/O外设: 就是左边很多绿色小格子,有SPI,I2C,UART,GPIO等等。今天实验咱们用到的就是GPIO和UART接口。
3.MIO: 复用多用接口,就是板子接口不够用了怎么办,把接口给到MIO,通过软件控制来确定此时此刻是哪个接口在工作。
先介绍这么多,够咱们这次实验了即可。
2.2 开始操作
首先,我们需要明确,大致需要干什么。 —> (五步)
Step1 : 创建一个BD (Block Design)
这样第一步就完成了。接下来开始第二步
Step2 : 配置BD
咱们只需要红色部分,其他的都给他去掉。
点击OK,这样咱们就配置好了
然后点击绿色栏的蓝色字体即可。
Step3 : 创建顶层HDL
等待生成结束,之后按照下图操作
完成后,就会变成下图模样,顶层HDL即创建完成
Step4 : 导出硬件,启动SDK
结束后,进行下图操作
进入SDK,硬件部分结束,进入软件部分
Step5 : 代码编写
这就是刚进去加载完成的页面,咱们来创建工程
因为这部分很机械而且太繁琐了,没有技术含量,我是想主要搞代码的,所以就当大家创建已经OK了,咱们先来看代码部分。创建的问题,我有时间的话放到评论区吧。
这就是代码编写的界面了
代码还是老规矩,先给到大家。
#include "stdio.h"
#include "xparameters.h"
#include "xscugic.h"
#include "xgpiops.h"
#include "xil_printf.h"
#include "xil_exception.h"
#include "sleep.h"
/* GPIO paramter */
#define MIO_ID XPAR_PS7_GPIO_0_DEVICE_ID
#define PS_KEY_MIO 0
#define PS_LED1_MIO 50
#define PS_LED2_MIO 51
#define GPIO_INPUT 0
#define GPIO_OUTPUT 1
XGpioPs GPIO_PTR ;
XScuGic INTCInst;
int mio_value=0;
int main()
{
XGpioPs_Config *GpioConfig ;
int Status ;
printf("PS MIO input demo,both key1 pressed and up!\n");
/*
* Initialize the gpio.
*/
GpioConfig = XGpioPs_LookupConfig(MIO_ID);
Status = XGpioPs_CfgInitialize(&GPIO_PTR, GpioConfig, GpioConfig->BaseAddr) ;
if (Status != XST_SUCCESS) return XST_FAILURE ;
/*
* Set the direction for the pin to be input.
* Set interrupt type as rising edge and enable gpio interrupt
*/
XGpioPs_SetDirectionPin(&GPIO_PTR, PS_KEY_MIO, GPIO_INPUT) ;
XGpioPs_SetDirectionPin(&GPIO_PTR, PS_LED1_MIO, GPIO_OUTPUT) ;
XGpioPs_SetDirectionPin(&GPIO_PTR, PS_LED2_MIO, GPIO_OUTPUT) ;
XGpioPs_SetOutputEnablePin(&GPIO_PTR, PS_LED1_MIO,1);
XGpioPs_SetOutputEnablePin(&GPIO_PTR, PS_LED2_MIO,1);
XGpioPs_SetIntrTypePin(&GPIO_PTR, PS_KEY_MIO,XGPIOPS_IRQ_TYPE_EDGE_BOTH) ;//interrupt rising falling edge
XGpioPs_IntrEnablePin(&GPIO_PTR, PS_KEY_MIO) ;
/*
* sets up the interrupt system
*/
//if you want use interrupt detect,use follow init code:
//Status = IntrInitFuntion(&INTCInst, MIO_ID, &GPIO_PTR) ;
//if (Status != XST_SUCCESS)return XST_FAILURE ;
while(1)
{
usleep(500000);
mio_value=XGpioPs_ReadPin(&GPIO_PTR, PS_KEY_MIO) ;
printf("the key value=%d\n",mio_value);
if (mio_value==0)
{
XGpioPs_WritePin(&GPIO_PTR, PS_LED1_MIO, 1);
XGpioPs_WritePin(&GPIO_PTR, PS_LED2_MIO, 1);
}
else if(mio_value==1)
{
XGpioPs_WritePin(&GPIO_PTR, PS_LED1_MIO, 0);
XGpioPs_WritePin(&GPIO_PTR, PS_LED2_MIO, 0);
}
}
return 0 ;
}
一如既往的很长很难看。咱们还是先看看几个重要的东西
1.前期准备
#include "stdio.h" //引入库
#include "xparameters.h"
#include "xscugic.h"
#include "xgpiops.h"
#include "xil_printf.h"
#include "xil_exception.h"
#include "sleep.h"
/* GPIO paramter */ //宏定义参数,包括引脚
#define MIO_ID XPAR_PS7_GPIO_0_DEVICE_ID
#define PS_KEY_MIO 0
#define PS_LED1_MIO 50
#define PS_LED2_MIO 51
#define GPIO_INPUT 0
#define GPIO_OUTPUT 1
XGpioPs GPIO_PTR ; //就是在代码开头来这么一行 XGpioPs InstancePt,调用的时候为&InstancePt
XScuGic INTCInst;
int mio_value=0;
int main()
{
XGpioPs_Config *GpioConfig ;
int Status ;
printf("PS MIO input demo,both key1 pressed and up!\n");
2.初始化
GpioConfig = XGpioPs_LookupConfig(MIO_ID);
Status = XGpioPs_CfgInitialize(&GPIO_PTR, GpioConfig, GpioConfig->BaseAddr) ;
if (Status != XST_SUCCESS) return XST_FAILURE ;
调用了两个函数进行初始化。
3.配置输入输出
主要是通过函数进行配置。
XGpioPs_SetDirectionPin(&GPIO_PTR, PS_KEY_MIO, GPIO_INPUT) ;
XGpioPs_SetDirectionPin(&GPIO_PTR, PS_LED1_MIO, GPIO_OUTPUT) ;
XGpioPs_SetDirectionPin(&GPIO_PTR, PS_LED2_MIO, GPIO_OUTPUT) ;
XGpioPs_SetOutputEnablePin(&GPIO_PTR, PS_LED1_MIO,1);
XGpioPs_SetOutputEnablePin(&GPIO_PTR, PS_LED2_MIO,1);
XGpioPs_SetIntrTypePin(&GPIO_PTR, PS_KEY_MIO,XGPIOPS_IRQ_TYPE_EDGE_BOTH) ;//interrupt rising falling edge
XGpioPs_IntrEnablePin(&GPIO_PTR, PS_KEY_MIO) ;
4.控制逻辑的编写
这个逻辑很简单,我想大家都能看懂。只是不理解函数的作用罢了。
while(1)
{
usleep(500000); //每隔0.5s打印一次按键状态
mio_value=XGpioPs_ReadPin(&GPIO_PTR, PS_KEY_MIO) ;
printf("the key value=%d\n",mio_value);
if (mio_value==0)
{
XGpioPs_WritePin(&GPIO_PTR, PS_LED1_MIO, 1);
XGpioPs_WritePin(&GPIO_PTR, PS_LED2_MIO, 1);
}
else if(mio_value==1)
{
XGpioPs_WritePin(&GPIO_PTR, PS_LED1_MIO, 0);
XGpioPs_WritePin(&GPIO_PTR, PS_LED2_MIO, 0);
}
}
好,咱们现在开始凝练调用的函数。万一以后忘了,这里还能帮助你回忆。
XGpioPs_LookupConfig(DEVICE_ID); //初始化,ID一般由硬件配置好,这里给他接入到函数里面即可
XGpioPs_CfgInitialize(XGpioPs *InstancePtr, XGpioPs_Config *ConfigPtr,u32 EffectiveAddr); //初始化,判断是否初始化成功的
XGpioPs_SetDirectionPin(XGpioPs *InstancePtr, u32 Pin, u32 Direction); //设置引脚输入输出状态 0 输出; 1 输入
XGpioPs_SetOutputEnablePin(XGpioPs *InstancePtr, u8 Bank, u32 OpEnable); //设置引脚使能状态 0 关闭; 1 打开
XGpioPs_ReadPin(XGpioPs *InstancePtr, u32 Pin); //读出当前引脚状态
XGpioPs_WritePin(XGpioPs *InstancePtr, u8 Bank, u32 Data); //对引脚写入数据
//XGpioPs *InstancePtr 这个参数只需要在函数前定义了就行,系统内部经过某些函数会给它赋值
//就是在代码开头来这么一行 XGpioPs InstancePtr,调用的时候为&InstancePtr
三. 上机验证
经过本人上机验证,可以看到,按下灯亮,不按灯灭的实验结果。本次试验成功。