You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MSP-EXP430FR4133代码调试模式正常,电池供电时功能异常求助

MSP-EXP430FR4133 电池供电功能失效问题

调试模式下通过PC供电运行完全正常,但改用电压充足的电池供电时,无法实现预期功能;切换至Release模式后问题仍存在。

预期功能:LCD随机显示情绪同义词,通过按键设置buttonIndex,匹配displayIndex与buttonIndex,正确则分数加1,错误则显示当前分数并触发看门狗重启。

项目代码:

#include "hal_LCD.h"
#include "gpio.h"
#include <stdlib.h>
#include <time.h>
#include <string.h>

// Define the GPIO pins corresponding to each emotion button
#define JOY_PIN   BIT4 // P1.4
#define SAD_PIN   BIT3 // P1.3
#define ANGRY_PIN BIT6 // P1.6
#define FEAR_PIN  BIT7 // P1.7
#define MALICE_PIN BIT5 // P2.5
#define AMAZE_PIN BIT7 // P2.7

// Define maximum number of synonyms for each emotion
#define MAX_SYNONYMS 5

// Define synonyms for each emotion
const char* joySynonyms[MAX_SYNONYMS] = {"HAPPY", "GLAD", "CHEER", "DELITE", "MIRTH"};
const char* sadSynonyms[MAX_SYNONYMS] = {"GLOOM", "MELAN", "SORROW", "DESOL", "TEARS"};
const char* angrySynonyms[MAX_SYNONYMS] = {"FUROR", "IRATE", "RAGE", "ANGER", "STRESS"};
const char* fearSynonyms[MAX_SYNONYMS] = {"TERROR", "DREAD", "ANX", "ALARM", "PANIC"};
const char* maliceSynonyms[MAX_SYNONYMS] = {"SPITE", "HATE", "VENOM", "MALICE", "SPURN"};
const char* amazeSynonyms[MAX_SYNONYMS] = {"WONDER", "AMAZE", "ASTON", "AWING", "MARVEL"};

// Global variables to hold the display index, button index, and score
int displayIndex = 0;
int buttonIndex = 0;


// Function to display a word on the LCD
void displayWord(const char* word) {
    clearLCD();
    int len = strlen(word);
    if (len <= 3) {
        showChar(word[0], pos1);
        if (len >= 2) {
            showChar(word[1], pos2);
        }
        if (len == 3) {
            showChar(word[0], pos1);
            showChar(word[1], pos2);
            showChar(word[2], pos3);
        }
    } else if (len == 4) {
        showChar(word[0], pos1);
        showChar(word[1], pos2);
        showChar(word[2], pos3);
        showChar(word[3], pos4);
    } else if (len == 5) {
        showChar(word[0], pos1);
        showChar(word[1], pos2);
        showChar(word[2], pos3);
        showChar(word[3], pos4);
        showChar(word[4], pos5);
    } else if (len == 6){
        showChar(word[0], pos1);
        showChar(word[1], pos2);
        showChar(word[2], pos3);
        showChar(word[3], pos4);
        showChar(word[4], pos5);
        showChar(word[5], pos6);
    }
}

// Function to display "START" on the LCD for 3 seconds
void displayStartScreen() {
    clearLCD();
    showChar('S', pos1);
    showChar('T', pos2);
    showChar('A', pos3);
    showChar('R', pos4);
    showChar('T', pos5);
    __delay_cycles(3000000); // Delay for 3 seconds
}

void displayScore(int score) {
    clearLCD();
    showChar('P', pos1);
    showChar('T', pos2);
    showChar('S', pos3);

    int hundreds = score/100;
    int tens = score / 10;
    int units = score % 10;
    showChar(hundreds + '0', pos4);
    showChar(tens + '0', pos4);
    showChar(units + '0', pos5);
    __delay_cycles(4000000);
    WDTCTL = 0; //Trigger watchdog reset
}

// Function to initialize button pins
void initButtonPins() {
    // Set button pins as inputs with internal pull-up resistors
    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, JOY_PIN);
    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, SAD_PIN);
    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, ANGRY_PIN);
    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, FEAR_PIN);
    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2, MALICE_PIN);
    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2, AMAZE_PIN);
}

