【普中DSP28335开发攻略】-- 第 15 章 外部中断实验

(1)实验平台:普中DSP28335开发板


上一章我们介绍了 DSP28335 的中断, 这一章我们就来学习下外部中断。 通过上一章的介绍我们知道, F28335 外部中断有 7 个, 外部中断 1-7, 其中外部中断 1 和 2 只能对 GPIO0-GPIO31 配置; 外部中断 3 和 4、5、6、7 只对 GPIO32-GPIO63配置, 它们的使用方法是一样的, 所以只要学会一个即可掌握所有外部中断。 本章所要实现的功能是: 使用外部中断 1 功能通过按键 K1 控制 D2 亮灭, K4按键控制D3 亮灭 , D1指示灯闪烁提示系统运行状态 。 学习本章可 以参考"TMS320x2833x, 2823x System Control and Interrupts Reference Guide (Rev. D).pdf" 的"8 Peripheral Interrupt Expansion (PIE)" 章节, 特别是在涉及到寄存器功能部分。 若结合视频学习效果更佳。 本章分为如下几部分内容:

[15.1 外部中断介绍](#15.1 外部中断介绍)

[15.1.1 外部中断简介](#15.1.1 外部中断简介)

[15.1.2 外部中断相关寄存器](#15.1.2 外部中断相关寄存器)

[15.2 外部中断配置步骤](#15.2 外部中断配置步骤)

[15.3 硬件设计](#15.3 硬件设计)

[15.4 软件设计](#15.4 软件设计)

[15.4.1 外部中断初始化函数](#15.4.1 外部中断初始化函数)

[15.4.2 外部中断服务函数](#15.4.2 外部中断服务函数)

[15.4.3 主函数](#15.4.3 主函数)

[15.5 实验现象](#15.5 实验现象)

课后作业


15.1 外部中断介绍

15.1.1 外部中断简介

F28335 共 支 持 7 个 外 部中 断 XINT1-XINT7 , 其 中 XINT1-XINT2 只 能 对GPIO0-GPIO31 配置; XINT3-XINT7 只对 GPIO32-GPIO63 配置。 XINT13 还有一个不可屏蔽的外部中断 XNMI 共用中断源。 每一个外部中断可以被选择为正边沿或负边沿触发, 也可以被使能或者禁止(包括 XNMI) 。 可屏蔽中断单元包括一个16 位增计数器, 该计数器在检测到有效中断边沿时复位为 0, 同时用来准确记录中断发生的时间。

其结构框图如下图所示:

15.1.2 外部中断相关寄存器

(1) 外部中断控制寄存器(XINTnCR)

F28335 共支持 7 个外部中断 XINT1-XINT7, XINT13 还有一个不可屏蔽的外部中断 XNMI 共用中断源。 每一个外部中断可以被选择为正边沿或负边沿触发, 也可以被使能或者禁止(包括 XNMI) 。 可屏蔽中断单元包括一个 16 位增计数器,该计数器在检测到有效中断边沿时复位为 0, 同时用来准确记录中断发生的时间。

外部中断控制寄存器(XINTnCR n=1-7) 各位信息如下图所示:

(2) 外部 NMI 中断控制寄存器(XNMICR)

外部 NMI 中断控制寄存器(XNMICR) 各位信息如下图所示:

(3) 外部中断 x 计数器(XINTxCTR)

外部中断 x 计数器(XINTxCTR) 各位信息如下图所示:

15.2 外部中断配置步骤

接下来我们介绍下如何对外部中断进行配置。 这个也是在编写程序中必须要了解的。 具体步骤如下: (外部中断相关函数及寄存器在 DSP2833x_PieCtrl.c、DSP2833x_PieVect.c、 DSP2833x_GlobalVariableDefs.c 文件及其对应的头文件内查找到)

(1) 失能 CPU 级中断, 并初始化 PIE 控制器寄存器和 PIE 中断向量表

在前面学习中断章节中, 我们知道 F28335 的外设中断需通过 PIE 控制器来管理, 因此需要初始化 PIE 相应的寄存器和中断向量表。 TI 公司已经提供了对应的函数来完成这些操作。 分别是 InitPieCtrl()和 InitPieVectTable()。 从函数名即可明白它的功能, 所以在开发 F28335 程序时不需要准确记住函数, 知道其含义然后查找即可。 这两个函数分别在 DSP2833x_PieVect.c、DSP2833x_GlobalVariableDefs.c 文件中。 大家可以打开看下, 这里就不列出了。

此步代码如下:

cpp 复制代码
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();

(2) 使能 IO 口时钟, 配置 IO 口为输入

由于本章使用开发板上矩阵按键 IO 口作为外部中断输入线, 因此需要使能对应的 IO 口时钟及配置 IO 口模式, 在按键实验章节中, 我们就介绍过要把对应 IO 口设置为输入模式, 这部分配置与按键实验一样。

(3) 设置 IO 口与中断线的映射关系

前面说过, F28335 共支持 7 个外部中断 XINT1-XINT7, 其中 XINT1-XINT2 只能对 GPIO0-GPIO31 配置; XINT3-XINT7 只对 GPIO32-GPIO63 配置。 所以需要选择对应的外部中断线及 IO 口配置, 比如我们 K1 它是连接在 GPIO12 上, 要使用外部中断功能可以是外部中断 1 或者外部中断 2, 假如使用外部中断 1, 其代码如下:

cpp 复制代码
EALLOW;
GpioIntRegs.GPIOXINT1SEL.bit.GPIOSEL = 12; // XINT1 是 GPIO12
EDIS;

(4) 指定中断向量表中断服务函数地址

这个通过对 PIE 中断向量表寄存器的相应位进行设置, 中断服务函数名可自定义, 但是要符合 C 语言标识符命名规则, 在中断函数名前需加上地址符"&" 。在对 PIE 中断向量表寄存器设置时要先声明 EALLOW, 修改完成后还要声明 EDIS。比如外部中断 1, 其设置如下:

cpp 复制代码
EALLOW; // 修改被保护的寄存器, 修改前应添加 EALLOW 语句
PieVectTable.XINT1 = &EXTI1_IRQn;
EDIS; // EDIS 的意思是不允许修改被保护的寄存器

(5) 使能外设对应的 PIE 中断

由于外设中断较多, 它们是由 PIE 统一管理, 所以要根据你所使用的外设中断选择对应的组和该组内的通道, 比如外部中断 1, 它是由 PIE 组 1 的第 4 通道连接, 这个在前面中断介绍时讲解过。 因此可由 PIE 控制寄存器中相应中断使能位来控制。 其实现代码如下所示:

cpp 复制代码
PieCtrlRegs.PIEIER1.bit.INTx4 = 1; // 使能 PIE 组 1 的 INT4

(6) 设置外部中断触发方式并使能中断

我们知道外部中断的触发方式有上升沿触发(正边沿) 和下降沿触发(负边沿) , 根据自己的需求来选择。 当按键按下时, 我们是让其输入一个低电平到IO 口, 而默认处于高电平, 所以按键按下时会产生一个下降沿, 因此选择下降沿触发。 外部中断的触发方式及中断使能是由 XIntruptRegs 寄存器控制, 具体实现代码如下:

cpp 复制代码
XIntruptRegs.XINT1CR.bit.POLARITY = 0; // 下降沿触发中断
XIntruptRegs.XINT1CR.bit.ENABLE= 1; // 使能 XINT1

(7) 使能 CPU 级中断及全局中断, 这个通过对 IER 和 EINT 寄存器相应位设置进行使能或者失能。 其代码如下:

cpp 复制代码
IER |= M_INT1; // 使能 CPU 中断 1(INT1)
EINT; // 开全局中断
ERTM;

当使用仿真器调试时可开启 DEBUG 中断, 即使用 ERTM 语句。

(8) 编写外部中断服务函数

配置好中断后如果有触发, 即会进入中断服务函数, 中断服务函数名在前面已定义好, 所以要保证一致, 否则将不会进入中断服务函数内执行。 在 DSP28335软件开发中, 要在中断服务函数名前加上关键字 interrupt。 例如外部中断 1 的中断服务函数:

cpp 复制代码
interrupt void EXTI1_IRQn(void)
{
...功能程序
}

在中断执行结束前要清除相应的中断标志位, 以等待下次中断的到来。

15.3 硬件设计

本实验使用到硬件资源如下:

(1) 矩阵按键

(2) 外部中断 1

矩阵按键模块电路在前面章节已介绍, 这里就不多说, 至于外不中断 1 是F28335 芯片内部资源, 只要对其配置即可使用。

15.4 软件设计

本章所要实现的功能是: 使用外部中断 1 功能通过按键 K1 控制 D2 亮灭, K4按键控制 D3 亮灭, D1 指示灯闪烁提示系统运行状态。 程序框架如下:

(1) 初始化对应端口的外部中断功能

(2) 编写外部中断函数

(3) 编写主函数

打开"E:\DSP8233x_ProjectExample\DSP2833x_Example\Example09_DSP2833x_ External_Interruption" 工程, 在 APP 文件夹内可以看到又新建了一个exti 文件夹。 在 DSP2833x_Libraries 工程组中添加了 DSP2833x_PieCtrl.c、DSP2833x_PieVect.c 库文件。 外部中断操作的库函数及寄存器都放在文件中,所以使用到外部中断就必须加入这两个文件, 同时要包含对应的头文件路径, 这个在前面创建工程模板时已完成。 这里我们分析几个重要函数, 其他部分程序大家可以打开工程查看。

15.4.1 外部中断初始化函数

要使用外部中断, 我们必须先对它进行配置。 其初始化代码如下:

cpp 复制代码
void EXTI1_Init(void)
{
    EALLOW;
    SysCtrlRegs.PCLKCR3.bit.GPIOINENCLK = 1; // GPIO input clock
    EDIS;
    EALLOW;
    //KEY 端口配置
    GpioCtrlRegs.GPAMUX1.bit.GPIO12=0;
    GpioCtrlRegs.GPADIR.bit.GPIO12=0;
    GpioCtrlRegs.GPAPUD.bit.GPIO12=0;
    GpioCtrlRegs.GPAQSEL1.bit.GPIO12 = 0; // 外部中断 1(XINT1) 与系统时钟 SYSCLKOUT 同步
    GpioCtrlRegs.GPBMUX2.bit.GPIO48=0;
    GpioCtrlRegs.GPBDIR.bit.GPIO48=1;
    GpioCtrlRegs.GPBPUD.bit.GPIO48=0;
    GpioDataRegs.GPBCLEAR.bit.GPIO48=1;
    EDIS;
    EALLOW;
    GpioIntRegs.GPIOXINT1SEL.bit.GPIOSEL = 12; // XINT1 是 GPIO12
    EDIS;
    EALLOW; // 修改被保护的寄存器, 修改前应添加 EALLOW 语句
    PieVectTable.XINT1 = &EXTI1_IRQn;
    EDIS; // EDIS 的意思是不允许修改被保护的寄存器
    PieCtrlRegs.PIEIER1.bit.INTx4 = 1; // 使能 PIE 组 1 的 INT4
    XIntruptRegs.XINT1CR.bit.POLARITY = 0; // 下降沿触发中断
    XIntruptRegs.XINT1CR.bit.ENABLE= 1; // 使能 XINT1
    IER |= M_INT1; // 使能 CPU 中断 1(INT1)
    EINT; // 开全局中断
    ERTM;
}

在EXTI1_Init()函数中, 首先开启 GPIO 时钟, 并初始化 GPIO12 为输入状态,然后选择 GPIO12 为外部中断 1 功能, 设置外部中断入口函数, 使能 PIE 中断,最后选择外部中断触发方式为下降沿触发, 并开启外部中断功能和总中断。 这些配置是按照前面介绍的步骤完成, 除了时钟外, 其他顺序可以调换。

其实如果你会配置外部中断 1, 那么其他外部中断都是类似的。

15.4.2 外部中断服务函数

初始化外部中断后, 中断就已经开启了, 当指定按键按下后会触发一次中断,这时程序就会进入中断服务函数执行, 所以我们还需要编写对应的 外部中断函数, 这里我们以 GPIO12 管脚的 K1 按键进行讲解, 其他的按键的中断函数类似,具体代码如下:

cpp 复制代码
interrupt void EXTI1_IRQn(void)
{
    Uint32 i;
    for(i=0;i<10000;i++); //键盘消抖动
    while(!KEY_H1);
    LED2_TOGGLE;
    PieCtrlRegs.PIEACK.bit.ACK1=1;
}

在F28335 中断服务函数中, 需要在中断服务函数名前加上一个关键字"interrupt" 标识为中断函数。 进入中断函数后, 还需要对按键进行消抖处理,每当 K1 按键按下, D2 指示灯都会状态取反一次。 最后特别注意, 在中断函数执行完成前一定要记得将相应的 PIEACKx 清零, 否则下次将不再进入中断。 可通过PIE 控制寄存器的 PIEACK 中的 ACK1 写 1 来完成清零操作。

程序中的 KEY_H1 是按键驱动文件内定义的宏, 这个在按键实验章节已介绍,这里不再重复。

15.4.3 主函数

编写好外部中断初始化和中断服务函数后, 接下来就可以编写主函数了, 代码如下:

cpp 复制代码
/****************************************************************
***************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*****************************************************************
**************/
void main()
{
    int i=0;
    InitSysCtrl();
    InitPieCtrl();
    IER = 0x0000;
    IFR = 0x0000;
    InitPieVectTable();
    LED_Init();
    EXTI1_Init();
    EXTI2_Init();
    while(1)
    {
        i++;
        if(i%2000==0)
        {
            LED1_TOGGLE;
        } 
        DELAY_US(100);
    }
}

主函数实现的功能很简单, 首先初始化系统时钟、 PIE 中断相关寄存器及中断向量表, 本套教程所有有关中断代码都采用这种设置, 后面就不做重复。 再对使用到的硬件端口时钟和 IO 口初始化, 然后调用我们前面编写的 EXTI 的初始化函数, 最后进入 while 循环语句, 不断让 D1 指示间隔 200ms 闪烁。

有的朋友就会问, 在主函数中怎么没有看到按键对 LED 的控制呢? 因为我们在 EXTI1_Init()和 EXTI2_Init()函数内就已经把按键管脚映射到中断线上,并配置了相应的触发方式, 当有按键按下, 即会进入对应中断服务函数执行相应的功能程序, LED 的控制就在中断函数内完成的。

15.5 实验现象

使用仿真器将开发板和电脑连接成功后, 把编写好的程序编译后, 如果没有报错即可将点击仿真调试, 程序即会写入到芯片的 RAM 内, 运行结果是按键 K1控制 D2 亮灭, K4 按键控制 D3 亮灭, D1 指示灯闪烁提示系统运行状态。 当系统断电后, 程序不会继续执行, 因为我们现在使用的是仿真调试, 即程序写入到RAM 内, 而非 FLASH。

课后作业

(1) 使用外部中断方式来调节蜂鸣器的音调和声音。 (温馨提示: 方法和按键实验章节类似, 只不过这里采用外部中断来处理)

相关推荐
IT阳晨。2 小时前
【STM32】ADC
stm32·单片机·嵌入式硬件
纳祥科技4 小时前
方案分享:一款基于高性能单片机的落日灯方案
单片机·嵌入式硬件
三佛科技-134163842125 小时前
智能保温杯方案,保温杯MCU控制方案设计
单片机·嵌入式硬件·智能家居·pcb工艺
Wave8456 小时前
STM32_标准库转hal库
stm32·单片机·嵌入式硬件
智者知已应修善业7 小时前
【51单片机:两边向中间流水:即两边先点亮然后熄灭,次边的点亮再熄灭,直到最中间的两个点亮再熄灭,然后重复动作。】2023-3-4
c语言·c++·经验分享·笔记·嵌入式硬件·算法·51单片机
嵌入式软硬件攻城狮8 小时前
6.单片机回调函数
单片机·嵌入式硬件
就是蠢啊8 小时前
单片机入门实验——点灯
单片机·嵌入式硬件
@曾记否8 小时前
瑞控FPVF405飞控开发板硬件功能整理
stm32·嵌入式硬件
oshan20129 小时前
小华HC32L136K8TA 单片机LED(三)
单片机·嵌入式硬件