找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 8265|回复: 33
打印 上一主题 下一主题
收起左侧

用STC单片机DIY 3D立体数字滑块推盘游戏 3d Puzzle 4x4x4 串口版 全球首发!

  [复制链接]
跳转到指定楼层
楼主
ID:57657 发表于 2016-10-10 17:53 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
用STC单片机DIY 3D立体数字滑块推盘游戏 3d Puzzle 4x4x4 串口版 全球首发!
传统的2D数字滑块推盘现已有百年历史,现3D立体数字推盘正式于2016年诞生!
由4个平面推盘组成,只有一层有空区,其余的没有。
平面移动方法与传统推盘一致,立体移动方法是层之间进行移动。
可移植到数码管进行显示,共需要128个数码管进行显示,只用IO口驱动大量数码管是不可能的,而且动态扫描亮度影响非常大,所以要用到74系列芯片或者其他LED数码管驱动芯片进行驱动。
还原技巧以及算法比传统的更加复杂,可能会难倒世界顶级拼图还原高手!
3D数字推盘由于机械式设计非常复杂,采用单片机和数码管和按键实现了电子式设计。
若发现建议意见以及BUG等问题请在下面回复,谢谢合作!
以下源码用Keil4编译后直接烧写到单片机内即可运行,根据晶振频率修改串口位延时时间即可。


  1. #include "reg51.h"
  2. #include "intrins.h"
  3. sbit rxd=P3^0; //数据接收口
  4. sbit txd=P3^1; //数据发送口

  5. unsigned char l1[16]={ //推盘层1
  6. 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
  7. };
  8. unsigned char l2[16]={ //推盘层2
  9. 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
  10. };
  11. unsigned char l3[16]={ //推盘层3
  12. 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47
  13. };
  14. unsigned char l4[16]={ //推盘层4
  15. 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63
  16. };

  17. unsigned char code xyd[64] = { //拼图板移动方向与0交换坐标数据,请勿修改否则数字会无法正常移动。
  18. 0x04, 0x10, 0x01, 0x10, 0x05, 0x10, 0x02, 0x00, 0x06, 0x10, 0x03, 0x01, 0x07, 0x10, 0x10, 0x02,
  19. 0x08, 0x00, 0x05, 0x10, 0x09, 0x01, 0x06, 0x04, 0x0A, 0x02, 0x07, 0x05, 0x0B, 0x03, 0x10, 0x06,
  20. 0x0C, 0x04, 0x09, 0x10, 0x0D, 0x05, 0x0A, 0x08, 0x0E, 0x06, 0x0B, 0x09, 0x0F, 0x07, 0x10, 0x0A,
  21. 0x10, 0x08, 0x0D, 0x10, 0x10, 0x09, 0x0E, 0x0C, 0x10, 0x0A, 0x0F, 0x0D, 0x10, 0x0B, 0x10, 0x0E
  22. };

  23. sfr AUXR   = 0x8E; //定义AUXR寄存器
  24. sfr INT_CLKO = 0x8F; //定义下降沿中断寄存器

  25. //------------------------软串口驱动程序------------------------
  26. /*
  27. void init_uart(){ //初始化串口 使用硬件下降沿中断必须初始化
  28.       AUXR |= 0x80;        //设置AUXR寄存器
  29.       INT_CLKO |= 0x40;           //开串口中断 (允许串口接收数据)
  30.        EA = 1;        //启用I/O口外部中断功能
  31. }
  32. */
  33. void delay_uart(){ //延时时间1除以波特率秒 1/9600秒
  34.     unsigned char a,b;
  35.     for(b=114;b>0;b--)
  36.         for(a=1;a>0;a--);
  37. }
  38. void txd_data(unsigned char i){  //发送数据
  39. unsigned char j=1;//控制移位
  40. unsigned char k=8;//控制循环次数
  41.   delay_uart();//延时时间
  42.   txd=0; //发送起始位,低电平
  43.   while(k--){ //下面循环8次
  44.   delay_uart();//延时时间
  45.   txd=(i&j)/j; //发送数据
  46.   j<<=1; //左移1位,发送下1位数据
  47.   }
  48.   delay_uart();//延时时间
  49.   txd=1;  //发送停止位
  50. }
  51. unsigned char rxd_data(){ //接收数据
  52. unsigned char j=1;//控制移位
  53. unsigned char k=8;//控制循环次数
  54. unsigned char d=0;//存放数据
  55.   while(rxd == 1); //等待起始位低电平
  56.   while(k--){//下面循环8次
  57.   delay_uart(); //延时时间
  58.   d|=(rxd*j); //存入数据
  59.   j<<=1;  //左移1位,接收下1位数据
  60.   }
  61.   delay_uart();//延时时间
  62.   if(rxd == 1){ //停止位为高电平
  63.   return d; //返回数据
  64.   } else {
  65.   return 0; //无效数据 返回0
  66.   }
  67. }
  68. void send_text(unsigned char *text){ //发送字符串
  69. for(;*text!=0;text++){  //遇到停止符0结束发送
  70.   txd_data(*text); //发送数据
  71. }
  72. }
  73. void send_enter(){ //发送换行
  74.   txd_data(0x0D);
  75.   txd_data(0x0A);
  76. }
  77. //------------------------3D推盘驱动程序------------------------
  78. //0的坐标:0~15 移动方向:1234 表示上下左右
  79. unsigned char get_adj_coo(unsigned char zero_adj,unsigned char mov_dir){ //获取相邻坐标
  80. return xyd[zero_adj*4+mov_dir-1];
  81. }
  82. unsigned char get_0_lay(){ //获取0所在的层数 返回1~4
  83. unsigned char add=0;
  84. for(add=0;add<16;add++){
  85.   if(l1[add] == 0){
  86.    return 1;
  87.    }
  88.   if(l2[add] == 0){
  89.    return 2;
  90.    }
  91.   if(l3[add] == 0){
  92.    return 3;
  93.    }
  94.   if(l4[add] == 0){
  95.    return 4;
  96.    }
  97. }
  98. return 0;
  99. }
  100. unsigned char get_0_pla(){ //获取0的平面坐标 返回0~15
  101. unsigned char lay=0;
  102. unsigned char add=0; //当前扫描的坐标
  103. lay=get_0_lay(); //获取0所在的层数
  104. for(add=0;add<16;add++){
  105.   if(lay == 1){
  106.    if(l1[add] == 0){
  107.    return add;
  108.    }
  109.   }
  110.   if(lay == 2){
  111.    if(l2[add] == 0){
  112.    return add;
  113.    }
  114.   }
  115.   if(lay == 3){
  116.    if(l3[add] == 0){
  117.    return add;
  118.    }
  119.   }
  120.   if(lay == 4){
  121.    if(l4[add] == 0){
  122.    return add;
  123.    }
  124.   }


  125. }
  126. return 0;
  127. }
  128. //平面交换数字位置 层数:1~4 坐标A 坐标B
  129. void pec(unsigned char s,unsigned char a,unsigned char b){
  130. unsigned char ad=0; //坐标A数据
  131. unsigned char bd=0; //坐标B数据
  132. if(a > 15 || b > 15) {
  133.   return;
  134.   }
  135.   if(s == 1){ad=l1[a];bd=l1[b];l1[a]=bd;l1[b]=ad;return;}
  136.   if(s == 2){ad=l2[a];bd=l2[b];l2[a]=bd;l2[b]=ad;return;}
  137.   if(s == 3){ad=l3[a];bd=l3[b];l3[a]=bd;l3[b]=ad;return;}
  138.   if(s == 4){ad=l4[a];bd=l4[b];l4[a]=bd;l4[b]=ad;return;}
  139. return;
  140. }
  141. void up_mov(){ //拼图上移
  142. unsigned char lay0=0;
  143. unsigned char pla0=0;
  144. unsigned char adj=0;
  145. lay0=get_0_lay(); //获取0的坐标所在层数
  146. pla0=get_0_pla(); //获取0的平面坐标
  147. adj=get_adj_coo(pla0,1); //获取相邻坐标
  148. pec(lay0,pla0,adj); //平面交换数字位置

  149. }
  150. void down_mov(){ //拼图下移
  151. unsigned char lay0=0;
  152. unsigned char pla0=0;
  153. unsigned char adj=0;
  154. lay0=get_0_lay(); //获取0的坐标所在层数
  155. pla0=get_0_pla(); //获取0的平面坐标
  156. adj=get_adj_coo(pla0,2); //获取相邻坐标
  157. pec(lay0,pla0,adj); //平面交换数字位置

  158. }
  159. void left_mov(){ //拼图左移
  160. unsigned char lay0=0;
  161. unsigned char pla0=0;
  162. unsigned char adj=0;
  163. lay0=get_0_lay(); //获取0的坐标所在层数
  164. pla0=get_0_pla(); //获取0的平面坐标
  165. adj=get_adj_coo(pla0,3); //获取相邻坐标
  166. pec(lay0,pla0,adj); //平面交换数字位置

  167. }
  168. void right_mov(){ //拼图右移
  169. unsigned char lay0=0;
  170. unsigned char pla0=0;
  171. unsigned char adj=0;
  172. lay0=get_0_lay(); //获取0的坐标所在层数
  173. pla0=get_0_pla(); //获取0的平面坐标
  174. adj=get_adj_coo(pla0,4); //获取相邻坐标
  175. pec(lay0,pla0,adj); //平面交换数字位置

  176. }
  177. void in_mov(){ //拼图里移
  178. unsigned char lay0=0; //0的坐标所在层数
  179. unsigned char pla0=0; //0的平面坐标
  180. unsigned char add=0; //累加计数

  181. lay0=get_0_lay(); //获取0的坐标所在层数
  182. pla0=get_0_pla(); //获取0的平面坐标
  183.   if(lay0 < 4){
  184.    if(lay0 == 3){l3[pla0]=l4[pla0];l4[pla0]=0;}
  185.    if(lay0 == 2){l2[pla0]=l3[pla0];l3[pla0]=0;}
  186.    if(lay0 == 1){l1[pla0]=l2[pla0];l2[pla0]=0;}
  187.   }
  188. }
  189. void out_mov(){ //拼图外移
  190. unsigned char lay0=0; //0的坐标所在层数
  191. unsigned char pla0=0; //0的平面坐标
  192. unsigned char add=0; //累加计数

  193. lay0=get_0_lay(); //获取0的坐标所在层数
  194. pla0=get_0_pla(); //获取0的平面坐标
  195.   if(lay0 > 1){
  196.    if(lay0 == 4){l4[pla0]=l3[pla0];l3[pla0]=0;}
  197.    if(lay0 == 3){l3[pla0]=l2[pla0];l2[pla0]=0;}
  198.    if(lay0 == 2){l2[pla0]=l1[pla0];l1[pla0]=0;}
  199.   }
  200. }

  201. void send_puzzle_l1(){
  202. unsigned char a=0;

  203. send_text("┏━┳━┳━┳━┓");send_enter(); //发送顶部表格框架
  204.   for(a=0;a<16;a++){
  205.   send_text("┃");
  206.   if(l1[a] == 0){ //读取到的数字为0则发送2个空格
  207.    txd_data(0x20);
  208.    txd_data(0x20);
  209.   } else { //不为0则发送数字
  210.    txd_data((l1[a]/10)|0x30);  //发送数字十位
  211.    txd_data((l1[a]%10)|0x30);  //发送数字个位
  212.   }
  213.   
  214.     if(a==3 || a==7 || a==11){ //读取到第3 7 11个数字
  215.     send_text("┃"); //发送分隔符
  216.     send_enter();
  217.     send_text("┣━╋━╋━╋━┫"); //发送中间表格框架
  218.     send_enter();
  219.     }
  220.   }
  221. send_text("┃");
  222. send_enter();
  223. send_text("┗━┻━┻━┻━┛"); //发送底部表格框架

  224. }
  225. void send_puzzle_l2(){
  226. unsigned char a=0;

  227. send_text("┏━┳━┳━┳━┓");send_enter(); //发送顶部表格框架
  228.   for(a=0;a<16;a++){
  229.   send_text("┃");
  230.   if(l2[a] == 0){ //读取到的数字为0则发送2个空格
  231.    txd_data(0x20);
  232.    txd_data(0x20);
  233.   } else { //不为0则发送数字
  234.    txd_data((l2[a]/10)|0x30);  //发送数字十位
  235.    txd_data((l2[a]%10)|0x30);  //发送数字个位
  236.   }
  237.   
  238.     if(a==3 || a==7 || a==11){ //读取到第3 7 11个数字
  239.     send_text("┃"); //发送分隔符
  240.     send_enter();
  241.     send_text("┣━╋━╋━╋━┫"); //发送中间表格框架
  242.     send_enter();
  243.     }
  244.   }
  245. send_text("┃");
  246. send_enter();
  247. send_text("┗━┻━┻━┻━┛"); //发送底部表格框架

  248. }
  249. void send_puzzle_l3(){
  250. unsigned char a=0;

  251. send_text("┏━┳━┳━┳━┓");send_enter(); //发送顶部表格框架
  252.   for(a=0;a<16;a++){
  253.   send_text("┃");
  254.   if(l3[a] == 0){ //读取到的数字为0则发送2个空格
  255.    txd_data(0x20);
  256.    txd_data(0x20);
  257.   } else { //不为0则发送数字
  258.    txd_data((l3[a]/10)|0x30);  //发送数字十位
  259.    txd_data((l3[a]%10)|0x30);  //发送数字个位
  260.   }
  261.   
  262.     if(a==3 || a==7 || a==11){ //读取到第3 7 11个数字
  263.     send_text("┃"); //发送分隔符
  264.     send_enter();
  265.     send_text("┣━╋━╋━╋━┫"); //发送中间表格框架
  266.     send_enter();
  267.     }
  268.   }
  269. send_text("┃");
  270. send_enter();
  271. send_text("┗━┻━┻━┻━┛"); //发送底部表格框架

  272. }
  273. void send_puzzle_l4(){
  274. unsigned char a=0;

  275. send_text("┏━┳━┳━┳━┓");send_enter(); //发送顶部表格框架
  276.   for(a=0;a<16;a++){
  277.   send_text("┃");
  278.   if(l4[a] == 0){ //读取到的数字为0则发送2个空格
  279.    txd_data(0x20);
  280.    txd_data(0x20);
  281.   } else { //不为0则发送数字
  282.    txd_data((l4[a]/10)|0x30);  //发送数字十位
  283.    txd_data((l4[a]%10)|0x30);  //发送数字个位
  284.   }
  285.   
  286.     if(a==3 || a==7 || a==11){ //读取到第3 7 11个数字
  287.     send_text("┃"); //发送分隔符
  288.     send_enter();
  289.     send_text("┣━╋━╋━╋━┫"); //发送中间表格框架
  290.     send_enter();
  291.     }
  292.   }
  293. send_text("┃");
  294. send_enter();
  295. send_text("┗━┻━┻━┻━┛"); //发送底部表格框架

  296. }
  297. void send_3dpuzzle(){ //通过串口发送拼图数据
  298. txd_data(0x0C);
  299. send_text("3D立体数字滑块推盘游戏 4x4x4 串口版 WASD控制上下左右 Q里 E外,全球首发! ");
  300. send_enter();
  301. send_text("第一层(最里层):");send_enter();
  302. send_puzzle_l1();send_enter();send_enter();
  303. send_text("第二层:");send_enter();
  304. send_puzzle_l2();send_enter();send_enter();
  305. send_text("第三层:");send_enter();
  306. send_puzzle_l3();send_enter();send_enter();
  307. send_text("第四层(最外层):");send_enter();
  308. send_puzzle_l4();send_enter();send_enter();
  309. }
  310. void exint4() //interrupt 16
  311. { //P3.0下降沿中断 (串口接收到数据)
  312. unsigned char dat=0;  //数据存放变量
  313. // INT_CLKO &= 0xBF;  //关闭中断,避免重复触发中断程序。
  314. dat=rxd_data();    //串口接收数据。
  315.   if(dat == 0x57 || dat == 0x77) up_mov(); //W 上
  316.   if(dat == 0x41 || dat == 0x61) left_mov(); //A 左
  317.   if(dat == 0x53 || dat == 0x73) down_mov(); //S 下
  318.   if(dat == 0x44 || dat == 0x64) right_mov(); //D 右
  319.   if(dat == 0x51 || dat == 0x71) in_mov(); //Q 里
  320.   if(dat == 0x45 || dat == 0x65) out_mov(); //E 外
  321.   send_3dpuzzle();
  322. // INT_CLKO |= 0x40; //开启中断,允许下次接收数据。        
  323. }

  324. void main(){ //入口函数

  325. //init_uart();
  326. send_3dpuzzle(); //发送拼图数据
  327. while(1){
  328.   if(rxd == 0){ //串口收到低电平
  329.    exint4(); //处理数据
  330.   }
  331. }
  332. }

