news 2026/5/30 12:20:40

混多功能合混合按键处理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
混多功能合混合按键处理
/************************************************************ * @brief 按键驱动 * @param NULL * @return NULL * @author * @date 2018-xx-xx * @version v1.0 * @note button.c ***********************************************************/ #include "button.h" #include "hardware_config.h" #include "Global_Variable.h" #include "Key.h" /******************************************************************* * 变量声明 *******************************************************************/ static struct button* Head_Button = NULL; /******************************************************************* * 用户代码 *******************************************************************/ Button_t Button1; Button_t Button2; Button_t Button3; Button_t Button4; uint16_t test_button_Dowm; uint16_t test_button_Double; uint16_t test_button_Long; uint16_t test_button_Continuos; uint16_t test_button_ContinuosFree; u32 motor_speed_set; uint8_t Read_KEY1_Level_Func(void) { return Read_KEY1_Level(); // 调用宏 } uint8_t Read_KEY2_Level_Func(void) { return Read_KEY2_Level(); // 调用宏 } uint8_t Read_KEY3_Level_Func(void) { return Read_KEY3_Level(); // 调用宏 } uint8_t Read_KEY4_Level_Func(void) { return Read_KEY4_Level(); // 调用宏 } //按键任务回调函数 void Btn1_Dowm_CallBack(void *btn) { motor_speed_set += 10000; } void Btn1_Double_CallBack(void *btn) { test_button_Double++; } void Btn1_Long_CallBack(void *btn) { test_button_Long++; motor_speed_set+=1000; } void Btn1_Continuos_CallBack(void *btn) { test_button_Continuos++; // PRINT_INFO("Button1 连按!"); } void Btn1_ContinuosFree_CallBack(void *btn) { test_button_ContinuosFree++; // PRINT_INFO("Button1 连按释放!"); } void Btn2_Dowm_CallBack(void *btn) { motor_speed_set-=10000; } void Btn2_Double_CallBack(void *btn) { test_button_Double++; } void Btn2_Long_CallBack(void *btn) { test_button_Long++; motor_speed_set-=1000; } void Btn2_Continuos_CallBack(void *btn) { test_button_Continuos++; } void Btn2_ContinuosFree_CallBack(void *btn) { test_button_ContinuosFree++; } ////////////////////////////////////////////////////// void Btn3_Dowm_CallBack(void *btn) { motor_speed_set+=100; } void Btn3_Double_CallBack(void *btn) { test_button_Double++; } void Btn3_Long_CallBack(void *btn) { test_button_Long++; motor_speed_set-=100; } void Btn3_Continuos_CallBack(void *btn) { test_button_Continuos++; } void Btn3_ContinuosFree_CallBack(void *btn) { test_button_ContinuosFree++; } void Btn4_Dowm_CallBack(void *btn) { motor_speed_set-=100; test_button_Dowm++; } void Btn4_Double_CallBack(void *btn) { test_button_Double++; } void Btn4_Long_CallBack(void *btn) { test_button_Long++; motor_speed_set-=100; } void Btn4_Continuos_CallBack(void *btn) { test_button_Continuos++; } void Btn4_ContinuosFree_CallBack(void *btn) { test_button_ContinuosFree++; } void Button_Init(void) { Button_Create("Button1", &Button1, Read_KEY1_Level_Func, KEY_ON); Button_Create("Button2", &Button2, Read_KEY2_Level_Func, KEY_ON); Button_Create("Button3", &Button3, Read_KEY3_Level_Func, KEY_ON); Button_Create("Button4", &Button4, Read_KEY4_Level_Func, KEY_ON); Button_Attach(&Button1,BUTTON_DOWM,Btn1_Dowm_CallBack); //单击 Button_Attach(&Button1,BUTTON_DOUBLE,Btn1_Double_CallBack); //双击 // Button_Attach(&Button1,BUTTON_CONTINUOS,Btn1_Continuos_CallBack); //连按 // Button_Attach(&Button1,BUTTON_CONTINUOS_FREE,Btn1_ContinuosFree_CallBack); //连按释放 Button_Attach(&Button1,BUTTON_LONG,Btn1_Long_CallBack); //长按 Button_Attach(&Button2,BUTTON_DOWM,Btn2_Dowm_CallBack); //单击 // Button_Attach(&Button1,BUTTON_DOUBLE,Btn1_Double_CallBack); //双击 // Button_Attach(&Button1,BUTTON_CONTINUOS,Btn1_Continuos_CallBack); //连按 // Button_Attach(&Button1,BUTTON_CONTINUOS_FREE,Btn1_ContinuosFree_CallBack); //连按释放 Button_Attach(&Button2,BUTTON_LONG,Btn2_Long_CallBack); //长按 Button_Attach(&Button3,BUTTON_DOWM,Btn3_Dowm_CallBack); //单击 // Button_Attach(&Button1,BUTTON_DOUBLE,Btn1_Double_CallBack); //双击 // Button_Attach(&Button1,BUTTON_CONTINUOS,Btn1_Continuos_CallBack); //连按 // Button_Attach(&Button1,BUTTON_CONTINUOS_FREE,Btn1_ContinuosFree_CallBack); //连按释放 Button_Attach(&Button3,BUTTON_LONG,Btn3_Long_CallBack); //长按 Button_Attach(&Button4,BUTTON_DOWM,Btn4_Dowm_CallBack); //单击 // Button_Attach(&Button1,BUTTON_DOUBLE,Btn1_Double_CallBack); //双击 // Button_Attach(&Button1,BUTTON_CONTINUOS,Btn1_Continuos_CallBack); //连按 // Button_Attach(&Button1,BUTTON_CONTINUOS_FREE,Btn1_ContinuosFree_CallBack); //连按释放 Button_Attach(&Button4,BUTTON_LONG,Btn4_Long_CallBack); //长按 } /******************************************************************* * 函数声明 *******************************************************************/ static char *StrnCopy(char *dst, const char *src, uint32_t n); static void Print_Btn_Info(Button_t* btn); static void Add_Button(Button_t* btn); /************************************************************ * @brief 按键创建 * @param name : 按键名称 * @param btn : 按键结构体 * @param read_btn_level : 按键电平读取函数,需要用户自己实现返回uint8_t类型的电平 * @param btn_trigger_level : 按键触发电平 * @return NULL * @date 2018-xx-xx * @version v1.0 * @note NULL ***********************************************************/ void Button_Create(const char *name, Button_t *btn, uint8_t(*read_btn_level)(void), uint8_t btn_trigger_level) { if( btn == NULL) { return; } memset(btn, 0, sizeof(struct button)); //清除结构体信息,建议用户在之前清除 StrnCopy(btn->Name, name, BTN_NAME_MAX); /* 创建按键名称 */ btn->Button_State = NONE_TRIGGER; //按键状态 btn->Button_Last_State = NONE_TRIGGER; //按键上一次状态 btn->Button_Trigger_Event = NONE_TRIGGER; //按键触发事件 btn->Read_Button_Level = read_btn_level; //按键读电平函数 btn->Button_Trigger_Level = btn_trigger_level; //按键触发电平 btn->Button_Last_Level = btn->Read_Button_Level(); //按键当前电平 btn->Debounce_Time = 0; Add_Button(btn); //创建的时候添加到单链表中 Print_Btn_Info(btn); // 打印信息 } /************************************************************ * @brief 按键触发事件与回调函数映射链接起来 * @param btn : 按键结构体 * @param btn_event : 按键触发事件 * @param btn_callback : 按键触发之后的回调处理函数。需要用户实现 * @return NULL * @date 2018-xx-xx * @version v1.0 ***********************************************************/ void Button_Attach(Button_t *btn,Button_Event btn_event,Button_CallBack btn_callback) { if( btn == NULL) { return; } if(BUTTON_ALL_RIGGER == btn_event) { for(uint8_t i = 0 ; i < number_of_event-1 ; i++) btn->CallBack_Function[i] = btn_callback; //按键事件触发的回调函数,用于处理按键事件 } else { btn->CallBack_Function[btn_event] = btn_callback; //按键事件触发的回调函数,用于处理按键事件 } } /************************************************************ * @brief 删除一个已经创建的按键 * @param NULL * @return NULL * @date 2018-xx-xx * @version v1.0 * @note NULL ***********************************************************/ void Button_Delete(Button_t *btn) { struct button** curr; for(curr = &Head_Button; *curr;) { struct button* entry = *curr; if (entry == btn) { *curr = entry->Next; } else { curr = &entry->Next; } } } Button_Event button_evennt; /************************************************************ * @brief 获取按键触发的事件 * @param NULL * @return NULL * @date 2018-xx-xx * @version v1.0 ***********************************************************/ void Get_Button_EventInfo(Button_t *btn) { //按键事件触发的回调函数,用于处理按键事件 for(uint8_t i = 0 ; i < number_of_event-1 ; i++) { if(btn->CallBack_Function[i] != 0) { button_evennt = btn->Button_Trigger_Event; } } } uint8_t Get_Button_Event(Button_t *btn) { return (uint8_t)(btn->Button_Trigger_Event); } /************************************************************ * @brief 获取按键触发的事件 * @param NULL * @return NULL * @date 2018-xx-xx * @version v1.0 ***********************************************************/ uint8_t Get_Button_State(Button_t *btn) { return (uint8_t)(btn->Button_State); } /************************************************************ * @brief 按键周期处理函数 * @param btn:处理的按键 * @return NULL * @date 2018-xx-xx * @version v1.0 * @note 必须以一定周期调用此函数,建议周期为20~50ms ***********************************************************/ void Button_Cycle_Process(Button_t *btn) { uint8_t current_level = (uint8_t)btn->Read_Button_Level();//获取当前按键电平 if((current_level != btn->Button_Last_Level)&&(++(btn->Debounce_Time) >= BUTTON_DEBOUNCE_TIME)) //按键电平发生变化,消抖 { btn->Button_Last_Level = current_level; //更新当前按键电平 btn->Debounce_Time = 0; //确定了是按下 //如果按键是没被按下的,改变按键状态为按下(首次按下/双击按下) if((btn->Button_State == NONE_TRIGGER)||(btn->Button_State == BUTTON_DOUBLE)) { btn->Button_State = BUTTON_DOWM; } //释放按键 else if(btn->Button_State == BUTTON_DOWM) { btn->Button_State = BUTTON_UP; TRIGGER_CB(BUTTON_UP); // 触发释放 } } switch(btn->Button_State) { case BUTTON_DOWM : // 按下状态 { if(btn->Button_Last_Level == btn->Button_Trigger_Level) //按键按下 { #if CONTINUOS_TRIGGER //支持连续触发 if(++(btn->Button_Cycle) >= BUTTON_CONTINUOS_CYCLE) { btn->Button_Cycle = 0; btn->Button_Trigger_Event = BUTTON_CONTINUOS; TRIGGER_CB(BUTTON_CONTINUOS); //连按 //PRINT_DEBUG("连按"); } #else btn->Button_Trigger_Event = BUTTON_DOWM; if(++(btn->Long_Time) >= BUTTON_LONG_TIME) //释放按键前更新触发事件为长按 { #if LONG_FREE_TRIGGER btn->Button_Trigger_Event = BUTTON_LONG; #else if(++(btn->Button_Cycle) >= BUTTON_LONG_CYCLE) //连续触发长按的周期 { btn->Button_Cycle = 0; btn->Button_Trigger_Event = BUTTON_LONG; TRIGGER_CB(BUTTON_LONG); //长按 } #endif if(btn->Long_Time == 0xFFFF) //更新时间溢出 { btn->Long_Time = BUTTON_LONG_TIME; } //PRINT_DEBUG("长按"); } #endif } break; } case BUTTON_UP : // 弹起状态 { if(btn->Button_Trigger_Event == BUTTON_DOWM) //触发单击 { if((btn->Timer_Count <= BUTTON_DOUBLE_TIME)&&(btn->Button_Last_State == BUTTON_DOUBLE)) // 双击 { btn->Button_Trigger_Event = BUTTON_DOUBLE; TRIGGER_CB(BUTTON_DOUBLE); //PRINT_DEBUG("双击"); btn->Button_State = NONE_TRIGGER; btn->Button_Last_State = NONE_TRIGGER; } else { btn->Timer_Count=0; btn->Long_Time = 0; //检测长按失败,清0 #if (SINGLE_AND_DOUBLE_TRIGGER == 0) TRIGGER_CB(BUTTON_DOWM); //单击 #endif btn->Button_State = BUTTON_DOUBLE; btn->Button_Last_State = BUTTON_DOUBLE; } } else if(btn->Button_Trigger_Event == BUTTON_LONG) { #if LONG_FREE_TRIGGER TRIGGER_CB(BUTTON_LONG); //长按 #else TRIGGER_CB(BUTTON_LONG_FREE); //长按释放 #endif btn->Long_Time = 0; btn->Button_State = NONE_TRIGGER; btn->Button_Last_State = BUTTON_LONG; } #if CONTINUOS_TRIGGER else if(btn->Button_Trigger_Event == BUTTON_CONTINUOS) //连按 { btn->Long_Time = 0; TRIGGER_CB(BUTTON_CONTINUOS_FREE); //连发释放 btn->Button_State = NONE_TRIGGER; btn->Button_Last_State = BUTTON_CONTINUOS; } #endif break; } case BUTTON_DOUBLE : { btn->Timer_Count++; //时间记录 if(btn->Timer_Count>=BUTTON_DOUBLE_TIME) { btn->Button_State = NONE_TRIGGER; btn->Button_Last_State = NONE_TRIGGER; } #if SINGLE_AND_DOUBLE_TRIGGER if((btn->Timer_Count>=BUTTON_DOUBLE_TIME)&&(btn->Button_Last_State != BUTTON_DOWM)) { btn->Timer_Count=0; TRIGGER_CB(BUTTON_DOWM); //单击 btn->Button_State = NONE_TRIGGER; btn->Button_Last_State = BUTTON_DOWM; } #endif break; } default : break; } } /************************************************************ * @brief 遍历的方式扫描按键,不会丢失每个按键 * @param NULL * @return NULL * @date 2018-xx-xx * @version v1.0 * @note 此函数要周期调用,建议20-50ms调用一次 ***********************************************************/ void Button_Process(void) { struct button* pass_btn; for(pass_btn = Head_Button; pass_btn != NULL; pass_btn = pass_btn->Next) { Button_Cycle_Process(pass_btn); } } /************************************************************ * @brief 遍历按键 * @param NULL * @return NULL * @date 2018-xx-xx * @version v1.0 * @note NULL ***********************************************************/ void Search_Button(void) { struct button* pass_btn; for(pass_btn = Head_Button; pass_btn != NULL; pass_btn = pass_btn->Next) { //PRINT_INFO("button node have %s",pass_btn->Name); } } /************************************************************ * @brief 处理所有按键回调函数 * @param NULL * @return NULL * @date 2018-xx-xx * @version v1.0 * @note 暂不实现 ***********************************************************/ void Button_Process_CallBack(void *btn) { uint8_t btn_event = Get_Button_Event(btn); switch(btn_event) { case BUTTON_DOWM: { //PRINT_INFO("添加你的按下触发的处理逻辑"); break; } case BUTTON_UP: { //PRINT_INFO("添加你的释放触发的处理逻辑"); break; } case BUTTON_DOUBLE: { //PRINT_INFO("添加你的双击触发的处理逻辑"); break; } case BUTTON_LONG: { //PRINT_INFO("添加你的长按触发的处理逻辑"); break; } case BUTTON_LONG_FREE: { //PRINT_INFO("添加你的长按释放触发的处理逻辑"); break; } case BUTTON_CONTINUOS: { //PRINT_INFO("添加你的连续触发的处理逻辑"); break; } case BUTTON_CONTINUOS_FREE: { //PRINT_INFO("添加你的连续触发释放的处理逻辑"); break; } } } /**************************** 以下是内部调用函数 ********************/ /************************************************************ * @brief 拷贝指定长度字符串 * @param NULL * @return NULL * @date 2018-xx-xx * @version v1.0 * @note NULL ***********************************************************/ static char *StrnCopy(char *dst, const char *src, uint32_t n) { if (n != 0) { char *d = dst; const char *s = src; do { if ((*d++ = *s++) == 0) { while (--n != 0) *d++ = 0; break; } } while (--n != 0); } return (dst); } /************************************************************ * @brief 打印按键相关信息 * @param NULL * @return NULL * @date 2018-xx-xx * @version v1.0 * @note NULL ***********************************************************/ static void Print_Btn_Info(Button_t* btn) { //PRINT_INFO("button struct information:\n\ btn->Name:%s \n\ btn->Button_State:%d \n\ btn->Button_Trigger_Event:%d \n\ btn->Button_Trigger_Level:%d \n\ btn->Button_Last_Level:%d \n\ ",btn->Name,btn->Button_State,btn->Button_Trigger_Event,btn->Button_Trigger_Level,btn->Button_Last_Level); Search_Button(); } /************************************************************ * @brief 使用单链表将按键连接起来 * @param NULL * @return NULL * @date 2018-xx-xx * @version v1.0 * @note NULL ***********************************************************/ static void Add_Button(Button_t* btn) { btn->Next = Head_Button; Head_Button = btn; }
#ifndef BUTTON_H #define BUTTON_H #include <stdint.h> #include <string.h> /***************************外部调用头文件*************************************/ #include "USER_APP.h" /***************************************************************************/ #define BTN_NAME_MAX 32 //名字最大为32字节 // 按下有效电平 #define KEY_ON 0 /* 是否支持连续触发 按键消抖时间40ms, 建议调用周期为20ms 只有连续检测到40ms状态不变才认为有效,包括弹起和按下两种事件*/ #define CONTINUOS_TRIGGER 0 //是否支持连续触发,连发的话就不要检测单双击与长按了 /* 是否支持单击&双击同时存在触发 如果选择开启宏定义的话,单双击都回调,只不过单击会延迟响应, 因为必须判断单击之后是否触发了双击否则,延迟时间是双击间隔时间 BUTTON_DOUBLE_TIME。 而如果不开启这个宏定义,建议工程中只存在单击/双击中的一个,否则,在双击响应的时候会触发一次单击, 因为双击必须是有一次按下并且释放之后才产生的 */ #define SINGLE_AND_DOUBLE_TRIGGER 0 /* 是否支持长按释放才触发 如果打开这个宏定义,那么长按释放之后才触发单次长按, 否则在长按指定时间就一直触发长按,触发周期由 BUTTON_LONG_CYCLE 决定 */ #define LONG_FREE_TRIGGER 1 #define BUTTON_DEBOUNCE_TIME 40 //消抖时间 (n-1)*调用周期 40ms #define BUTTON_CONTINUOS_CYCLE 20 //连按触发周期时间 (n-1)*调用周期 #define BUTTON_LONG_CYCLE 2 //长按触发周期时间 (n-1)*调用周期 #define BUTTON_DOUBLE_TIME 300 //双击间隔时间 (n-1)*调用周期 500ms 建议在200-600ms #define BUTTON_LONG_TIME 2000 //持续n秒 (n-1)*调用周期,认为长按事件 2000ms #define TRIGGER_CB(event) \ if(btn->CallBack_Function[event]) \ btn->CallBack_Function[event]((Button_t*)btn) typedef void (*Button_CallBack)(void*); /* 按键触发回调函数,需要用户实现 */ #define Key1_port GPIO0 #define Key1_port_pin GPIO_Pin_6 #define Read_KEY1_Level() GPIO_ReadInputDataBit(Key1_port, Key1_port_pin) #define Key2_port GPIO3 #define Key2_port_pin GPIO_Pin_5 #define Read_KEY2_Level() GPIO_ReadInputDataBit(Key2_port, Key2_port_pin) #define Key3_port GPIO1 #define Key3_port_pin GPIO_Pin_0 #define Read_KEY3_Level() GPIO_ReadInputDataBit(Key3_port, Key3_port_pin) #define Key4_port GPIO3 #define Key4_port_pin GPIO_Pin_2 #define Read_KEY4_Level() GPIO_ReadInputDataBit(Key4_port, Key4_port_pin) typedef enum { NONE_TRIGGER = 0, BUTTON_DOWM, BUTTON_UP, BUTTON_DOUBLE, BUTTON_LONG, BUTTON_LONG_FREE, BUTTON_CONTINUOS, BUTTON_CONTINUOS_FREE, BUTTON_ALL_RIGGER, number_of_event /* 触发回调的事件 */ }Button_Event; /* 每个按键对应1个全局的结构体变量。 其成员变量是实现滤波和多种按键状态所必须的 */ typedef struct button { /* 下面是一个函数指针,指向判断按键手否按下的函数 */ uint8_t (*Read_Button_Level)(void); /* 读取按键电平函数,需要用户实现 */ char Name[BTN_NAME_MAX]; uint8_t Button_State : 4; /* 按键当前状态(按下还是弹起) */ uint8_t Button_Last_State : 4; /* 上一次的按键状态,用于判断双击 */ uint8_t Button_Trigger_Level : 2; /* 按键触发电平 */ uint8_t Button_Last_Level : 2; /* 按键当前电平 */ uint8_t Button_Trigger_Event; /* 按键触发事件,单击,双击,长按等 */ Button_CallBack CallBack_Function[number_of_event]; uint8_t Button_Cycle; /* 连续按键周期 */ uint16_t Timer_Count; /* 计时 */ uint8_t Debounce_Time; /* 消抖时间 */ uint16_t Long_Time; /* 按键按下持续时间 */ struct button *Next; }Button_t; extern Button_t Button1; /* 供外部调用的函数声明 */ void Button_Create(const char *name, Button_t *btn, uint8_t(*read_btn_level)(void), uint8_t btn_trigger_level); void Button_Attach(Button_t *btn,Button_Event btn_event,Button_CallBack btn_callback); void Button_Cycle_Process(Button_t *btn); void Button_Process(void); void Button_Delete(Button_t *btn); void Search_Button(void); void Get_Button_EventInfo(Button_t *btn); uint8_t Get_Button_Event(Button_t *btn); uint8_t Get_Button_State(Button_t *btn); void Button_Process_CallBack(void *btn); void Button_Init(void); #endif
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/30 12:19:10

