This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] CCS/MSP432P401R:同一端口的多个引脚上的 GPIO 中断

Guru**** 2039500 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/691161/ccs-msp432p401r-gpio-interrupt-on-multiple-pins-of-the-same-port

器件型号:MSP432P401R

工具/软件:Code Composer Studio

我正在尝试在 P3.0、P3.2、P3.3、P3.5和 P3.6上启用 GPIO 中断、我在这里连接了外部按钮。 当我仅为 P3.0启用中断时、我可以让我的代码执行、但我不确定需要启用什么才能在其他引脚上获得中断。

此外、我知道、通常、当您在同一端口的多个引脚上有中断时、您需要确定 ISR 中设置了哪个 IFG。 但是、我不确定是否需要这样做、因为我希望我的所有中断都完成相同的任务、所以我不关心哪个引脚触发中断。

我附加了在 P3.0上启用中断的代码、如果有人能够提供有关如何在其他引脚上初始化中断的任何见解、我尝试在下面为 P3.2启用中断、但未成功。 以及如何在 ISR 中处理 IFG 位、我会非常感激!

/*使用外部按钮测试 ADC、使用计时器 A 测试 ADC */

#include "msp.h"
#include "mytime.h"

volatile unsigned int UART_flag = 0;
volatile unsigned int timer_flag = 0;
volatile unsigned int
var = 0;
int mvoltv = 0;

void UART0_init (void);
setfreq (void);int freq (void)

