微机原理实验——并行IO接口(二)

简介: 微机原理实验——并行IO接口(二)

实现过程


1 硬件平台搭建:

在Vivado 2018.1中,使用Xilinx

Nexys4开发板,搭建基于MicroBlaze软核的嵌入式系统硬件平台如下图8所示:


中断方式使用一个中断控制器:其中GPIO_0中断输出连接到Intr0,GPIO_2中断输出连接到Intr1,Timer_0中断输出连接到Intr2;中断控制器的中断向量输出连接到MicroBlaze微处理器的中断输入总线上。


其中对常用并行IO外设GPIO接口进行了配置(如图9):


16位开关和16位LED灯共用一个GPIO

IP核(设为GPIO_1),其中,开关使用GPIO通道,LED灯使用GPI2通道;四位七段数码管的位码与段码共用另一个GPIO

IP核(设为GPIO_0),其中,位码使用GPIO通道,段码使用GPIO2通道;两位按键使用另一个GPIO

IP核(设为GPIO_2)的GPIO通道;延时T0与T1使用Timer IP核(设为Timer_0)。



对并行IO中断系统进行了配置(如图10):


中断方式使用一个中断控制器:其中GPIO_1中断输出连接到Intr0;GPIO_2中断输出连接到Intr1;UART_0中断输出连接到Intr2;Timer_0中断输出连接到Intr3;


SPI_0中断输出连接到Intr4;

SPI_1中断输出连接到Intr5;;UART_1中断输出连接到Intr6;UART_2中断输出连接到Intr7.


中断控制器的中断向量输出连接到MicroBlaze微处理器的中断输入总线上。


如图所示:



对串行IO接口外设UART、SPI进行了配置(如图11):



生成HDL封装,查看硬件平台存储空间布局如下(如图12):



2. 程序控制方式实现任务1:

根据上面的分析,在主程序中设置按键对应GPIO通道工作在输入模式,开关对应的GPIO通道工作在输入模式,LED灯对应的GPIO通道工作在输出模式,设置并开始循环读取按键状态,如果按键状态改变,则根据按键的不同值,进入不同的if语句,来实现相应的功能:


· 当按键值为0x10,即BTNC被按下时,读取此时对应开关状态,存为csw1,并将其显示在LED灯上;


· 当按键值为0x10,即BTNR被按下时,读取此时对应开关状态,存为csw2,并将其显示在LED灯上;


· 当按键值为0x10,即BTNU被按下时,结果取r1 = csw1 +

csw2,并将结果r1显示在LED灯上;


· 当按键值为0x10,即BTND被按下时,结果取r2 = csw1

*csw2,并将结果r2显示在LED灯上.

\#include "stdio.h"
                \#include "xil_io.h"
                \#include "xgpio.h"
                int main()
                {
                short button;
                unsigned short csw1,csw2,r1,r2;
                Xil_Out8(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_TRI_OFFSET,0x1f);
                Xil_Out16(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_TRI2_OFFSET,0xffff);
                Xil_Out16(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_TRI_OFFSET,0x0);
                while(1)
                while((Xil_In8(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_DATA_OFFSET)&0x1f)!=0)
                {
                button =
                Xil_In8(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_DATA_OFFSET)\&0x1f;
                while((Xil_In8(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_DATA_OFFSET)\&0x1f)!=0);
                xil_printf("The pushed button's code is %d\\n" , button);
                if(button==0x10 ){
                csw1 =
                Xil_In16(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_DATA2_OFFSET)\&0xffff;
                Xil_Out16(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_DATA_OFFSET,csw1);
                }
                if(button ==0x8){
                csw2 =
                Xil_In16(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_DATA2_OFFSET)\&0xffff;
                Xil_Out16(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_DATA_OFFSET,csw2);
                }
                if(button ==0x1){
                r1 = csw1 + csw2;
                Xil_Out16(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_DATA_OFFSET,r1);
                }
                if(button ==0x4){
                r2 = csw1 \* csw2;
                Xil_Out16(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_DATA_OFFSET,r2);
                }
                }
                }