// Function to configure interrupts for button pins
void configureButtonInterrupts() {
    // Enable interrupts for each button pin
    GPIO_selectInterruptEdge(GPIO_PORT_P1, JOY_PIN, GPIO_LOW_TO_HIGH_TRANSITION);
    GPIO_selectInterruptEdge(GPIO_PORT_P1, SAD_PIN, GPIO_LOW_TO_HIGH_TRANSITION);
    GPIO_selectInterruptEdge(GPIO_PORT_P1, ANGRY_PIN, GPIO_LOW_TO_HIGH_TRANSITION);
    GPIO_selectInterruptEdge(GPIO_PORT_P1, FEAR_PIN, GPIO_LOW_TO_HIGH_TRANSITION);
    GPIO_selectInterruptEdge(GPIO_PORT_P2, MALICE_PIN, GPIO_LOW_TO_HIGH_TRANSITION);
    GPIO_selectInterruptEdge(GPIO_PORT_P2, AMAZE_PIN, GPIO_LOW_TO_HIGH_TRANSITION);
    GPIO_clearInterrupt(GPIO_PORT_P1, JOY_PIN | SAD_PIN | ANGRY_PIN | FEAR_PIN);
    GPIO_clearInterrupt(GPIO_PORT_P2, MALICE_PIN | AMAZE_PIN);
    GPIO_enableInterrupt(GPIO_PORT_P1, JOY_PIN | SAD_PIN | ANGRY_PIN | FEAR_PIN);
    GPIO_enableInterrupt(GPIO_PORT_P2, MALICE_PIN | AMAZE_PIN);
}

// Function to check if any button is pressed
int isAnyButtonPressed() {
    return GPIO_getInputPinValue(GPIO_PORT_P1, JOY_PIN) ||
           GPIO_getInputPinValue(GPIO_PORT_P1, SAD_PIN) ||
           GPIO_getInputPinValue(GPIO_PORT_P1, ANGRY_PIN) ||
           GPIO_getInputPinValue(GPIO_PORT_P1, FEAR_PIN) ||
           GPIO_getInputPinValue(GPIO_PORT_P2, MALICE_PIN) ||
           GPIO_getInputPinValue(GPIO_PORT_P2, AMAZE_PIN);
}

int main(void)
{
    // Stop watchdog timer
    WDTCTL = WDTPW + WDTHOLD;
    // Initialize LCD
    Init_LCD();
    displayStartScreen();
    PMM_unlockLPM5();
    // Initialize button pins
    initButtonPins();

    // Enable interrupts for button pins
    configureButtonInterrupts();

    // Enable global interrupts
    __enable_interrupt();

    int score = 0; // Variable to store the score

    while (1)
    {
        // Generate a random number to represent the emotion
        srand(time(NULL)); // Seed the random number generator
        int randomNumber = rand() % 6 + 1; // Generate a random number between 1 and 6

        // Set the display index based on the random number
        switch (randomNumber) {
            case 1:
                displayIndex = 1;
                displayWord(joySynonyms[rand() % MAX_SYNONYMS]);
                break;
            case 2:
                displayIndex = 2;
                displayWord(sadSynonyms[rand() % MAX_SYNONYMS]);
                break;
            case 3:
                displayIndex = 3;
                displayWord(angrySynonyms[rand() % MAX_SYNONYMS]);
                break;
            case 4:
                displayIndex = 4;
                displayWord(fearSynonyms[rand() % MAX_SYNONYMS]);
                break;
            case 5:
                displayIndex = 5;
                displayWord(maliceSynonyms[rand() % MAX_SYNONYMS]);
                break;
            case 6:
                displayIndex = 6;
                displayWord(amazeSynonyms[rand() % MAX_SYNONYMS]);
                break;
            default:
                break;
        }

        // Wait until any button is pressed
        while (!isAnyButtonPressed());

        // Compare displayIndex and buttonIndex to update the score
        if (displayIndex == buttonIndex) {
            score++; // Increment score for correct button press
        }else{
            displayScore(score);
        }
    }
}


// Interrupt service routine for button presses on port 1
#pragma vector = PORT1_VECTOR
__interrupt void Port1_ISR(void) {
    switch (__even_in_range(P1IV, P1IV_P1IFG7)) {
        case P1IV_P1IFG4:
            buttonIndex = 1; // JOY button
            break;
        case P1IV_P1IFG3:
            buttonIndex = 2; // SAD button
            break;
        case P1IV_P1IFG6:
            buttonIndex = 3; // ANGRY button
            break;
        case P1IV_P1IFG7:
            buttonIndex = 4; // FEAR button
            break;
        default:
            break;
    }
    // Clear the interrupt flag
    P1IFG &= ~(JOY_PIN | SAD_PIN | ANGRY_PIN | FEAR_PIN);
}