int main (void){

setFreq (FREQ_3_MHz);

int mV_char_0 = 0;
int mV_char_1 = 0;
int mV_char_2 = 0;
int mV_char_3 = 0;
字符 UART_0;
字符 UART_1;
字符 UART_2;
字符 UART_3;

WDT_A->CTL = WDT_A_CTL_PW | //停止 WDT
WDT_A_CTL_HOLD;

// GPIO 设置
P5->SEL1 |= BIT4; //为 ADC 配置 P5.4
P5->SEL0 |= BIT4;

//初始化端口3 (按钮连接)
P3->SEL0 = 0;//清除寄存器选择
P3->SEL1 = 0;//清除寄存器选择
P3->SEL0 |= BIT2;
P3->SEL1 |= BIT2;
P3->DIR = 0;
P3->DIR = BIT2;
P3->OUT = BIT0;
P3->OUT = BIT2;
P3->REN = BIT0;//启用上拉电阻
P3->REN = BIT2;

P3->IES = BIT0;//高-低转换时中断
P3->IES = BIT2;
P3->IFG = 0; //清除任何挂起标志
P3->IE = BIT0;//启用端口3中断
P3->IE = BIT2;

UART0_init();

//启用全局中断
__ENABLE_IRQ();

//在 NVIC 模块中启用 ADC 和计时器 A0中断
NVIC_EnableIRQ (TA0_0_IRQn);
NVIC_EnableIRQ (ADC14_IRQn);
NVIC_EnableIRQ (PORT3_IRQn);

//采样时间、S&H=16、ADC14打开
ADC14->CTL0 = ADC14_CTL0_SHT0_2 | ADC14_CTL0_SHP | ADC14_CTL0_ON;
ADC14->CTL1 = ADC14_CTL1_RES_2;
ADC14->MCTL[0]|= ADC14_MCTLN_INCH_1;/* A1 ADC 输入选择;
VREF=AVCC */
ADC14->IER0 |= ADC14_IER0_IE0; /*启用 ADC 转换
完成中断*/

SCB->SCR &=~SCB_SCR_SLEEPONEXIT_MSK;/*退出时唤醒
ISR */

while (1){
if (button_flag){ //按钮被按下、打开 ADC
ADC14->CTL0 |= ADC14_CTL0_ENC | ADC14_CTL0_SC;//开始采样/转换
button_flag = 0; //复位标志
P3->IFG = 0; //清除任何挂起标志
}
if (timer_flag){ //time up、关闭 ADC
ADC14->CTL0 &=~ADC14_CTL0_ENC;//关闭 ADC
Timer_flag = 0;
P3->IE |= BIT0; //重新启用 P3.0中断
P3->IE |= BIT2; //重新启用 P3.2中断
}
if (UART_flag){
UART_FLAG = 0;
毫伏=(int)((var + 1.46)/ 1.2361);
mV_char_3 =毫伏/1000;
mV_char_2 =毫伏/100 -(mV_char_3 * 10);
MV_CHAR_1 =毫伏/ 10 -(MV_CHAR_3 * 100 + MV_CHAR_2 * 10);
mV_char_0 =毫伏-(mV_char_1 * 10 + mV_char_3 * 1000 + mV_char_2 * 100);
UART_0 =(char) MV_char_0 +"0";
UART_1 =(char) MV_char_1 +"0";
UART_2 =(char) MV_char_2 +"0";
UART_3 =(char) MV_char_3 +"0";
while (!(EUSCI_A0->IFG & 0x02)){}
EUSCI_A0->TXBUF = UART_3;
while (!(EUSCI_A0->IFG & 0x02)){}
EUSCI_A0->TXBUF = UART_2;
while (!(EUSCI_A0->IFG & 0x02)){}
EUSCI_A0->TXBUF = UART_1;
while (!(EUSCI_A0->IFG & 0x02)){}
EUSCI_A0->TXBUF = UART_0;
while (!(EUSCI_A0->IFG & 0x02)){}
EUSCI_A0->TXBUF = 0x0D;
}
}
//

ADC14中断服务例程
void ADC14_IRQHandler (void){
UART_FLAG = 1;
VAR = ADC14->MEM[0];
}

//计时器 A0中断服务例程
void TA0_0_IRQHandler (void){
Timer_flag = 1; 定时器达到值时为//flag
TA0CCTL0 &=~CCIFG; //清除挂起中断标志
TA0CTL = 0; //关闭计时器
}

void PORT3_IRQHandler (void) //端口3
的中断处理程序{
button_flag = 1; //set flag to signal button pressed.(检测到按压信号。
//配置计时器 A0
TA0CCR0 = 900000; //计时器长度= 300ms
TA0CCTL0 |= CCIE;
TA0CTL |= TASSEL_2 | MC_1;
P3->IFG = 0; //清除挂起中断标志
P3->IE &=~BIT0; //禁用 P3.0的去抖中断
P3->IE &=~BIT2; //禁用 P3.2的去抖中断

}

void UART0_init (void)
{
EUSCI_A0->CTLW0 |= 1; //为 config 进入复位模式
EUSCI_A0->MCTLW = 0; //禁用过采样
EUSCI_A0->CTLW0 = 0x0081;/* 1停止位、无奇偶校验、SMCLK、字节
数据*/
EUSCI_A0->BRW = 26; // 3、000、000 / 115200 = 26
P1->SEL0 |= 0x0C; //对于 UART、P1.3、P1.2
P1->SEL1 &=~0x0C;
EUSCI_A0->CTLW0 &=~1; //使 UART 退出复位模式
}

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    代码使用的位置有几个=,但应该已经使用了|=。
    使用|=设置一些位;使用=也会清除所有其他位。

    中断处理程序的标志处理看起来正确。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我更改了=的所有实例、我认为应该是|=、当按钮连接到 P3.0而不是 P3.2时、我具有适当的中断功能。 当我将一个外部按钮连接到 P3.2时、没有发生任何事情、我不确定原因。

    /*使用外部按钮测试 ADC、使用计时器 A 测试 ADC */
    
    #include "msp.h"
    #include "mytime.h"
    
    volatile unsigned int UART_flag = 0;
    volatile unsigned int timer_flag = 0;
    volatile unsigned int
    var = 0;
    int mvoltv = 0;
    
    void UART0_init (void);
    setfreq (void);int freq (void)
    
    int main (void){
    
    setFreq (FREQ_3_MHz);
    
    int mV_char_0 = 0;
    int mV_char_1 = 0;
    int mV_char_2 = 0;
    int mV_char_3 = 0;
    字符 UART_0;
    字符 UART_1;
    字符 UART_2;
    字符 UART_3;
    
    WDT_A->CTL = WDT_A_CTL_PW | //停止 WDT
    WDT_A_CTL_HOLD;
    
    // GPIO 设置
    P5->SEL1 |= BIT4; //为 ADC 配置 P5.4
    P5->SEL0 |= BIT4;
    
    //初始化端口3 (按钮连接)
    P3->SEL0 = 0;//清除寄存器选择
    P3->SEL1 = 0;//清除寄存器选择
    P3->SEL0 |= BIT2;
    P3->SEL1 |= BIT2;
    P3->DIR |= BIT0;
    P3->DIR |= BIT2;
    P3->OUT |= BIT0;
    P3->OUT |= BIT2;
    P3->REN |= BIT0;//enable 上拉电阻器
    P3->REN |= BIT2;
    
    P3->IES |= BIT0;//高-低转换时中断
    P3->IES |= BIT2;
    P3->IFG = 0; //清除任何挂起标志
    P3->IE |= BIT0;//启用端口3中断
    P3->IE |= BIT2;
    
    UART0_init();
    
    //启用全局中断
    __ENABLE_IRQ();
    
    //在 NVIC 模块中启用 ADC 和计时器 A0中断
    NVIC_EnableIRQ (TA0_0_IRQn);
    NVIC_EnableIRQ (ADC14_IRQn);
    NVIC_EnableIRQ (PORT3_IRQn);
    
    //采样时间、S&H=16、ADC14打开
    ADC14->CTL0 = ADC14_CTL0_SHT0_2 | ADC14_CTL0_SHP | ADC14_CTL0_ON;
    ADC14->CTL1 = ADC14_CTL1_RES_2;
    ADC14->MCTL[0]|= ADC14_MCTLN_INCH_1;/* A1 ADC 输入选择;
    VREF=AVCC */
    ADC14->IER0 |= ADC14_IER0_IE0; /*启用 ADC 转换
    完成中断*/
    
    SCB->SCR &=~SCB_SCR_SLEEPONEXIT_MSK;/*退出时唤醒
    ISR */
    
    while (1){
    if (button_flag){ //按钮被按下、打开 ADC
    ADC14->CTL0 |= ADC14_CTL0_ENC | ADC14_CTL0_SC;//开始采样/转换
    button_flag = 0; //复位标志
    P3->IFG = 0; //清除任何挂起标志
    }
    if (timer_flag){ //time up、关闭 ADC
    ADC14->CTL0 &=~ADC14_CTL0_ENC;//关闭 ADC
    Timer_flag = 0;
    P3->IE |= BIT0; //重新启用 P3.0中断
    P3->IE |= BIT2;
    }
    if (UART_flag){
    UART_FLAG = 0;
    毫伏=(int)((var + 1.46)/ 1.2361);
    mV_char_3 =毫伏/1000;
    mV_char_2 =毫伏/100 -(mV_char_3 * 10);
    MV_CHAR_1 =毫伏/ 10 -(MV_CHAR_3 * 100 + MV_CHAR_2 * 10);
    mV_char_0 =毫伏-(mV_char_1 * 10 + mV_char_3 * 1000 + mV_char_2 * 100);
    UART_0 =(char) MV_char_0 +"0";
    UART_1 =(char) MV_char_1 +"0";
    UART_2 =(char) MV_char_2 +"0";
    UART_3 =(char) MV_char_3 +"0";
    while (!(EUSCI_A0->IFG & 0x02)){}
    EUSCI_A0->TXBUF = UART_3;
    while (!(EUSCI_A0->IFG & 0x02)){}
    EUSCI_A0->TXBUF = UART_2;
    while (!(EUSCI_A0->IFG & 0x02)){}
    EUSCI_A0->TXBUF = UART_1;
    while (!(EUSCI_A0->IFG & 0x02)){}
    EUSCI_A0->TXBUF = UART_0;
    while (!(EUSCI_A0->IFG & 0x02)){}
    EUSCI_A0->TXBUF = 0x0D;
    }
    }
    //
    
    ADC14中断服务例程
    void ADC14_IRQHandler (void){
    UART_FLAG = 1;
    VAR = ADC14->MEM[0];
    }
    
    //计时器 A0中断服务例程
    void TA0_0_IRQHandler (void){
    Timer_flag = 1; 定时器达到值时为//flag
    TA0CCTL0 &=~CCIFG; //清除挂起中断标志
    TA0CTL = 0; //关闭计时器
    }
    
    void PORT3_IRQHandler (void) //端口3
    的中断处理程序{
    button_flag = 1; //set flag to signal button pressed.(检测到按压信号。
    //配置计时器 A0
    TA0CCR0 = 900000; //计时器长度= 300ms
    TA0CCTL0 |= CCIE;
    TA0CTL |= TASSEL_2 | MC_1;
    P3->IFG = 0; //清除 P3.0挂起中断标志
    P3->IE &=~BIT0; //禁用 P3.0的去抖中断
    P3->IE &=~BIT2; //禁用 P3.0的去抖中断
    
    }
    
    void UART0_init (void)
    {
    EUSCI_A0->CTLW0 |= 1; //为 config 进入复位模式
    EUSCI_A0->MCTLW = 0; //禁用过采样
    EUSCI_A0->CTLW0 = 0x0081;/* 1停止位、无奇偶校验、SMCLK、字节
    数据*/
    EUSCI_A0->BRW = 26; // 3、000、000 / 115200 = 26
    P1->SEL0 |= 0x0C; //对于 UART、P1.3、P1.2
    P1->SEL1 &=~0x0C;
    EUSCI_A0->CTLW0 &=~1; //使 UART 退出复位模式
    }
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    由于您计划执行更多的操作、我建议您使用辅助函数来帮助您跟踪:

    void pi_setup (unsigned char pinmask)
    {
    P3->SEL0 &=~Ω 引脚掩码;// GPIO、非
    P3->SEL1 &=~Ω 引脚掩码;//替代功能
    P3->DIR &=~引脚掩码;//输入
    P3->OUT |= pinmask;//上拉,而不是下拉
    P3->REN |= pinmask;//启用上拉
    P3->IES |= pinmask;//高->低转换
    p3->IFG &=~pinmask;//清除可能的过时 IFG
    P3->IE |= pinmask;//启用 IFG
    返回;
    }
    

    例如、使用"pi_setup (BIT2);"来调用它。 这不是最快的方法、但您只能在启动时执行一次。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我实现了一个类似的功能、并且能够使一切按预期工作。 非常感谢!