3. 并行IO接口中断控制方式实现任务2:

1.GPIO初始化:


对于程序控制方式,依据GPIO表格,写GPIO的TRI寄存器设置输入输出模式;



对于中断控制方式,还需要写IER寄存器以及GIER寄存器


实现代码如下:

Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR+XGPIO_TRI_OFFSET,0x0);//设段码输出方式
    Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR+XGPIO_TRI2_OFFSET,0x0);//设位码为输出方式
    Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_TRI_OFFSET,0x1f);//设地BUTTON方输入方式
    Xil_Out32(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_TRI2_OFFSET,0xffff);//设地Switch方输入方式
    Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_IER_OFFSET,XGPIO_IR_CH1_MASK);//允许中断
    Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_GIE_OFFSET,XGPIO_GIE_GINTR_ENABLE_MASK);//GPIO中断输出
    Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,


2.Timer_0初始化:


Timer_0初始化的操作流程为:首先停止计时(通过写TCSR寄存器使使能定时器这一位为0实现),然后再是写预置值(通过写TLR寄存器实现),紧接着装载预置值(通过写TCSR寄存器使装载这一位为1实现)然后再是写TCSR寄存器,控制定时器使能。清除源中断状态、使能中断、使能自动装载、减计数。


实现代码如下:

Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,
       Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET)&~XTC_CSR_ENABLE_TMR_MASK);//写TCSR,停止计数
    Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TLR_OFFSET,RESET_VALUE);//TLR,预置计数值
    Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,
        Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET)|XTC_CSR_LOAD_MASK);//
    Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,
        (Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET)&~XTC_CSR_LOAD_MASK)\
        |XTC_CSR_ENABLE_TMR_MASK|XTC_CSR_AUTO_RELOAD_MASK|XTC_CSR_ENABLE_INT_MASK|XTC_CSR_DOWN_COUNT_MASK);


3.INTC初始化与微处理器开中断:


INTC内部寄存器如下:


对中断控制器开中断:首先清除原中断状态,然后使能intr1和intr3对应的中断输入并使能中断输出(分别通过写IAR、IER以及MER寄存器实现);


MicroBlaze微处理器开中断:要实现微处理器开中断,我们可通过调用microblaze_enable_interrupt实现:


实现代码如下:

//INTC初始化
        Xil_Out32(XPAR_INTC_0_BASEADDR+XIN_IER_OFFSET,XPAR_AXI_GPIO_2_IP2INTC_IRPT_MASK\|XPAR_AXI_TIMER_0_INTERRUPT_MASK);//
        Xil_Out32(XPAR_INTC_0_BASEADDR+XIN_MER_OFFSET,0x3);
        //微处理器开中断
        microblaze_enable_interrupts();


1.总中断服务程序:


总中断服务程序,首先读取中断控制器的中断状态寄存器;然后判断D3是否为1,如果是1则表示按键状态发生了变化,因此调用按键对应的GPIO中断事务处理函数,返回之后,判断D3是否为1如果是1则表示Timer_0定时器计时时间到,因此调用Timer_0对应的中断事务处理函数。


实现代码如下:

void My_ISR()
        {
        int status;
        status=Xil_In32(XPAR_INTC_0_BASEADDR+XIN_ISR_OFFSET);//续敢ISR
        if((status&0x8)==0x8)
        Seg_TimerCounterHandler();//l溉用用户中断服务狂序
        else if((status&0x2)==0x2)
        BtnHandler();//l遴用按痉中断
        Xil_Out32(XPAR_INTC_0_BASEADDR+XIN_IAR_OFFSET,status);//写IAR
        }


2.Timer_0的中断事务处理函数:


T0通过gpio_0的GPIO2通道控制一位LED灯点亮,并准备下一位的输出后直接退出。


实现代码如下:

void Seg_TimerCounterHandler()
        {
        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR+XGPIO_DATA_OFFSET,segcode[j]);
        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR+XGPIO_DATA2_OFFSET,pos);
        pos=pos\>\>1;
        j++;
        if(j==8)
        {
        j=0;
        pos=0xff7f;
        }
        Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET));//满总中断
        }


