• S02_CH09_UART串口中断实验


    S02_CH09_UART串口中断实验

    本章的UART中断将在之前PL_PS中断和定时器中断上推导出来,因此本章有点难度,如果前两章还不是很熟悉的话,需要返回到前面两章把这两章的内容再次消化一下,再来学习本章的内容。本章的硬件工程可以直接使用定时器中断的硬件工程,因此此次试验就直接到SDK软件部分。

    9.1 加载到SDK

    Step1:打开定时器中断的工程。

    Step2:导出硬件。

    Step3:新建一个空SDK工程,并添加一个main.c的文件。

    Step4:在main.c文件中添加以下程序,按Ctrl+S保存后自动开始编译。

    /*

    * main.c

    *

    *  Created on: 2016年6月26日

    *      Author: Administrator

    */

    #include <stdio.h>

    #include "xadcps.h"

    #include "xil_types.h"

    #include "Xscugic.h"

    #include "Xil_exception.h"

    #include "xuartps.h"

    //timer info

    #define UART_DEVICE_ID      XPAR_PS7_UART_1_DEVICE_ID

    #define INTC_DEVICE_ID      XPAR_SCUGIC_SINGLE_DEVICE_ID

    #define UART_IRPT_INTR      XPAR_XUARTPS_1_INTR

    static XScuGic Intc; //GIC

    static XUartPs Uart;//uart

    static void UartIntrHandler(void *CallBackRef)

    {

        XUartPs *InstancePtr = (XUartPs *) CallBackRef;

    u32 IsrStatus;

    u32 ReceivedCount=0;

    u32 CsrRegister;

    /*

    * Read the interrupt ID register to determine which

    * interrupt is active

    */

    IsrStatus = XUartPs_ReadReg(InstancePtr->Config.BaseAddress,

       XUARTPS_IMR_OFFSET);//e0001000+10=regaddr=e0001010

    IsrStatus &= XUartPs_ReadReg(InstancePtr->Config.BaseAddress,

       XUARTPS_ISR_OFFSET);//e0001000+14=regaddr=e0001014

    /* Dispatch an appropriate handler. */

    if((IsrStatus & ((u32)XUARTPS_IXR_RXOVR | (u32)XUARTPS_IXR_RXEMPTY |

    (u32)XUARTPS_IXR_RXFULL)) != (u32)0) {

    CsrRegister = XUartPs_ReadReg(InstancePtr->Config.BaseAddress,//判断FIFO触发标准位

    XUARTPS_SR_OFFSET);//e0001000+2c=regaddr=e000102c

    while((CsrRegister & XUARTPS_SR_RXEMPTY)== (u32)0){//读取FIFO中所有数据

    //InstancePtr->ReceiveBuffer.NextBytePtr[ReceivedCount] =//每次循环读取1byte

    ;

    XUartPs_WriteReg(InstancePtr->Config.BaseAddress,//每次循环发送读取到的数据

       XUARTPS_FIFO_OFFSET,

       XUartPs_ReadReg(InstancePtr->Config.

      BaseAddress,

      XUARTPS_FIFO_OFFSET));

    ReceivedCount++;//计数

    CsrRegister = XUartPs_ReadReg(InstancePtr->Config.BaseAddress,

    XUARTPS_SR_OFFSET);

    }

    }

    printf("this time ReceivedCount=%d ",ReceivedCount);

    XUartPs_WriteReg(InstancePtr->Config.BaseAddress, XUARTPS_ISR_OFFSET,

    IsrStatus);

    }

    void SetupInterruptSystem(XScuGic *GicInstancePtr,

    XUartPs *UartInstancePtr, u16 UartIntrId)

    {

            XScuGic_Config *IntcConfig; //GIC config

            Xil_ExceptionInit();

            //initialise the GIC

            IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);

            XScuGic_CfgInitialize(GicInstancePtr, IntcConfig,

                            IntcConfig->CpuBaseAddress);

            Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,

                        (Xil_ExceptionHandler)XScuGic_InterruptHandler,//connect to the hardware

                        GicInstancePtr);

            Xil_ExceptionEnable();

            XScuGic_Connect(GicInstancePtr, UartIntrId,

                            (Xil_InterruptHandler)UartIntrHandler,//set up the timer interrupt

                            (void *)UartInstancePtr);

            XScuGic_Enable(GicInstancePtr, UartIntrId);//enable the interrupt for the Timer at GIC

            XUartPs_SetInterruptMask(UartInstancePtr, XUARTPS_IXR_RXOVR/* | XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_TNFUL*/ );

           // XUartPs_EnableUart(UartInstancePtr);//enable interrupt on the timer

            Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ); //Enable interrupts in the Processor.

        }

    int main()

    {

    XUartPs_Config *UartConfigPtr;     //timer config

    //    printf("------------START------------- ");

         UartConfigPtr = XUartPs_LookupConfig(UART_DEVICE_ID);

         XUartPs_CfgInitialize(&Uart,UartConfigPtr,UartConfigPtr->BaseAddress);

         //set up the interrupts

         SetupInterruptSystem(&Intc,&Uart,UART_IRPT_INTR);

         while(1);

         return 0;

    }

    Step4:右击工程,选择Debug as ->Debug configuration。

    Step5:选中system Debugger,双击创建一个系统调试。

    wps7CA1.tmp

    Step6:设置系统调试。

    wps7CA2.tmp

    打开系统自带的窗口调试助手,点击运行按钮开始运行程序。

    wps7CB3.tmp

    系统运行结果如下图所示:

    wps7CB4.tmp

    9.2 程序分析

    本章的程序与之前两章的程序都大同小异,一些函数都在我们之前两章中看到和介绍过。

    首先我们先介绍下面三个宏定义。

    wps7CB5.tmp

    第一个是我们的UART的设备ID,第二个是我们中断的设备ID,第三个是UART的中断号。

    把鼠标停留在UART的中断号上,按下F3跟踪它,经过两次跟踪后,得到UART的中断号如下图所示:

    wps7CB6.tmp

    我们可以在ug585中查看一下中断号82是否是串口中断。

    wps7CC6.tmp

    可以看到,确实是串口中断,高电平触发。

    再来看看main函数中的内容。首先依然是通过查找配置程序来获取串口的硬件配置。我们跟踪这个程序,看看他获取的配置是什么。

    wps7CC7.tmp

    这个程序还是从一个配置表数组中查找的配置文件,继续往下剥离,看一看这个数组中的内容。

    wps7CD8.tmp

    可以看到,这个数组里存放的是UART的设备ID,UART的基地址,时钟频率和一个不知道什么作用的对象。后两个参数是我们没用到的,因此就略过了。前两个都是我们在硬件工程中添加了中断后,系统自动生成的。

    接下来还是一个熟悉的函数,对UART进行了初始化。可以看到这个函数的第一个参数指向了定义的UART指针,我们就跟踪一下这个指针。

    wps7CD9.tmp我们发现它指向了一个结构体,那么我们继续跟踪看看结构体中内容。

    wps7CDA.tmp

    这个结构体中的内容比较多,第一个对象是我们UART硬件的一些配置,它指向的是一个结构体。那么就来看看这个结构体吧。

    wps7CDB.tmp

    可以看到,这些就是刚才我们查找配置程序获取到的硬件参数。

    回到XUartPs结构体的分析。第二个对象是输入时钟频率,第三个是设备是否初始化并准备好,第四个是波特率,第五个是两个buffer,一个发送的一个接收的。挑选一个参看一下。

    wps7CEC.tmp

    接着第七个是一个Hander,第八个是一个回掉函数,最后一个是platform具体是什么意思不得而知。

    回到初始化程序。我们来看看这个函数与之前有什么不同了。

    wps7CED.tmp

    wps7CEE.tmp

    一开始是一长串的初始化,如下图所示:

    wps7CFE.tmp

    接下来的这个函数是一个用于判断芯片类型的函数。

    wps7CFF.tmp

    接下来,程序将Instance(也就是我们的UART硬件)的标志设置为XIL_COMPONENT_IS_READY,表明此时UART已经可以使用了。

    wps7D10.tmp

    接下来,程序将UART的波特率设置为了115200。

    wps7D11.tmp

    接下来的这一句是读取UART的模式寄存器。

    wps7D12.tmp

    我们可以来看看读取的什么内容,把鼠标停放在这个函数的上方,看到函数显示出了这个函数的原函数。

    wps7D13.tmp

    与我们定时器实验中讲到的读写寄存器的函数差不多,第一个参数是UART的基地址,这在我们一开始的分析中就提到过,我们反回去看看UART的基地址是多少。

    wps7D23.tmp

    可以知道,此处的基地址为0xE000100,直接计算:E0001000+0x0004= E0001004。打开ug585查看下这个寄存器的介绍。

    wps7D24.tmp

    wps7D25.tmp

    可以看到,这是一个UART的模式寄存器,通过这个寄存器可以设置串口的数据位宽,有无停止位和奇偶校验位等信息。

    再来看看下一句程序。这句是对刚才读出的寄存器的一个运算。

    wps7D36.tmp

    首先得到方框中这三个参数的值。这里我们已经查看程序得知这三个值分别为:6,A0,38。然后进行运算:ModeRegister=E0001004 & (~(6|A0|38))=E0001004 & 11 =0。

    wps7D37.tmp

    接下来的这一句也是一个运算,不多讲,直接运算。ModeRegister=0|(0|0|20)=20。

    wps7D48.tmp

    这段程序就是一个写寄存器的功能了。看看这个函数的原函数。

    wps7D49.tmp

    由此得出,这个函数读写的地址为刚才模式寄存器的地址,写入的数据就是运算得出的20h。参照刚才ug585里的模式寄存器说明,显而易见,经过这段程序之后,把UART设置为了8个数据位,1个停止位和无奇偶校验位的模式。

    接下来的还有3个写寄存器的程序,分析方法与刚才的一致。这里就只给出它们实现的功能。分别是:设置UART的RX FIFO在8bit处触发、设置UART的超时为1(4个字符时间)、禁止所有中断轮询模式为默认的样式。

    回到main函数的分析当中,接下来的函数实现的是建立起中断的功能,这个函数在我们上一章也进行过详细的讲解。这里我们关注一下下面这个函数。

    wps7D4A.tmp

    当我们运行XScuGic_Connect这个函数的时候,实际运行的就是这个回调函数。这个函数也是真正实现UART发送与接收功能的函数。可以看到这个程序是通过读写寄存器的方式来工作的,我们可以用刚才我们讲到的方法对其进行分析,在程序中,我们也给出了分析的过程。大家可以认真的去看一看。

    9.3 本章小结

    本章主要详细的分析了UART中断的实现过程,通过本章,我们重点需要掌握的是怎样分析一个问题的方法。通过这几张中断部分的讲解,我们应该做到对中断部分得心应手的程度。

  • 相关阅读:
    NC6开发配置流程
    触发器
    U8采购订单联查采购入库单
    sqlserver 游标
    windows服务 定时任务
    ORACLE 导入导出
    laravel 在模板中使select保存的值下单选中
    laravel 中request
    laravel中 url() route() URL::asset()
    laravel 中 后台管理的 路由设计
  • 原文地址:https://www.cnblogs.com/milinker/p/6474665.html
Copyright © 2020-2023  润新知