【stm32单片机基础】按键状态机实现长按和短按

2023-11-04

【stm32单片机基础】按键状态机



前言

在单片机的教学例程中,常使用delay延迟的方式消除按键抖动,而delay延迟的方式使CPU处于空等的状态,不能进行其他任务,直到结束delay延时函数,这种阻塞的方式不利于多任务的情形。本文将使用非阻塞的方式消抖,并采用状态机的模式编写按键处理函数。

一、按键的消抖

按键消抖:通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开,因而在闭合及断开的瞬间均伴随有一连串的抖动,按键抖动会引起一次按键被误读多次。

在这里插入图片描述
抖动时间的长短由按键的机械特性决定,一般为5ms~10ms

软件消抖:硬件方法将导致系统硬件电路设计复杂化,常采用软件方法进行消抖。

软件方法去抖,即检测出键闭合后执行一个延时程序,5ms~10ms的延时,让前沿抖动消失后再一次检测键的状态,如果仍保持闭合状态电平,则确认为真正有键按下。

二、按键状态机实现

0.状态机模式

简单理解为:将一个事件划分为有限个状态,满足相应的条件,在有限个状态之间跳转;可以使用状态图来描述事件处理过程,这种方式使得程序逻辑思路更加清晰严谨。以按键为例,按键检测的过程可以分为三个状态:按键检测状态、按键确认状态、按键释放状态;而在这三个状态之间跳转的条件为当前状态下按键的值。
在单片机中实现状态机最常用的语句便是switch case语句。

【状态机中如何非阻塞消抖】:使用定时器中断,定时每10ms执行一次switch case语句,即两个状态之间跳转的时间为10ms,这样便代替了delay延时。当定时中断发生时,才跳转到中断服务函数执行。

1.单个按键检测

独立按键电路
按键
单个按键的状态转移图如下:
S1状态为按键检测,S2为按键确认,S3为释放按键;状态跳转条件为当前状态下读取到的按键高低电平Key,当Result为1时,表示按键已经成功按下。
在这里插入图片描述

单个按键检测的代码实现:

#ifdef SingleKeyEvent 

typedef enum
{
    KEY_CHECK = 0,
    KEY_COMFIRM = 1,
    KEY_RELEASE = 2 
}KEY_STATE;

KEY_STATE KeyState =KEY_CHECK;  // 初始化按键状态为检测状态
u8 g_KeyFlag = 0;                 // 按键有效标志,0: 按键值无效; 1:按键值有效
/**
 * 单个按键检测事件
 * 功能:使用状态机方式,扫描单个按键;扫描周期为10ms,10ms刚好跳过抖动;
 * 状态机使用switch case语句实现状态之间的跳转
 * 
 */
void Key_Scan(void)
{
    switch (KeyState)
    {
        //按键未按下状态,此时判断Key的值
        case   KEY_CHECK:    
            if(!Key)   
            {
                KeyState =  KEY_COMFIRM;  //如果按键Key值为0,说明按键开始按下,进入下一个状态
            }
            break;
         //按键按下状态:
        case   KEY_COMFIRM:
            if(!Key)                     //查看当前Key是否还是0,再次确认是否按下
            {
                KeyState =  KEY_RELEASE;  //进入下一个释放状态
                g_KeyFlag = 1;           //按键有效值为1, 按键确认按下,按下就执行按键任务;        
            }   
            else                         //当前Key值为1,确认为抖动,则返回上一个状态
            {
                KeyState =  KEY_CHECK;      //返回上一个状态
            } 
            break;
         //按键释放状态
         case  KEY_RELEASE:
             if(Key)                     //当前Key值为1,说明按键已经释放,返回开始状态
             { 
                 KeyState =  KEY_CHECK;
               //  g_KeyFlag = 1;        //如果置于此,则在按键释放状态后,才执行按键任务;
             } 
             break;
         default: break;
    }
}

#endif

2.单个按键实现长按和短按

