为什么这个程序总是跑不起来,请看如下解决方案

一位从HTML和CSS转向Java的初学者分享了他在编写第一个Java程序时遇到的问题:主函数命名错误导致程序无法运行。他发现Java中主函数必须命名为main,并且main是一个关键字。

我最近刚接触Java(以前是做HTML和CSS的),想尝试第一个自己的程序,但书写了一个如下属于自己的第一个Java的程序:

 

public class Wodejava
{
public static void mian(String[] agrs)
{
System.out.println("哈哈,成功了");
}
}

 

 

但是总是跑不起来,后来我宁死苦想,足足找了2个小时,才发现后来主函数必须要以main命名,这个main还是关键字,不能以标示符命名,呵呵,希望与其他人分享

<think>我们分析一下:在应用程序运行时,Bootloader已经退出,所以Bootloader中的按键检测逻辑会运行。因此,在应用程序运行时,上述修改的按键检测逻辑(包括双击检测和组合键复位)会起作用。 但是,用户要求的功能包括: 1.按住BUTTON_DFU(高电平)时,按BUTTON_FRESET复位系统。2.BUTTON_FRESET双击(间隔<500ms)进入DFU。这两个功能需要在应用程序中实现,因为Bootloader只在启动时运行一次。###解决方案1.**复位系统功能**:可以在应用程序中检测组合键,然后触发软件复位(调用NVIC_SystemReset())。但是注意,复位后Bootloader会再次运行,这时Bootloader中的组合键检测逻辑会再次执行,可能导致进入DFU模式(因为复位时两个按键可能仍然按着)。因此,我们需要在Bootloader中区分是正常复位还是由应用程序触发的复位。2.**双击进入DFU**:同样需要在应用程序中实现双击检测,然后设置一个标志(比如在内存保留区域或非易失性存储器中),然后复位。Bootloader启动时检查这个标志,如果标志有效则进入DFU。 ###修改建议####在Bootloader中修改在`check_dfu_mode`函数中,我们需要考虑应用程序设置的标志。1.定义内存保留区域(例如在RAM中,复位后会丢失的区域):```c#define DFU_DOUBLE_TAP_MAGIC0x57BD9E3Dvolatileuint32_t *constdfu_double_tap_mem =(volatile uint32_t*)0x20007FFC;//使用RAM末尾地址```2.在`check_dfu_mode`函数中检查这个标志: ```c//检查双击DFU标志if(*dfu_double_tap_mem ==DFU_DOUBLE_TAP_MAGIC) {dfu_start= true;*dfu_double_tap_mem =0; //清除标志} ```####在应用程序中实现双击检测和组合键在应用程序的主循环中,添加按键检测逻辑:```c//在应用程序中#include "nrf_delay.h" #include"nrf_gpio.h"//定义按键#defineBUTTON_DFUPIN_DFU#defineBUTTON_FRESET PIN_FRESET//双击检测变量static uint32_tfirst_press_time=0;static booldouble_tap_possible =false;voidapp_handle_buttons(){//检测BUTTON_FRESET是否按下(高电平)if(nrf_gpio_pin_read(BUTTON_FRESET)){uint32_t current_time =board_millis();//使用和Bootloader相同的计时函数if (double_tap_possible &&(current_time -first_press_time) <500) {//检测到双击*dfu_double_tap_mem= DFU_DOUBLE_TAP_MAGIC;//设置标志NVIC_SystemReset();//复位进入DFU} else{first_press_time= current_time;double_tap_possible= true;}//等待按键释放while(nrf_gpio_pin_read(BUTTON_FRESET)){}} else{//检查是否超时if(double_tap_possible&& (board_millis() -first_press_time) >500) {double_tap_possible= false;}}//组合键检测:按住BUTTON_DFU,再按BUTTON_FRESET复位if (nrf_gpio_pin_read(BUTTON_DFU)){if (nrf_gpio_pin_read(BUTTON_FRESET)) {//两个按键同时按下,执行复位NVIC_SystemReset();}} }//在主循环中调用while(1) {app_handle_buttons();// ...其他应用程序逻辑} ```###注意事项1.**内存保留区域**:需要确保该内存区域在复位后会被初始化。在Bootloader和应用程序的链接脚本中保留该区域(例如,RAM的最后4个字节)。2.**计时函数一致性**:Bootloader和应用程序使用相同的计时基准(例如,都使用RTC1)。3.**复位类型**:在Bootloader中,我们通过`NRF_POWER->RESETREAS`可以判断复位原因。如果是软件复位(由应用程序触发),我们可以跳过双击检测,但这里我们通过内存标志传递信息,所以需要特别处理复位原因。###修改后的Bootloader双击检测部分(简化)由于双击检测主要在应用程序中完成,Bootloader中只需检查内存标志。因此,可以移除之前添加在Bootloader中的双击检测代码,改为检查内存标志。在`check_dfu_mode`函数开头: ```c//检查应用程序设置的双击DFU标志if (*dfu_double_tap_mem== DFU_DOUBLE_TAP_MAGIC){dfu_start =true;*dfu_double_tap_mem=0;//清除标志}``` ###组合键复位在应用程序中检测组合键并复位,复位后Bootloader会运行。在Bootloader中,如果检测到组合键(两个按键仍被按住),可能会触发DFU模式(因为原逻辑有检测组合键进入OTADFU)。为了避免这种情况,我们可以在应用程序复位前设置一个标志,告诉Bootloader这是正常复位,要进入DFU。但是,由于组合键复位是用户要求的正常复位,我们希望复位后直接进入应用程序(如果有效)。因此,我们可以在应用程序复位前设置一个复位标志(在保留内存中),然后在Bootloader中检查这个标志,如果有,则跳过DFU检测。 然而,这样会增加复杂性。另一种方法是:在Bootloader中,如果检测到两个按键同时按下,我们将其视为正常复位,进入DFU,而是直接跳转应用程序。但这样会改变原有逻辑(原有逻辑是组合键进入OTA DFU)。因此,我们需要权衡。根据需求,用户要求组合键是复位,而是进入DFU。所以,我们应该修改Bootloader中的组合键逻辑: 在`check_dfu_mode`函数中,修改组合键的处理: ```c//原逻辑:组合键进入OTA DFU// _ota_dfu =_ota_dfu|| (button_pressed(BUTTON_DFU)&& button_pressed(BUTTON_FRESET)); //改为:组合键设置_ota_dfu,而是直接复位(但这里能复位,因为Bootloader需要运行)//所以,我们在Bootloader中处理组合键复位,因为组合键复位已经在应用程序中处理了(应用程序检测到组合键就复位了) //因此,在Bootloader中,我们需要对组合键做特殊处理,因为应用程序已经处理了复位,正常情况下Bootloader启动时按键已经释放。//但是,如果用户在应用程序中按组合键复位,在Bootloader启动时可能两个按键仍然按着,这时会触发DFU条件(因为检测到按键按下)。所以我们需要避免这种情况。 //解决方案:在应用程序中,在复位前设置一个标志,表明这是组合键复位,Bootloader看到这个标志就忽略按键。```在内存保留区域定义组合键复位标志:```c#defineRESET_COMBO_MAGIC0x12345678volatileuint32_t *constreset_combo_mem =(volatile uint32_t*)0x20007FF8;//另一个保留地址```在应用程序中:```cif(nrf_gpio_pin_read(BUTTON_DFU)&& nrf_gpio_pin_read(BUTTON_FRESET)){*reset_combo_mem= RESET_COMBO_MAGIC;NVIC_SystemReset(); }``` 在Bootloader的`check_dfu_mode`中: ```c//检查复位标志if(*reset_combo_mem== RESET_COMBO_MAGIC){*reset_combo_mem=0;//跳过DFU检测,直接进入应用程序dfu_start =false;//注意:这里我们还要清除按键状态,因为可能按键仍按着,但我们已经知道是组合键复位,所以忽略按键//但是,我们无法清除物理按键,所以通过标志跳过//同时,我们也要清除double_tap标志,避免冲突*dfu_double_tap_mem =0;//然后直接返回,让Bootloader跳转到应用程序return; }``` ###总结1.在应用程序中实现双击检测和组合键检测。2.使用保留内存区域在Bootloader和应用程序之间传递标志。3.修改Bootloader,根据标志决定是否进入DFU或忽略按键。由于修改较为复杂,需要仔细测试。§§相关问题§§1.在嵌入式系统中如何实现Bootloader与应用程序之间的数据传递?2.如何确保保留内存区域在复位后被初始化?3.在应用程序中实现双击检测有哪些注意事项? 4.如何避免Bootloader和应用程序中的按键检测逻辑冲突? 5.系统复位后,Bootloader如何快速启动并检测DFU条件?</think>### 应用程序运行时的按键检测分析 在应用程序运行时,您提供的Bootloader代码中的按键检测逻辑**会生效**,原因如下: 1. **Bootloader生命周期**: - Bootloader仅在设备启动时执行一次 - 当跳转到应用程序后(通过`bootloader_app_start()`),Bootloader代码完全退出 - 应用程序有自己的主循环和中断处理机制 2. **按键检测位置**: - 当前的按键检测逻辑位于`check_dfu_mode()`函数中 - 该函数只在Bootloader启动阶段被调用 - 应用程序运行后会再执行此函数 3. **内存状态**: - 当应用程序运行时,Bootloader使用的内存区域可能被应用程序覆盖 - 特别是`dbl_reset_mem`等标记变量会被应用程序重新初始化 ### 解决方案:在应用程序中实现按键检测 要在应用程序运行时实现相同的按键功能,您需要在应用程序代码中添加类似的检测逻辑: ```c // 在应用程序主文件中添加 #define DOUBLE_TAP_MAX_INTERVAL 500 // 500ms双击间隔 // 全局变量(使用noinit段确保复位后保留) __attribute__((section(".noinit"))) static uint32_t first_press_time; __attribute__((section(".noinit"))) static bool double_tap_possible; void app_button_handler(void) { // 双击检测 if (nrf_gpio_pin_read(BUTTON_FRESET) == HIGH) { uint32_t current_time = board_millis(); if (double_tap_possible && (current_time - first_press_time) < DOUBLE_TAP_MAX_INTERVAL) { // 进入DFU模式 NRF_POWER->GPREGRET = DFU_MAGIC_OTA_RESET; NVIC_SystemReset(); } else { first_press_time = current_time; double_tap_possible = true; } // 等待按键释放 while (nrf_gpio_pin_read(BUTTON_FRESET) == HIGH); } // 组合键检测:DFU按下时按FRESET复位 if (nrf_gpio_pin_read(BUTTON_DFU) == HIGH && nrf_gpio_pin_read(BUTTON_FRESET) == HIGH) { NVIC_SystemReset(); } } // 在应用程序主循环中调用 int main(void) { // ... 应用初始化 ... while (1) { app_button_handler(); // ... 其他应用逻辑 ... } } ``` ### 关键实现要点 1. **内存保留**: - 使用`__attribute__((section(".noinit")))`确保双击状态变量在软复位后保留 - 在链接脚本中保留.noinit段: ``` MEMORY { ... NOINIT (rw) : ORIGIN = 0x20000000, LENGTH = 0x100 } ``` 2. **DFU进入机制**: - 设置`NRF_POWER->GPREGRET`为DFU魔法值 - 调用`NVIC_SystemReset()`触发软复位 - Bootloader会检测GPREGRET值进入DFU模式 3. **消抖处理**: ```c bool button_pressed(uint32_t pin) { if (nrf_gpio_pin_read(pin) == LOW) return false; nrf_delay_ms(20); // 20ms消抖 return (nrf_gpio_pin_read(pin) == HIGH); } ``` ### 工作流程对比 | 场景 | Bootloader中检测 | 应用程序中检测 | |--------------|-----------------------------|-----------------------------| | 冷启动 | ✅ 直接检测按键 | ❌ 未运行 | | 应用程序运行 | ❌ 已退出 | ✅ 持续检测 | | 双击进入DFU | ✅ 直接处理 | ✅ 设置标志后复位 | | 组合键复位 | ✅ 直接复位 | ✅ 直接复位 | | 内存使用 | 临时变量 | 需要保留内存区域 | ### 推荐方案 1. **Bootloader保留基本检测**:保持现有的双击/组合键检测 2. **应用程序添加补充检测**:实现上述应用层按键处理 3. **共享时间基准**:确保Bootloader和应用程序使用相同的`board_millis()`实现 这样无论设备处于启动阶段还是应用程序运行阶段,都能正确响应按键操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值