基于51单片机和8X8点阵屏、矩阵按键的匹对消除类小游戏
目录
- 系列文章目录
- 前言
- 一、效果展示
- 二、原理分析
- 三、各模块代码
- 1、8X8点阵屏
- 2、矩阵按键
- 3、定时器0
- 4、定时器1
- 四、主函数
- 总结
系列文章目录
前言
用的是普中A2开发板,用到板上的8X8LED点阵屏和矩阵按键。
【单片机】STC89C52RC
【频率】12T@11.0592MHz
效果查看/操作演示:B站搜索“甘腾胜”或“gantengsheng”查看。
源代码下载:B站对应视频的简介有工程文件下载链接。
一、效果展示
二、原理分析
1、方块类型
总共有四种方块类型,分别是1个点、2个点、3个点、4个点。
开始游戏后,6个方块都是显示4个点,按确认键后,会显示是1个点、2个点还是3个点,对两个方块按了确认键“翻开”后,检查两个方块是否是相同的类型,如果是,则消除,不再显示,如果不是,则这两个方块恢复显示4个点。
2、方块的选择
通过闪烁来显示玩家选择的方块。
用一个 unsigned char 变量 Select 来保存闪烁的位置,0~2:第一行,3~5:第二行。
用6个字节组成的数组来记录这6个方块是否显示(消除后就不再显示了),当全部消除后游戏结束。
3、游戏用时
用一个 unsigned char 或 unsigned int 变量来记录游戏所用的时间,通过定时器来进行计时。
4、字母和数字的滚动显示
提前将字母和数字的字模存储到数组中(数据保存到单片机的Flash中),将数组的首地址和偏移量传给函数,可以轻松实现滚动显示。
5、矩阵按键
利用定时器每隔20ms检测一次按键,跟上一次检测的结果对比,可判断是按下瞬间、长按还是松手瞬间。本代码用的是松手的键码,因为如果硬件没问题的话,是一定能检测出松手的键码的,不管完成一次while(1)循环需要多长时间。
6、方块类型的随机排列
总共有三对方块类型,用到两个数组。
TypeForPick[]={0,1,2,0,1,2};
Type[6];
举例:
先利用rand()函数产生一个0~5的随机数,假设是2,则将TypeForPick[2]赋值给Type[0],然后将数组TypeForPick中TypeForPick[3]之后的数据往前移动一个索引,即TypeForPick[3]赋值给TypeForPick[2],TypeForPick[4]赋值给TypeForPick[3],TypeForPick[5]赋值给TypeForPick[4],亦即是变成TypeForPick[]={0,1,0,1,2,2},第6个数据TypeForPick[5]没有用了,之后用到前5个数据:0,1,0,1,2,。
第二次,利用rand()函数产生一个0~4的随机数,假设是1,则将TypeForPick[1]赋值给Type[1],然后将数组TypeForPick中TypeForPick[1]之后的数据往前移动一个索引,即变成TypeForPick[]={0,0,1,2,2,2},第5、6个数据没有用了,之后用到前4个数据:0,0,1,2,。
以此类推。
这些过程可以通过嵌套for循环来实现。
7、真随机的实现
如果没有设置随机数的种子,每次上电后产生的是一样的排列,这个是伪随机,本代码老夫在每次获取非0键码后都用定时器0的低八位做种子,这样用rand()函数产生的随机数就跟按下按键的时刻有关,产生的是真随机数。
三、各模块代码
1、8X8点阵屏
h文件
#ifndef __MATRIXLED__
#define __MATRIXLED__extern unsigned char DisplayBuffer[];
void MatrixLED_Clear(void);
void MatrixLED_Init(void);
void MatrixLED_MoveLeft(unsigned char *Array,unsigned int Offset);
void MatrixLED_MoveUp(unsigned char *Array,unsigned int Offset);
void MatrixLED_Tick(void);
void MatrixLED_DrawPoint(unsigned char X,unsigned char Y);
void MatrixLED_ClearPoint(unsigned char X,unsigned char Y);
unsigned char MatrixLED_GetPoint(unsigned char X,unsigned char Y);
void MatrixLED_DrawBlock(unsigned char X,unsigned char Y,unsigned char Type);
void MatrixLED_ClearBlock(unsigned char X,unsigned char Y);#endif
c文件
#include <REGX52.H>/*引脚定义*/sbit _74HC595_DS=P3^4; //串行数据输入
sbit _74HC595_STCP=P3^5; //储存寄存器时钟输入,上升沿有效
sbit _74HC595_SHCP=P3^6; //移位寄存器时钟输入,上升沿有效/*
每一个B对应一个灯。缓存数组DisplayBuffer的8个字节分别对应这8列,高位在下
B0 B0 B0 B0 B0 B0 B0 B0
B1 B1 B1 B1 B1 B1 B1 B1
B2 B2 B2 B2 B2 B2 B2 B2
B3 B3 B3 B3 B3 B3 B3 B3
B4 B4 B4 B4 B4 B4 B4 B4
B5 B5 B5 B5 B5 B5 B5 B5
B6 B6 B6 B6 B6 B6 B6 B6
B7 B7 B7 B7 B7 B7 B7 B7
*///想要改变显示内容,改变数组DisplayBuffer的数据就行了,由定时器自动扫描
unsigned char DisplayBuffer[8];/*函数定义*//*** 函 数:LED点阵屏清空显示* 参 数:无* 返 回 值:无* 说 明:直接更改缓存数组的数据就行了,由定时器自动扫描显示*/
void MatrixLED_Clear(void)
{unsigned char i;for(i=0;i<8;i++){DisplayBuffer[i]=0;}
}/*** 函 数:MatrixLED初始化(即74HC595初始化)* 参 数:无* 返 回 值:无*/
void MatrixLED_Init(void)
{_74HC595_SHCP=0; //移位寄存器时钟信号初始化_74HC595_STCP=0; //储存寄存器时钟信号初始化MatrixLED_Clear(); //点阵屏清屏
}/*** 函 数:74HC595写入字节* 参 数:Byte 要写入的字节* 返 回 值:无*/
void _74HC595_WriteByte(unsigned char Byte)
{unsigned char i;for(i=0;i<8;i++) //循环8次{_74HC595_DS=Byte&(0x01<<i); //低位先发_74HC595_SHCP=1; //SHCP上升沿时,DS的数据写入移位寄存器_74HC595_SHCP=0;}_74HC595_STCP=1; //STCP上升沿时,数据从移位寄存器转存到储存寄存器_74HC595_STCP=0;
}/*** 函 数:8X8LED点阵屏显示数组内容* 参 数:Array 传递过来的数组的首地址(即指针),数组名就是数组的首地址* 返 回 值:Offset 偏移量,向左偏移Offset个像素* 说 明:要求逐列式取模,高位在下*/
void MatrixLED_MoveLeft(unsigned char *Array,unsigned int Offset)
{unsigned char i;Array+=Offset;for(i=0;i<8;i++){DisplayBuffer[i]=*Array;Array++; //地址自增}
}/*** 函 数:8X8LED点阵屏显示数组内容* 参 数:Array 传递过来的数组的首地址(即指针),数组名就是数组的首地址* 返 回 值:Offset 显示数组数据的偏移量,向上偏移Offset个像素* 说 明:要求逐列式取模,高位在下*/
void MatrixLED_MoveUp(unsigned char *Array,unsigned int Offset)
{unsigned char i,m,n;m=Offset/8;n=Offset%8;Array+=m*8;for(i=0;i<8;i++){DisplayBuffer[i]=(*Array>>n)|(*(Array+8)<<(8-n));Array++;}
}/*** 函 数:LED点阵屏驱动函数,中断中调用* 参 数:无* 返 回 值:无*/
void MatrixLED_Tick(void)
{static unsigned char i=0; //定义静态变量P0=0xFF; //消影_74HC595_WriteByte(DisplayBuffer[i]); //将数据写入到74HC595中锁存P0=~(0x80>>i); //位选,低电平选中i++; //下次进中断后扫描下一列i%=8; //显示完第八列后,又从第一列开始显示
}/*** 函 数:MatrixLED在指定位置画一个点* 参 数:X 指定点的横坐标,范围:0~7* 参 数:Y 指定点的纵坐标,范围:0~7* 返 回 值:无* 说 明:左上角的LED为原点(0,0),向右为X轴正方向,向下为Y轴正方向*/
void MatrixLED_DrawPoint(unsigned char X,unsigned char Y)
{if(X>=0 && X<=7 && Y>=0 && Y<=7){ DisplayBuffer[X] |= 0x01<<Y; }
}/*** 函 数:MatrixLED在指定位置清除一个点* 参 数:X 指定点的横坐标,范围:0~7* 参 数:Y 指定点的纵坐标,范围:0~7* 返 回 值:无* 说 明:左上角的LED为原点(0,0),向右为X轴正方向,向下为Y轴正方向*/
void MatrixLED_ClearPoint(unsigned char X,unsigned char Y)
{if(X>=0 && X<=7 && Y>=0 && Y<=7){ DisplayBuffer[X] &= ~(0x01<<Y); }
}/*** 函 数:MatrixLED获取其中一个LED的状态* 参 数:X 指定点的横坐标,范围:0~7* 参 数:Y 指定点的纵坐标,范围:0~7* 返 回 值:LED的亮灭状态,1:亮,0:灭,2:说明超出了屏幕范围* 说 明:左上角的LED为原点(0,0),向右为X轴正方向,向下为Y轴正方向*/
unsigned char MatrixLED_GetPoint(unsigned char X,unsigned char Y)
{if(X>=0 && X<=7 && Y>=0 && Y<=7){if( DisplayBuffer[X] & (0x01<<Y) ) {return 1;}else {return 0;}}else {return 2;}
}/*** 函 数:MatrixLED在指定位置显示一个指定类型的方块,方块大小:2X2* 参 数:X 方块位置,范围:0~2(0:1、2列, 1:4、5列, 2:7、8列)* 参 数:Y 方块位置,范围:0~6(0:1、2行, 1:2、3行, ..., 6:7、8行)* 参 数:Type 要显示方块的类型,0:全部不亮,1:方块的左下角的LED点亮,2:方块的左边两个LED点亮,3:左边两个LED和右下角的LED点亮,4:全部4个LED点亮* 返 回 值:无*/
void MatrixLED_DrawBlock(unsigned char X,unsigned char Y,unsigned char Type)
{if(X==0){switch(Type){case 0: DisplayBuffer[0] |= 0x02<<Y; break;case 1: DisplayBuffer[0] |= 0x03<<Y; break;case 2: DisplayBuffer[0] |= 0x03<<Y; DisplayBuffer[1] |= 0x02<<Y; break;case 3: DisplayBuffer[0] |= 0x03<<Y; DisplayBuffer[1] |= 0x03<<Y; break;default:break;}}if(X==1){switch(Type){case 0: DisplayBuffer[3] |= 0x02<<Y; break;case 1: DisplayBuffer[3] |= 0x03<<Y; break;case 2: DisplayBuffer[3] |= 0x03<<Y; DisplayBuffer[4] |= 0x02<<Y; break;case 3: DisplayBuffer[3] |= 0x03<<Y; DisplayBuffer[4] |= 0x03<<Y; break;default:break;}}if(X==2){switch(Type){case 0: DisplayBuffer[6] |= 0x02<<Y; break;case 1: DisplayBuffer[6] |= 0x03<<Y; break;case 2: DisplayBuffer[6] |= 0x03<<Y; DisplayBuffer[7] |= 0x02<<Y; break;case 3: DisplayBuffer[6] |= 0x03<<Y; DisplayBuffer[7] |= 0x03<<Y; break;default:break;}}
}/*** 函 数:MatrixLED在指定位置清除一个方块,方块大小:2X2* 参 数:X 方块位置,范围:0~2(0:1、2列, 1:4、5列, 2:7、8列)* 参 数:Y 方块位置,范围:0~6(0:1、2行, 1:2、3行, ..., 6:7、8行)* 返 回 值:无*/
void MatrixLED_ClearBlock(unsigned char X,unsigned char Y)
{if(X==0){DisplayBuffer[0] &= ~(0x03<<Y);DisplayBuffer[1] &= ~(0x03<<Y);}if(X==1){DisplayBuffer[3] &= ~(0x03<<Y);DisplayBuffer[4] &= ~(0x03<<Y);}if(X==2){DisplayBuffer[6] &= ~(0x03<<Y);DisplayBuffer[7] &= ~(0x03<<Y);}
}
2、矩阵按键
h文件
#ifndef __MATRIXKEYSCAN_H__
#define __MATRIXKEYSCAN_H__unsigned char MatrixKey(void);
void MatrixKey_Tick(void);#endif
c文件
#include <REGX52.H>#define Matrix_Port P1 //矩阵按键接口unsigned char KeyNumber;/*** 函 数:获取矩阵按键键码* 参 数:无* 返 回 值:按下按键的键码,范围:0~48,0表示无按键按下* 说 明:在下一次检测按键之前,第二次获取键码一定会返回0*/
unsigned char MatrixKey(void)
{unsigned char KeyTemp=0;KeyTemp=KeyNumber;KeyNumber=0;return KeyTemp;
}/*** 函 数:检测当前按下的按键,无消抖及松手检测* 参 数:无* 返 回 值:按下按键的键值,范围:0~16,无按键按下时返回值为0*/
unsigned char Key_GetState()
{unsigned char KeyValue=0;unsigned char i=0;Matrix_Port=0x0F; //给所有行赋值0,列全为1i=2;while(i--); //适当延时,延时5usif(Matrix_Port!=0x0F){Matrix_Port=0x0F; //测试列i=2;while(i--);switch(Matrix_Port) //所有行拉低,检测哪一列按下{case 0x07:KeyValue=1;break;case 0x0B:KeyValue=2;break;case 0x0D:KeyValue=3;break;case 0x0E:KeyValue=4;break;default:break;}Matrix_Port=0xF0; //测试行i=2;while(i--);switch(Matrix_Port) //所有列拉低,检测哪一行按下{case 0x70:KeyValue=KeyValue;break;case 0xB0:KeyValue=KeyValue+4;break;case 0xD0:KeyValue=KeyValue+8;break;case 0xE0:KeyValue=KeyValue+12;break;default:break;}}else{KeyValue=0;}return KeyValue;
}/*** 函 数:矩阵按键驱动函数,在中断中调用* 参 数:无* 返 回 值:无*/
void MatrixKey_Tick(void)
{static unsigned char NowState,LastState;static unsigned int KeyCount;LastState=NowState; //更新上一次的键值NowState=Key_GetState(); //获取当前的键值//如果上个时间点按键未按下,这个时间点按键按下,则是按下瞬间if(LastState==0){switch(NowState){case 1:KeyNumber=1;break;case 2:KeyNumber=2;break;case 3:KeyNumber=3;break;case 4:KeyNumber=4;break;case 5:KeyNumber=5;break;case 6:KeyNumber=6;break;case 7:KeyNumber=7;break;case 8:KeyNumber=8;break;case 9:KeyNumber=9;break;case 10:KeyNumber=10;break;case 11:KeyNumber=11;break;case 12:KeyNumber=12;break;case 13:KeyNumber=13;break;case 14:KeyNumber=14;break;case 15:KeyNumber=15;break;case 16:KeyNumber=16;break;default:break;}}//如果上个时间点按键按下,这个时间点按键还是按下,则是长按if(LastState && NowState){KeyCount++;if(KeyCount%50==0) //定时器中断函数中每隔20ms检测一次按键{ //长按后每隔1s返回一次长按的键码if (LastState== 1 && NowState== 1){KeyNumber=17;}else if(LastState== 2 && NowState== 2){KeyNumber=18;}else if(LastState== 3 && NowState== 3){KeyNumber=19;}else if(LastState== 4 && NowState== 4){KeyNumber=20;}else if(LastState== 5 && NowState== 5){KeyNumber=21;}else if(LastState== 6 && NowState== 6){KeyNumber=22;}else if(LastState== 7 && NowState== 7){KeyNumber=23;}else if(LastState== 8 && NowState== 8){KeyNumber=24;}else if(LastState== 9 && NowState== 9){KeyNumber=25;}else if(LastState==10 && NowState==10){KeyNumber=26;}else if(LastState==11 && NowState==11){KeyNumber=27;}else if(LastState==12 && NowState==12){KeyNumber=28;}else if(LastState==13 && NowState==13){KeyNumber=29;}else if(LastState==14 && NowState==14){KeyNumber=30;}else if(LastState==15 && NowState==15){KeyNumber=31;}else if(LastState==16 && NowState==16){KeyNumber=32;}}}else{KeyCount=0;}//如果上个时间点按键按下,这个时间点按键未按下,则是松手瞬间if(NowState==0){switch(LastState){case 1:KeyNumber=33;break;case 2:KeyNumber=34;break;case 3:KeyNumber=35;break;case 4:KeyNumber=36;break;case 5:KeyNumber=37;break;case 6:KeyNumber=38;break;case 7:KeyNumber=39;break;case 8:KeyNumber=40;break;case 9:KeyNumber=41;break;case 10:KeyNumber=42;break;case 11:KeyNumber=43;break;case 12:KeyNumber=44;break;case 13:KeyNumber=45;break;case 14:KeyNumber=46;break;case 15:KeyNumber=47;break;case 16:KeyNumber=48;break;default:break;}}}
3、定时器0
h文件
#ifndef __TIMER0_H__
#define __TIMER0_H__void Timer0_Init(void);#endif
c文件
#include <REGX52.H>/*** 函 数:定时器0初始化* 参 数:无* 返 回 值:无*/
void Timer0_Init(void)
{ TMOD&=0xF0; //设置定时器模式(高四位不变,低四位清零)TMOD|=0x01; //设置定时器模式(通过低四位设为16位不自动重装)TL0=0x66; //设置定时初值,定时1ms,12T@11.0592MHzTH0=0xFC; //设置定时初值,定时1ms,12T@11.0592MHzTF0=0; //清除TF0标志TR0=1; //定时器0开始计时ET0=1; //打开定时器0中断允许EA=1; //打开总中断PT0=0; //当PT0=0时,定时器0为低优先级,当PT0=1时,定时器0为高优先级
}/*定时器中断函数模板
void Timer0_Routine() interrupt 1 //定时器0中断函数
{static unsigned int T0Count; //定义静态变量TL0=0x66; //设置定时初值,定时1ms,12T@11.0592MHzTH0=0xFC; //设置定时初值,定时1ms,12T@11.0592MHzT0Count++;if(T0Count>=1000){T0Count=0;}
}
*/
4、定时器1
h文件
#ifndef __TIMER1_H__
#define __TIMER1_H__void Timer1_Init(void);#endif
c文件
#include <REGX52.H>/*** 函 数:定时器1初始化* 参 数:无* 返 回 值:无*/
void Timer1_Init(void)
{TMOD&=0x0F; //设置定时器模式(低四位不变,高四位清零)TMOD|=0x10; //设置定时器模式(通过高四位设为16位不自动重装的模式)TL1=0x66; //设置定时初值,定时1ms,12T@11.0592MHzTH1=0xFC; //设置定时初值,定时1ms,12T@11.0592MHzTF1=0; //清除TF1标志TR1=1; //定时器1开始计时ET1=1; //打开定时器1中断允许EA=1; //打开总中断PT1=1; //当PT1=0时,定时器1为低优先级,当PT1=1时,定时器1为高优先级
}/*定时器中断函数模板
void Timer1_Routine() interrupt 3 //定时器1中断函数
{static unsigned int T1Count; //定义静态变量TL1=0x66; //设置定时初值,定时1ms,12T@11.0592MHzTH1=0xFC; //设置定时初值,定时1ms,12T@11.0592MHzT1Count++;if(T1Count>=1000){T1Count=0;}
}
*/
四、主函数
main.c
/*by甘腾胜@20250503
【效果查看/操作演示】B站搜索“甘腾胜”或“gantengsheng”查看
【单片机】STC89C52RC
【频率】12T@11.0592MHz
【外设】8X8LED点阵屏、矩阵按键
【简单的原理分析】https://blog.csdn.net/gantengsheng/article/details/143581157
【注意】点阵屏旁边的跳线帽要接三个排针的左边两个
【操作说明】
(1)显示游戏英文名的界面按任意按键进入游戏
(2)S10、S14、S13、S15四个按键分别是上、下、左、右
(3)按下S16(确认键)后,方块会显示是什么类型(1~3个点)
(4)游戏结束全屏闪烁界面按S16进入显示游戏用时的英文的界面
(5)显示游戏用时的英文的界面可按S16跳过
(6)循环显示游戏用时的界面可按S12返回重新开始游戏
*/#include <REGX52.H> //51单片机头文件
#include "MatrixLED.h" //8X8点阵屏
#include "MatrixKeyScan.h" //矩阵按键
#include "Timer0.h" //定时器0
#include "Timer1.h" //定时器1
#include <STDLIB.H> //随机函数unsigned char KeyNum; //存储获取的键码
unsigned char Mode; //游戏模式,0:循环滚动显示游戏英文名,1:游戏中,2:游戏结束全屏闪烁,3:滚动显示游戏用时的英文,4:循环滚动显示游戏用时
bit OnceFlag; //各模式中切换为其他模式前只执行一次的标志,用于模式的初始化,功能类似于while(1)前面那部分,1:执行,0:不执行
unsigned char Offset; //偏移量,用来控制英文字母或数字向左滚动显示
bit RollFlag; //字母滚动一个像素的标志,1:滚动,0:不滚动
bit GameOverFlag; //游戏结束的标志,1:游戏结束,0:游戏未结束
bit FlashFlag; //闪烁的标志,1:不显示,0:显示
unsigned char Select; //方块选择变量,范围:0~5
unsigned char T0Count; //定时器0计数全局变量
unsigned char idata TypeForPick[]={0,1,2,0,1,2}; //六个方块(三对)的类型,用来将这三对方块随机打乱顺序保存到数组Type中
unsigned char idata Type[]={0,1,1,2,0,2}; //六个方块的类型(idata:变量保存在片内间接访问区)
unsigned char idata IsShow[]={1,1,1,1,1,1}; //六个方块是否显示的标志,1:显示,0:不显示
unsigned char ConfirmFlag; //按下确认键的标志,0:未确认,1:第一次确认,2:第二次确认
unsigned char FirstConfirm=6; //第一次确认的方块,范围:0~5,初始值为0~5以外的任意一个数字,并要求FirstConfirm和SecondConfirm的初始值不一样
unsigned char SecondConfirm=7; //第二次确认的方块,范围:0~5,初始值为0~5以外的任意一个数字,并要求FirstConfirm和SecondConfirm的初始值不一样
unsigned int UsedTime; //全部配对所用的时间,单位:100ms,范围:0~6553.5s
bit NoFlashFlag; //翻开两个方块后暂不闪烁的标志,1:不闪烁,0:闪烁unsigned char idata UsedTimeShow[]={ //游戏用时,用于游戏结束后循环滚动显示
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 无显示
0x00,0x00,0x00,0x00,0x00,0x00, // 用时的十位
0x00,0x00,0x00,0x00,0x00,0x00, // 用时的个位
0x00,0x00,0x60,0x60,0x00,0x00, // 用时的小数点
0x00,0x00,0x00,0x00,0x00,0x00, // 用时的十分位
0x00,0x48,0x54,0x54,0x54,0x20, // “秒”的英文缩写:小写的“s”
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 无显示
};//取模要求:阴码(亮点为1),纵向取模,高位在下
//我分享的工程文件夹中有6X8像素的ASCII字符字模
unsigned char code Table1[]={ //游戏名称的英文:<<MAKE PAIRS>>
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 无显示
0x00,0x08,0x14,0x22,0x49,0x14,0x22,0x41, // << 宽8高8(自定义书名号:两个小于号)
0x00,0x7F,0x02,0x0C,0x02,0x7F, // M
0x00,0x7C,0x12,0x11,0x12,0x7C, // A
0x00,0x7F,0x08,0x14,0x22,0x41, // K
0x00,0x7F,0x49,0x49,0x49,0x41, // E
0x00,0x00,0x00,0x00,0x00,0x00, //
0x00,0x7F,0x09,0x09,0x09,0x06, // P
0x00,0x7C,0x12,0x11,0x12,0x7C, // A
0x00,0x00,0x41,0x7F,0x41,0x00, // I
0x00,0x7F,0x09,0x19,0x29,0x46, // R
0x00,0x46,0x49,0x49,0x49,0x31, // S
0x00,0x41,0x22,0x14,0x49,0x22,0x14,0x08, // >>(自定义书名号:两个大于号)
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 无显示
};
unsigned char code Table2[]={ //“所用时间”的英文:“USED TIME”,宽6高8
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //无显示
0x00,0x3F,0x40,0x40,0x40,0x3F, // U
0x00,0x46,0x49,0x49,0x49,0x31, // S
0x00,0x7F,0x49,0x49,0x49,0x41, // E
0x00,0x7F,0x41,0x41,0x22,0x1C, // D
0x00,0x00,0x00,0x00,0x00,0x00, //
0x00,0x01,0x01,0x7F,0x01,0x01, // T
0x00,0x00,0x41,0x7F,0x41,0x00, // I
0x00,0x7F,0x02,0x0C,0x02,0x7F, // M
0x00,0x7F,0x49,0x49,0x49,0x41, // E
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //无显示
};
unsigned char code Table3[]={ //游戏得分的字模数据,宽6高8
0x00,0x3E,0x51,0x49,0x45,0x3E, // 0
0x00,0x00,0x42,0x7F,0x40,0x00, // 1
0x00,0x42,0x61,0x51,0x49,0x46, // 2
0x00,0x21,0x41,0x45,0x4B,0x31, // 3
0x00,0x18,0x14,0x12,0x7F,0x10, // 4
0x00,0x27,0x45,0x45,0x45,0x39, // 5
0x00,0x3C,0x4A,0x49,0x49,0x30, // 6
0x00,0x01,0x71,0x09,0x05,0x03, // 7
0x00,0x36,0x49,0x49,0x49,0x36, // 8
0x00,0x06,0x49,0x49,0x29,0x1E, // 9
};/*** 函 数:主函数(有且仅有一个)* 参 数:无* 返 回 值:无* 说 明:主函数是程序执行的起点,负责执行整个程序的主要逻辑*/
void main()
{unsigned char i,j,k;P2_5=0; //防止开发板上的蜂鸣器发出声音Timer0_Init(); //定时器0初始化Timer1_Init(); //定时器1初始化MatrixLED_Init(); //点阵屏初始化while(1){KeyNum=MatrixKey(); //获取独立按键的键码/*键码处理*/if(KeyNum){srand(TL0); //每次获取非0的键码值后用定时器0的低8位做种子,从而产生真随机数if(Mode==0) //如果是循环滚动显示游戏英文名“<<MAKE PAIRS>>”的界面{if(KeyNum>=33 && KeyNum<=48) //如果按下任意按键(松手瞬间){Mode=1; //切换到模式1OnceFlag=1; //切换模式前只执行一次的标志置1}}else if(Mode==1) //如果是游戏界面{if(KeyNum==47) //如果按了右键S15(松手瞬间){if(Select/3==0) //如果是第一行{Select++; //变量自增Select%=3; //第一行对应的Select的范围是0~2,用于按左右键时循环选择while(IsShow[Select%3]==0) //如果对应的方块已经消除(不显示了),则往右选择下一个{Select++;Select%=3;}}else if(Select/3==1) //如果是第二行{Select++; //变量自增Select=Select%3+3; //第二行对应的Select的范围是3~5,用于按左右键时循环选择while(IsShow[Select%3+3]==0) //如果对应的方块已经消除(不显示了),则往右选择下一个{Select++;Select=Select%3+3;}}}if(KeyNum==45) //如果按了左键S13(松手瞬间){if(Select/3==0){Select=(Select+3-1)%3;while(IsShow[Select%3]==0){Select=(Select+3-1)%3;}}else if(Select/3==1){Select=(Select+3-1)%3+3;while(IsShow[Select%3+3]==0){Select=(Select+3-1)%3+3;}}}if(KeyNum==42 || KeyNum==46) //如果按了下键S14(松手瞬间)或者按了上键S10(松手瞬间){if(IsShow[(Select+3)%6]) //如果另外一行正对的方块还未消除{Select=(Select+3)%6; //则选择变量改成正对的这个方块}else //如果另外一行正对的方块已经消除{if(Select/3==0) //如果原来是第一行{if(IsShow[3]+IsShow[4]+IsShow[5]) //如果第二行还有方块未消除{if(Select%3==2) //如果原来在第一行第三列{while(IsShow[Select%3+3]==0) //则换成第二行后向左寻找第一个未消除的方块{Select=(Select+3-1)%3+3;}}else //如果原来不是在第一行第三列{while(IsShow[Select%3+3]==0) //则换成第二行后向右寻找第一个未消除的方块{Select++;Select=Select%3+3;}}}}else if(Select/3==1) //如果原来是第二行{if(IsShow[0]+IsShow[1]+IsShow[2]) //如果第一行还有方块未消除{if(Select%3==2) //如果原来在第二行第三列{while(IsShow[Select%3]==0) //则换成第一行后向左寻找第一个未消除的方块{Select=(Select+3-1)%3;}}else //如果原来不是在第二行第三列{while(IsShow[Select%3]==0) //则换成第一行后向右寻找第一个未消除的方块{Select++;Select%=3;}}}}}}if(KeyNum==48) //如果按了确认键S16(松手瞬间){if(ConfirmFlag!=1 || Select!=FirstConfirm) //第一次确认的和第二次确认的必须是不同的方块{ConfirmFlag++;ConfirmFlag%=3; //确认标志ConfirmFlag的范围是0~2}if(ConfirmFlag==0){if(NoFlashFlag) //如果第二次确认后暂不闪烁的标志为真{ConfirmFlag=0; //确认的标志置0NoFlashFlag=0; //暂不闪烁的标志置0if(Type[FirstConfirm]==Type[SecondConfirm]) //如果两次确认的方块是相同的类型{ //则这两个方块不再显示IsShow[FirstConfirm]=0;IsShow[SecondConfirm]=0;}}FirstConfirm=6; //FirstConfirm和SecondConfirm必须为0~5以外的两个不等的数SecondConfirm=7; //FirstConfirm和SecondConfirm必须为0~5以外的两个不等的数}if(ConfirmFlag==1){FirstConfirm=Select; //保存第一次确认对应的方块}if(ConfirmFlag==2){SecondConfirm=Select; //保存第二次确认对应的方块T0Count=0; //定时器0的全局计数变量清零NoFlashFlag=1; //第二次确认后暂不闪烁的标志置1}}if(KeyNum==42 || KeyNum==46 || KeyNum==45 || KeyNum==47) //如果按了上、下、左或右键{if(NoFlashFlag) //如果第二次确认后暂不闪烁的标志为真{ConfirmFlag=0; //确认的标志置0NoFlashFlag=0; //暂不闪烁的标志置0if(Type[FirstConfirm]==Type[SecondConfirm]) //如果两次确认的方块是相同的类型{ //则这两个方块不再显示IsShow[FirstConfirm]=0;IsShow[SecondConfirm]=0;}FirstConfirm=6; //FirstConfirm和SecondConfirm必须为0~5以外的两个不等的数SecondConfirm=7; //FirstConfirm和SecondConfirm必须为0~5以外的两个不等的数}}MatrixLED_Clear(); //清屏}else if(Mode==2) //如果是游戏结束全屏闪烁{if(KeyNum==48) //如果按下S16(松手瞬间){Mode=3;OnceFlag=1;}}else if(Mode==3) //如果是滚动显示游戏用时的英文“USED TIME”的界面{if(KeyNum==48) //如果按下S16(松手瞬间){Mode=4;OnceFlag=1;}}else if(Mode==4) //如果是循环滚动显示游戏用时的界面{if(KeyNum==44) //如果按下S12(松手瞬间){Mode=1; //重新开始游戏OnceFlag=1;}}}/*游戏处理*/if(Mode==0) //循环滚动显示游戏英文名{if(OnceFlag) //切换到其他模式前,此if中的代码只执行1次{OnceFlag=0; //只执行一次的标志清零Offset=0; //滚动显示的偏移量清零}if(RollFlag) //如果滚动的标志RollFlag为真(非零即真){RollFlag=0; //滚动的标志RollFlag清零MatrixLED_MoveLeft(Table1,Offset); //向左滚动Offset++; //每次向左移动一个像素Offset%=84; //越界清零,循环滚动显示}}else if(Mode==1) //游戏进行中{if(OnceFlag){OnceFlag=0;//游戏初始化MatrixLED_Clear(); //清屏ConfirmFlag=0; //确认的标志置0Select=0; //方块选择变量置0for(i=0;i<6;i++) //全部方块都显示{IsShow[i]=1;}TypeForPick[0]=0;TypeForPick[1]=1;TypeForPick[2]=2;TypeForPick[3]=0;TypeForPick[4]=1;TypeForPick[5]=2; //数组TypeForPick的值重置for(i=0;i<6;i++) //将数组TypeForPick随机打乱放入数组Type中{j=rand()%(6-i);Type[i]=TypeForPick[j];for(k=j;k<6-i-1;k++){TypeForPick[k]=TypeForPick[k+1];}}UsedTime=0; //游戏用时清零GameOverFlag=0; //游戏结束的标志置0MatrixLED_DrawBlock(0,1,3);MatrixLED_DrawBlock(1,1,3);MatrixLED_DrawBlock(2,1,3);MatrixLED_DrawBlock(0,4,3);MatrixLED_DrawBlock(1,4,3);MatrixLED_DrawBlock(2,4,3); //显示六个“未翻转”的方块}if(IsShow[0]+IsShow[1]+IsShow[2]+IsShow[3]+IsShow[4]+IsShow[5]) //如果还有方块未消除{if(IsShow[0]+IsShow[1]+IsShow[2]==0 && Select/3==0){Select=3;} //如果第一行全部都消除了,则选择第二行的第一个if(IsShow[3]+IsShow[4]+IsShow[5]==0 && Select/3==1){Select=0;} //如果第二行全部都消除了,则选择第一行的第一个if(Select/3==0) //如果是第一行{while(IsShow[Select%3]==0) //向右选择第一个未消除的方块{Select++;Select%=3;}}else if(Select/3==1) //如果是第二行{while(IsShow[Select%3+3]==0) //向右选择第一个未消除的方块{Select++;Select=Select%3+3;}}}else //如果所有方块都消除了{GameOverFlag=1; //则游戏结束}if(ConfirmFlag==0) //如果确认标志为0{if( (Select==0 && FlashFlag) || IsShow[0]==0){MatrixLED_ClearBlock(0,1);}else{MatrixLED_DrawBlock(0,1,3);}if( (Select==1 && FlashFlag) || IsShow[1]==0){MatrixLED_ClearBlock(1,1);}else{MatrixLED_DrawBlock(1,1,3);}if( (Select==2 && FlashFlag) || IsShow[2]==0){MatrixLED_ClearBlock(2,1);}else{MatrixLED_DrawBlock(2,1,3);}if( (Select==3 && FlashFlag) || IsShow[3]==0){MatrixLED_ClearBlock(0,4);}else{MatrixLED_DrawBlock(0,4,3);}if( (Select==4 && FlashFlag) || IsShow[4]==0){MatrixLED_ClearBlock(1,4);}else{MatrixLED_DrawBlock(1,4,3);}if( (Select==5 && FlashFlag) || IsShow[5]==0){MatrixLED_ClearBlock(2,4);}else{MatrixLED_DrawBlock(2,4,3);} }else if(ConfirmFlag==1) //如果确认标志为1{ //则闪烁显示选择的方块,其他的不闪烁,且已经“翻转”的方块显示对应的类型if( (Select==0 && FlashFlag) || IsShow[0]==0){MatrixLED_ClearBlock(0,1);}else if(FirstConfirm==0){MatrixLED_DrawBlock(0,1,Type[0]);}else{MatrixLED_DrawBlock(0,1,3);}if( (Select==1 && FlashFlag) || IsShow[1]==0){MatrixLED_ClearBlock(1,1);}else if(FirstConfirm==1){MatrixLED_DrawBlock(1,1,Type[1]);}else{MatrixLED_DrawBlock(1,1,3);}if( (Select==2 && FlashFlag) || IsShow[2]==0){MatrixLED_ClearBlock(2,1);}else if(FirstConfirm==2){MatrixLED_DrawBlock(2,1,Type[2]);}else{MatrixLED_DrawBlock(2,1,3);}if( (Select==3 && FlashFlag) || IsShow[3]==0){MatrixLED_ClearBlock(0,4);}else if(FirstConfirm==3){MatrixLED_DrawBlock(0,4,Type[3]);}else{MatrixLED_DrawBlock(0,4,3);}if( (Select==4 && FlashFlag) || IsShow[4]==0){MatrixLED_ClearBlock(1,4);}else if(FirstConfirm==4){MatrixLED_DrawBlock(1,4,Type[4]);}else{MatrixLED_DrawBlock(1,4,3);}if( (Select==5 && FlashFlag) || IsShow[5]==0){MatrixLED_ClearBlock(2,4);}else if(FirstConfirm==5){MatrixLED_DrawBlock(2,4,Type[5]);}else{MatrixLED_DrawBlock(2,4,3);} }else if(ConfirmFlag==2) //如果确认标志为2{if(NoFlashFlag) //如果暂不闪烁的标志为真{ //则6个方块均不闪烁if(IsShow[0]==0){MatrixLED_ClearBlock(0,1);}else if(FirstConfirm==0 || SecondConfirm==0){MatrixLED_DrawBlock(0,1,Type[0]);}else{MatrixLED_DrawBlock(0,1,3);}if(IsShow[1]==0){MatrixLED_ClearBlock(1,1);}else if(FirstConfirm==1 || SecondConfirm==1){MatrixLED_DrawBlock(1,1,Type[1]);}else{MatrixLED_DrawBlock(1,1,3);}if(IsShow[2]==0){MatrixLED_ClearBlock(2,1);}else if(FirstConfirm==2 || SecondConfirm==2){MatrixLED_DrawBlock(2,1,Type[2]);}else{MatrixLED_DrawBlock(2,1,3);}if(IsShow[3]==0){MatrixLED_ClearBlock(0,4);}else if(FirstConfirm==3 || SecondConfirm==3){MatrixLED_DrawBlock(0,4,Type[3]);}else{MatrixLED_DrawBlock(0,4,3);}if(IsShow[4]==0){MatrixLED_ClearBlock(1,4);}else if(FirstConfirm==4 || SecondConfirm==4){MatrixLED_DrawBlock(1,4,Type[4]);}else{MatrixLED_DrawBlock(1,4,3);}if(IsShow[5]==0){MatrixLED_ClearBlock(2,4);}else if(FirstConfirm==5 || SecondConfirm==5){MatrixLED_DrawBlock(2,4,Type[5]);}else{MatrixLED_DrawBlock(2,4,3);} }else //如果暂不闪烁的标志为0{ConfirmFlag=0; //确认的标志置0if(Type[FirstConfirm]==Type[SecondConfirm]) //如果“翻开”的两个方块的类型相同{ //则这两个方块不再显示IsShow[FirstConfirm]=0;IsShow[SecondConfirm]=0;}}}if(GameOverFlag) //如果游戏结束的标志为真{Mode=2; //切换到全屏闪烁的模式OnceFlag=1;}}else if(Mode==2) //游戏结束全屏闪烁{if(OnceFlag){OnceFlag=0;MatrixLED_DrawBlock(0,1,Type[0]);MatrixLED_DrawBlock(1,1,Type[1]);MatrixLED_DrawBlock(2,1,Type[2]);MatrixLED_DrawBlock(0,4,Type[3]);MatrixLED_DrawBlock(1,4,Type[4]);MatrixLED_DrawBlock(2,4,Type[5]); //闪烁显示6个方块的类型}//在定时器1中实现全屏闪烁}else if(Mode==3) //滚动显示英文“USED TIME”{if(OnceFlag){OnceFlag=0;Offset=0;}if(RollFlag && Offset<=62) //只滚动显示一次英文“SCORE”{RollFlag=0;MatrixLED_MoveLeft(Table2,Offset);Offset++;}else if(Offset>62) //滚动结束后,自动切换到循环显示得分的模式{Mode=4;OnceFlag=1;} }else if(Mode==4) //循环滚动显示得分{if(OnceFlag){OnceFlag=0;Offset=0;//将游戏用时对应的字模写入数组UsedTimeShow中for(i=0;i<6;i++){UsedTimeShow[ 8+i]=Table3[(UsedTime/100%10)*6+i]; //十位}for(i=0;i<6;i++){UsedTimeShow[14+i]=Table3[(UsedTime/10%10)*6+i]; //个位}for(i=0;i<6;i++){UsedTimeShow[26+i]=Table3[(UsedTime%10)*6+i]; //十分位}}if(RollFlag){RollFlag=0;MatrixLED_MoveLeft(UsedTimeShow,Offset);Offset++;Offset%=38; //循环滚动显示}}}
}/*** 函 数:定时器0中断函数* 参 数:无* 返 回 值:无*/
void Timer0_Routine() interrupt 1
{static unsigned char T0Count1,T0Count2,T0Count3,T0Count4; //定时器计数变量TL0=0x00; //设置定时初值,定时10ms,12T@11.0592MHzTH0=0xDC; //设置定时初值,定时10ms,12T@11.0592MHzT0Count1++;T0Count2++;T0Count3++;T0Count++;if(T0Count1>=2) //每隔20ms检测一次键码{T0Count1=0;MatrixKey_Tick();}if(T0Count2>=25) //每隔250ms置反FlashFlag{T0Count2=0;FlashFlag=!FlashFlag;}if(T0Count3>=10) //每隔100ms滚动显示一次字母或数字{T0Count3=0;RollFlag=1;}if(GameOverFlag==0) //如果游戏没结束{T0Count4++;if(T0Count4>=10) //每隔100ms将游戏用时变量UsedTime加1{T0Count4=0;UsedTime++;}}else //如果游戏结束{T0Count4=0;}if(T0Count>=100) //第二次确认后1s内不闪烁{T0Count=0;NoFlashFlag=0;}
}/*** 函 数:定时器1中断函数* 参 数:无* 返 回 值:无* 说 明:专门用定时器1来扫描显示LED点阵屏,定时器1的优先级要比定时器0的高,否则显示会有闪烁现象*/
void Timer1_Routine() interrupt 3
{TL1=0x66; //设置定时初值,定时1ms,12T@11.0592MHzTH1=0xFC; //设置定时初值,定时1ms,12T@11.0592MHzif(Mode==2 && FlashFlag){P0=0xFF;} //控制游戏结束后的全屏闪烁else{MatrixLED_Tick();}
}
总结
此小游戏难在消除后,有些方块不显示了,需要对按键的选择做一些处理,跳过不显示的方块,也难在3对方块类型的随机排列。
相关文章:
基于51单片机和8X8点阵屏、矩阵按键的匹对消除类小游戏
目录 系列文章目录前言一、效果展示二、原理分析三、各模块代码1、8X8点阵屏2、矩阵按键3、定时器04、定时器1 四、主函数总结 系列文章目录 前言 用的是普中A2开发板,用到板上的8X8LED点阵屏和矩阵按键。 【单片机】STC89C52RC 【频率】12T11.0592MHz 效果查看/操…...
智能呼叫系统中的NLP意图理解:核心技术解析与实战
引言:当AI拿起电话时 在智能客服、电话营销等场景中,智能呼叫系统正以每年23%的增长率重塑人机交互方式。而支撑这一变革的核心技术,正是自然语言处理(NLP)中的意图理解模块。本文将深入解析意图理解的技术原理&#…...
信号灯和旋钮在接地电阻柜内的作用主要包括以下几个方面
信号灯的作用: 指示状态:信号灯用于指示接地电阻柜的工作状态,如正常运行、故障报警等。通过不同颜色的灯光(如红色表示故障,绿色表示正常)来提醒操作人员柜子的当前状态,确保及时处理潜…...
MongoDB 应用实战
1. java 原生客户端 引入maven 1 <dependencies> 2 <dependency> 3 <groupId>org.mongodb</groupId> 4 <artifactId>mongodb‐driver‐sync</artifactId> 5 <version>4.1.1</version> 6 </dependency> 7 </depende…...
Java EE初阶——wait 和 notify
1. 线程饥饿 线程饥饿是指一个或多个线程因长期无法获取所需资源(如锁,CPU时间等)而持续处于等待状态,导致其任务无法推进的现象。 典型场景 优先级抢占: 在支持线程优先级的系统中,高优先级线程可能持续…...
SpringBoot--Bean管理详解
Bean管理 Bean扫描 回顾spring: 在XML配置文件中,可以借助 <context:component-scan base-package "com.lyc"> 或者注解 ComponentScan(basePackages"com.lyc") 再springboot项目中,既没有标签,也…...
python爬虫实战训练
前言:哇,今天终于能访问豆瓣了,前几天爬太多次了,网页都不让我访问了(要登录)。 先来个小练习试试手吧! 爬取豆瓣第一页(多页同上篇文章)所有电影的排名、电影名称、星…...
探索大型语言模型(LLM)的开源学习路径:mlabonne/llm-course 深度解析
引言:为什么LLM学习需要系统化课程? 近年来,大型语言模型(Large Language Models, LLMs)彻底改变了自然语言处理领域。从GPT系列到Llama、Mistral等开源模型,掌握LLM的开发和应用能力已成为技术人员的核心竞争力。然而,LLM技术栈涵盖从理论基础到工程实践的复杂内容,如…...
IDEA怎么汉化idea中文改回英文版
第一步:点击左上角的File,然后选择Setting 第二步:Setting页面选择 Appearance & Behavior,然后展开System Settings,然后选择 Language and Region,进行修改 我操作的是2024年的版本 File->Settings -> Ap…...
Flutter目录结构介绍、入口、Widget、Center组件、Text组件、MaterialApp组件、Scaffold组件
目录 1. 创建Flutter项目 1.1使用Android Studio创建Flutter项目 1.2 使用命令行创建Flutter项目 2. Flutter项目介绍 2.1所有代码都在lib目录下编写 2.1 pubspec.yaml 依赖库/图片的引用 编辑 3. 运行项目 4. 编写mian.dart文件 4.1 使用MaterialApp 和 Scaffold两个组件…...
C++23 中的 ranges::fold_left:范围折叠算法
文章目录 1. **ranges::fold_left 的基本概念**2. **使用示例**示例 1:计算整数范围的和示例 2:计算字符串范围的连接示例 3:使用自定义函数 3. **与其他折叠算法的比较**4. **为什么需要 ranges::fold_left**5. **总结** 随着 C23 的到来&am…...
Vue2项目created不执行
Vue2项目created不执行 设置唯一值 name在 created 调用方法在 watch 中监听路由完整代码示例 设置唯一值 name 在 Vue 组件中,name 属性用于标识组件。确保每个组件的 name 属性是唯一的,这有助于在调试和开发过程中更好地识别组件。 export default …...
mysql的not exists走索引吗
在MySQL中,NOT EXISTS子句是否使用索引取决于子查询中关联字段是否建立了合适的索引。以下是关键点总结: 索引的作用: 当子查询的关联字段(例如B.a_id)存在索引(如普通B-tree索引)时&…...
红黑树实现
1.红黑树的概念 红黑树是一棵二叉搜索树,他的每个节点增加一个存储位来表示节点的颜色,可以是红丝或者黑色。通过对任何一条从根到叶子的路径上各个节点的颜色进行约束,红黑树确保没有一条路径会比其他路径长出两倍,因而是接近平…...
将已打包好的aar文件,上传到 Coding 的 Maven 仓库
将已打包好的aar文件,上传到 Coding 的 Maven 仓库。 在android stuio项目的build.gradle 进行上传。 编写代码 plugins {id maven-publish }// 配置要上传的本地 AAR 文件 def aarFile file(D:\\mylibrary-1.0.0.aar)publishing {publications {mavenAar(MavenP…...
海康相机连接测试-极简版
文章目录 1、下载客户端 1、下载客户端 海康机器人官网下载软件 软件下载地址 先下载客户端测试连接 按照你的相机的类型选择客户端 安装完毕后,确保USB线插的是3.0的端口 软件会自动识别相机型号 在上方有播放按钮,可以采集图像信息显示...
深入探索:Core Web Vitals 进阶优化与新兴指标
一、INP(Interaction to Next Paint)深度解析 INP 与 FID 的核心差异 • 响应范围:FID仅测量首次输入延迟,而INP跟踪页面生命周期中所有关键交互 • 测量维度:INP综合考虑输入延迟、处理时间和下一帧渲染时间 • 评…...
AI与产品架构设计系列(2):Agent系统的应用架构与落地实
什么是AI Agent?其在架构中的独特定位 AI Agent(人工智能代理)是一种模拟人类智能行为的自主系统,通常以大型语言模型(LLM)作为核心引擎。简单来说,Agent能够像人一样感知环境信息、规划行动方…...
OpenAI与微软洽谈新融资及IPO,Instagram因TikTok流失四成用户
OpenAI与微软洽谈新融资及IPO 据悉,OpenAI 正与微软洽谈新融资及筹备 IPO,关键问题是微软在 OpenAI 重组后的股权比例。微软已投资超 130 亿美元,双方修订 2019 年合同,微软拟弃部分股权换新技术访问权。OpenAI 上周放弃了有争议转…...
架构篇、第五章_05Jenkins的部署与构建
Linux_架构篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:Jenkins的部署与构建 版本号: 1.0,0 作者: 老王要学习 日期: 2025.05.15 适用环境: Centos7 文档说明 本文档围绕 Jenkins 的部署与构建展开&a…...
`ParameterizedType` 和 `TypeVariable` 的区别
在 Java 的泛型系统中,ParameterizedType 和 TypeVariable 是两个不同的类型表示,它们都属于 java.lang.reflect.Type 接口的子接口。两者都在反射(Reflection)中用于描述泛型信息,但用途和含义不同。 🌟 一…...
HTML 中的 input 标签详解
HTML 中的 input 标签详解 一、基础概念 1. 定义与作用 HTML 中的 <input> 标签是表单元素的核心组件,用于创建各种用户输入字段。作为一个空标签(没有闭合标签),它通过 type 属性来决定呈现何种输入控件,是实…...
从 Vue3 回望 Vue2:性能优化内建化——从黑盒优化到可控编译
文章目录 从 Vue3 回望 Vue2:性能优化内建化——从黑盒优化到可控编译1. 引言2. Vue2 的性能优化机制解析3. Vue3 的编译期优化能力拆解3.1 静态提升(Static Hoisting)3.2 Patch Flag 精确标记3.3 Block Tree (块级更新边界&#…...
HOW - React NextJS 的同构机制
文章目录 一、什么是 Next.js 的同构?二、核心目录结构三、关键函数:如何实现不同渲染方式?1. getServerSideProps —— 实现 SSR(每次请求动态获取数据)2. getStaticProps getStaticPaths —— 实现 SSG(…...
电动汽车直流快充充电桩AEV200-DC240M4的详细介绍
电动汽车直流快充充电桩AEV200-DC240M4产品简介 AEV系列为全新一代分体式电动汽车直流恒功率快速充电机。系统内置 30/40kW 恒功率充电模块,最高输出电压1000V,满足各类车辆充电需求。模块采用隔离风道灌胶设 计 ,可靠性高 ,可应…...
YOLOv7训练时4个类别只出2个类别
正常是4个类别: 但是YOLOv7训练完后预测总是只有两个类别: 而且都是LFM和SFM 我一开始检查了下特征图大小,如果输入是640*640的话,三个尺度特征图是80*80,40*40,20*20;如果输入是416*416的话,三个尺度特征…...
数据赋能(224)——数据与业务协同——数据动态调整原则
概述 数据动态调整原则不仅能帮助组织迅速响应业务需求和技术环境的变化,还能确保数据应用始终与最新的数据处理技术、算法和工具保持同步。通过实施数据动态调整,企业能够更准确地捕捉业务趋势,优化数据质量,以及提高资源利用效…...
Vulfocus靶场-文件上传-3
WSO2 文件上传 (CVE-2022-29464) WSO2是一家成立于 2005 年的开源技术提供商。它提供了一个企业平台,用于在本地和整个 Internet 上 集成应用程序编程接口(API)、应用程序和 Web 服务。 某些 WSO2 产品允许无限制的文件上传和远程代码执行。…...
(for 循环) VS (LINQ) 性能比拼 ——c#
在大多数情况下,for 循环的原始性能会优于 LINQ,尤其是在处理简单遍历、数据筛选或属性提取等场景时。这是由两者的实现机制和抽象层次决定的。以下是具体分析: 一、for 循环与 LINQ 的性能差异原因 1. 抽象层次与执行机制 for 循环&#…...
自学嵌入式 day19-数据结构 链表
二、线性表的链式存储 1.特点: (1)线性表链式存储结构的特点是一组任意的存储单位存储线性表的数据元素,存储单元可以是连续的,也可以不连续。可以被存储在任意内存未被占用的位置上。 (2)所以…...
一发入魂:极简解决 SwiftUI 复杂视图未能正确刷新的问题(中)
概述 各位似秃非秃小码农们都知道,在 SwiftUI 中视图是状态的函数,这意味着状态的改变会导致界面被刷新。 但是,对于有些复杂布局的 SwiftUI 视图来说,它们的界面并不能直接映射到对应的状态上去。这就会造成一个问题:状态的改变并没有及时的引起 UI 的变化。 如上图所示…...
UI自动化测试详解
🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 1、about自动化测试 定义:把人为驱动的测试转化为机器执行的一种过程,重点在于持续集成这个概念; 优势:节约人力…...
数学复习笔记 14
前言 和家里人交流了一下,他们还是希望我全力以赴初试,我确实也得放开了干,不要束手束脚的。好好加油。感觉公共课都没有啥压力,主要是专业课要好好加油,真不能过不了线,要是过不了线,啥都白搭…...
单元化架构
目录 编辑 单元化 逻辑单元 单元化 多地多机房部署,是互联网系统的必然发展方向,一个系统要走到这一步,也就必然要解决上面提到的问题:流量调配、数据拆分、延时等。业界有很多技术方案可以用来解决这些问题&…...
硬件厂商的MIB文档详解 | 如何查询OID? | MIB Browser实战指南-优雅草卓伊凡
硬件厂商的MIB文档详解 | 如何查询OID? | MIB Browser实战指南-优雅草卓伊凡 一、硬件厂商的MIB文档是什么? 1. MIB的本质:设备的”数据字典” MIB(Management Information Base) 是SNMP协议的核心数据库,定义了设备…...
遥感图像露天矿区检测数据集VOC+YOLO格式1542张1类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):1542 标注数量(xml文件个数):1542 标注数量(txt文件个数):1542 …...
【python基础知识】Day 27 函数专题2:装饰器
知识点: 装饰器的思想:进一步复用函数的装饰器写法注意内部函数的返回值 装饰器教程 作业: 编写一个装饰器 logger,在函数执行前后打印日志信息(如函数名、参数、返回值) def logger(func):def wrapper(*ar…...
游戏站的几种形式
游戏站点的主要形式:单品游戏站、游戏盒子站与单类型游戏盒子站 随着互联网的普及和游戏产业的快速发展,游戏站点作为玩家获取游戏资源和信息的重要平台,呈现出多种形式。本文将分析三种常见的游戏站点形式:单品游戏站、游戏盒子站…...
动态IP赋能业务增效:技术解构与实战应用指南
在数字化转型加速的今天,IP地址作为网络通信的基础设施,其技术特性正深刻影响着企业业务架构的效率与安全性。动态IP(Dynamic IP)作为互联网资源分配的核心机制,早已突破传统认知中的"临时地址"定位…...
Redis 五种类型基础操作(redis-cli + Spring Data Redis)
目录 一、什么是 Redis? 二、Redis 的特点 三、Redis 常见的数据类型 四、Redis 的典型应用场景 五、redis-cli(命令行工具)练习命令 1.1、String 类型(最基本的数据类型) 1.2、List 类型(链表结构&a…...
Gitee DevOps:中国企业数字化转型的加速引擎
随着中国数字经济规模突破50万亿元大关,研发效能已成为企业数字化转型的核心竞争力指标。在2025年这个关键节点,中国企业面临的不再是是否采用DevOps的选择题,而是如何选择最适合本土环境的DevOps平台的战略决策。Gitee DevOps平台凭借其独特…...
【数据仓库面试题合集①】数据建模高频面试题及解析
🧠 面试官爱问什么?——核心考察点 数据建模作为数仓岗位面试的重头戏,考察的不只是模型知识,更是对业务理解、抽象能力和工程落地经验的综合评估。常见题型可分为三类: 概念类:模型类型、建模方法论(如维度建模、范式建模) 场景类:给定一个业务场景进行模型设计(如…...
华为云Flexus+DeepSeek征文|SpringBoot开发实战:基于ModelArts Studio高效集成DeepSeek大模型服务
目录 一、前言 二、ModelArts Studio(MaaS)介绍与使用 2.1ModelArts Studio(MaaS)介绍 2.2 ModelArts Studio(MaaS)使用场景 2.3 开通MaaS服务 2.4 开通DeepSeek-V3商用服务 三、MaaS模型服务接口测试 3.1 …...
【C++】类与对象
C语言结构体中只能定义变量,在C中,结构体内不仅可以定义变量,也可以定义函数。比如:之前在数据结构中,用C语言方式实现的栈,结构体中只能定义变量;现在以C方式实现,会发现struct中也可以定义函数。 struct Stack {// 成员函数void Init(int defaultCapacity 4){a (int*)mall…...
mac M芯片运行docker-desktop异常问题
虽然mac已经迭代到m4了,但官方的docker-desktop运行仍然有问题,包括但不限于: 命令行docker找不到docker-desk打不开docker-desktop闪退容器起不来 尝试不同版本后,看到了其他可以在mac跑docker的开源方法,更简单、轻…...
5G 技术在智能制造中的应用:加速工业革命的新引擎
5G 技术在智能制造中的应用:加速工业革命的新引擎 在过去几十年里,制造业经历了从机械化到自动化,再到如今的智能化变革。而 5G 技术的出现,不仅是一次通信技术的升级,更是为 智能制造 注入了新的动力。从 智能工厂、工业物联网(IIoT) 到 远程控制与数据智能分析,5G 正…...
数据治理域——数据同步设计
摘要 本文主要介绍了数据同步的多种方式,包括直连同步、数据文件同步和数据库日志解析同步。每种方式都有其适用场景、技术特点、优缺点以及适用的数据类型和实时性要求。文章还详细探讨了数据直连同步的特点、工作原理、优点、缺点、适用场景等,并对数…...
系统架构设计师案例分析题——web篇
软考高项系统架构设计师,其中的科二案例分析题为5选3,总分75达到45分即合格。本贴来归纳web设计题目中常见的知识点即细节: 目录 一.核心知识 1.常见英文名词 2.私有云 3.面向对象三模型 4.计网相关——TCP和UDP的差异 5.MQTT和AMQP协…...
FC7300 SPI MCAL配置引导
一、MCU 组件 - 配置SPI时钟 MCU中配置的SPI输入时钟频率至少应大于2倍的SPI组件中配置的外设波特率。SPI时钟配置为30MHz 二、SPI 组件 - General Spi Level Delivered: 0 级:仅简单同步行为1 级:基本异步行为,通过中断实现2 级:增强型行为,通过轮询实现根据AUTOSAR SPI…...
【记录】Windows|竖屏怎么调整分辨率使横竖双屏互动鼠标丝滑
本文版本:Windows11,记录一下,我最后调整的比较舒适的分辨率是800*1280。 文章目录 第一步 回到桌面第二步 右键桌面第三步 设置横屏为主显示器第四步 调整分辨率使之符合你的需求第五步 勾选轻松在显示器之间移动光标第六步 拖动屏幕符合物理…...