基于51单片机(STC32G12K128)和8X8彩色点阵屏(WS2812B驱动)的小游戏《贪吃蛇》
目录
- 系列文章目录
- 前言
- 一、效果展示
- 二、原理分析
- 三、各模块代码
- 1、定时器0
- 2、矩阵按键模块
- 3、8X8彩色点阵屏
- 四、主函数
- 总结
系列文章目录
前言
《贪吃蛇》,一款经典的、怀旧的小游戏,单片机入门必写程序。
以《贪吃蛇》为载体,熟悉各种屏幕的使用。
所用单片机:STC32G12K128-Beta。
有两个版本:自制独立按键版本和矩阵按键模块版本。
本文代码对应的是矩阵按键模块版本。
效果查看/操作演示:B站搜索“甘腾胜”或“gantengsheng”查看。
源代码下载:B站对应视频的简介有工程文件下载链接。
一、效果展示
(1)自制独立按键版本
(2)矩阵按键模块版本
二、原理分析
游戏原理可以参考以下这篇文章:
基于51单片机和8X8LED点阵屏(板载74HC595驱动)的普中开发板矩阵按键控制的小游戏《贪吃蛇》
这里主要说一下8X8彩色点阵屏(WS2812B)的显示问题。
一个灯(图片中白色正方形)里面有三个LED,分别是红、绿、蓝,白色正方形中其实也集成了WS2812B芯片,一个芯片可以存储3个字节(Byte)的数据,接收到3个字节的数据后,会把后面接收到的数据传给下一个灯的WS2812B芯片。一个字节控制一种颜色的LED,即一个灯需要用24位(Bit)控制,所以一个灯的颜色变化种类有224=16777216种。
如何发送0和1呢?类似DS18B20的数据发送,通过高电平的时长来确定发送的是0还是1,“0”的高电平时长较短,“1”的高电平时长较长,具体的时序图可以参考一下其他博主的文章。经过测试,高低电平的时长要求不算严格,但是需要注意的是,如果不注意定时器中断函数打断的影响,屏幕会出现“花屏”的情况,即一个字节才发送一半就被定时器中断函数打断的话,原来要发送的数据就改变了。如果以一个字节为单位,发送一个字节前关闭总中断(EA=0),发送完一个字节后再开启中断(EA=1),这样显示就不会出现问题,这样即不影响显示,也不影响定时器的运行,但是要注意,定时器中断函数代码的执行时间不能太长,太长的话相当于发送了重置(RESET)指令给WS2812B芯片,屏幕会乱闪。
三、各模块代码
1、定时器0
h文件
#ifndef __TIMER0_H__
#define __TIMER0_H__void Timer0_Init(void);#endif
c文件
#include <STC32G.H>/*** @brief 定时器0初始化* @param 无* @retval 无*/
void Timer0_Init(void)
{ AUXR|=0x80; //定时器时钟1T模式TMOD&=0xF0; //设置定时器模式(16位不自动重载)(高四位不变,低四位清零)TMOD|=0x01; //设置定时器模式(16位不自动重载)(通过低四位设为“定时器0工作方式1”的模式)TL0=0x40; //设置定时初值,定时1ms,1T@24.000MHzTH0=0xA2; //设置定时初值,定时1ms,1T@24.000MHzTF0=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=0x40; //设置定时初值,定时1ms,1T@24.000MHzTH0=0xA2; //设置定时初值,定时1ms,1T@24.000MHzT0Count++;if(T0Count>=1000){T0Count=0;}
}
*/
2、矩阵按键模块
h文件
#ifndef __MATRIXKEYSCAN_H__
#define __MATRIXKEYSCAN_H__unsigned char Key(void);
void Key_Tick(void);#endif
c文件
#include <STC32G.H>
#include <INTRINS.H> //需要用空操作_nop_();来延时#define Matrix_Port P2 //矩阵按键接口unsigned char KeyNumber;/*** @brief 获取矩阵按键键码,扫描周期内第二次获取键码值,会返回0* @param 无* @retval 按下按键的键码,范围:0~48,0表示无按键按下*/
unsigned char Key(void)
{unsigned char KeyTemp=0;KeyTemp=KeyNumber;KeyNumber=0;return KeyTemp;
}/*** @brief 检测当前按下按键的状态,无消抖及松手检测* @param 无* @retval 按下按键的键值,范围:0~16,无按键按下时返回值为0*/
unsigned char Key_GetState()
{unsigned char KeyValue=0;Matrix_Port=0x0F; //给所有行赋值0,列全为1_nop_();_nop_(); //适当延时(若不加延时,就不能正确检测按键)if(Matrix_Port!=0x0F){Matrix_Port=0x0F; //测试列_nop_();_nop_();switch(Matrix_Port) //保存行为0时,按键按下后的列值{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; //测试行_nop_();_nop_();switch(Matrix_Port) //保存列为0时,按键按下后的键值{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;
}/*** @brief 矩阵按键驱动函数,在中断中调用* @param 无* @retval 无*/
void Key_Tick(void)
{static unsigned char NowState,LastState;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){if(LastState==1 && NowState==1){KeyNumber=17;}if(LastState==2 && NowState==2){KeyNumber=18;}if(LastState==3 && NowState==3){KeyNumber=19;}if(LastState==4 && NowState==4){KeyNumber=20;}if(LastState==5 && NowState==5){KeyNumber=21;}if(LastState==6 && NowState==6){KeyNumber=22;}if(LastState==7 && NowState==7){KeyNumber=23;}if(LastState==8 && NowState==8){KeyNumber=24;}if(LastState==9 && NowState==9){KeyNumber=25;}if(LastState==10 && NowState==10){KeyNumber=26;}if(LastState==11 && NowState==11){KeyNumber=27;}if(LastState==12 && NowState==12){KeyNumber=28;}if(LastState==13 && NowState==13){KeyNumber=29;}if(LastState==14 && NowState==14){KeyNumber=30;}if(LastState==15 && NowState==15){KeyNumber=31;}if(LastState==16 && NowState==16){KeyNumber=32;}}//如果上个时间点按键按下,这个时间点按键未按下,则是松手瞬间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、8X8彩色点阵屏
h文件
#ifndef __WS2812B_H__
#define __WS2812B_H__extern unsigned char ColorStyle; //extern:外部可使用
extern unsigned char xdata WS2812B_Buffer[];
extern unsigned char code MyColor[];
void WS2812B_SetBuf(unsigned char Position,unsigned char R,unsigned char G,unsigned char B);
void WS2812B_WriteByte(unsigned char Byte);
void WS2812B_Clear(void);
void WS2812B_UpdateDisplay(void);
void WS2812B_MoveLeft(unsigned char *Array,unsigned char R,unsigned char G,unsigned char B,unsigned int Offset);
void WS2812B_MoveUp(unsigned char *Array,unsigned char R,unsigned char G,unsigned char B,unsigned int Offset);#endif
c文件
#include <STC32G.H>
#include <INTRINS.H> //需要用空操作_nop_();来延时sbit WS2812B_DI=P5^4;unsigned char ColorStyle; //颜色类型//用64*3=192个字节作为WS2812B彩色点阵屏的缓存,共有64个灯,每个灯需要写入24Bit(3个字节)控制显示的颜色
//每三个字节为一组,每一组分别对应彩色灯的G(绿)、R(红)、B(蓝)三原色
unsigned char xdata WS2812B_Buffer[192];//预设颜色(数值设小一些是为了防止太刺眼)
unsigned char code MyColor[]={
16,0,0, //红色
0,16,0, //绿色
0,0,16, //蓝色
8,8,0, //黄色
8,0,8, //紫色
0,8,8, //青色
};/*** @brief WS2812B彩色点阵屏私有延时函数,1T@24.000MHz调用可延时约100us* @param 无* @retval 无*/
void WS2812B_Delay100Us(void)
{unsigned long edata i;i=600UL;while(i){i--;}
}/*** @brief WS2812B彩色点阵屏设置一个点的缓存* @param Position 要设置的位置,高四位(0~7)对应1~8列(从左到右),低四位(0~7)对应1~8行(从上到下)* @param R 红(Red),范围:0~255* @param G 绿(Green),范围:0~255* @param B 蓝(Blue),范围:0~255* @retval 无*/
/*
本函数适用于以下数据传输顺序的8X8彩色点阵屏,如果不是的话,需要修改函数
数据从第一列的B7开始,往上到B0,然后再到第二列的B7,再往上到第二列的B0,以此类推
每一个B对应一个灯。缓存数组SnakeBuffer的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
*/
void WS2812B_SetBuf(unsigned char Position,unsigned char R,unsigned char G,unsigned char B)
{WS2812B_Buffer[Position/16*24+(21-Position%16*3)]=G;WS2812B_Buffer[Position/16*24+(22-Position%16*3)]=R;WS2812B_Buffer[Position/16*24+(23-Position%16*3)]=B;
}/*** @brief WS2812B彩色点阵屏写入一个字节* @brief 要求:1T@24.000MHz,频率如果不一样,需要调“_nop_();”的数量* @param Byte 要写入的字节* @retval 无*/
void WS2812B_WriteByte(unsigned char Byte)
{unsigned char i;EA=0; //关闭总中断(时序要求严格,不能被打断),要求中断函数执行的时间不能太长,否则会“花屏”for(i=0;i<8;i++){if(Byte&(0x80>>i)) //高位先发{ //写1WS2812B_DI=1; //根据高电平的时长确定发送的是1还是0,跟DS18B20类似_nop_();_nop_();_nop_();_nop_();_nop_(); //用空操作进行延时_nop_();_nop_();_nop_();_nop_();_nop_(); //单片机使用不同的频率,“_nop_();”的数量就不一样WS2812B_DI=0; //经测试,数据线拉低后可以不用延时}else{ //写0WS2812B_DI=1;_nop_();_nop_();_nop_();_nop_();_nop_();WS2812B_DI=0;}}EA=1; //开启总中断
}/*** @brief WS2812B彩色点阵屏清空缓存* @param 无* @retval 无*/
void WS2812B_Clear(void)
{unsigned char i;for(i=0;i<192;i++){WS2812B_Buffer[i]=0;}
}/*** @brief WS2812B彩色点阵屏更新屏幕显示,将缓存数组WS2812B_Buffer的192个字节写入64个灯的芯片内* @param 无* @retval 无*/
void WS2812B_UpdateDisplay(void)
{unsigned char i;for(i=0;i<192;i++){WS2812B_WriteByte(WS2812B_Buffer[i]);} //连续写入192个字节WS2812B_Delay100Us(); //Reset(重置)信号
}/*** @brief WS2812B彩色点阵屏向左滚动显示* @param Array 传递过来的数组的指针(地址),数组名就是数组的首地址* @param R 红(Red),范围:0~255* @param G 绿(Green),范围:0~255* @param B 蓝(Blue),范围:0~255* @param Offset 偏移量,向左平移Offset个像素* @retval 无*/
void WS2812B_MoveLeft(unsigned char *Array,unsigned char R,unsigned char G,unsigned char B,unsigned int Offset)
{unsigned char i,j;Array+=Offset;for(i=0;i<8;i++) //每个亮点都写入相同的颜色{for(j=0;j<8;j++){if(*(Array+i)&(0x80>>j)){WS2812B_Buffer[3*8*i+3*j]=G; //调了一下顺序,数组WS2812B_Buffer中按WS2812B_Buffer[3*8*i+3*j+1]=R; //GRB的顺序放置,因WS2812B芯片就是要求按WS2812B_Buffer[3*8*i+3*j+2]=B; //GRB的顺序发送数据的,方便数据发送给芯片}else{WS2812B_Buffer[3*8*i+3*j]=0;WS2812B_Buffer[3*8*i+3*j+1]=0;WS2812B_Buffer[3*8*i+3*j+2]=0;}}}
}/*** @brief WS2812B彩色点阵屏向上滚动显示* @param Array 传递过来的数组的指针(地址),数组名就是数组的首地址* @param R 红(Red),范围:0~255* @param G 绿(Green),范围:0~255* @param B 蓝(Blue),范围:0~255* @param Offset 偏移量,向上平移Offset个像素* @retval 无*/
void WS2812B_MoveUp(unsigned char *Array,unsigned char R,unsigned char G,unsigned char B,unsigned int Offset)
{unsigned char i,j;unsigned char m,n;unsigned char Temp[8];m=Offset/8;n=Offset%8;Array+=8*m;for(i=0;i<8;i++) //将偏移后的数据保存到缓存数组Temp中,一个Bit对应一个灯{Temp[i]=(*Array>>n) | (*(Array+8)<<(8-n));Array++;}for(i=0;i<8;i++) //每个亮点都写入相同的颜色{for(j=0;j<8;j++){if(Temp[i]&(0x80>>j)){WS2812B_Buffer[3*8*i+3*j]=G;WS2812B_Buffer[3*8*i+3*j+1]=R;WS2812B_Buffer[3*8*i+3*j+2]=B;}else{WS2812B_Buffer[3*8*i+3*j]=0;WS2812B_Buffer[3*8*i+3*j+1]=0;WS2812B_Buffer[3*8*i+3*j+2]=0;}}}
}
四、主函数
main.c
/*
by甘腾胜@20241225
效果查看/操作演示:可以在B站搜索“甘腾胜”或“gantengsheng”查看
开发环境:Keil C251
单片机:STC32G12K128-Beta
分频系数及频率:1T@24.000MHz
外设:4X4矩阵按键模块、8X8LED彩色点阵屏(WS2812B驱动)
原理分析:https://blog.csdn.net/gantengsheng/article/details/143581157
注意:驱动WS2812B彩色点阵屏需要用1T的单片机,传统的12T单片机无法驱动操作说明:(1)自制独立按键版本K7 K2 上:K7下:K6K8 K5 K4 K1 左:K8右:K5K6 K3 开始/暂停/继续:K1返回:K2(2)普中开发板矩阵按键版本S1 S2 S3 S4 上:S10 下:S14 S5 S6 S7 S8 左:S13右:S15S9 S10 S11 S12 开始/暂停/继续:S16返回:S12S13 S14 S15 S16 本代码适用于以下数据传输顺序的8X8彩色点阵屏,如果不是的话,需要修改函数
数据从第一列的B7(点阵屏左下角)开始,往上到B0,然后再到第二列的B7,再往上到第二列的B0,以此类推
每一个B对应一个灯。缓存数组SnakeBuffer的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*/#include <STC32G.H> //包含寄存器的定义
#include <STDLIB.H> //包含随机函数的声明
#include "WS2812B.h" //包含工程目录下的头文件,相当于把头文件内容插入此处
#include "MatrixKeyScan.h"
#include "Timer0.h"unsigned char KeyNum; //存储获得的键码值
unsigned char Mode; //游戏模式,0:显示流水灯及呼吸灯,1:显示游戏名“<<SNAKE>>”,2:显示难度的英文“DIFFICULTY”,//3:难度选择界面,难度范围是1~5,4:游戏模式,5:游戏结束全屏闪烁,6:显示英文“SCORE”,//7:循环滚动显示二位数得分,8:循环滚动显示作者和编程日期
unsigned char Mode0; //Mode=0下的子模式,0:拖尾流水灯显示数据传输顺序,1:六种颜色的从左到右的拖尾流水灯,2:六种颜色的呼吸灯
unsigned char MoveFlag; //移动蛇身的标志,1:移动,0:不移动
unsigned char NowDirection=1; //蛇头移动的方向,1:向右,2:向上,3:向左,4:向下,游戏开始时默认向右移动(此处可以不赋初值)
unsigned char LastDirection=1; //蛇头上一次移动的方向,1:向右,2:向上,3:向左,4:向下,游戏开始时默认向右移动(此处可以不赋初值)
unsigned char Length=2; //蛇的长度,初始值为2(此处可以不赋初值,因为每次游戏开始前会重新赋值一次)
unsigned char Head=1; //保存整条蛇的数据的数组SnakeBody(共64个数据,数据索引为:0~63)中,蛇头对应的数据的索引,蛇的初始长度为2,//开始时只用了两个数据(数组的第1个数据和第2个数据),蛇头对应的是第2个数据(索引为1),Head的范围:0~63
unsigned char GameOverFlag; //游戏结束的标志,1:游戏结束,0:游戏未结束
unsigned char FlashFlag; //闪烁的标志,1:不显示,0:显示
unsigned char Food; //保存创造出来的食物的位置,高四位(0~7)对应1~8列(从左到右),低四位(0~7)对应1~8行(从上到下)
unsigned int Offset1; //偏移量,用来控制汉字或数字向左滚动显示(切换模式后清零)
unsigned int Offset2; //偏移量,用来控制难度选择界面对应的数字上下滚动显示(切换模式后不清零)
unsigned char RollFlag; //滚动的标志,1:滚动,0:不滚动
unsigned char RollUpFlag; //难度选择界面,数字向上滚动的标志,1:滚动,0:不滚动
unsigned char RollDownFlag; //难度选择界面,数字向下滚动的标志,1:滚动,0:不滚动
unsigned char RollCount; //上下滚动的计次
unsigned char ExecuteOnceFlag; //各模式中(切换到该模式后,切换为其他模式前)只执行一次的标志,1:执行,0:不执行
unsigned int SnakeMoveSpeed=1000; //控制蛇移动的速度,值越小,速度越快
unsigned int T0Count0,T0Count1,T0Count2,T0Count3,T0Count4,T0Count5; //定时器计数的变量
unsigned char PauseFlag; //暂停的标志,1:暂停,0:不暂停
unsigned char SnakeBody[64]; //点阵屏是8*8=64个像素,需要用64个数据记录蛇身的数据
unsigned char SnakeBuffer[8]; //显示缓存,一个字节对应8个点,屏幕总共64个点,所以需要8个字节//阴码(亮点为1),逐列式取模,高位在下//此数组用来保存点阵屏哪些点亮,哪些点不亮
unsigned char Breath=1; //用来实现呼吸灯的效果
unsigned char BreathInOrOut=1; //用来控制呼吸灯变亮还是变暗
unsigned char BreathFlag; //呼吸灯改变亮度的标志,定时器中每隔一段时间将此标志置1
unsigned char BreathCount; //用来使呼吸灯熄灭后的时间长一点
unsigned char BreathColor; //控制呼吸灯显示的颜色
unsigned char ExecuteOnceFlag0; //子模式中只执行一次的标志,1:执行,0:不执行unsigned char Score[]={ //用来滚动显示得分
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //无显示
0x00,0x00,0x00,0x00,0x00,0x00, //游戏结束后将蛇身长度Length的十位的数字字模写入到这一行
0x00,0x00,0x00,0x00,0x00,0x00, //游戏结束后将蛇身长度Length的个位的数字字模写入到这一行
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //无显示
};unsigned char code FlowingWaterLight1[]={ //流水灯1(拖尾)
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,191,0,0,127,0,0,95,0,0,63,0,0,47,0,0,31,0,0,23,0, //红
0,15,0,0,11,0,0,7,0,0,5,0,0,3,0,0,2,0,0,1,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,191,0,0,127,0,0,95,0,0,63,0,0,47,0,0,31,0,0,23, //绿
0,0,15,0,0,11,0,0,7,0,0,5,0,0,3,0,0,2,0,0,1,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,191,0,0,127,0,0,95,0,0,63,0,0,47,0,0,31,0,0,23,0,0, //蓝
15,0,0,11,0,0,7,0,0,5,0,0,3,0,0,2,0,0,1,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0,191,191,0,127,127,0,95,95,0,63,63,0,47,47,0,31,31,0,23,23, //黄
0,15,15,0,11,11,0,7,7,0,5,5,0,3,3,0,2,2,0,1,1,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0,191,191,0,127,127,0,95,95,0,63,63,0,47,47,0,31,31,0,23,23,0, //紫
15,15,0,11,11,0,7,7,0,5,5,0,3,3,0,2,2,0,1,1,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,255,191,0,191,127,0,127,95,0,95,63,0,63,47,0,47,31,0,31,23,0,23, //青
15,0,15,11,0,11,7,0,7,5,0,5,3,0,3,2,0,2,1,0,1,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
};unsigned char code FlowingWaterLight2[]={ //流水灯2(拖尾)
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0, //红
0,127,0,0,127,0,0,127,0,0,127,0,0,127,0,0,127,0,0,127,0,0,127,0,
0,63,0,0,63,0,0,63,0,0,63,0,0,63,0,0,63,0,0,63,0,0,63,0,
0,31,0,0,31,0,0,31,0,0,31,0,0,31,0,0,31,0,0,31,0,0,31,0,
0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,
0,7,0,0,7,0,0,7,0,0,7,0,0,7,0,0,7,0,0,7,0,0,7,0,
0,3,0,0,3,0,0,3,0,0,3,0,0,3,0,0,3,0,0,3,0,0,3,0,
0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255, //绿
0,0,127,0,0,127,0,0,127,0,0,127,0,0,127,0,0,127,0,0,127,0,0,127,
0,0,63,0,0,63,0,0,63,0,0,63,0,0,63,0,0,63,0,0,63,0,0,63,
0,0,31,0,0,31,0,0,31,0,0,31,0,0,31,0,0,31,0,0,31,0,0,31,
0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,
0,0,7,0,0,7,0,0,7,0,0,7,0,0,7,0,0,7,0,0,7,0,0,7,
0,0,3,0,0,3,0,0,3,0,0,3,0,0,3,0,0,3,0,0,3,0,0,3,
0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0, //蓝
127,0,0,127,0,0,127,0,0,127,0,0,127,0,0,127,0,0,127,0,0,127,0,0,
63,0,0,63,0,0,63,0,0,63,0,0,63,0,0,63,0,0,63,0,0,63,0,0,
31,0,0,31,0,0,31,0,0,31,0,0,31,0,0,31,0,0,31,0,0,31,0,0,
15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,
7,0,0,7,0,0,7,0,0,7,0,0,7,0,0,7,0,0,7,0,0,7,0,0,
3,0,0,3,0,0,3,0,0,3,0,0,3,0,0,3,0,0,3,0,0,3,0,0,
1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0,255,255,0,255,255,0,255,255,0,255,255,0,255,255,0,255,255,0,255,255, //黄
0,127,127,0,127,127,0,127,127,0,127,127,0,127,127,0,127,127,0,127,127,0,127,127,
0,63,63,0,63,63,0,63,63,0,63,63,0,63,63,0,63,63,0,63,63,0,63,63,
0,31,31,0,31,31,0,31,31,0,31,31,0,31,31,0,31,31,0,31,31,0,31,31,
0,15,15,0,15,15,0,15,15,0,15,15,0,15,15,0,15,15,0,15,15,0,15,15,
0,7,7,0,7,7,0,7,7,0,7,7,0,7,7,0,7,7,0,7,7,0,7,7,
0,3,3,0,3,3,0,3,3,0,3,3,0,3,3,0,3,3,0,3,3,0,3,3,
0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0,255,255,0,255,255,0,255,255,0,255,255,0,255,255,0,255,255,0,255,255,0, //紫
127,127,0,127,127,0,127,127,0,127,127,0,127,127,0,127,127,0,127,127,0,127,127,0,
63,63,0,63,63,0,63,63,0,63,63,0,63,63,0,63,63,0,63,63,0,63,63,0,
31,31,0,31,31,0,31,31,0,31,31,0,31,31,0,31,31,0,31,31,0,31,31,0,
15,15,0,15,15,0,15,15,0,15,15,0,15,15,0,15,15,0,15,15,0,15,15,0,
7,7,0,7,7,0,7,7,0,7,7,0,7,7,0,7,7,0,7,7,0,7,7,0,
3,3,0,3,3,0,3,3,0,3,3,0,3,3,0,3,3,0,3,3,0,3,3,0,
1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,255,255,0,255,255,0,255,255,0,255,255,0,255,255,0,255,255,0,255,255,0,255, //青
127,0,127,127,0,127,127,0,127,127,0,127,127,0,127,127,0,127,127,0,127,127,0,127,
63,0,63,63,0,63,63,0,63,63,0,63,63,0,63,63,0,63,63,0,63,63,0,63,
31,0,31,31,0,31,31,0,31,31,0,31,31,0,31,31,0,31,31,0,31,31,0,31,
15,0,15,15,0,15,15,0,15,15,0,15,15,0,15,15,0,15,15,0,15,15,0,15,
7,0,7,7,0,7,7,0,7,7,0,7,7,0,7,7,0,7,7,0,7,7,0,7,
3,0,3,3,0,3,3,0,3,3,0,3,3,0,3,3,0,3,3,0,3,3,0,3,
1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
};//取模要求:阴码(亮点为1),逐列式取模,高位在下
//点阵屏摆放方向不同,取模要求也不同,很多函数也需要修改
unsigned char code Table1[]={ //“<<SNAKE>>”
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //无显示
0x00,0x08,0x14,0x22,0x49,0x14,0x22,0x41, // << 宽8高8
0x00,0x46,0x49,0x49,0x49,0x31, // S 51 宽6高8
0x00,0x7F,0x04,0x08,0x10,0x7F, // N 46
0x00,0x7C,0x12,0x11,0x12,0x7C, // A 33
0x00,0x7F,0x08,0x14,0x22,0x41, // K 43
0x00,0x7F,0x49,0x49,0x49,0x41, // E 37
0x00,0x41,0x22,0x14,0x49,0x22,0x14,0x08, // >>
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //无显示
};
unsigned char code Table2[]={ //“DIFFICULTY”,宽6高8
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //无显示
0x00,0x7F,0x41,0x41,0x22,0x1C, // D 36
0x00,0x00,0x41,0x7F,0x41,0x00, // I 41
0x00,0x7F,0x09,0x09,0x09,0x01, // F 38
0x00,0x7F,0x09,0x09,0x09,0x01, // F 38
0x00,0x00,0x41,0x7F,0x41,0x00, // I 41
0x00,0x3E,0x41,0x41,0x41,0x22, // C 35
0x00,0x3F,0x40,0x40,0x40,0x3F, // U 53
0x00,0x7F,0x40,0x40,0x40,0x40, // L 44
0x00,0x01,0x01,0x7F,0x01,0x01, // T 52
0x00,0x07,0x08,0x70,0x08,0x07, // Y 57
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //无显示
0x00,0x00,0x00,0x42,0x7F,0x40,0x00,0x00, // 1 17 如果不按按键跳过,则在显示“1”后自动切换到下一个模式
};
unsigned char code Table3[]={ //“123451”,宽8高8
0x00,0x00,0x00,0x42,0x7F,0x40,0x00,0x00, // 1 17
0x00,0x00,0x42,0x61,0x51,0x49,0x46,0x00, // 2 18
0x00,0x00,0x21,0x41,0x45,0x4B,0x31,0x00, // 3 19
0x00,0x00,0x18,0x14,0x12,0x7F,0x10,0x00, // 4 20
0x00,0x00,0x27,0x45,0x45,0x45,0x39,0x00, // 5 21
0x00,0x00,0x00,0x42,0x7F,0x40,0x00,0x00, // 1 17
};
unsigned char code Table4[]={ //“SCORE”,宽6高8
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //无显示
0x00,0x46,0x49,0x49,0x49,0x31, // S 51
0x00,0x3E,0x41,0x41,0x41,0x22, // C 35
0x00,0x3E,0x41,0x41,0x41,0x3E, // O 47
0x00,0x7F,0x09,0x19,0x29,0x46, // R 50
0x00,0x7F,0x49,0x49,0x49,0x41, // E 37
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //无显示
};
unsigned char code Table5[]={ //“0~9”,宽6高8
0x00,0x3E,0x51,0x49,0x45,0x3E, // 0 16
0x00,0x00,0x42,0x7F,0x40,0x00, // 1 17
0x00,0x42,0x61,0x51,0x49,0x46, // 2 18
0x00,0x21,0x41,0x45,0x4B,0x31, // 3 19
0x00,0x18,0x14,0x12,0x7F,0x10, // 4 20
0x00,0x27,0x45,0x45,0x45,0x39, // 5 21
0x00,0x3C,0x4A,0x49,0x49,0x30, // 6 22
0x00,0x01,0x71,0x09,0x05,0x03, // 7 23
0x00,0x36,0x49,0x49,0x49,0x36, // 8 24
0x00,0x06,0x49,0x49,0x29,0x1E, // 9 25
};
unsigned char code Table6[]={ //“by gantengsheng at 20241225”,宽6高8
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //无显示
0x00,0x7F,0x48,0x44,0x44,0x38, // b 66
0x00,0x1C,0xA0,0xA0,0xA0,0x7C, // y 89
0x00,0x00,0x00,0x00,0x00,0x00, // 0
0x00,0x18,0xA4,0xA4,0xA4,0x7C, // g 71
0x00,0x20,0x54,0x54,0x54,0x78, // a 65
0x00,0x7C,0x08,0x04,0x04,0x78, // n 78
0x00,0x04,0x3F,0x44,0x40,0x20, // t 84
0x00,0x38,0x54,0x54,0x54,0x18, // e 69
0x00,0x7C,0x08,0x04,0x04,0x78, // n 78
0x00,0x18,0xA4,0xA4,0xA4,0x7C, // g 71
0x00,0x48,0x54,0x54,0x54,0x20, // s 83
0x00,0x7F,0x08,0x04,0x04,0x78, // h 72
0x00,0x38,0x54,0x54,0x54,0x18, // e 69
0x00,0x7C,0x08,0x04,0x04,0x78, // n 78
0x00,0x18,0xA4,0xA4,0xA4,0x7C, // g 71
0x00,0x00,0x00,0x00,0x00,0x00, // 0
0x00,0x20,0x54,0x54,0x54,0x78, // a 65
0x00,0x04,0x3F,0x44,0x40,0x20, // t 84
0x00,0x00,0x00,0x00,0x00,0x00, // 0
0x00,0x42,0x61,0x51,0x49,0x46, // 2 18
0x00,0x3E,0x51,0x49,0x45,0x3E, // 0 16
0x00,0x42,0x61,0x51,0x49,0x46, // 2 18
0x00,0x18,0x14,0x12,0x7F,0x10, // 4 20
0x00,0x00,0x42,0x7F,0x40,0x00, // 1 17
0x00,0x42,0x61,0x51,0x49,0x46, // 2 18
0x00,0x42,0x61,0x51,0x49,0x46, // 2 18
0x00,0x27,0x45,0x45,0x45,0x39, // 5 21
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //无显示
};/*** @brief 创造出一个随机位置的食物* @param 无* @retval 创造出的食物位置的数据,高四位(0~7)对应1~8列(从左到右),低四位(0~7)对应1~8行(从上到下)*/
unsigned char CreateFood(void)
{unsigned char FoodTemp;unsigned char i,j,m,n;m=rand()%8; //产生一个0~7的随机数n=rand()%8; //产生一个0~7的随机数for(i=0;i<8;i++) //产生一个随机位置,判断该位置是否是蛇身{ //如果不是,就返回该位置所对应的数据,如果是蛇身的位置,则从该点向周围寻找不是蛇身的空位置for(j=0;j<8;j++){if( ( SnakeBuffer[(m+i)%8] & (0x01<<((n+j)%8)) ) == 0 ){FoodTemp=(m+i)%8*16+(n+j)%8;break; //找到了空位置就退出循环}}}return FoodTemp;
}/*** @brief 改变缓存数组SnakeBuffer的数据* @param Position 要设置的位置,高四位(0~7)对应1~8列(从左到右),低四位(0~7)对应1~8行(从上到下)* @param State 要修改成的状态,范围:0~1,0:对应的那个Bit置0,1:对应的那个Bit置1* @retval 无*/
void ChangeSnakeBuffer(unsigned char Position,unsigned char State)
{if(State){SnakeBuffer[Position/16] |= (0x01<<(Position%16));}else{SnakeBuffer[Position/16] &= ~(0x01<<(Position%16));}
}/*** @brief 控制蛇的移动* @param 无* @retval 无*/
void MoveSnake(void)
{if(NowDirection==1) //如果向右移动{//移动前判断一下移动后是否撞墙,如果是,则游戏结束,游戏结束的标志置1if(SnakeBody[Head]/16==7){GameOverFlag=1;}//(Head+1)%64,取余的目的是为了防止越界,SnakeBody数组的索引范围是:0~63,索引为63后再加1,就越界了//SnakeBody数组中索引为(Head+1)%64的数据(准蛇头)等于索引为Head的数据(现蛇头)加16(高四位加1),即蛇头移动到了右边这一列else{SnakeBody[(Head+1)%64]=SnakeBody[Head]+16;}}if(NowDirection==2) //如果向上移动{if(SnakeBody[Head]%16==0){GameOverFlag=1;}//SnakeBody数组中索引为(Head+1)%64的数据(准蛇头)等于索引为Head的数据(现蛇头)减1(低四位减1),即蛇头移动到了上边这一行else{SnakeBody[(Head+1)%64]=SnakeBody[Head]-1;}}if(NowDirection==3) //如果向左移动{if(SnakeBody[Head]/16==0){GameOverFlag=1;}//SnakeBody数组中索引为(Head+1)%64的数据(准蛇头)等于索引为Head的数据(现蛇头)减16(高四位减1),即蛇头移动到了左边这一列else{SnakeBody[(Head+1)%64]=SnakeBody[Head]-16;}}if(NowDirection==4) //如果向下移动{if(SnakeBody[Head]%16==7){GameOverFlag=1;}//SnakeBody数组中索引为(Head+1)%64的数据(准蛇头)等于索引为Head的数据(现蛇头)加1(低四位减1),即蛇头移动到了下边这一行else{SnakeBody[(Head+1)%64]=SnakeBody[Head]+1;}}Head++; //SnakeBody数组中,蛇头对应的数据的索引加1Head%=64; //蛇头变量Head的范围是0~63if(GameOverFlag==0) //如果没撞墙{if(SnakeBody[Head]==Food) //判断蛇头移动后的位置是否是食物所在的位置{ //如果是Length++; //蛇身长度加1ColorStyle++; //蛇身和食物均切换为下一种颜色ColorStyle%=6; //预设了6种颜色:红、绿、蓝、黄、紫、青ChangeSnakeBuffer(Food,1); //更新缓存数组SnakeBody的数据if(Length<64) //如果蛇身长度没有达到最大值64{Food=CreateFood(); //重新创造一个食物}else //如果蛇身长度达到了最大值64{GameOverFlag=1; //游戏结束}FlashFlag=0; //创造出新的食物时,食物暂不闪烁T0Count4=0; //定时器T0Count4重新计数}else if( SnakeBuffer[SnakeBody[Head]/16] & (0x01<<(SnakeBody[Head]%16)) ){ //如果蛇头移动后的位置不是食物,且撞在蛇身上,则游戏结束GameOverFlag=1; //游戏结束的标志置1}else //如果蛇头移动后的位置不是食物,也不是撞墙,也不是撞到蛇身的话{ChangeSnakeBuffer(SnakeBody[Head],1);ChangeSnakeBuffer(SnakeBody[(Head+64-Length)%64],0);}}}/*** @brief IO口初始化,全部设置为上拉模式* @param 无* @retval 无*/
void GPIO_Init(void)
{P0M1=0;P0M0=0;P1M1=0;P1M0=0;P2M1=0;P2M0=0;P3M1=0;P3M0=0;P4M1=0;P4M0=0;P5M1=0;P5M0=0;P6M1=0;P6M0=0;P7M1=0;P7M0=0;
}void main()
{unsigned char i;WTST=0; //不加这句,则延时不准确GPIO_Init(); //IO口初始化Timer0_Init(); //定时器初始化ExecuteOnceFlag=1;while(1){KeyNum=Key(); //获取键码值if(KeyNum) //如果有按键按下{srand(TL0); //以定时器0的低八位数据作为随机数的种子,用来产生真随机的数据if(Mode==8) //如果是显示作者和编程日期的界面{if(KeyNum==44) //如果按下K12(松手瞬间){Mode=3; //返回难度选择界面ExecuteOnceFlag=1; //各模式只执行一次代码的标志置1}}if(Mode==7) //如果是滚动显示得分的界面{if(KeyNum==41) //如果按下K9(松手瞬间){Mode=8; //切换到显示作者和编程日期的界面ExecuteOnceFlag=1;}if(KeyNum==44) //如果按下K12(松手瞬间){Mode=3; //返回难度选择界面ExecuteOnceFlag=1;}}if(Mode==6) //如果是滚动显示英文“SCORE”的界面{if(KeyNum!=9 && KeyNum!=25 && KeyNum!=41 && KeyNum!=12 && KeyNum!=28 && KeyNum!=44){ //如果按下K9和K12以外的按键Mode=7; //跳过英文显示,切换到滚动显示得分界面ExecuteOnceFlag=1;}}if(Mode==5) //如果是游戏结束全屏闪烁界面{if(KeyNum==48) //如果按下K16(松手瞬间){Mode=6; //切换到滚动显示英文“SCORE”的界面ExecuteOnceFlag=1;}}if(Mode==4) //如果是游戏进行中{if(KeyNum==48) //按下K16暂停或继续(松手瞬间){PauseFlag=!PauseFlag;if(PauseFlag==0){T0Count3=0;}}if(PauseFlag==0) //如果不是暂停{ //按下瞬间、长按、松手瞬间都进行检测,这样控制方向更有效,防止按键没检测出来导致没能改变方向if((KeyNum==13 || KeyNum==29 || KeyNum==45) && LastDirection!=1){ //如果按了“左”键,且蛇头原来的移动方向不是向右NowDirection=3; //则方向蛇头方向改为向左}if((KeyNum==10 || KeyNum==26 || KeyNum==42) && LastDirection!=4){ //如果按了“上”键,且蛇头原来的移动方向不是向下NowDirection=2; //则方向蛇头方向改为向上}if((KeyNum==14 || KeyNum==30 || KeyNum==46) && LastDirection!=2){ //如果按了“下”键,且蛇头原来的移动方向不是向上NowDirection=4; //则方向蛇头方向改为向左}if((KeyNum==15 || KeyNum==31 || KeyNum==47) && LastDirection!=3){ //如果按了“右”键,且蛇头原来的移动方向不是向左NowDirection=1; //则方向蛇头方向改为向左}}}if(Mode==3) //如果是难度选择界面{if(KeyNum==42) //如果按了“上”键K10(松手瞬间){RollUpFlag=1; //数字向上滚动的标志置1}if(KeyNum==46) //如果按了“下”键K14(松手瞬间){RollDownFlag=1; //数字向下滚动的标志置1}if(KeyNum==48) //如果按了开始键K16(松手瞬间){Mode=4; //切换到游戏模式ExecuteOnceFlag=1;}}if(Mode==2) //如果是显示英文“DIFFICULTY”的界面{if(KeyNum>=33 && KeyNum<=48) //如果按下任意按键(松手瞬间){Mode=3; //切换到难度选择界面ExecuteOnceFlag=1;}}if(Mode==1) //如果是显示游戏名“<<SNAKE>>”的界面{if(KeyNum>=33 && KeyNum<=48) //如果按下任意按键(松手瞬间){Mode=2; //切换到英文“DIFFICULTY”的显示界面ExecuteOnceFlag=1;}}if(Mode==0) //如果是显示流水灯界面{if(KeyNum==42) //如果按了“上”键K10(松手瞬间){Mode0++; //切换子模式Mode0%=3; //共有三个子模式ExecuteOnceFlag0=1;}if(KeyNum==46) //如果按了“下”键K14(松手瞬间){if(Mode0==0){Mode0=2;}else{Mode0--;}ExecuteOnceFlag0=1;}if(KeyNum>=33 && KeyNum<=48 && KeyNum!=42 && KeyNum!=46){ //如果按了K10和K14以外的按键(松手瞬间),切换为显示游戏名“<<SNAKE>>”的模式Mode=1; //切换到游戏模式ExecuteOnceFlag=1;}}}if(Mode==0) //如果是显示彩色流水灯的界面{if(ExecuteOnceFlag) //切换模式前,此if的内容只执行一次{ExecuteOnceFlag=0;Offset1=0; //偏移量清零for(i=0;i<8;i++) //呼吸灯需要用到数组SnakeBuffer{SnakeBuffer[i]=0xFF;}}if(Mode0==0) //拖尾流水灯(六种颜色:红、绿、蓝、黄、紫、青)显示数据传输顺序{if(ExecuteOnceFlag0) //切换到Mode0==0后,切换为其他模式前,此if的代码只执行一次{ExecuteOnceFlag0=0;Offset1=0; //偏移量清零}if(RollFlag){RollFlag=0;for(i=0;i<192;i++) //通过查表的方法显示流水灯{WS2812B_Buffer[i]=FlowingWaterLight1[191-i+3*Offset1];}WS2812B_UpdateDisplay(); //改变缓存WS2812B_Buffer后,更新到屏幕的显示Offset1++;Offset1%=400;}}if(Mode0==1) //显示从左到右的六种颜色(红、绿、蓝、黄、紫、青)的拖尾流水灯{if(ExecuteOnceFlag0){ExecuteOnceFlag0=0;Offset1=0;} if(RollFlag){RollFlag=0;for(i=0;i<192;i++) //通过查表的方法显示流水灯{WS2812B_Buffer[i]=FlowingWaterLight2[191-i+24*Offset1];}WS2812B_UpdateDisplay();Offset1++;Offset1%=96;}}if(Mode0==2) //六种颜色(红、绿、蓝、黄、紫、青)的呼吸灯{if(ExecuteOnceFlag0){ExecuteOnceFlag0=0;Breath=1;BreathInOrOut=1;BreathColor=0;}if(BreathFlag){BreathFlag=0;if(Breath==0 && BreathCount<15){BreathCount++;PauseFlag=1;} //完全熄灭后延时一小段时间else{BreathCount=0;PauseFlag=0;}if(PauseFlag==0){if(Breath==0){BreathInOrOut=1;BreathColor++;BreathColor%=6;}if(Breath==255){BreathInOrOut=0;} //Breath的值决定亮度if(BreathInOrOut){Breath++;} //变亮else{Breath--;} //变暗switch(BreathColor){case 0:WS2812B_MoveLeft(SnakeBuffer,Breath,0,0,0);break; //红case 1:WS2812B_MoveLeft(SnakeBuffer,0,Breath,0,0);break; //绿case 2:WS2812B_MoveLeft(SnakeBuffer,0,0,Breath,0);break; //蓝case 3:WS2812B_MoveLeft(SnakeBuffer,(unsigned char)(Breath/2),(unsigned char)(Breath/2),0,0);break; //黄case 4:WS2812B_MoveLeft(SnakeBuffer,(unsigned char)(Breath/2),0,(unsigned char)(Breath/2),0);break; //紫case 5:WS2812B_MoveLeft(SnakeBuffer,0,(unsigned char)(Breath/2),(unsigned char)(Breath/2),0);break; //青default:break;}WS2812B_UpdateDisplay();}}}}if(Mode==1) //如果是显示游戏名称“<<SNAKE>>”的界面{if(ExecuteOnceFlag){ExecuteOnceFlag=0;Offset1=0;}if(RollFlag){RollFlag=0;WS2812B_MoveLeft(Table1,16,0,0,Offset1); //红色WS2812B_UpdateDisplay();Offset1++;Offset1%=54; //循环滚动显示}}if(Mode==2) //如果是显示英文“DIFFICULTY”的界面{if(ExecuteOnceFlag){ExecuteOnceFlag=0;Offset1=0;}if(RollFlag) //只向左滚动显示一次,不循环滚动显示{if(Offset1<=68) //只向左滚动显示一次,不循环滚动显示{RollFlag=0;WS2812B_MoveLeft(Table2,0,16,0,Offset1); //绿色WS2812B_UpdateDisplay();Offset1++;}else if(Offset1<=76) //只向左滚动显示一次,不循环滚动显示{RollFlag=0;WS2812B_MoveLeft(Table2,0,0,16,Offset1); //蓝色WS2812B_UpdateDisplay();Offset1++;}else //显示数字“1”之后,自动切换到难度选择界面{Mode=3;ExecuteOnceFlag=1;}}}if(Mode==3) //如果是难度选择界面{if(ExecuteOnceFlag){ExecuteOnceFlag=0;WS2812B_MoveUp(Table3,0,0,16,Offset2); //蓝色WS2812B_UpdateDisplay();}if(RollFlag && RollUpFlag) //如果滚动标志为1,且向上滚动的标志也为1{RollFlag=0;Offset2++; //向上移动一个像素Offset2%=40; //越界清零,总共5个数字,每个数字的高度是8,所以是5*8=40WS2812B_MoveUp(Table3,0,0,16,Offset2);WS2812B_UpdateDisplay();RollCount++;if(RollCount==8) //移动了8个像素后停止移动{RollCount=0;RollUpFlag=0;Offset2=(Offset2/8)*8; //防止移动到一半的时候按下“上”或“下”按键导致数字没有在点阵屏中间//Offset2的值必须是8的整数倍switch(Offset2/8){case 0:SnakeMoveSpeed=1000;break; //难度1,1s移动1次case 1:SnakeMoveSpeed=750;break; //难度2,0.75s移动1次case 2:SnakeMoveSpeed=500;break; //难度3,0.5s移动1次case 3:SnakeMoveSpeed=250;break; //难度4,0.25s移动1次case 4:SnakeMoveSpeed=120;break; //难度5,0.12s移动1次default:break;}}}if(RollFlag && RollDownFlag) //如果滚动标志为1,且向下滚动的标志也为1{RollFlag=0;if(Offset2==0){Offset2=40;}Offset2--;WS2812B_MoveUp(Table3,0,0,16,Offset2);WS2812B_UpdateDisplay();RollCount++;if(RollCount==8){RollCount=0;RollDownFlag=0;Offset2=(Offset2/8)*8;switch(Offset2/8){case 0:SnakeMoveSpeed=1000;break;case 1:SnakeMoveSpeed=750;break;case 2:SnakeMoveSpeed=500;break;case 3:SnakeMoveSpeed=250;break;case 4:SnakeMoveSpeed=120;break;default:break;}}}}if(Mode==4) //如果是游戏进行模式{if(ExecuteOnceFlag) //游戏初始化{ExecuteOnceFlag=0;WS2812B_Clear(); //清除WS2812B显示缓存ColorStyle=rand()%6; //从预设的六种颜色中随机选一种作为蛇的起始颜色GameOverFlag=0; //游戏结束标志清零PauseFlag=0; //游戏暂停标志清零NowDirection=1; //蛇头默认向右移动LastDirection=1; //上一次蛇头默认向右移动Length=2; //蛇的初始长度为2Head=1; //蛇头对应数组中的第2个数据(索引为1)for(i=0;i<8;i++){SnakeBuffer[i]=0;} //SnakeBuffer显示缓存全部清零SnakeBody[0]=1*16+1; //蛇身数据全部清零后,写入蛇身初始的两个数据SnakeBody[1]=2*16+1;ChangeSnakeBuffer(SnakeBody[0],1);ChangeSnakeBuffer(SnakeBody[1],1);WS2812B_SetBuf(SnakeBody[0],MyColor[ColorStyle%6*3],MyColor[ColorStyle%6*3+1],MyColor[ColorStyle%6*3+2]);WS2812B_SetBuf(SnakeBody[1],MyColor[ColorStyle%6*3],MyColor[ColorStyle%6*3+1],MyColor[ColorStyle%6*3+2]);Food=CreateFood(); //开始游戏前,先创造出一个食物WS2812B_SetBuf(Food,MyColor[(ColorStyle+1)%6*3],MyColor[(ColorStyle+1)%6*3+1],MyColor[(ColorStyle+1)%6*3+2]);WS2812B_UpdateDisplay(); //更改缓存后,更新屏幕的显示MoveFlag=0; //蛇移动的标志清零T0Count3=0; //定时器计数变量T0Count3清零,重新计数}if(GameOverFlag==0) //如果游戏没结束{if(MoveFlag && PauseFlag==0){MoveFlag=0; //移动标志清零MoveSnake(); //移动一次LastDirection=NowDirection; //保存上一次移动的方向,用于按键的判断(蛇不能往后移动)WS2812B_MoveLeft(SnakeBuffer,MyColor[ColorStyle%6*3],MyColor[ColorStyle%6*3+1],MyColor[ColorStyle%6*3+2],0);}if(PauseFlag) //如果暂停了{ //(ColorStyle+1)%6:食物的颜色是预设模式中,蛇的颜色的下一种颜色,预设颜色:红绿蓝黄紫青WS2812B_SetBuf(Food,MyColor[(ColorStyle+1)%6*3],MyColor[(ColorStyle+1)%6*3+1],MyColor[(ColorStyle+1)%6*3+2]); //食物不闪烁,一直显示} else if(FlashFlag) //如果不暂停,且闪烁标志为1{WS2812B_SetBuf(Food,0,0,0); //不显示食物}else //如果不暂停,且闪烁标志为0{WS2812B_SetBuf(Food,MyColor[(ColorStyle+1)%6*3],MyColor[(ColorStyle+1)%6*3+1],MyColor[(ColorStyle+1)%6*3+2]); //显示食物}WS2812B_UpdateDisplay();}else //如果游戏结束{Mode=5; //切换到全屏闪烁模式ExecuteOnceFlag=1; } }if(Mode==5) //全屏闪烁{if(FlashFlag) //不显示{WS2812B_Clear();WS2812B_UpdateDisplay();}else //显示{WS2812B_MoveLeft(SnakeBuffer,MyColor[ColorStyle%6*3],MyColor[ColorStyle%6*3+1],MyColor[ColorStyle%6*3+2],0);if(Length<64) //防止长度为64时有一个点的颜色(食物的颜色)跟其它的不一样{WS2812B_SetBuf(Food,MyColor[(ColorStyle+1)%6*3],MyColor[(ColorStyle+1)%6*3+1],MyColor[(ColorStyle+1)%6*3+2]);}WS2812B_UpdateDisplay(); }}if(Mode==6) //如果是显示英文“SCROE”的界面{if(ExecuteOnceFlag){ExecuteOnceFlag=0;Offset1=0;}if(RollFlag){if(Offset1<=38) //只滚动显示一次英文“SCORE”{RollFlag=0;WS2812B_MoveLeft(Table4,8,8,0,Offset1); //黄色WS2812B_UpdateDisplay();Offset1++;}else //滚动结束后,自动切换到循环显示得分的模式{Mode=7;ExecuteOnceFlag=1;} }}if(Mode==7) //如果是滚动显示得分界面{if(ExecuteOnceFlag){ExecuteOnceFlag=0;for(i=0;i<6;i++) //将得分(即蛇身的长度)的十位和个位的字模写入数组ScoreShow中{Score[8+i]=Table5[(Length/10)*6+i];}for(i=0;i<6;i++){Score[14+i]=Table5[(Length%10)*6+i];}Offset1=0;}if(RollFlag) //如果滚动的标志为1{RollFlag=0;WS2812B_MoveLeft(Score,8,0,8,Offset1); //紫色WS2812B_UpdateDisplay();Offset1++;Offset1%=20; //循环滚动}}if(Mode==8) //如果是显示作者和编程日期的界面{if(ExecuteOnceFlag){ExecuteOnceFlag=0;Offset1=0;}if(RollFlag) //如果滚动的标志为1{RollFlag=0;WS2812B_MoveLeft(Table6,0,8,8,Offset1); //青色WS2812B_UpdateDisplay();Offset1++;Offset1%=170; //循环滚动}}}
}void Timer0_Routine() interrupt 1 //定时器0中断函数
{TL0=0x80; //设置定时初值,定时2ms,1T@24.000MHzTH0=0x44; //设置定时初值,定时2ms,1T@24.000MHzT0Count1++;T0Count2++;if(PauseFlag==0){T0Count3++;} //不暂停时,T0Count3才计数else{T0Count3=0;} //暂停后继续游戏时,T0Count3重新计数T0Count4++;T0Count5++;if(T0Count1>=10) //每隔20ms检测一次按键{T0Count1=0;Key_Tick();}if(T0Count2>=50) //每隔100ms滚动一次{T0Count2=0;RollFlag=1;}if(T0Count3>=SnakeMoveSpeed/2) //控制蛇的移动速度{T0Count3=0;MoveFlag=1;}if(T0Count4>=125) //每隔250ms改变FlashFlag的值{T0Count4=0;FlashFlag=!FlashFlag;}if(T0Count5>=3) //每隔6ms呼吸灯的亮度改变一次{T0Count5=0;BreathFlag=1;}
}
总结
用彩色点阵屏玩《贪吃蛇》更有趣了,可以显示不同的颜色,弄出很多花样。
相关文章:
基于51单片机(STC32G12K128)和8X8彩色点阵屏(WS2812B驱动)的小游戏《贪吃蛇》
目录 系列文章目录前言一、效果展示二、原理分析三、各模块代码1、定时器02、矩阵按键模块3、8X8彩色点阵屏 四、主函数总结 系列文章目录 前言 《贪吃蛇》,一款经典的、怀旧的小游戏,单片机入门必写程序。 以《贪吃蛇》为载体,熟悉各种屏幕…...
Ceph 手动部署(CentOS9)
#Ceph手动部署、CentOS9、squid版本、数字版本19.2.0 #部署服务:块、对象、文件 一、部署前规划 1、兼容性确认 2、资源规划 节点类型节点名称操作系统CPU/内存硬盘网络组件安装集群节点CephAdm01CentOS94U/8GOS:40G,OSD:2*100GIP1:192.169.0.9(管理&集群),IP2:…...
Reactor测试框架之StepVerifier
Reactor测试框架之StepVerifier 测试步骤1、创建StepVerifier实例2、添加断言3、执行验证 代码实例 在响应式编程中,Reactor框架提供了StepVerifier测试类,用于对响应式序列进行断言和验证。StepVerifier主要用于对Publisher发出的元素序列进行逐步的、精…...
unity 播放 序列帧图片 动画
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、方法一:代码控制播放序列帧1、设置图片属性2、创建Image组件3、简单的代码控制4、挂载代码并赋值 二、方法二:直接使用1.Image上添加…...
1-markdown转网页样式页面 --[制作网页模板] 【测试代码下载】
markdown转网页 将Markdown转换为带有样式的网页页面通常涉及以下几个步骤:首先,需要使用Markdown解析器将Markdown文本转换为HTML;其次,应用CSS样式来美化HTML内容。此外,还可以加入JavaScript以增加交互性。下面我将…...
ubuntu 创建服务、查看服务日志
1. 在 /etc/systemd/system/ 下创建文件,名称为 xxx.service [Unit] DescriptionYour Service Description Afternetwork.target[Service] Typesimple ExecStart/path/to/your/service/executable Restarton-failure[Install] WantedBymulti-user.target2. 配置服务…...
[python3]Excel解析库-openpyxl
https://openpyxl.readthedocs.io/en/stable/ openpyxl 是一个用于读写 Excel 2010 xlsx/xlsm/xltx/xltm 文件的 Python 库。它允许开发者创建、修改和保存电子表格,而无需依赖 Microsoft Excel 软件本身。openpyxl 支持读取和写入 Excel 的工作簿(Work…...
使用 LlamaIndex 构建智能文档查询系统
使用 LlamaIndex 构建智能文档查询系统 1. 环境准备2. 初始化模型3. 加载文档4. 构建索引和查询引擎5. 生成扩展查询6. 主函数7. 总结 在现代信息检索系统中,如何高效地从大量文档中提取出有用的信息是一个重要的挑战。本文将介绍如何使用 LlamaIndex 构建一个智能文…...
C++——继承
目录 前言 1. 继承的概念和定义 1.1 继承的概念 1.2 继承的定义 1.2.1 定义格式 1.2.2 继承基类成员访问方式的变化 1.3 继承类模板 2. 基类和派生类之间的转换 3. 继承中的作用域 3.1 隐藏规则 3.2 考察继承作用域相关选择题 4. 派生类的默认成员函数 4.1 4个常…...
01:C语言的本质
C语言的本质 1、ARM架构与汇编2、局部变量初始化与空间分配2.1、局部变量的初始化2.1、局部变量数组初始化 3、全局变量/静态变量初始化化与空间分配4、堆空间5、函数 1、ARM架构与汇编 ARM简要架构如下:CPU,ARM(能读能写),Flash(…...
Jmeter进阶篇(32)Jmeter 在 MySQL 数据库压测中的应用
一、引言 在当今数字化时代,数据库性能的优化对于企业的发展至关重要。随着业务量的不断增长,数据库需要承受越来越大的压力。MySQL作为一种广泛使用的开源数据库,其性能和稳定性备受关注。为了确保数据库在高负载情况下能够正常运行,进行压测是必不可少的环节。Jmeter作为…...
TCPDump参数详解及示例
TCPDump参数详解及示例 TCPDump参数详解TCPDump -G的示例TCPDump -i any -s 2048 -G 600 -p udp -Z root -n -X -tt -w %Y_%m%d_%H%M_%S.pcap &的含义TCPDump是一款强大的网络数据包截获分析工具,可以将网络中传送的数据包的完全截获下来提供分析。它支持针对网络层、协议…...
Protocol Buffer
1、什么是 Protocol Buffers? Protocol Buffers (protobuf) 是一种序列化结构化数据的方法,由 Google 开发。它们提供了一种与语言无关、与平台无关且可扩展的机制,用于高效序列化结构化数据。 Protocol Buffers 中的…...
高等数学学习笔记 ☞ 连续与间断
1. 连续 1. 点连续定义: 设函数在点的某邻域内有定义,取附近的点,对应的函数值分别和, 令,当时,若,则称函数在点处连续。 记作。 此式为增量形式。 又知,则可改写为:。 …...
【three.js】Shader着色器
原始着色器材质RawShaderMaterial 两种着色器材质的 RawShaderMaterial 和 ShaderMaterial 的区别和用法 区别: ShaderMaterial 会自动将一些初始化着色器的参数添加到代码中(内置 attributes 和 uniforms) RawShaderMaterial 则什么都不会添…...
在 macOS 中,设置自动将文件夹排在最前
文章目录 1、第一步访达设置2、第二步排序方式 需要两步设置 1、第一步访达设置 按名称排序的窗口中 2、第二步排序方式 选择名称...
创建并配置华为云虚拟私有云
目录 私有云 创建虚拟私有云 私有云 私有云是一种云计算模式,它将云服务部署在企业或组织内部的私有基础设施上,仅供该企业或组织内部使用,不对外提供服务.私有云的主要特点包括: 私密性:私有云的资源(如…...
Spark是什么?Flink和Spark区别
Spark是什么?Flink和Spark区别 一、Spark二、Spark和Flink区别三、总结 一、Spark Apache Spark 是一个开源的大数据处理框架,主要用于大规模数据处理和分析。它支持多种数据处理模式,包括批处理、流处理、SQL 查询、机器学习和图处理等。 核…...
代码随想录 day 25
第七章 回溯算法 part04 491.递增子序列 本题和大家刚做过的 90.子集II 非常像,但又很不一样,很容易掉坑里。 https://programmercarl.com/0491.%E9%80%92%E5%A2%9E%E5%AD%90%E5%BA%8F%E5%88%97.html 视频讲解:https://www.bilibili.com/…...
数据仓库中的指标体系模型介绍
数据仓库中的指标体系介绍 文章目录 数据仓库中的指标体系介绍前言什么是指标体系指标体系设计有哪些模型?1. 指标分层模型2. 维度模型3. 指标树模型4. KPI(关键绩效指标)模型5. 主题域模型6.平衡计分卡(BSC)模型7.数据指标框架模…...
xr-frame 通过shader去除视频背景色,加载透明视频
目录 前言 实现思路 获取 XR 框架系统: 注册自定义效果 创建效果对象 渲染通道配置 着色器代码 顶点着色器 片元着色器(颜色分量g达到条件的片元将被透透明) effect-removeBlack 完整代码 wxml中使用 前言 实现了一个用于注册自定…...
论文解读 | NeurIPS'24 IRCAN:通过识别和重新加权上下文感知神经元来减轻大语言模型生成中的知识冲突...
点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入! 点击 阅读原文 观看作者讲解回放! 作者简介 史丹,天津大学博士生 内容简介 大语言模型(LLM)经过海量数据训练后编码了丰富的世界知识。最近的研究表明,…...
Kraft模式安装Kafka(含常规、容器两种安装方式)
一、#创作灵感# 公司使用Kafka的软件项目较多,故写技术笔记巩固知识要点 二、软件环境 - Kafka 3.9.0 官方下载地址:Kafka 3.9.0 - Docker Desktop 4.37 容器图形化工具 官方下载地址:Docker Desktop 4.37 特别说明 - Docker Desktop…...
旷视科技C++面试题及参考答案
在 Linux 系统下常用的命令有哪些? 在 Linux 系统中有许多常用命令。首先是文件和目录操作相关的命令。“ls” 命令用于列出目录的内容,它有很多选项,比如 “ls -l” 可以以长格式显示文件和目录的详细信息,包括文件权限、所有者、大小、修改时间等;“ls -a” 则会显示所有…...
IWOA-GRU和GRU时间序列预测(改进的鲸鱼算法优化门控循环单元)
时序预测 | MATLAB实现IWOA-GRU和GRU时间序列预测(改进的鲸鱼算法优化门控循环单元) 目录 时序预测 | MATLAB实现IWOA-GRU和GRU时间序列预测(改进的鲸鱼算法优化门控循环单元)预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 MATLAB实现IWOA-GRU和GRU时间序列预测…...
edeg插件/扩展推荐:助力生活工作
WeTab 此插件在我看来有2个作用 1.改变edeg的主页布局和样式,使其更加精简,无广告 2.提供付费webtab Ai(底层是chatGpt) 沉浸式翻译 此插件可翻译网页的内容 假设我们浏览github 翻译前 翻译后 Better Ruler 可以对网页的距离进行测量 适合写前端的小伙伴 用法示例:...
TPS和QPS的区别
TPS全称(Transactions Per Second)QPS全称(Queries Per Second)它们都是衡量系统性能的指标,都是表示单位时间内处理的事务或者查询的数量 TPS 定义:TPS指的是系统每秒可以处理的事务数量,一个…...
鸿蒙HarmonyOS开发:拨打电话、短信服务、网络搜索、蜂窝数据、SIM卡管理、observer订阅管理
文章目录 一、call模块(拨打电话)1、使用makeCall拨打电话2、获取当前通话状态3、判断是否存在通话4、检查当前设备是否具备语音通话能力 二、sms模块(短信服务)1、创建短信2、发送短信 三、radio模块(网络搜索&#x…...
如何处理 JavaScript 中的函数防抖问题?
在 JavaScript 中,函数防抖(Debouncing)是一种控制函数执行频率的技术,通常用于处理用户输入事件(例如键盘输入、滚动事件等)。防抖的核心思想是:在连续触发某个事件时,只有在事件停…...
sql server期末复习
表操作 创建create 删除drop 修改alter 数据操作 查询 select from <tableName> 插入 insert into <tableName> values 修改 update <tableName> set 删除 delete from <tableName> 授权与收回对数据的操作权限 授予 grant <权…...
初学STM32 --- 外部SRAM
目录 SRAM简介 SRAM特性: XM8A51216 功能框图 8080并口读时序编辑 8080并口写时序 SRAM 读写操作步骤 FSMC介绍 FSMC时序介绍 FSMC控制器对内核地址映射编辑 FSMC HAL库相关驱动 SRAM驱动步骤 SRAM简介 静态随机存取存储器(Static Random-Access Memory&am…...
XXX公司面试真题
一、一面问题 1.线程池的主要参数 核心线程数最大线程数空闲线程存活时间存活时间单位任务队列线程工厂拒绝策略允许核心线程超时 2. 线程的状态 新建状态就绪状态运行状态阻塞状态死亡状态 补充:线程阻塞的原因 线程调用sleep()方法进入睡眠状态 线程得到一个…...
MySQL 01 02 章——数据库概述与MySQL安装篇
一、数据库概述 (1)为什么要使用数据库 数据库可以实现持久化,什么是持久化:数据持久化意味着将内存中的数据保存到硬盘上加以“固化”持久化的主要作用是:将内存中的数据存储在关系型数据库中,当然也可以…...
[读书日志]8051软核处理器设计实战(基于FPGA)第四篇:verilog语法特性
第一篇https://blog.csdn.net/m0_74021449/article/details/144796689 第二篇https://blog.csdn.net/m0_74021449/article/details/144813103 第三篇https://blog.csdn.net/m0_74021449/article/details/144834117 4.verilog硬件描述语言基础 这部分主要讲述verilog基础语法…...
大模型高效推理综述
大模型高效推理综述 1 Introduction2 Preliminaries2.1 transformer架构的LLM2.2 大模型推理过程2.3 推理效率分析 3 TAXONOMY(分类)4.数据级别优化4.1输入压缩4.1.1 提示词裁剪(prompt pruning)4.1.2 提示词总结(prompt summary)…...
HTML5实现好看的博客网站、通用大作业网页模板源码
HTML5实现好看的博客网站、通用大作业网页模板源码 前言一、设计来源1.1 主界面1.2 列表界面1.3 文章界面 二、效果和源码2.1 动态效果2.2 源代码 源码下载结束语 HTML5实现好看的博客网站、通用大作业网页模板源码,博客网站源码,HTML模板源码࿰…...
在Microsoft Windows上安装MySQL
MySQL仅适用于Microsoft Windows 64位操作系统,在Microsoft Windows上安装MySQL有不同的方法:MSI、包含您解压缩的所有必要文件的标准二进制版本(打包为压缩文件)以及自己编译MySQL源文件。 注意:MySQL8.4服务器需要在…...
adaface人脸特征提取之ncnn推理
目录 1. 背景2. 准备工作2.1 ncnn库下载2.2 adaface模型下载2.3 模型转换 3. 代码实现4. 模型量化 1. 背景 最近项目要求Android端使用adaface做人脸特征提取,最终选择ncnn作为推理框架 2. 准备工作 2.1 ncnn库下载 https://github.com/Tencent/ncnn/tree/maste…...
iOS 逆向学习 - iOS Security Features:硬件与软件多重防护体系
iOS 逆向学习 - iOS Security Features:硬件与软件多重防护体系 iOS 安全特性全面解析:构筑多层次防御体系一、iOS 的硬件安全特性1. Secure Enclave(安全隔区)2. Hardware Root of Trust(硬件信任根)3. De…...
纯前端实现将pdf转为图片(插件pdfjs)
需求来源 预览简历功能在移动端,由于用了一层iframe把这个功能嵌套在了app端,再用一个iframe来预览,只有ios能看到,安卓就不支持,查了很多资料和插件,原理基本上都是用iframe实现的。最终转换思路…...
stm32HAL库使LED闪烁
PC13引脚为开漏接法 生成代码时设置为out put open drain gpio out put level 设置为high 1表示熄灭 我们将pa9引脚连接为推挽接法 生成代码时设置为 out put push pull Gpio out put level 设置为low 0 表示熄灭 代码使其亮起再延时0.5秒再熄灭再延时0.5秒...
《数据结构》期末考试测试题【中】
《数据结构》期末考试测试题【中】 21.循环队列队空的判断条件为?22. 单链表的存储密度比1?23.单链表的那些操作的效率受链表长度的影响?24.顺序表中某元素的地址为?25.m叉树第K层的结点数为?26. 在双向循环链表某节点…...
【Vue3项目实战系列一】—— 全局样式处理,导入view-ui-plus组件库,定制个性主题
😉 你好呀,我是爱编程的Sherry,很高兴在这里遇见你!我是一名拥有十多年开发经验的前端工程师。这一路走来,面对困难时也曾感到迷茫,凭借不懈的努力和坚持,重新找到了前进的方向。我的人生格言是…...
ChatGPT 主流模型GPT-4/GPT-4o mini的参数规模是多大?
微软论文又把 OpenAI 的机密泄露了??在论文中明晃晃写着: o1-preview 约 300B;o1-mini 约 100BGPT-4o 约 200B;GPT-4o-mini 约 8BClaude 3.5 Sonnet 2024-10-22 版本约 175B微软自己的 Phi-3-7B,这个不用约…...
初学stm32 --- RTC实时时钟
目录 RTC简介 常用的RTC方案 STM32 F1 RTC框图介绍 后备寄存器和RTC寄存器特性(F1) F1 RTC相关寄存器介绍 RCC_APB1ENR寄存器编辑 PWR_CR寄存器 RCC_BDCR寄存器 RTC_CRL寄存器 RTC_CRH寄存器 RTC_PRLH寄存器 RTC_PRLL寄存器 RTC_CNTH寄存器 …...
Qt之屏幕录制设计(十六)
Qt开发 系列文章 - screencap(十六) 目录 前言 一、实现原理 二、实现方式 1.创建录屏窗口 2.录屏窗口类定义 3.自建容器对象定义 4.用户使用 5.效果演示 总结 前言 利用Qt实现屏幕录制设计,可以通过使用Qt自带的类QScreen、QPixma…...
25年1月更新。Windows 上搭建 Python 开发环境:Python + PyCharm 安装全攻略(文中有安装包不用官网下载)
引言 随着 Python 在数据科学、Web 开发、自动化脚本等多个领域的广泛应用,越来越多的开发者选择它作为首选编程语言。而 PyCharm 作为一个功能强大的集成开发环境(IDE),为 Python 开发者提供了极大的便利。本文将详细介绍如何在 …...
CTF杂项——[LitCTF 2024]涐贪恋和伱、甾―⑺dé毎兮毎秒
得到一张图片 有两种方式可以得到flag 第一种:LSB 第二种:zsteg...
从零开始手写缓存之如何实现固定缓存大小
cache 发展之路 1、HashMap或者ConcurrentHashMap public class CustomerService {private HashMap<String,String> hashMap new HashMap<>();private CustomerMapper customerMapper;public String getCustomer(String name){String customer hashMap.get(nam…...
Kubernetes——part4-1 Kubernetes集群 服务暴露 Nginx Ingress Controller
Kubernetes集群 服务暴露 Nginx Ingress Controller 一、ingress控制器 1.1 ingress控制器作用 (类似于slb,做代理服务) ingress controller可以为kubernetes 集群外用户访问Kubernetes集群内部pod提供代理服务。 提供全局访问代理访问流程…...