初学51单片机之长短键应用定时炸弹及扩展应用

51单片机RAM区域划分

51单片机的RAM分为两个部分,一块是片内RAM,一块是片外RAM。

data: 片内RAM从 0x00 ~0x7F 寻址范围(0-127) 容量共128B

idata:   片外RAM从 0x00~0xFF 寻址范围(0-255)    容量共256B

pdata:片外RAM从 0x00~0xFF 寻址范围(0-255)  容量共256B

xdata:片外RAM从 0x0000~0xFFFF 寻址范围(0-65535)容量共65536B

从上述的范围可以看出,data是idata的一部分,pdata是xdata的一部分

可以这么定义一个变量啊:unsigned char data a = 0,但事实上我们平时书写的时候是不写data的

因为在Keil默认的设置下,data是可以省略的。

片内RAM的访问速度会比片外的访问速度快,但是一般不用idata 0x80~0XFF这部分范围。因为这块通常用于中断与函数调用的堆栈。所以绝大部分情况下,使用内部RAM的时候,只用data就可以了。

STC89C52共512字节的RAM,分为256字节的片内RAM和256字节的片外RAM。一般情况下使用data区域,如果data不够用了,就用xdata。如果希望程序执行效率尽量高一点,就用pdata关键字来定义。

事实上真正的芯片外扩展很少用到了,虽然它还是叫片外RAM,但实际上它现在也在单片机内部,只是响应速度不太一样而已。

定时炸弹的基本要求

1:利用蜂鸣器鸣叫与点亮LED来表示炸弹爆炸。

2:可以用按键调整定时时间。长按调整按键可以是连续增加或减少定时时间。

3:ESC键清0暂停倒计时,Entel键开始倒计时,到了0秒爆炸。

上代码

