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
相关产品推荐
相关产品推荐