单个按键实现短按和长按是个很常用的方式,区别单个按键是否是长按和短按依靠检测按键按下的持续时间。

此处将短按时间T设为 10ms < T <1 s;长按时间的T设置为:T > 1s.

在上面的按键实现基础上可继续实现长按和短按判断,具体程序如下:

代码如下(示例):

#ifdef SingleKey_LongShort_Event 
/**
 * 单个按键检测短按和长按事件
 * 短按:时间 10ms < T < 1 s, 长按:时间 T >1 s
 * 功能:使用状态机方式,扫描单个按键;扫描周期为10ms,10ms刚好跳过抖动;
 * 状态机使用switch case语句实现状态之间的跳转
 * lock变量用于判断是否是第一次进行按键确认状态
 * :按键释放后才执行按键事件
 */
void Key_Scan(void)
{
    static u8 TimeCnt = 0;
    static u8 lock = 0;
    switch (KeyState)
    {
        //按键未按下状态,此时判断Key的值
        case   KEY_CHECK:    
           if(!Key)   
            {
                KeyState =  KEY_COMFIRM;  //如果按键Key值为0,说明按键开始按下,进入下一个状态 
            }
            TimeCnt = 0;                  //计数复位
            lock = 0;
            break;
            
        case   KEY_COMFIRM:
            if(!Key)                     //查看当前Key是否还是0,再次确认是否按下
            {
                if(!lock)   lock = 1;
               
                TimeCnt++;   
                               
            }   
            else                       
            {
                if(lock)                // 不是第一次进入,  释放按键才执行
                {
                    /*按键时长判断*/
                    if(TimeCnt > 100)            // 长按 1 s
                    {
                        g_KeyActionFlag = LONG_KEY;
                        TimeCnt = 0;  
                    }
                    else                         // Key值变为了1,说明此处动作为短按
                    {
                        g_KeyActionFlag = SHORT_KEY;          // 短按
                    }
                    /*按键时长判断*/
                    
                    KeyState =  KEY_RELEASE;    // 需要进入按键释放状态 
                }
                
                else                          // 当前Key值为1,确认为抖动,则返回上一个状态
                {
                    KeyState =  KEY_CHECK;    // 返回上一个状态
                }
               
            } 
            break;
            
         case  KEY_RELEASE:
             if(Key)                     //当前Key值为1,说明按键已经释放,返回开始状态
             { 
                 KeyState =  KEY_CHECK;    
             }
             break;
             
         default: break;
    }    
}
#endif


按键释放之后,才检测不太合理,做如下调整,长按事件需要达到时长就执行,短按可以在按键释放后执行。

/**
 * 单个按键检测短按和长按事件
 * 短按:时间 10ms < T < 1 s, 长按:时间 T >1 s
 * 功能:使用状态机方式,扫描单个按键;扫描周期为10ms,10ms刚好跳过抖动;
 * 状态机使用switch case语句实现状态之间的跳转
 * lock变量用于判断是否是第一次进行按键确认状态
 * :长按键事件提前执行,短按键事件释放后才执行
 */
void Key_Scan(void)
{
    static u8 TimeCnt = 0;
    static u8 lock = 0;
    switch (KeyState)
    {
        //按键未按下状态,此时判断Key的值
        case   KEY_CHECK:    
           if(!Key)   
            {
                KeyState =  KEY_COMFIRM;  //如果按键Key值为0,说明按键开始按下,进入下一个状态 
            }
            TimeCnt = 0;                  //计数复位
            lock = 0;
            break;
            
        case   KEY_COMFIRM:
            if(!Key)                     //查看当前Key是否还是0,再次确认是否按下
            {
                if(!lock)   lock = 1;
               
                TimeCnt++;  
                
                /*按键时长判断*/
                if(TimeCnt > 100)            // 长按 1 s
                {
                    g_KeyActionFlag = LONG_KEY;
                    TimeCnt = 0;  
                    lock = 0;               //重新检查
                    KeyState =  KEY_RELEASE;    // 需要进入按键释放状态
                }                
                               
            }   
            else                       
            {
                if(1==lock)                // 不是第一次进入,  释放按键才执行
                {

                    g_KeyActionFlag = SHORT_KEY;          // 短按
                    KeyState =  KEY_RELEASE;    // 需要进入按键释放状态 
                }
                
                else                          // 当前Key值为1,确认为抖动,则返回上一个状态
                {
                    KeyState =  KEY_CHECK;    // 返回上一个状态
                }
       
            } 
            break;
            
         case  KEY_RELEASE:
             if(Key)                     //当前Key值为1,说明按键已经释放,返回开始状态
             { 
                 KeyState =  KEY_CHECK;    
             }
             break;
             
         default: break;
    }    
}