亚马逊 Q1 税务报表大规模异常,官方确认:2 周内补发正确版本

近期&#xff0c;大批亚马逊卖家在调取 2026 年第一季度税务申报报表时&#xff0c;发现后台数据出现严重偏差&#xff0c;佣金、服务费、配送费等核心费用项统计失真、数值异常&#xff0c;直接影响财务核算与税务抵扣&#xff0c;引发行业广泛关注。不少卖家反馈&#xff0c;…

作者头像 李华
网站建设 2026/5/30 12:18:20

树莓派变无线AP:NetworkManager实战配置与网络扩展指南

1. 项目概述与核心价值手头正好有个闲置的树莓派4B&#xff0c;琢磨着怎么把它利用起来。之前用它跑过一些轻量服务&#xff0c;但总觉得网络这块儿还能再挖掘一下。比如&#xff0c;书房角落的Wi-Fi信号总是不太稳定&#xff0c;或者想在院子里临时搞个小工作区&#xff0c;拉…

作者头像 李华
网站建设 2026/5/30 12:18:19

基于ESP32与MQTT的物联网可穿戴设备开发实战

1. 项目概述&#xff1a;从“捉迷藏”到物联网可穿戴设备几年前&#xff0c;我和我的团队在构思一个学期项目时&#xff0c;想找回点童年的乐趣。我们想做一个游戏&#xff0c;融合了“捉迷藏”的紧张感和“抓人”游戏的团队对抗性。这个想法很简单&#xff1a;分成猎人和猎物两…