3.按键的中断事务处理函数:


首先读取按键的状态,根据按键的值来实现相应功能:


实现代码如下:

void BtnHandler()
        {
        int button;
        unsigned short sw;
        int i;
        int temp;
        int q,w,e,r,t;
        sw = Xil_In16(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_DATA2_OFFSET)\&0xffff;
        button = Xil_In8(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_DATA_OFFSET)\&0x1f;
        if(button == 0x10) //(1)
        {
        short pos1 = 0x0080;
        for(i=0;i\<8;i++)
        {
        if((sw&pos1) != 0)
        temp = 1;
        else
        temp = 0;
        segcode[i] = segtable[temp];
        pos1=pos1\>\>1;
        }
        }
        else if(button == 0x1) //(2)
        {
        for(i=0;i\<8;i++)
        {
        if(i\>3){
        temp = ( sw \>\>(4\*(7-i)))\&0xf;
        segcode[i]=segtable[temp];
        }
        else
        segcode[i] = 0xff;
        }
        }else if(button == 0x4) //(3)
        {
        q = sw/10000;
        w = (sw-10000\*q)/1000;
        e = (sw-10000\*q-1000\*w)/100;
        r = (sw-10000\*q-1000\*w-100\*e)/10;
        t = (sw-10000\*q-1000\*w-100\*e-10\*r)/1;
        xil_printf("q=%d,w=%d,e=%d,r=%d,t=%d,",q,w,e,r,t);
        for(i=0;i\<8;i++)
        {
        if(i\>2){
        switch(i)
        {
        case 3:temp =q;break;
        case 4:temp =w;break;
        case 5:temp =e;break;
        case 6:temp =r;break;
        case 7:temp =t;break;
        default: break;
        }
        segcode[i] = segtable[temp];
        }
        else
        segcode[i] = 0xff;
        }
        }
        Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_ISR_OFFSET,
        Xil_In32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_ISR_OFFSET));
        }

 

4.完整代码:


最终的实现代码如下(上面的中断事务处理函数已折叠):

\#include "xil_io.h"
        \#include "stdio.h"
        \#include "xgpio_l.h"
        \#include "xintc_l.h"
        \#include "xtmrctr_l.h"
        \#define RESET_VALUE 100000
        void Seg_TimerCounterHandler();
        void BtnHandler();
        void My_ISR()__attribute__((interrupt_handler));//总中断服务雅序
        char segtable[16] = { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
        0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e };
        char segcode[8]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};//缓冲区
        short pos=0xff7f;
        int j = 0;
        int main()
        {
        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR+XGPIO_TRI_OFFSET,0x0);//设段码输出方式
        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR+XGPIO_TRI2_OFFSET,0x0);//设位码为输出方式
        Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_TRI_OFFSET,0x1f);//设地BUTTON方输入方式
        Xil_Out32(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_TRI2_OFFSET,0xffff);//设地Switch方输入方式
        Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_IER_OFFSET,XGPIO_IR_CH1_MASK);//允许中断
        Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_GIE_OFFSET,XGPIO_GIE_GINTR_ENABLE_MASK);//GPIO中断输出
        Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,
        Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET)\&\~XTC_CSR_ENABLE_TMR_MASK);//琛TCSR,停止计数
        Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TLR_OFFSET,RESET_VALUE);//TLR,预置计数值
        Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,
        Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET)\|XTC_CSR_LOAD_MASK);//
        Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,
        (Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET)&\~XTC_CSR_LOAD_MASK)\\
        \|XTC_CSR_ENABLE_TMR_MASK\|XTC_CSR_AUTO_RELOAD_MASK\|XTC_CSR_ENABLE_INT_MASK\|XTC_CSR_DOWN_COUNT_MASK);
        //INTC初始化
        Xil_Out32(XPAR_INTC_0_BASEADDR+XIN_IER_OFFSET,XPAR_AXI_GPIO_2_IP2INTC_IRPT_MASK\|XPAR_AXI_TIMER_0_INTERRUPT_MASK);//
        Xil_Out32(XPAR_INTC_0_BASEADDR+XIN_MER_OFFSET,0x3);
        //微处理器开中断
        microblaze_enable_interrupts();
        return 0;
        }
        void My_ISR()……
        void Seg_TimerCounterHandler()……
        void BtnHandler()……