三、长按和短按测试示例

头文件

/**
  * 使用定时器来轮询Key_Scan()函数,定时节拍为2ms,
  * 状态转换时间为10ms,即每次进入switch case语句的时间差为10ms
  * 利用该10ms的间隙跳过按键抖动
  */
#ifndef __BUTTON_H
#define __BUTTON_H
#include "stm32f10x.h"

//按键对应的IO管脚 KEY1  PA.15
#define KEY_IO_RCC        RCC_APB2Periph_GPIOA      
#define KEY_IO_PORT       GPIOA
#define KEY_IO_PIN        GPIO_Pin_15

//Key: 1:高电平,按键未按下, 0:低电平,按键按下
#define Key  GPIO_ReadInputDataBit(KEY_IO_PORT,KEY_IO_PIN)

typedef enum
{
    KEY_CHECK = 0,
    KEY_COMFIRM = 1,
    KEY_RELEASE = 2
}KEY_STATE;

typedef enum 
{
    NULL_KEY = 0,
    SHORT_KEY =1,
    LONG_KEY
}KEY_TYPE;

//extern u8 g_KeyFlag;
//extern KEY_TYPE g_KeyActionFlag; 

//单个按键事件
//#define SingleKeyEvent

//单个按键实现长按和短按
#define SingleKey_LongShort_Event	1
void Key_Init(void);
void Key_Scan(void);

main函数

KEY_STATE KeyState =KEY_CHECK;  // 初始化按键状态为检测状态
u8 g_KeyFlag = 0;                // 按键有效标志,0: 按键值无效; 1:按键值有效

KEY_TYPE g_KeyActionFlag;		//用于区别长按和短按

int main()
{
    Key_Init();
    Timer_init(19,7199);//10Khz的计数频率,计数到20为2ms
    while(1)
    {
         switch(g_KeyActionFlag)
        {
            case SHORT_KEY:
                /*
                执行短按对应的事件
                */
            g_KeyActionFlag = 0;		//状态回到空
            break;
            
            case LONG_KEY:
                 /*
                执行长按对应的事件
                */
            g_KeyActionFlag = 0;		//状态回到空
            default: break;
        }
    }
}


void TIM3_IRQHandler(void)   //TIM3 每 2ms 中断一次
{   
    static u8 cnt;
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 
		{
		cnt++;
        if(cnt>5)           // 每10ms 执行一次按键扫描程序
        {
            Key_Scan();
            cnt = 0;
        }
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);  //清除TIMx的中断待处理位:TIM 中断源 
		}   
}

四 、多按键检测

同样的,多按键也是一样的;
示例如下:
Buttion.h 头文件中只需要把Key做下修改;


#define KEY0  GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)//读取按键0
#define KEY1  GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)//读取按键1
#define WK_UP   GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)//读取按键2 
#define Key  (KEY0 && KEY1 && (!WK_UP))

typedef enum
{
    KEY_CHECK = 0,
    KEY_COMFIRM = 1,
    KEY_RELEASE = 2,
}KEY_STATE;

//对应的按键值,
typedef enum
{
    KEY_NULL = 0,
    KEY_0,
    KEY_1,
    KEY_WK_UP
}KEY_VALUE;