// Interrupt service routine for button presses on port 2
#pragma vector = PORT2_VECTOR
__interrupt void Port2_ISR(void) {
    switch (__even_in_range(P2IV, P2IV_P2IFG7)) {
        case P2IV_P2IFG5:
            buttonIndex = 5; // MALICE button
            break;
        case P2IV_P2IFG7:
            buttonIndex = 6; // AMAZE button
            break;
        default:
            break;
    }
    // Clear the interrupt flag
    P2IFG &= ~(MALICE_PIN | AMAZE_PIN);
}

问题分析与修复方案

1. 按键检测逻辑完全反转

按键使用内部上拉电阻,未按下时引脚为高电平(GPIO_getInputPinValue返回1),按下时为低电平(返回0)。原函数判断的是“是否有引脚为高”,永远为真,导致程序不等待按键就执行分数判断,此时buttonIndex为0,直接触发重启。

修复:

int isAnyButtonPressed() {
    return !GPIO_getInputPinValue(GPIO_PORT_P1, JOY_PIN) ||
           !GPIO_getInputPinValue(GPIO_PORT_P1, SAD_PIN) ||
           !GPIO_getInputPinValue(GPIO_PORT_P1, ANGRY_PIN) ||
           !GPIO_getInputPinValue(GPIO_PORT_P1, FEAR_PIN) ||
           !GPIO_getInputPinValue(GPIO_PORT_P2, MALICE_PIN) ||
           !GPIO_getInputPinValue(GPIO_PORT_P2, AMAZE_PIN);
}

2. 看门狗复位操作错误

MSP430的WDTCTL寄存器写操作必须携带WDTPW密码,否则会立即触发复位。原代码无密码的写法在调试时被JTAG屏蔽,电池供电时直接导致程序异常。

修复:

void displayScore(int score) {
    clearLCD();
    showChar('P', pos1);
    showChar('T', pos2);
    showChar('S', pos3);

    int hundreds = score / 100;
    int tens = (score / 10) % 10;
    int units = score % 10;
    showChar(hundreds + '0', pos4);
    showChar(tens + '0', pos5);
    showChar(units + '0', pos6);
    __delay_cycles(4000000);
    // 用错误密码触发看门狗复位
    WDTCTL = 0xDEAD;
}

同时修复了分数计算和显示位置的错误。

3. 随机数种子初始化无效

time(NULL)依赖未初始化的RTC,导致每次生成相同随机序列。调试时JTAG提供时钟掩盖了问题,电池供电时无此支持。

修复:

int main(void)
{
    // ... 原有初始化代码 ...
    int score = 0;

    // 用状态寄存器值作为随机种子
    srand((unsigned int)__read_status_register());

    while (1)
    {
        int randomNumber = rand() % 6 + 1;
        // ... 原有显示逻辑 ...

        while (!isAnyButtonPressed());
        // 等待按键释放,避免重复触发
        while (isAnyButtonPressed());

        if (displayIndex == buttonIndex) {
            score++;
        }else{
            displayScore(score);
        }
        // 重置buttonIndex,避免下一轮误判
        buttonIndex = 0;
    }
}

4. 中断标志清除冗余

MSP430读取中断向量寄存器后,对应IFG位会自动清除,手动清除可能误操作其他标志。

修复:删除ISR中手动清除标志的代码:

#pragma vector = PORT1_VECTOR
__interrupt void Port1_ISR(void) {
    switch (__even_in_range(P1IV, P1IV_P1IFG7)) {
        case P1IV_P1IFG4: buttonIndex = 1; break;
        case P1IV_P1IFG3: buttonIndex = 2; break;
        case P1IV_P1IFG6: buttonIndex = 3; break;
        case P1IV_P1IFG7: buttonIndex = 4; break;
        default: break;
    }
}

#pragma vector = PORT2_VECTOR
__interrupt void Port2_ISR(void) {
    switch (__even_in_range(P2IV, P2IV_P2IFG7)) {
        case P2IV_P2IFG5: buttonIndex = 5; break;
        case P2IV_P2IFG7: buttonIndex = 6; break;
        default: break;
    }
}

5. LCD显示逻辑冗余

原函数中len==3分支重复写入字符,简化逻辑:

void displayWord(const char* word) {
    clearLCD();
    int len = strlen(word);
    if (len >= 1) showChar(word[0], pos1);
    if (len >= 2) showChar(word[1], pos2);
    if (len >= 3) showChar(word[2], pos3);
    if (len >= 4) showChar(word[3], pos4);
    if (len >= 5) showChar(word[4], pos5);
    if (len >= 6) showChar(word[5], pos6);
}

内容的提问来源于stack exchange,提问作者Hamid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 23:44:54