复制代码

评分

参与人数 1黑币 +100 收起 理由
admin + 100 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:142233 发表于 2016-10-10 19:17 | 只看该作者
学习一下!!
回复

使用道具 举报

板凳
ID:93151 发表于 2016-10-14 21:24 | 只看该作者
新产品,看看
回复

使用道具 举报

地板
ID:152682 发表于 2016-12-24 10:22 | 只看该作者
学习一下!谢楼主分享!
回复

使用道具 举报

5#
ID:152682 发表于 2016-12-24 10:23 | 只看该作者
楼主你的硬件图呢?求分享!谢谢!
回复

使用道具 举报

6#
ID:136460 发表于 2016-12-24 20:24 | 只看该作者
学习一下!!
回复

使用道具 举报

7#
ID:157266 发表于 2016-12-27 19:37 | 只看该作者
再回复一次!只求资料
回复

使用道具 举报

8#
ID:158903 发表于 2016-12-30 16:01 | 只看该作者

再回复一次!只求资料
回复

使用道具 举报

9#
ID:153626 发表于 2016-12-31 15:04 | 只看该作者
这个东西没看过
回复

使用道具 举报

10#
ID:98741 发表于 2016-12-31 15:34 | 只看该作者
看看。。。。
回复

使用道具 举报

11#
ID:159086 发表于 2016-12-31 16:10 | 只看该作者
学习一下
回复