对应的状态机中对按键值进行区分即可:

void Key_Scan(void)
{
    switch (KeyState)
    {
        //按键未按下状态,此时判断Key的值
        case   KEY_CHECK:    
            if(!Key)   
            {
                KeyState =  KEY_COMFIRM;  //如果按键Key值为0,说明按键开始按下,进入下一个状态
            }
            break;
         //按键按下状态:
        case   KEY_COMFIRM:
            if(!Key)                     //查看当前Key是否还是0,再次确认是否按下
            {
                KeyState =  KEY_RELEASE;  //进入下一个释放状态
                //g_KeyFlag = 1;           //按键有效值为1, 按键确认按下,按下就执行按键任务; 
                
                // 多按键判断
                if(0 == KEY0)
                    g_Key = KEY_0;
                else if(0 == KEY1)
                    g_Key = KEY_1;
                else if(1 == WK_UP)
                    g_Key = KEY_WK_UP;
            }   
            else                         //当前Key值为1,确认为抖动,则返回上一个状态
            {
                KeyState =  KEY_CHECK;      //返回上一个状态
            } 
            break;
         //按键释放状态
         case  KEY_RELEASE:
             if(Key)                     //当前Key值为1,说明按键已经释放,返回开始状态
             { 
                 KeyState =  KEY_CHECK;
             } 
             break;
         default: break;
    }
}

main函数中也是一样,使用switch case 语句执行按键事件即可:

	extern KEY_VALUE g_Key;
  
     switch(g_Key)
    {
        case KEY_0:
            /* 
            KEY 0 按键事件 
            */
        g_Key=KEY_NULL;
        break;
        
        case KEY_1:
             /* 
             KEY 1 按键事件 
             */
        g_Key=KEY_NULL;
        break;
        
        case KEY_WK_UP:
             /* 
             KEY_WK_UP 按键事件 
             */
        g_Key=KEY_NULL;
        break;
        
        default: break;
     }
  

按键处理经典例程:

以下是按键处理的经典程序:这是一个论坛中某位博主写的,在csdn这个blog中的也对这种方法进行了归纳:
[独立按键] - 1: 单击,双击,三击以及N击
按键处理的核心就是把driver层和中间层进行拆分,driver层只需要判断长按,短按和无按下这三种状态,中间层再在上面进行处理,即可处理更多种情况;

示例场景:一个按键需要通过长按和短按实现三种功能;短按的时候,在2 秒之内,继续短按,即转变为其他功能,长按的时候则是另外一种功能。对应具体需求就是:首先短按1下开机,开机之后,如果2秒之内继续短按,则短按切换为设置键;超过2秒之后,短按1下,则关机;
这种情况下,程序可以如下:
driver 层不需要更改,只需要对中间层进行处理;

//============================ key.c ===================

#define KEY_INPUT           P1.0    // 按键IO

#define KEY_STATE_0         0       // 按键状态
#define KEY_STATE_1         1
#define KEY_STATE_2         2
#define KEY_STATE_3         3

#define LONG_KEY_TIME       300     // LONG_KEY_TIME*10MS = 3S
#define SINGLE_KEY_TIME     3       // SINGLE_KEY_TIME*10MS = 30MS

#define N_KEY    0                  // no click
#define S_KEY    1                  // single click
#define L_KEY    10                 // long press

