|
- /*
- 基于STC15系列的3D立体数字滑块推盘游戏 软串口版
- 以下源码用Keil4编译后直接烧写到STC单片机内即可运行,根据晶振频率修改串口位延时时间即可。
- 使用XP自带的超级终端进行即可,其他系统可能需要下载安装包。
- By:LscmunaixMG 2017-07-03
- */
- #include "reg51.h" //定义头文件reg51.h
- #include "intrins.h" //定义头文件intrins.h
- sbit rxd=P3^0; //数据接收口
- sbit txd=P3^1; //数据发送口
- //--------4层 推盘层数据--------
- unsigned char l1[16]={ //推盘层1
- 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
- };
- unsigned char l2[16]={ //推盘层2
- 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
- };
- unsigned char l3[16]={ //推盘层3
- 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47
- };
- unsigned char l4[16]={ //推盘层4
- 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63
- };
- /*
- 通过获取0的坐标和被移动的坐标交换数值实现移动的功能以及判断数字是否能被移动。
- 若没有任何不能正常移动数字的现象,严禁修改任何1字节否则会导致某些位置的数字跳格或者无法移动还会导致数组越界等严重后果。
- 每4字节表示4个移动方向的与0的坐标与其他坐标进行交换实现移动。
- 0的坐标从左上到右下排序:
- 0 1 2 3
- 4 5 6 7
- 8 9 A B
- C D E F
- 前4字节:0x04, 0x10, 0x01, 0x10
- 比如数值0在坐标0的位置上,
- 上移将坐标4的值移入坐标0。
- 下移为0x10,不能被移动。
- 左移将坐标1的值移入坐标0。
- 右移同样为0x10,不能被移动。
- 移入的方法则是与数值0的坐标进行数值交换而实现移动。
- 数值0在坐标1的位置上,则获取后面的4字节进行判断,以此类推。
- */
- unsigned char code xyd[64] = { //拼图板移动方向与0(空白)交换坐标数据,请勿修改否则数字会跳格或无法正常移动。
- 0x04, 0x10, 0x01, 0x10, 0x05, 0x10, 0x02, 0x00, 0x06, 0x10, 0x03, 0x01, 0x07, 0x10, 0x10, 0x02,
- 0x08, 0x00, 0x05, 0x10, 0x09, 0x01, 0x06, 0x04, 0x0A, 0x02, 0x07, 0x05, 0x0B, 0x03, 0x10, 0x06,
- 0x0C, 0x04, 0x09, 0x10, 0x0D, 0x05, 0x0A, 0x08, 0x0E, 0x06, 0x0B, 0x09, 0x0F, 0x07, 0x10, 0x0A,
- 0x10, 0x08, 0x0D, 0x10, 0x10, 0x09, 0x0E, 0x0C, 0x10, 0x0A, 0x0F, 0x0D, 0x10, 0x0B, 0x10, 0x0E
- };
- sfr AUXR = 0x8E; //定义AUXR寄存器
- sfr INT_CLKO = 0x8F; //定义下降沿中断寄存器
- //------------------------软串口驱动程序------------------------
- /*
- void init_uart(){ //初始化串口 使用硬件下降沿中断必须初始化
- AUXR |= 0x80; //设置AUXR寄存器
- INT_CLKO |= 0x40; //开串口中断 (允许串口接收数据)
- EA = 1; //启用I/O口外部中断功能
- }
- */
- void delay_uart(){ //延时时间1除以波特率秒 1/9600秒
- unsigned char a,b;
- for(b=114;b>0;b--)
- for(a=1;a>0;a--);
- }
- void txd_data(unsigned char i){ //软串口发送数据
- unsigned char j=1;//控制移位
- unsigned char k=8;//控制循环次数
- delay_uart();//延时时间
- txd=0; //发送起始位,低电平
- while(k--){ //下面循环8次
- delay_uart();//延时时间
- txd=(i&j)/j; //发送数据
- j<<=1; //左移1位,发送下1位数据
- }
- delay_uart();//延时时间
- txd=1; //发送停止位
- }
- unsigned char rxd_data(){ //软串口接收数据
- unsigned char j=1;//控制移位
- unsigned char k=8;//控制循环次数
- unsigned char d=0;//存放数据
- while(rxd == 1); //等待起始位低电平
- while(k--){//下面循环8次
- delay_uart(); //延时时间
- d|=(rxd*j); //存入数据
- j<<=1; //左移1位,接收下1位数据
- }
- delay_uart();//延时时间
- if(rxd == 1){ //停止位为高电平
- return d; //返回数据
- } else {
- return 0; //无效数据 返回0
- }
- }
- void send_text(unsigned char *text){ //发送一段字符串
- for(;*text!=0;text++){ //遇到停止符0结束发送
- txd_data(*text); //发送数据
- }
- }
- void send_enter(){ //发送换行(回车)
- txd_data(0x0D);
- txd_data(0x0A);
- }
- //------------------------3D推盘驱动程序------------------------
- //0的坐标:0~15 移动方向:1234 表示上下左右
- unsigned char get_adj_coo(unsigned char zero_adj,unsigned char mov_dir){ //获取相邻坐标
- return xyd[zero_adj*4+mov_dir-1];
- }
- unsigned char get_0_lay(){ //获取0(空白)所在的层数 返回1~4
- unsigned char add=0;
- for(add=0;add<16;add++){
- if(l1[add] == 0){
- return 1;
- }
- if(l2[add] == 0){
- return 2;
- }
- if(l3[add] == 0){
- return 3;
- }
- if(l4[add] == 0){
- return 4;
- }
- }
- return 0;
- }
- unsigned char get_0_pla(){ //获取0(空白)的平面坐标 返回0~15
- unsigned char lay=0;
- unsigned char add=0; //当前扫描的坐标
- lay=get_0_lay(); //获取0所在的层数
- for(add=0;add<16;add++){
- if(lay == 1){
- if(l1[add] == 0){
- return add;
- }
- }
- if(lay == 2){
- if(l2[add] == 0){
- return add;
- }
- }
- if(lay == 3){
- if(l3[add] == 0){
- return add;
- }
- }
- if(lay == 4){
- if(l4[add] == 0){
- return add;
- }
- }
- }
- return 0;
- }
- //平面交换数字位置 层数:1~4 坐标A 坐标B
- void pec(unsigned char s,unsigned char a,unsigned char b){
- unsigned char ad=0; //坐标A数据
- unsigned char bd=0; //坐标B数据
- if(a > 15 || b > 15) {
- return;
- }
- if(s == 1){ad=l1[a];bd=l1[b];l1[a]=bd;l1[b]=ad;return;}
- if(s == 2){ad=l2[a];bd=l2[b];l2[a]=bd;l2[b]=ad;return;}
- if(s == 3){ad=l3[a];bd=l3[b];l3[a]=bd;l3[b]=ad;return;}
- if(s == 4){ad=l4[a];bd=l4[b];l4[a]=bd;l4[b]=ad;return;}
- return;
- }
- void up_mov(){ //拼图上移
- unsigned char lay0=0;
- unsigned char pla0=0;
- unsigned char adj=0;
- lay0=get_0_lay(); //获取0的坐标所在层数
- pla0=get_0_pla(); //获取0的平面坐标
- adj=get_adj_coo(pla0,1); //获取相邻坐标
- pec(lay0,pla0,adj); //平面交换数字位置
- }
- void down_mov(){ //拼图下移
- unsigned char lay0=0;
- unsigned char pla0=0;
- unsigned char adj=0;
- lay0=get_0_lay(); //获取0的坐标所在层数
- pla0=get_0_pla(); //获取0的平面坐标
- adj=get_adj_coo(pla0,2); //获取相邻坐标
- pec(lay0,pla0,adj); //平面交换数字位置
- }
- void left_mov(){ //拼图左移
- unsigned char lay0=0;
- unsigned char pla0=0;
- unsigned char adj=0;
- lay0=get_0_lay(); //获取0的坐标所在层数
- pla0=get_0_pla(); //获取0的平面坐标
- adj=get_adj_coo(pla0,3); //获取相邻坐标
- pec(lay0,pla0,adj); //平面交换数字位置
- }
- void right_mov(){ //拼图右移
- unsigned char lay0=0;
- unsigned char pla0=0;
- unsigned char adj=0;
- lay0=get_0_lay(); //获取0的坐标所在层数
- pla0=get_0_pla(); //获取0的平面坐标
- adj=get_adj_coo(pla0,4); //获取相邻坐标
- pec(lay0,pla0,adj); //平面交换数字位置
- }
- void in_mov(){ //拼图里移
- unsigned char lay0=0; //0的坐标所在层数
- unsigned char pla0=0; //0的平面坐标
- unsigned char add=0; //累加计数
- lay0=get_0_lay(); //获取0的坐标所在层数
- pla0=get_0_pla(); //获取0的平面坐标
- if(lay0 < 4){
- if(lay0 == 3){l3[pla0]=l4[pla0];l4[pla0]=0;}
- if(lay0 == 2){l2[pla0]=l3[pla0];l3[pla0]=0;}
- if(lay0 == 1){l1[pla0]=l2[pla0];l2[pla0]=0;}
- }
- }
- void out_mov(){ //拼图外移
- unsigned char lay0=0; //0的坐标所在层数
- unsigned char pla0=0; //0的平面坐标
- unsigned char add=0; //累加计数
- lay0=get_0_lay(); //获取0的坐标所在层数
- pla0=get_0_pla(); //获取0的平面坐标
- if(lay0 > 1){
- if(lay0 == 4){l4[pla0]=l3[pla0];l3[pla0]=0;}
- if(lay0 == 3){l3[pla0]=l2[pla0];l2[pla0]=0;}
- if(lay0 == 2){l2[pla0]=l1[pla0];l1[pla0]=0;}
- }
- }
- void send_puzzle_l1(){
- unsigned char a=0;
-
- send_text("┏━┳━┳━┳━┓");send_enter(); //发送顶部表格框架
- for(a=0;a<16;a++){ //变量a循环0~15
- send_text("┃");
- if(l1[a] == 0){ //读取到的数字为0则发送2个半角空格
- txd_data(0x20);
- txd_data(0x20);
- } else { //不为0则发送数字
- txd_data((l1[a]/10)|0x30); //发送数字十位
- txd_data((l1[a]%10)|0x30); //发送数字个位
- }
-
- if(a==3 || a==7 || a==11){ //读取到第3 7 11个数字 每列最后1个数字
- send_text("┃"); //发送分隔符
- send_enter();
- send_text("┣━╋━╋━╋━┫"); //发送中间表格框架
- send_enter();
- }
- }
- send_text("┃");
- send_enter();
- send_text("┗━┻━┻━┻━┛"); //发送底部表格框架
- }
- void send_puzzle_l2(){
- unsigned char a=0;
-
- send_text("┏━┳━┳━┳━┓");send_enter(); //发送顶部表格框架
- for(a=0;a<16;a++){
- send_text("┃");
- if(l2[a] == 0){ //读取到的数字为0则发送2个空格
- txd_data(0x20);
- txd_data(0x20);
- } else { //不为0则发送数字
- txd_data((l2[a]/10)|0x30); //发送数字十位
- txd_data((l2[a]%10)|0x30); //发送数字个位
- }
-
- if(a==3 || a==7 || a==11){ //读取到第3 7 11个数字
- send_text("┃"); //发送分隔符
- send_enter();
- send_text("┣━╋━╋━╋━┫"); //发送中间表格框架
- send_enter();
- }
- }
- send_text("┃");
- send_enter();
- send_text("┗━┻━┻━┻━┛"); //发送底部表格框架
- }
- void send_puzzle_l3(){
- unsigned char a=0;
-
- send_text("┏━┳━┳━┳━┓");send_enter(); //发送顶部表格框架
- for(a=0;a<16;a++){
- send_text("┃");
- if(l3[a] == 0){ //读取到的数字为0则发送2个空格
- txd_data(0x20);
- txd_data(0x20);
- } else { //不为0则发送数字
- txd_data((l3[a]/10)|0x30); //发送数字十位
- txd_data((l3[a]%10)|0x30); //发送数字个位
- }
-
- if(a==3 || a==7 || a==11){ //读取到第3 7 11个数字
- send_text("┃"); //发送分隔符
- send_enter();
- send_text("┣━╋━╋━╋━┫"); //发送中间表格框架
- send_enter();
- }
- }
- send_text("┃");
- send_enter();
- send_text("┗━┻━┻━┻━┛"); //发送底部表格框架
- }
- void send_puzzle_l4(){
- unsigned char a=0;
-
- send_text("┏━┳━┳━┳━┓");send_enter(); //发送顶部表格框架
- for(a=0;a<16;a++){
- send_text("┃");
- if(l4[a] == 0){ //读取到的数字为0则发送2个空格
- txd_data(0x20);
- txd_data(0x20);
- } else { //不为0则发送数字
- txd_data((l4[a]/10)|0x30); //发送数字十位
- txd_data((l4[a]%10)|0x30); //发送数字个位
- }
-
- if(a==3 || a==7 || a==11){ //读取到第3 7 11个数字
- send_text("┃"); //发送分隔符
- send_enter();
- send_text("┣━╋━╋━╋━┫"); //发送中间表格框架
- send_enter();
- }
- }
- send_text("┃");
- send_enter();
- send_text("┗━┻━┻━┻━┛"); //发送底部表格框架
- }
- void send_3dpuzzle(){ //通过串口发送拼图数据
- txd_data(0x0C); //发送 超级终端 清屏指令
- send_text("基于STC15F104E的3D立体数字滑块推盘游戏 软串口版 WASD控制上下左右 Q里 E外");
- send_enter();
- send_text("第一层(最里层):");send_enter();
- send_puzzle_l1();send_enter();send_enter();
- send_text("第二层:");send_enter();
- send_puzzle_l2();send_enter();send_enter();
- send_text("第三层:");send_enter();
- send_puzzle_l3();send_enter();send_enter();
- send_text("第四层(最外层):");send_enter();
- send_puzzle_l4();send_enter();send_enter();
- }
- void exint4() //interrupt 16{ //P3.0下降沿中断 (串口接收到数据)
- unsigned char dat=0; //数据存放变量
- // INT_CLKO &= 0xBF; //关闭中断,避免重复触发中断程序。
- dat=rxd_data(); //串口接收数据。
- if(dat == 0x57 || dat == 0x77) up_mov(); //W 上
- if(dat == 0x41 || dat == 0x61) left_mov(); //A 左
- if(dat == 0x53 || dat == 0x73) down_mov(); //S 下
- if(dat == 0x44 || dat == 0x64) right_mov(); //D 右
- if(dat == 0x51 || dat == 0x71) in_mov(); //Q 里
- if(dat == 0x45 || dat == 0x65) out_mov(); //E 外
- send_3dpuzzle(); //通过串口发送拼图数据
- // INT_CLKO |= 0x40; //开启中断,允许下次接收数据。
- }
- void main(){ //入口函数
- //init_uart();
- send_3dpuzzle(); //发送拼图数据
- while(1){ //进入死循环
- if(rxd == 0){ //串口收到低电平
- exint4(); //处理中断
- }
- }
- }
复制代码
|
|