使用道具 举报

12#
ID:317494 发表于 2018-6-16 11:59 | 只看该作者
觉得是个好东西,先看看
回复

使用道具 举报

13#
ID:277190 发表于 2018-8-21 20:10 | 只看该作者
谢谢,研究研究
回复

使用道具 举报

14#
ID:298016 发表于 2018-8-21 21:18 | 只看该作者

学习一下!!
回复

使用道具 举报

15#
ID:388788 发表于 2018-9-9 13:49 | 只看该作者
学习一下
回复

使用道具 举报

16#
ID:292943 发表于 2018-9-9 20:10 | 只看该作者
不错不错不错
回复

使用道具 举报

17#
ID:252841 发表于 2019-4-2 22:08 | 只看该作者
想看这吗厉害的东西
回复

使用道具 举报

18#
ID:268524 发表于 2019-4-3 16:57 | 只看该作者
学习一下!!
回复

使用道具 举报

19#
ID:505533 发表于 2019-4-5 23:10 | 只看该作者
学习一下
回复

使用道具 举报

20#
ID:476064 发表于 2019-4-6 02:05 来自触屏版 | 只看该作者
瞅瞅咋样
回复

使用道具 举报

21#
ID:240034 发表于 2019-4-6 09:29 | 只看该作者
我就看看,OK!
回复