unsigned char key_driver(void) 
{     
    static unsigned char key_state = 0;         // 按键状态变量
    static unsigned int key_time = 0;           // 按键计时变量
    unsigned char key_press, key_return; 

    key_return = N_KEY;                         // 清除 返回按键值

    key_press = KEY_INPUT;                      // 读取当前键值

    switch (key_state)     
    {       
        case KEY_STATE_0:                       // 按键状态0:判断有无按键按下
            if (!key_press)                     // 有按键按下
            {
                key_time = 0;                   // 清零时间间隔计数
                key_state = KEY_STATE_1;        // 然后进入 按键状态1
            }        
            break;

        case KEY_STATE_1:                       // 按键状态1:软件消抖(确定按键是否有效,而不是误触)。按键有效的定义:按键持续按下超过设定的消抖时间。
            if (!key_press)                     
            {
                key_time++;                     // 一次10ms
                if(key_time>=SINGLE_KEY_TIME)   // 消抖时间为:SINGLE_KEY_TIME*10ms = 30ms;
                {
                    key_state = KEY_STATE_2;    // 如果按键时间超过 消抖时间,即判定为按下的按键有效。按键有效包括两种:单击或者长按,进入 按键状态2, 继续判定到底是那种有效按键
                }
            }         
            else key_state = KEY_STATE_0;       // 如果按键时间没有超过,判定为误触,按键无效,返回 按键状态0,继续等待按键
            break; 

        case KEY_STATE_2:                       // 按键状态2:判定按键有效的种类:是单击,还是长按
            if(key_press)                       // 如果按键在 设定的长按时间 内释放,则判定为单击
            { 
                 key_return = S_KEY;            // 返回 有效按键值:单击
                 key_state = KEY_STATE_0;       // 返回 按键状态0,继续等待按键
            } 
            else
            {
                key_time++;                     

                if(key_time >= LONG_KEY_TIME)   // 如果按键时间超过 设定的长按时间(LONG_KEY_TIME*10ms=200*10ms=2000ms), 则判定为 长按
                {
                    key_return = L_KEY;         // 返回 有效键值值:长按
                    key_state = KEY_STATE_3;    // 去状态3,等待按键释放
                }
            }
            break;

      case KEY_STATE_3:                         // 等待按键释放
          if (key_press) 
          {
              key_state = KEY_STATE_0;          // 按键释放后,进入 按键状态0 ,进行下一次按键的判定
          }         
          break; 

        default:                                // 特殊情况:key_state是其他值得情况,清零key_state。这种情况一般出现在 没有初始化key_state,第一次执行这个函数的时候
            key_state = KEY_STATE_0;
            break;
    }

    return key_return;                          // 返回 按键值
} 

中间层接收到driver层的返回数据,再根据功能需求编写处理函数;

void key_event_handle(void)
{
	static uint8_t long_click_cnt = 0;
	static uint8_t short_click_cnt = 0;
	volatile static uint32_t prev_cnt, cur_cnt = 0;
	
	switch(key_return)
	{
		case S_KEY:	  // 短按 开关
		{
			/* turn on */
			if(power_state != ON)
			{
				prev_cnt = get_tim3_systick();
				power_state = ON;
				printf("turn on!! \r\n");	
			}			
			else
			{
				cur_cnt = get_tim3_systick();			// 在定时器3中获取最新计数值
				if((cur_cnt - prev_cnt) < 2000)			// 两次单击时间小于2s
				{
					short_click_cnt++;
					short_click_cnt = short_click_cnt%2;
					/* 根据按键的次数依次执行不同的动作 */
					switch(short_click_cnt)
					{
						case 0:
								printf("enter case 0 \r\n");
								/*此处可调用需要执行的函数*/	
						break;
						
						case 1:
								printf("enter case 1 \r\n");
								/*此处可调用需要执行的函数*/	
						break;
						
						default:break;
					}		
				}
				else     // 超过2秒,turn offs
				{
					printf("turn off \r\n");
					power_state = OFF;
				}
			/* 更新计数值 */
			prev_cnt = cur_cnt;
			}
		}
		break;
		
		case L_KEY:			
		{
			if(power_state)
			{
				long_click_cnt++;
				if(long_click_cnt > 50)  	// 500ms 进行一次调用
				{ 
					long_click_cnt = 0;
					printf("enter long press mode\r\n");
					/*
					此处调用长按处理函数
					*/
			 	}
			}
		}
		break;
		default:
		break;
	}
}
	

总结