作者头像 李华
网站建设 2026/5/30 12:18:18

5分钟学会E-Hentai画廊一键打包下载:完整配置指南

5分钟学会E-Hentai画廊一键打包下载&#xff1a;完整配置指南 【免费下载链接】E-Hentai-Downloader Download E-Hentai archive as zip file 项目地址: https://gitcode.com/gh_mirrors/eh/E-Hentai-Downloader 想要轻松保存E-Hentai画廊中的所有图片吗&#xff1f;E-H…

作者头像 李华
网站建设 2026/5/30 12:16:42

视频孪生重塑职业教育实训体系:从“虚拟操作”迈向“真实能力”

在职业教育与工程教育领域&#xff0c;始终存在一道难以真正跨越的“断层”——学生在虚拟仿真软件中能够熟练完成操作&#xff0c;但一旦进入真实设备、真实工况环境&#xff0c;往往难以快速建立有效的空间认知与操作能力。这一问题的根源在于&#xff0c;传统虚拟仿真实训更…

作者头像 李华
网站建设 2026/5/30 12:16:28

QEMU虚拟机执行启动脚本闪退

复制启动脚本里的内容&#xff0c;打开命令行&#xff0c;在命令行中执行启动脚本的内容就不会闪退&#xff0c;从而可以看到出错的打印信息&#xff0c;通过打印信息发现我遇到的情况是缺少文件&#xff0c;于是按照网上的配置流程检查缺少的文件&#xff0c;补充上即可。

作者头像 李华