初学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.mzph.cn/pingmian/36353.shtml

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

相关文章

定位问题6.27 petal数据接口问题

petal接口响应结果 响应结果为空的数据&#xff0c;而我们需要的是正确的响应结果。 排查问题 确认接口是否正确 以下是爬虫的配置文件内容&#xff0c;我查看了PETAL_URL的接口&#xff0c;并询问接口开发人员&#xff0c;得知接口地址并未改变 确认接口请求体是否正确 我使…

记一次对ouija渗透测试c语言逆向学习

概要 初始知识 web应用枚举 二进制逆向 文件枚举 堆栈溢出 学到知识 hash长度攻击 任意文件读取 二进制逆向分析 信息收集 端口扫描 nmap --min-rate 1000 -p- 10.129.30.104 发现22&#xff0c;80&#xff0c;3000端口 网站探测 目录枚举 feroxbuster -u http://10.1…

“数字政协”平台如何提高政协工作效率?正宇软件助力建设!

随着信息技术的飞速发展&#xff0c;数字化已成为推动各行各业转型升级的重要力量。在政协工作中&#xff0c;数字政协平台的建设与运用&#xff0c;正成为提高政协工作效率、促进民主协商的重要手段。本文将从数字政协平台的功能特点、优势分析以及实践应用等方面&#xff0c;…

何用Vue3和Plotly.js打造交互式3D图

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 利用 Plotly.js 创建交互式动画图表 应用场景 本代码适用于需要创建交互式动画图表的数据可视化项目。例如&#xff0c;可以用来展示时间序列数据或比较不同函数的行为。 基本功能 该代码使用 Plotly.js 库…

架构师篇-5、架构语言-ArchiMate

内容摘要&#xff1a; TOGAF内容元模型TOGAF架构语言ArchiMate3ArchiMate实践案例分享 TOGAF内容框架【核心内容元模型】 作为一个通用且开放式的标准&#xff0c;TOGAF需要采用一种非常灵活的方式来对其内容元模型进行定义&#xff0c;从而使得不同的企业可以根据自身需要对…

头歌——机器学习——决策树案例

第1关&#xff1a;基于决策树模型的应用案例 任务描述 本关任务&#xff1a;使用决策树算法完成成人收入预测。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;1.数据特征处理&#xff0c;2.使用决策树算法完成成人收入预测。 数据处理及特征工程 本次任务…

2024最新特种设备(锅炉作业)题库分享。

1.锅炉蒸发量大小是由(  )决定的。 A.压力的高低 B.受压元件多少 C.受热面积大小 答案:C 2.哪项不是自然循环的故障?&#xff08; &#xff09; A.停滞 B.倒流 C.下降管带汽 D.上升管带汽 答案:D 3.水冷壁被现代大型锅炉广泛采用的是(  )。 A.光管水冷壁 B.膜…

【C++】继承(详解)

前言&#xff1a;今天我们正式的步入C进阶内容的学习了&#xff0c;当然了既然是进阶意味着学习难度的不断提升&#xff0c;各位一起努力呐。 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏分类:高质量&#xff23;学习 &#x1f448; &#…

RabbitMQ安装部署

简介 RabbitMQ一款知名的开源消息队列系统&#xff0c;为企业提供消息的发布、订阅、点对点传输等消息服务。 RabbitMQ在企业开发中十分常见&#xff0c;课程为大家演示快速搭建RabbitMQ环境。 安装 rabbitmq在yum仓库中的版本比较老&#xff0c;所以我们需要手动构建yum仓库…

# Kafka_深入探秘者(8):kafka 高级应用

Kafka_深入探秘者&#xff08;8&#xff09;&#xff1a;kafka 高级应用 一、kafka 消费组管理 1、kafka 命令行工具 参考官网: http://kafka.apache.org/22/documentation.html 2、kafka 消费组管理&#xff1a;查看消费组 # 切换到 kafka 安装目录 cd /usr/local/kafka/…

leetCode.91. 解码方法

leetCode.91. 解码方法 题目思路 题解 class Solution { public:int numDecodings(string s) {int n s.size();// dp 中f[0]一般不做使用&#xff0c;只是存一个初值1&#xff0c;表示默认由一种方案s s;vector<int> f( n 1 );f[0] 1;for ( int i 1; i < n;…

【数学】100332. 包含所有 1 的最小矩形面积 II

本文涉及知识点 数学 LeetCode100332. 包含所有 1 的最小矩形面积 II 给你一个二维 二进制 数组 grid。你需要找到 3 个 不重叠、面积 非零 、边在水平方向和竖直方向上的矩形&#xff0c;并且满足 grid 中所有的 1 都在这些矩形的内部。 返回这些矩形面积之和的 最小 可能值…

vant4的组件气泡弹出框van-popover,在列表中遍历后点击一个全部/显示隐藏,解决办法

环境&#xff1a;vue3 vant-ui4 <div v-for"(info, index) in item.infoListVOs" :key"index"><van-popoverv-model:show"showPopover":actions"actions"overlayplacement"bottom-end"select"onSelect(info…

软件工程全套学习培训资料,实际优质项目编制及各类建设方案,信息安全,运维资料

目的&#xff1a;规范系统开发流程&#xff0c;提高系统开发效率。 立项申请需求分析方案设计方案评审开发调整测试阶段系统培训试运行测试验收投入使用 所有文档过去进主页获取。 获取方式&#xff1a;本文末个人名片直接获取。 软件资料清单列表部分文档清单&#xff1a;工作…

AGI 远不止 ChatGPT!一文入门 AGI 通识及应用开发_通向agi之路网站使用什么开发的网站

AI 大语言模型进入爆发阶段 2022 年 12 月 ChatGPT 突然爆火&#xff0c;原因是其表现出来的智能化已经远远突破了我们的常规认知。虽然其呈现在使用者面前仅仅只是一个简单的对话问答形式&#xff0c;但是它的内容化水平非常强大&#xff0c;甚至在某些方面已经超过人类了&am…

程序的调试技术,设置断点

断点&#xff08;break point&#xff09;是指在代码中指定位置&#xff0c;当程序运行到此位置时变中断下来&#xff0c;并让开发者可查看此时各变量的值。因断点中断的程序并没有结束&#xff0c;可以选择继续执行。 在程序的调试过程中&#xff0c;设置断点是一个很有用的分…

可用的搜索引擎

presearchhttps://presearch.com/yandexhttps://ya.ru

书归正传,说说颍川士族

我的非遗项目是《颍川士族传说》&#xff0c;此前做的视频只是触及了边缘&#xff0c;属于气氛的营造&#xff0c;今后就正式转入主题了。 首先说说什么是士族&#xff0c;它有两个同义词&#xff1a;世族和势族。“世”是一代又一代的意思&#xff0c;“势”是权势&#xff0…

python中类的继承详解

面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力&#xff1a;它可以使用现有类的所有功能&#xff0c;并在无需重新编写原来的类的情况下对这些功能进行扩展 &#xff08;1&#xff09;在类的继承中&#xff0c;存在父类跟子类&#xff0c;子类可以继…

【项目实训】数据库内容丰富

经团队讨论&#xff0c;对前端页面展示数据进行了增加&#xff0c;于是相应的修改数据库 经团队成员使用大模型对各公司面试经验中问题的总结优化&#xff0c;我们打算将大模型的回答存储到数据库中&#xff0c;以显示在前端页面 于是在数据库中存储大模型的回答&#xff1a;…