以上便是对按键状态机程序的总结,对长按和短按的判断实现……

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【stm32单片机基础】按键状态机实现长按和短按 的相关文章

  • 【STM32】stm32是什么

    作者 一只大喵咪1201 专栏 STM32学习 格言 你只管努力 剩下的交给时间 STM32的简单介绍 介绍 特点 认识STM32 总结 介绍 STM32是一款单片机 它由意法半导体公司制造 ST是意法半导体的简称 M是指微控制器 也就是单
  • 「react进阶」年终送给react开发者的八条优化建议(篇幅较长,占用20-30分钟)

    笔者是一个 react 重度爱好者 在工作之余 也看了不少的 react 文章 写了很多 react 项目 接下来笔者讨论一下 React 性能优化的主要方向和一些工作中的小技巧 送人玫瑰 手留余香 阅读的朋友可以给笔者点赞 关注一波 公众
  • API hook 原理与Windows hook 应用

    API hook 原理与Windows hook 应用 分类 系统程序 2012 04 14 12 20 3679人阅读 评论 3 收藏 举报 hook api windows attributes descriptor winapi 目录
  • seaborn.heatmap部分参数解释

    今天也是自己用seaborn的heatmap花了一个混淆矩阵 sns heatmap ConfusoinMatrix annot True ax ax cmap Greens 发现他这个对数据倾斜的数据很不友好啊 如果有一个类别的数据超级多
  • SystemC自带example的simple_perf研习

    simple perf SystemC的性能建模示例 也是SystemC中系统级建模的一个入门简介 SystemC自带example的系列 SystemC自带example的pipe研习 SystemC自带example的pkt switc