#include <reg52.h>sbit BUZZ  = P1^6;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY_IN_1  = P2^4;
sbit KEY_IN_2  = P2^5;
sbit KEY_IN_3  = P2^6;
sbit KEY_IN_4  = P2^7;
sbit KEY_OUT_1 = P2^3;
sbit KEY_OUT_2 = P2^2;
sbit KEY_OUT_3 = P2^1;
sbit KEY_OUT_4 = P2^0;unsigned char code LedChar[] = {  //数码管显示字符转换表0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[7] = {  //数码管+独立LED显示缓冲区0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
unsigned char code KeyCodeMap[4][4] = { //矩阵按键编号到标准键盘键码的映射表{ 0x31, 0x32, 0x33, 0x26 }, //数字键1、数字键2、数字键3、向上键{ 0x34, 0x35, 0x36, 0x25 }, //数字键4、数字键5、数字键6、向左键{ 0x37, 0x38, 0x39, 0x28 }, //数字键7、数字键8、数字键9、向下键{ 0x30, 0x1B, 0x0D, 0x27 }  //数字键0、ESC键、  回车键、 向右键
};
unsigned char KeySta[4][4] = {  //全部矩阵按键的当前状态{1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1}};
pdata unsigned long  KeyDownTime[4][4]= {{0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0}};bit enBuzz = 0;           //蜂鸣器使能标记bit flag1s = 0;           //1s定时标志bit flagStart = 0;        //倒计时启动标志unsigned char T0RH = 0;   //T0重载值高字节unsigned char T0RL = 0;   //T0重载值低字节unsigned char CountDown = 0;  //倒计时计数器void ConfigTimer0(unsigned int ms);  //定时器0初值设定函数void ShowNumber(unsigned long num); //倒计时调整时间,数码管显示函数void KeyDriver();void main(){EA = 1;ENLED = 0;ADDR3 = 1;ConfigTimer0(1); //定时1msShowNumber(0);  //数码管显示0while(1){KeyDriver();               //调用按键驱动函数if(flagStart && flag1s)    //倒计时启动且1秒定时到达时,处理倒计时{flag1s = 0;if(CountDown > 0)      //倒计时未到0时,计时器递减{CountDown--;        //ShowNumber(CountDown); //刷新倒计时数字显示if(CountDown == 0){enBuzz = 1;       //启动蜂鸣器LedBuff[6] = 0x00; //点亮独立LED;} }}}}/*配置并启动T0,ms-T0定时时间  */void ConfigTimer0(unsigned int ms){	unsigned long tmp;              //临时变量tmp = 11059200 / 12;              //每秒机器周期数tmp = (tmp * ms)/1000;            //计算传递实参的机器周期数tmp = 65536 - tmp ;               //设置定时器重载初值tmp = tmp +28;                    //初值补偿T0RH = (unsigned char)(tmp >> 8); //初值高低字节分离T0RL = (unsigned char)tmp;TMOD &= 0xF0;                     //清零定时器0控制位TMOD |= 0x01;                     //选择定时器0的工作模式TH0 = T0RH;                       //定时器0高低字节赋值TL0 = T0RL; ET0 = 1;                          //定时器0中断使能TR0 = 1;                          //使能定时器0}/*将一个无符号长整型的数字显示到数码管伤,num位待显示数字  */void ShowNumber(unsigned long num){signed char i;unsigned char buf[6]; //把长整形数,每个进制位上的数转化成十进制的数共6个存入数组for(i = 0; i <6; i++){buf[i] = num %10;num = num / 10;}for(i = 5;i >=1;i--) //从高位起,遇到0转换为0xff(不显示),遇到非零则退出循环{if(buf[i] == 0 )LedBuff[i] = 0xFF; // 作用:高位是零则不显示elsebreak;}for(; i >= 0; i--) //剩余低位都如实转换成数码管要显示的数{LedBuff[i] = LedChar[buf[i]];}}/* 按键动作函数,根据键码执行相应的操作,keycode 为按键键码 */void KeyAction(unsigned char keycode){if(keycode == 0x26)       //向上键,倒计时设定值每按一下加1{  if(CountDown < 9999)   //最大计数9999{CountDown++;ShowNumber(CountDown);}}else if (keycode == 0x28) //向下键 倒计时设定值递减{if(CountDown >1)         //最小计时1s{CountDown--;ShowNumber(CountDown);}}else if(keycode == 0x0D)  //回车键 ,启动倒计时{flagStart = 1;}else if(keycode == 0x1B)  //ESC 键 取消倒计时{enBuzz = 0;LedBuff[6] = 0xFF;flagStart = 0;CountDown = 0;ShowNumber(0);}}/*按键驱动函数,检测按键动作,调度相应动作函数,需要在主函数中调用    */	void KeyDriver(){unsigned char i,j;static unsigned char pdata backup[4][4] = {       //按键值备份,保存前一次的值{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};static unsigned long pdata TimeThr[4][4] = {  //快速输入执行的时间阈值{1000,1000,1000,1000},{1000,1000,1000,1000},{1000,1000,1000,1000},{1000,1000,1000,1000}};for(i = 0; i<4; i++)                  //循环扫描4*4的矩阵按键{for(j = 0; j<4; j++){if(backup[i][j] != KeySta[i][j]) //按键动作检查{	if(backup[i][j] != 0)                 //按键按下时执行{KeyAction(KeyCodeMap[i][j]);   //调用按键动作函数}backup[i][j] = KeySta[i][j];    //刷新前一次备份值}if(KeyDownTime[i][j] > 0)    //检测执行快速输入{if(KeyDownTime[i][j] >= TimeThr[i][j]){                                     //达到阈值时执行一次动作KeyAction(KeyCodeMap[i][j]);      //调用按键动作函数TimeThr[i][j] += 200;             //时间阈值增加200ms,以准备下一次执行}} else                     // 按键弹起时复位阈值时间{TimeThr[i][j] = 1000;  // 恢复1s的初始阈值时间}}}}/*按键扫描函数 ,需要在定时中断中调用  */void KeyScan(){unsigned char i;static unsigned char keyout = 0;static unsigned char keybuf[4][4] = {{0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF},};//将一行的4个按键值移入缓冲区keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4;//消抖后更新按键状态for(i = 0; i < 4; i++){if((keybuf[keyout][i] & 0x0F) == 0x00){//连续4次烧苗值为0,即4x4ms内都是按下状态时,可以认为按键已稳定的按下KeySta[keyout][i] = 0;KeyDownTime[keyout][i] += 4;//按下的持续时间累加}else if((keybuf[keyout][i] & 0x0F) == 0x0F){ //连续4次扫描值为1,即4x4ms内都是弹起状态时,可认为按键已稳定的弹起KeySta[keyout][i] = 1;KeyDownTime[keyout][i] = 0;//按下的持续时间清零}}keyout++;           //输出索引递增keyout &= 0x03;     //索引值逢4归0switch(keyout)     //根据索引,释放当前输出引脚,拉低下次的输出引脚{case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;default: break;}}/* 数码管与LED动态扫描函数,需要在定时中断中调用  */void LedScan(){static unsigned char i = 0; //动态扫描索引P0 = 0xFF;              //消除鬼影P1 = (P1 & 0xF8) | i;  // 0xF8 = 1111 1000,位选索引值赋值到P1口低3位P0 = LedBuff[i];      //缓冲区中索引位置的数据送到P0口if(i < 6)             //索引递增循环,遍历整个缓冲区i++;elsei = 0;}/* T0中断服务函数,完成数码管、按键扫描与定时 */void interruptTimer0() interrupt 1{static unsigned int tmr1s = 0; //1秒定时器TH0 = T0RH;TL0 = T0RL;if(enBuzz)BUZZ = ~BUZZ;    //蜂鸣器发声处理else               //驱动蜂鸣器发声BUZZ = 1;LedScan();         //关闭蜂鸣器KeyScan();         //LED 扫描显示if(flagStart)      //按键扫描{                  //倒计时启动时处理1秒定时tmr1s++;if(tmr1s >= 1000){tmr1s = 0;flag1s = 1;}}else{tmr1s = 0;    //倒计时未启动时1秒定时器始终归零}}

笔者的博文是单片机学习笔记:开发板和一些源代码都来自金沙滩工作室的产品,如果对代码中所有语句感兴趣,需要相关的资料(原理图,原代码)可以在该处下载,免费的:青岛金思特电子有限公司

代码主体是来自教材,不过一般笔者都会有些扩展。而且这些代码不是复制粘贴的,是笔者一个字一个字敲出来的。主要是笔者的C语言也是初学水平,哈哈哈。如果有小伙伴也用这套教材学习,有问题在相应的博文下可以留言交流下,毕竟初学者才知道初学者的难处。

前文提到了单片机的RAM区域的划分,编译一下程序。可以看到

这里data = 70.3就是片内RAM,xdata = 144是片外RAM。可以看到data不是一个正整数,是因为定义了三个位变量。因此是70.3

看源代码的数组关键字pdata

如果删除该关键字会如何,看下图

然后发现报错了,data的值变大了,xdata的值变小了。前文提到data的容量范围是128B,如果都要存入片内RAM需要加上关键字idata,看下图

可以看到data范围已经超过了128但是没有报错,是因为该数组用上了关键字idata,不过一般不用这个区域,因此本案函数是用pdata关键字。

然后分析一下程序的工作流程:

思维导图的地址  https://docs.qq.com/s/bktVAiM_bl91s3118HZurW

用的是腾讯文档免费的流程图,不过有图形限制因此分成了两章。

看下结果视频倒计时炸弹_哔哩哔哩_bilibili

可以看到功能都有都正常工作了,当然正常的倒计时炸弹是不会有ESC键的,启动按键肯定也不可能是按一下就触发,如果不小心碰到了那就完犊子了,因此Entel必然需要长按触发。程序需要一点改动。

如果对矩阵按键部分逻辑不清楚的可以看一下笔者之前关于矩阵按键的博文

初学51单片机矩阵按键与消抖_矩阵键盘消抖-CSDN博客

初学51单片机矩阵按键与消抖2_单片机矩阵键盘获取键值如何消抖-CSDN博客

初学51单片机之矩阵按键的应用末篇_矩阵按键能做些什么-CSDN博客

本案矩阵部分有一处变化但是主体和之前是一样的,数码管显示部分也包括在里面。因此不在详细分析。

接上述需要改动的有三处:

1:全局变量声明 bit LongPress = 0;//长按标志置0

2:是KeyDriver()函数里面的变化

void KeyDriver(){unsigned char i,j;static unsigned char pdata backup[4][4] = {       //按键值备份,保存前一次的值{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};static unsigned long pdata TimeThr[4][4] = {  //快速输入执行的时间阈值{1000,1000,1000,1000},{1000,1000,1000,1000},{1000,1000,1000,1000},{1000,1000,1000,1000}};for(i = 0; i<4; i++)                  //循环扫描4*4的矩阵按键{for(j = 0; j<4; j++){if(backup[i][j] != KeySta[i][j]) //按键动作检查{	if(backup[i][j] != 0)                 //按键按下时执行{KeyAction(KeyCodeMap[i][j]);   //调用按键动作函数}backup[i][j] = KeySta[i][j];    //刷新前一次备份值}if(KeyDownTime[i][j] > 0)    //检测执行快速输入{if(KeyDownTime[i][j] >= TimeThr[i][j]){                                     //达到阈值时执行一次动作KeyAction(KeyCodeMap[i][j]);      //调用按键动作函数TimeThr[i][j] += 200;             //时间阈值增加200ms,以准备下一次执行if(i == 3 && j == 2)   //注意entel键是3行2列,不是4行3列因为第1行一1列是0,0{LongPress = 1;}}} else                     // 按键弹起时复位阈值时间{TimeThr[i][j] = 1000;  // 恢复1s的初始阈值时间}}}}

这个位置使能长按标志置1。数组[3][2](4行3列)对应的是Entel键,注意不是[4][3]。因为数组是从[0][0]0行0列开始的,一开始笔者也是[4][3]花了笔者不少时间找问题,一度以为是不是逻辑哪里出错了,结果竟然是这个问题。对于初学者来说真是要注意的问题。逻辑认识上某行某列到程序上要减1。

3:KeyAction()函数里的变化

void KeyAction(unsigned char keycode){if(keycode == 0x26)       //向上键,倒计时设定值每按一下加1{  if(CountDown < 9999)   //最大计数9999{CountDown++;ShowNumber(CountDown);}}else if (keycode == 0x28) //向下键 倒计时设定值递减{if(CountDown >1)         //最小计时1s{CountDown--;ShowNumber(CountDown);}}else if(keycode == 0x0D)  //回车键 ,启动倒计时{if(LongPress){flagStart = 1;LongPress = 0;}}else if(keycode == 0x1B)  //ESC 键 取消倒计时{enBuzz = 0;LedBuff[6] = 0xFF;flagStart = 0;CountDown = 0;ShowNumber(0);}}

进入Entel键把长按标志作为判断条件,实现了长按Entel键开始倒计时。

看结果视频:长按触发倒计时_哔哩哔哩_bilibili

可以看到短按无法触发倒计时了,只能长按才能触发倒计时。

在现实使用时,都希望能够较准确的控制长按时间,如果某个按键造成的后果很严重,必然要让长按的时间足够的长,来体现使用者强烈的主观意志。防止后悔,出现勿碰,不小心的说辞。保护开发者与使用者的基本权益。

本案应该如何操作呢:

看下程序

如图如果开关已经准确的按下了,之后每4个中断执行一次KeyDownTime[keyout][i] += 4;语句,而该语句是每执行一次加4,因此可以认为是每次进入中断加1。

KeyDownTime的值在KeyDriver();函数中与预先设定的值1000判断,因此可知:当按住开关,再经过1000次中断(1000ms)后进入长按功能:看下进入函数的后续语句

if(KeyDownTime[i][j] > 0)    //检测执行快速输入{if(KeyDownTime[i][j] >= TimeThr[i][j]){                                     //达到阈值时执行一次动作KeyAction(KeyCodeMap[i][j]);      //调用按键动作函数TimeThr[i][j] += 200;             //时间阈值增加200ms,以准备下一次执行if(i == 3 && j == 2)   //注意entel键是3行2列,不是4行3列因为第1行一1列是0,0{LongPress = 1;}}} else                     // 按键弹起时复位阈值时间{TimeThr[i][j] = 1000;  // 恢复1s的初始阈值时间}

可以看到执行了1次按键调用函数,然后把比较值提高了200即1000变成1200。即下次再使能长按功能需要再经过200次中断。

因此这个函数可以这么设计:

设置一个变量cnt :让cnt >= 10,如此进入函数的时间是(200ms*10)2s加上之前的1s则长按该开关的时间判断就变成了3s,而且不影响其他开关的长按时间。

看代码:

if(KeyDownTime[i][j] > 0)    //检测执行快速输入{if(KeyDownTime[i][j] >= TimeThr[i][j]){                                     //达到阈值时执行一次动作KeyAction(KeyCodeMap[i][j]);      //调用按键动作函数TimeThr[i][j] += 200;             //时间阈值增加200ms,以准备下一次执行cnt++;if(cnt >= 10){cnt = 0;if(i == 3 && j == 2)   //注意entel键是3行2列,不是4行3列因为第1行一1列是0,0{LongPress = 1;}}																	   	}} else                     // 按键弹起时复位阈值时间{TimeThr[i][j] = 1000;  // 恢复1s的初始阈值时间}

结果视频就不上了,笔者这个已经试过了,没有问题的

至此本案倒计时的程序可以算基本完结了,但是以生活经验来说,对于生活中的电子产品,由于空间有限往往一个按键有两种不同的功能,短按的功能可能和长按的功能截然不同。以笔者的Switch游戏机来说:

短按电源键 :如果是黑屏,屏幕就变亮,如果是亮屏就变黑。

长按电源键:如果是黑屏,屏幕就变亮,如果是亮屏就进入关机选择界面。

对此,本案目前的程序需要些许改动才能实现长短键不同功能。对于开关动作可以这么设想,假设按住开关,短按功能你触不触发?如果你触发了长按功能怎么办?如果只使能长按功能,短按功能怎么办?毕竟长短按的功能不一样,如果是一样的可以按照本程序的逻辑来。

笔者前期的博文就有提到,一次开关动作包括两次状态变化:

1:从弹起状态进入按住状态

2:从按住状态回到弹起状态

开关的按键功能可以在状态1实现,也可以在状态2实现。之前的博文里笔者就演示了:按键开关按住加1和弹起加1的现象。因此长短按键的功能就可以分开实现了:

短按:开关动作状态2实现短按功能

长按:开关动作状态1实现长按功能

主要更改部分是KeyACtion()与void KeyDriver()函数

看代码

void KeyDriver(){unsigned char i,j,cnt;static unsigned char pdata backup[4][4] = {       //按键值备份,保存前一次的值{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};static unsigned long pdata TimeThr[4][4] = {  //快速输入执行的时间阈值{1000,1000,1000,1000},{1000,1000,1000,1000},{1000,1000,1000,1000},{1000,1000,1000,1000}};for(i = 0; i<4; i++)                  //循环扫描4*4的矩阵按键{for(j = 0; j<4; j++){if(backup[i][j] != KeySta[i][j]) //按键动作检查{	if(backup[i][j] == 0 && LongPress == 0) //前态如果是0那么现态是1,开关从按住弹起{if( Locksta == 0)KeyAction(KeyCodeMap[i][j]);   //调用按键动作函数Locksta = 0;}backup[i][j] = KeySta[i][j];    //刷新前一次备份值}if(KeyDownTime[i][j] > 0)    //检测执行快速输入{if(KeyDownTime[i][j] >= TimeThr[i][j]){   LongPress = 1;                 //长按标志置1KeyAction(KeyCodeMap[i][j]);      //调用按键动作函数TimeThr[i][j] += 200;             //时间阈值增加200ms,以准备下一次执行cnt++;if(cnt >= 10){cnt = 0;if(i == 3 && j == 2)   //注意entel键是3行2列,不是4行3列因为第1行一1列是0,0{EntelLongPress = 1;//entel长按标志Locksta = 1; //按键锁标志防止开关弹起进入短按函数}}																	   	}} else                     // 按键弹起时复位阈值时间{TimeThr[i][j] = 1000;  // 恢复1s的初始阈值时间}}}}
void KeyAction(unsigned char keycode){if(keycode == 0x26)       //向上键,倒计时设定值每按一下加1{  if(CountDown < 9999)   //最大计数9999{LongPress = 0;  //长按标志清零CountDown++;ShowNumber(CountDown);}}else if (keycode == 0x28) //向下键 倒计时设定值递减{if(CountDown >1)         //最小计时1s{LongPress = 0;CountDown--;ShowNumber(CountDown);}}else if(keycode == 0x0D)  //回车键 ,启动倒计时{if(EntelLongPress |  Locksta == 1){flagStart = 0;EntelLongPress = 0;LongPress = 0;}else{flagStart = 1;LongPress = 0;}}else if(keycode == 0x1B)  //ESC 键 取消倒计时{LongPress = 0;enBuzz = 0;LedBuff[6] = 0xFF;flagStart = 0;CountDown = 0;ShowNumber(0);}}

该程序与之前的相比引入了2个新的变量,原先的LongPress改成EntelLongPress 

新的变量是 LongPress LockSta, 这两个变量的作用是定义:一般长键状态,按键锁标志防止开关弹起进入短键函数

此函数把按键状态分为3种:

1:普通的短键触发功能

2:普通的长键触发功能

3:Entel键的加长长键触发功能

至此本篇定时炸弹长短键应用扩展结束,看下结果视频:长短键功能循环倒计时_哔哩哔哩_bilibili

可以看到Entel键的长短键切换,上下键的长短键切换正常,没有问题。

然后分享下最近关于中断方面的一些感受:51单片机是串行执行代码的,因此在视觉上的感受同时发生的事情也是1句1句执行的,只是速度很快罢了。如果真要说有什么好像与之并行的。那就是定时器,只要初值化设置好它就一直计时直到溢出停止。期间无论程序是在等待还是在执行什么都不会影响定时器计时。

程序执行如图:

     一般来说程序是在主函数与中断之间互相穿插执行的。对于本案来说只有定时器0中断,因此它是在主函数与定时器0中断之间循环执行的。一般主函数循环执行某个函数,会需求中断函数提供相应参数在主函数中执行。因此就需要设置的中断时间T>(t+t0)。

     中断的重载值一般都会在中断函数最前面执行,然后定时器就开始计时了。如果中断内部执行时间+主函数执行时间>  中断设置的间隔时间,那么就无法完整执行完一次主函数,又进入了中断函数,就可能让前一次中断传递的参数没有起作用。那么就会产生一些不好的结果。

如果笔者在中断函数里加一个时间延迟函数while(100--)近似1ms的延时函数,那么该程序就会无法正常工作,因为它一跳出中断,主函数没有执行,中断响应又到了。那么按键功能就无法正确执行了。

看视频:中断时间过长_哔哩哔哩_bilibili

可以看到主函数初始化0显示花的时间都变长了,并且按键不起作用。

至此博文到此结束。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/362267.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

昇思25天学习打卡营第1天|初学教程

文章目录 背景创建环境熟悉环境打卡记录学习总结展望未来 背景 参加了昇思的25天学习记录&#xff0c;这里给自己记录一下所学内容笔记。 创建环境 首先在平台注册账号&#xff0c;然后登录&#xff0c;按下图操作&#xff0c;创建环境即可 创建好环境后进入即可&#xff0…

基于elastic stack的docker-compose部署的ELK与LDAP集成

说明&#xff1a; ldap信息配置到es配置文件上&#xff0c;然后kibana读取es的配置信息 用户与角色的关系通过role_mapping.yml文件配置获取 角色与权限的关系通过elastic stack提供的DevTools或API进行维护 一、前置条件&#xff1a; 1.1 es已开启xpack&#xff08;已开启…

机器学习-数据预处理-聚类-回归-分类-单车数据集

机器学习-数据预处理-聚类-回归-分类-单车数据集 前言一、数据预处理1. 导入数据集2. 数据预处理3. 处理缺失值4. 生成特征用于后续进一步的分析 二、数据分布可视化1. 骑行时长分布2. 起始站和终点站分布可视化3. 高峰期与非高峰期骑行频次分布 三、聚类分析1. K-means聚类 四…

Android高级面试_2_IPC相关

Android 高级面试-3&#xff1a;语言相关 1、Java 相关 1.1 缓存相关 问题&#xff1a;LruCache 的原理&#xff1f; 问题&#xff1a;DiskLruCache 的原理&#xff1f; LruCache 用来实现基于内存的缓存&#xff0c;LRU 就是最近最少使用的意思&#xff0c;LruCache 基于L…

Vue3 + Element-plus + TS —— 动态表格自由编辑

前期回顾 《 穿越时空的代码、在回首&#xff1a;Evil.js两年后的全新解读 》-CSDN博客 Vue3 TS Element-Plus 封装Tree组件 《亲测可用》_ https://blog.csdn.net/m0_57904695/article/details/131664157?spm1001.2014.3001.5501 态表格 自由编辑 目录 ♻️ 效果图…

深圳技术大学oj B : 所有不含逆序对的组合数

Description 数组中可能包含重复的数字&#xff0c; 求由这些数字组成的不重复字符串&#xff0c; 且字符串中不包含逆序对。 Input 有若干组测试数据&#xff0c;&#xff08;1&#xff5e;20之间&#xff09; 每一组测试数据第一行输入一个整数 n (0 ≤ n ≤ 20)&#xff…

【仿真建模-anylogic】ViewArea解析

Author&#xff1a;赵志乾 Date&#xff1a;2024-06-27 Declaration&#xff1a;All Right Reserved&#xff01;&#xff01;&#xff01; 1. 应用场景 view area又叫视图区域&#xff0c;其作用是在presentation中标记一块区域&#xff0c;便于动画演示过程中快速切换可视区…

U盘提示格式化怎么搞定?本文有5种方法(内含教程)

U盘提示格式化是一种常见故障&#xff0c;即&#xff1a;当U盘插入电脑后&#xff0c;电脑上弹出对话框&#xff0c;提示该U盘需要格式化才能使用。 接触不良、文件系统损坏、热插拔、感染病毒、芯片损坏等原因都可能导致U盘出现此故障。这时点击“格式化”&#xff0c;大概率会…

Linux通过expect实现免交互

免交互 Here Document 用于将多行字符串直接传递给命令的方式&#xff0c;不需要人为交互命令界面&#xff0c;实现免交互 当使用Here Document操作文件时&#xff0c;需要借助一个文件结束符 EOF&#xff1a;文件结束符 示例 在脚本文件中写入以下内容 <<&#x…

Android 13 修改系统导航默认值

Android 13 原生系统上&#xff0c;设置-系统-手势-系统导航 菜单&#xff0c;可以修改系统导航方式。 手势导航&#xff1a; 三按钮导航&#xff1a; adb 获取当前导航方式&#xff0c;手势导航 是 2 &#xff0c;三按钮导航是 0 。 settings get secure navigation_mode 修…

《Mybatis-Plus》系列文章目录

什么是 MyBatis-Plus&#xff1f; Mybatis-Plus是一个在MyBatis基础上进行增强和扩展的开源Java持久层框架。 Mybatis-Plus&#xff08;简称MP&#xff09;旨在简化开发、提高效率&#xff0c;通过提供一系列便捷的功能和工具&#xff0c;大幅度减少开发人员编写重复代码的时…

RT-Thread Studio实现静态线程

1创建项目 &#xff08;STM32F03ZET6&#xff09; RT-Thread项目与RT-Thread Nano 项目区别 RT-Thread: 完整版&#xff1a;这是RT-Thread的完整形态&#xff0c;适用于资源较丰富的物联网设备。功能&#xff1a;它提供了全面的中间件组件&#xff0c;如文件系统、网络协议栈、…

Go语言之集合类型

个人网站&#xff1a; http://hardyfish.top/ 免费书籍分享&#xff1a; 资料链接&#xff1a;https://url81.ctfile.com/d/57345181-61545511-81795b?p3899 访问密码&#xff1a;3899 免费专栏分享&#xff1a; 资料链接&#xff1a;https://url81.ctfile.com/d/57345181-6…

swiper轮播 loop:true失效解决

数据是写死的时候&#xff0c;能够loop:true是有效的;数据是动态获取的loop:true就会失效。 方法一&#xff1a;在接收到数据后&#xff0c;使用 setTimeout(() > {this.getSwiper(); //生成swiper方法}, 0); 下面是我项目具体使用的参考例子&#xff1a; 方法二&#xff…

问题:ERROR:ldd outputLine:“libprotobuf.so.28 => not found“

想要在Ubuntu上面运行QT打包程序&#xff0c;出现一些问题报错&#xff1a; ERROR:ldd outputLine:"libprotobuf.so.28 > not found" 首先确定一下libprotobuf.so.28的位置&#xff1a; 然后建立一个软链接&#xff1a; ln -s /xxx/xxx/xx.so /usr/lib/xx.so #…

今天不看文章,明天变垃圾(明天收费)-----字节数据分析发展过程中所遭遇的挑战

字节数据分析发展过程中所遭遇的挑战 三个核心议题&#xff1a; 海量数据分析性能&#xff1a;会议指出Spark分析性能不足成为了一个显著问题&#xff0c;尤其是在需要毫秒级响应的业务场景中。实时导入与查询能力&#xff1a;目前Kylin只能以T1的形式提供分析服务&#xff0…

C# 信号量的使用

学习来源&#xff1a;《.net core 底层入门》 第六章第9节&#xff1a;信号量 案例&#xff1a;主线程负责添加数据&#xff0c;子线程负责获取数据 使用SemaphoreSlim&#xff08;轻信号量&#xff09;实现&#xff1a; using System; using System.Collections.Generic; us…

560.滑动窗口最大值

滑动窗口最大值 239. 滑动窗口最大值 - 力扣&#xff08;LeetCode&#xff09; 题目大意&#xff0c;返回每个窗口内的最大值。 思路-优先队列 优先队列&#xff08;堆&#xff09;&#xff0c;其中的大根堆可以实时维护一系列元素中的最大值。 每当我们向右移动窗口时&#…

vue3+ts <script setup lang=“ts“> element-plus的el-date-picker设置默认日期

效果图&#xff08;单个日期&#xff09;&#xff1a; utils.ts&#xff1a; /*** 格式化时间戳* param {number} timestamp 时间戳* param {string} format 格式* returns {string}*/ export const formatTimeStamp (timestamp: number, format: string) > {if (!timesta…

深入解析Java和Go语言中String与byte数组的转换原理

1.Java String与byte[]互相转换存在的问题 java中&#xff0c;按照byte[] 》string 》byte[]的流程转换后&#xff0c;byte数据与最初的byte不一致。 多说无益&#xff0c;上代码&#xff0c;本地macos机器执行&#xff0c;统一使用的UTF-8编码。 import java.nio.charset.S…