目录
相关文章
|
6月前
|
存储 传感器 数据可视化
【软件设计师备考 专题 】IO接口的功能、类型和特性
【软件设计师备考 专题 】IO接口的功能、类型和特性
180 1
|
3月前
|
Java 数据处理
Java IO 接口(Input)究竟隐藏着怎样的神秘用法?快来一探究竟,解锁高效编程新境界!
【8月更文挑战第22天】Java的输入输出(IO)操作至关重要,它支持从多种来源读取数据,如文件、网络等。常用输入流包括`FileInputStream`,适用于按字节读取文件;结合`BufferedInputStream`可提升读取效率。此外,通过`Socket`和相关输入流,还能实现网络数据读取。合理选用这些流能有效支持程序的数据处理需求。
44 2
【IO面试题 五】、 Serializable接口为什么需要定义serialVersionUID变量?
serialVersionUID用于标识类的序列化版本,确保在反序列化时类的版本一致性,避免因类定义变更导致的不兼容问题。
|
3月前
|
Ubuntu Linux
内核实验(九):添加IO驱动的阻塞读写功能
本文通过修改内核模块代码,介绍了如何在Linux内核中为IO驱动添加阻塞读写功能,使用等待队列和条件唤醒机制来实现读写操作的阻塞和非阻塞模式,并在Qemu虚拟机上进行了编译、部署和测试。
16 0
|
6月前
|
设计模式 缓存 Java
【Java技术专题】「入门到精通系列教程」深入探索Java特性中并发编程体系的原理和实战开发指南( 实现可伸缩IO专题)— 上
【Java技术专题】「入门到精通系列教程」深入探索Java特性中并发编程体系的原理和实战开发指南( 实现可伸缩IO专题)— 上
77 0
|
5月前
|
存储 缓存 NoSQL
Redis为什么速度快:数据结构、存储及IO网络原理总结
Redis为什么速度快:数据结构、存储及IO网络原理总结
|
6月前
|
存储 Java
java IO接口(Input)用法
【5月更文挑战第1天】Java的`java.io`包包含多种输入输出类。此示例展示了如何使用`FileInputStream`从`input.txt`读取数据。首先创建`FileInputStream`对象,接着创建一个字节数组存储读取的数据,调用`read()`方法将文件内容填充至数组。然后将字节数组转换为字符串并打印,最后关闭输入流。注意,`InputStream`是抽象类,此处使用其子类`FileInputStream`。其他子类如`ByteArrayInputStream`、`ObjectInputStream`和`BufferedInputStream`各有特定用途。
65 2
|
6月前
|
缓存 Java 数据库
深入理解 Java IO 流:原理与应用
【4月更文挑战第4天】Java IO 浴是处理文件和数据输入输出的关键,涉及数据传输和处理。核心概念包括输入流(从源头读取)和输出流(写入目标),由InputStream和OutputStream接口定义基础操作。具体实现如FileInputStream和FileOutputStream用于文件操作,BufferedInputStream和BufferedOutputStream提升性能。IO流广泛应用于文件操作、网络通信、数据库交互和系统交互。其优点在于灵活性、可扩展性和高效性。使用时注意关闭流、处理异常及选择合适流实现。理解IO流原理和应用能提升编程效率和程序性能。
170 1
|
6月前
|
传感器 编解码 C语言
【软件设计师备考 专题 】IO设备、通信设备的性能,以及基本工作原理
【软件设计师备考 专题 】IO设备、通信设备的性能,以及基本工作原理
85 1
|
6月前
|
Java 大数据 数据库
【Spring底层原理高级进阶】Spring Batch清洗和转换数据,一键处理繁杂数据!Spring Batch是如何实现IO流优化的?本文详解!
【Spring底层原理高级进阶】Spring Batch清洗和转换数据,一键处理繁杂数据!Spring Batch是如何实现IO流优化的?本文详解!