随机推荐

  • fabric1.0 错误分析总结

    个人在学习 fabric1 0 项目中遇到的 一些 错误和原因总结 如发现错误即时指出 1 ERROR could not find an available non overlapping IPv4 address pool among
  • 用Rancher RKE快速部署高可用k8s集群

    用Rancher部署高可用k8s集群 用Rancher RKE部署高可用k8s集群 1 主机配置 1 1 新建虚拟主机 1 2 主机初始化配置 安装一些必要的安装包 安全设置 ntp时钟同步 内核参数调优 hostname修改 关闭swap
  • 诠释韧性增长,知乎Q3财报里的社区优势和商业化价值

    当内容平台开始做生意 往往意味着它要扮演一个大包大揽的角色 从内容的可持续性到最终变现 设计一套完整的生态系统是必需的 但并非所有平台都对此感到棘手 或者说在某些平台 生态已经不是困难 而是优势和特色 知乎就是从好平台走向好公司的典型例子
  • scrapy中使用css选择器罗列下一级的所有标签

    使用 css dl gt 即为罗列dl标签的下一级所有标签 例子 dt dl a dl dl b dl dl h1 c h1 dl dt 使用 data dt response css dl dt id all child elements
  • Python-Tkinter 图形化界面设计

    摘抄来自Python Tkinter 图形化界面设计 还是自己去看一下比较好 我只是摘抄我用的上的 一 最基本框架 from tkinter import root Tk root title 我的第一个Python窗体 root geom
  • P2524 Uim的情人节礼物·其之弐【康托展开模板题】

    题目链接 我在这里加了树状数组来优化康托展开 但是这道题的数据其实很小 不需要加也是可以的 include
  • 27 类深度学习主要神经网络

    1 感知器 Perceptron P 感知器模型也称为单层神经网络 这个神经网络只包含两层 输入层 输出层 这种类型的神经网络没有隐藏层 它接受输入并计算每个节点的加权 然后 它使用激活函数 大多数是Sigmoid函数 进行分类 应用 分类
  • 49 题目 1431: [蓝桥杯][2014年第五届真题]分糖果

    题目 1431 蓝桥杯 2014年第五届真题 分糖果 时间限制 1Sec 内存限制 128MB 提交 5807 解决 2969 题目描述 问题描述 有n个小朋友围坐成一圈 老师给每个小朋友随机发偶数个糖果 然后进行下面的游戏 每个小朋友都把
  • Python中Requests模块的异常值处理

    在我们用Python的requests模块进行爬虫时 一个简单高效的模块就是requests模块 利用get 或者post 函数 发送请求 但是在真正的实际使用过程中 我们可能会遇到网络的各种变化 可能会导致请求过程发生各种未知的错误导致程
  • Vue中的路由以及默认路由跳转

    文章目录 官方网址 Vue路由配置 安装 引入并使用 配置路由 官方网址 https router vuejs org Vue路由配置 安装 npm install vue router save 或者 cnpm install vue r
  • SpringBoot集成XxlJob分布式任务调度中心(超详细之手把手教学)

    一 前言 废话就不多说了 介绍Xxl Job的网上已经有很多 本文就不多加复制粘贴了 直接步入第二步 PS 本文包括Xxl Job分布式定时任务调度中心的搭建 以及SpringBoot集成XxlJob的全过程 如果不想了解搭建的小伙伴可以直
  • 判断加密方式

    如何判断密文的加密方式 1 如果密文是十进制 字符范围是 0 9 可以猜测是ASCII编码 2 如果密文由 a z A Z 和 构成 特别是末尾有 那么判断可能是Base64编码 Base64在线解码网址 BASE64加密解密 3 如果密文
  • Docker 部署 RocketMQ

    文章目录 安装nameserver 拉取镜像 运行容器 出现问题卸载 安装broker 创建配置文件 运行容器 出现问题卸载 安装控制台 拉取镜像 运行容器 出现问题卸载 安装nameserver 拉取镜像 docker pull rock
  • 时序预测

    时序预测 MATLAB实现ARIMA时间序列预测 armax函数 本程序基于MATLAB的armax函数实现arima时间序列预测 实现了模型趋势分析 序列差分 序列平稳化 AIC准则模型参数识别与定阶 预测结果与误差分析过程 逻辑清晰 数
  • 【NLP实践】使用Pytorch进行文本分类——BILSTM+ATTENTION

    目录 网络结构 代码实现 Attention计算 模型效果 调参 相关文章 网络结构 代码实现 class TextBILSTM nn Module def init self config TRNNConfig char size 500
  • 学习Vue 之 创建一个 Vue 应用

    文章目录 Vue js 概述 了解 Vue 创建一个 Vue 应用 参考 Vue js 概述 计划学习前端 已有一些HTML js CSS的基础知识 下一步学习Vue js 以下是一些适合新手的Vue js教程 你可以根据自己的实际情况和需
  • Python提示 TypeError: super(type, obj): obj must be an instance or subtype of type问题

    Python提示 TypeError super type obj obj must be an instance or subtype of type问题 简述问题 在工作中有一天将debug下正常工作的python代码编译之后运行却抛出
  • 奇迹mu修改服务器名,奇迹MU 红名设置调整方案说明

    尊敬的用户 经过与游戏制作方的沟通 已经确认本次游戏版本中红名设置突然调整的原因 由于韩国奇迹MU之外的所有服务器 国际服 日服 中国服务器等 将对红名设置进行统一设置 红名设置将恢复成为Season 8版本期间的模式 红名2阶段之后可以继
  • 使用JAVA连接MySQL,储存歌曲,图片,影片文件

    MySQL中创建数据表 存放歌曲等文件字节流 使用longblob字段类型 我这个只是演示所以就一个字段 如果想比较好的管理文件 不要这么搞 create dadabase ttest use ttest create table musi
  • 【stm32单片机基础】按键状态机实现长按和短按

    stm32单片机基础 按键状态机 文章目录 stm32单片机基础 按键状态机 前言 一 按键的消抖 二 按键状态机实现 0 状态机模式 1 单个按键检测 2 单个按键实现长按和短按 三 长按和短按测试示例 四 多按键检测 按键处理经典例程