使用道具 举报

22#
ID:366958 发表于 2019-4-6 09:52 | 只看该作者
学习一下
回复

使用道具 举报

23#
ID:3802 发表于 2025-4-29 09:25 | 只看该作者
学习一下!!
回复

使用道具 举报

24#
ID:102702 发表于 2025-5-4 15:51 | 只看该作者
谢谢楼主分享,学习
回复

使用道具 举报

25#
ID:860248 发表于 2025-5-5 01:04 | 只看该作者
新产品,学习一下
回复

使用道具 举报

26#
ID:277290 发表于 2025-5-5 08:11 | 只看该作者
学习一下!!
回复

使用道具 举报

27#
ID:482794 发表于 2025-5-5 12:49 | 只看该作者

学习一下!!
回复

使用道具 举报

28#
ID:69536 发表于 2025-5-5 13:23 | 只看该作者
一起学习一下
回复

使用道具 举报

29#
ID:477512 发表于 2025-5-6 06:38 | 只看该作者
我是来学习一下!
回复

使用道具 举报

30#
ID:87631 发表于 2025-5-6 09:41 | 只看该作者
什么游戏,学习下
回复

使用道具 举报

31#
ID:688460 发表于 2025-5-8 17:10 | 只看该作者
不错,学习一下大侠的杰作了
回复

使用道具 举报

32#
ID:688460 发表于 2025-5-8 17:11 | 只看该作者
不错!学习一下大侠的杰作了!谢谢!
回复

使用道具 举报

33#
ID:307544 发表于 2025-5-9 10:18 | 只看该作者
学习一下!
回复

使用道具 举报

34#
ID:276663 发表于 2025-10-24 16:38 | 只看该作者
顶一下,看看啥东西
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表