找回密码
 立即注册

QQ登录

只需一步,快速开始

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

游戏用无线方向盘的制作 单片机加ADXL345传感器打造

[复制链接]
跳转到指定楼层
楼主
本作品Chinked-out工作室版权所有,给大家分享一款游戏用的无线方向盘的制作方法,是用51单片机加上ADXL345加速度传感器打造的,源码和原理图都有分享给51黑电子论坛的朋友们吧,大家先看下面的视频。

视频演示:


无线方向盘重要说明
蓝牙模块使用注意:
(1)当蓝牙模块连接到电路中后,会影响到单片机的程序下载,在下载程序之前,必须移除蓝牙串口模块。
(2)蓝牙串口模块在上单后会自行配对,但在配对过程中,蓝牙模块会自动溢出数据,从而影响到接收端单片机,进而导致单片机向PC机发送乱码。
为避免这种情况的发生,可上电后等待蓝牙模块配对成功后在打开单片机电源开关(原理图中已经是这样设计了)。
或在已经出现发送乱码的情况下,将单片机复位即可。

发送端原理图:


接收端原理图:



元件清单:
名称规格数量备注
万能板9x15cm2
单片机:STC12C5A60S2DIP402
40P单片机母座
2
晶振11.0592Mhz2
陶瓷电容22pF4
电解电容22uF2
10K电阻
2
拨动开关
2
排针1组40P1
杜邦线1组40P1
6x6x7.3mm方头按键
7
A44圆形按键帽颜色自选5按键帽与按键需匹配
5P排针母座
2用于固定ADXL345
4P排针母座
2用于固定蓝牙模块
ADXL345传感器
1
USB转TTL下载器CH340系列1
USB线母对母1
CH376S模块
2
蓝牙串口模块HC-052


无线方向盘发送端单片机源程序:
  1. #include "STC12C5A60S2.h"
  2. #include"intrins.h"
  3. #define key1  0x1d          //黑色           刹车 Z
  4. #define key2  0xE1          //黄色           left shift
  5. #define key3  0x04          //红色           油门         A
  6. #define key4  0x4f          //右                   右转         →
  7. #define key5  0x50          //左                   左转         ←
  8. sbit SCL=P0^6;      //IIC时钟引脚定义
  9. sbit SDA=P0^7;      //IIC数据引脚定义
  10. unsigned char idata BUF[6]; //接收数据缓存区  X轴高八位,X轴低八位; Y轴高八位,Y轴低八位; Z轴高八位,Z轴第低八位
  11. unsigned char idata key_buf[5]={0x00,0x00,0x00,0x00,0x00};
  12. unsigned char code key_judge_tab[]={0x01,0x02,0x04,0x08,0x10};
  13. void UartInit(void);
  14. void Send();
  15. void Clear();
  16. void Input_Data_Process();

  17. void Init_ADXL345(void);             //初始化ADXL345
  18. void  Single_Write_ADXL345(unsigned char REG_Address,unsigned char REG_data);   //单个写入数据
  19. void  Multiple_Read_ADXL345();                                  //连续的读取内部寄存器数据
  20. void ADXL345_Start();
  21. void ADXL345_Stop();
  22. void ADXL345_SendACK(bit ack);
  23. bit  ADXL345_RecvACK();
  24. void ADXL345_SendByte(unsigned char dat);
  25. unsigned char ADXL345_RecvByte();
  26. void ADXL345_Data_Process();

  27. void Delay5us();
  28. void Delay5ms();
  29. void Delay50ms();
  30. void Delay150ms();

  31. signed int idata X_data;
  32. unsigned char Data,judge;
  33. bit key_flag=0,flag;

  34. void main()
  35. {
  36.     Delay150ms();
  37.         P0M1=0x00;
  38.         P0M0=0x00;
  39.         UartInit();
  40.         Init_ADXL345();
  41.         while(1)
  42.         {        
  43.                
  44.                 Data=~P2&0x1f;                                 //读取按键状态
  45.    
  46.                 Multiple_Read_ADXL345();     //读取ADXL345数据
  47.         ADXL345_Data_Process();                 //ADXL345数据分析、处理
  48.                 Input_Data_Process();                 //按键数据分析、处理
  49.                 Send();                                                 //发送键盘代码
  50.                 Clear();                                         //清空缓存数据
  51.                 Delay50ms();        
  52.         }
  53. }
  54. void ADXL345_Data_Process()                                          
  55. {
  56.         X_data=BUF[1]<<8|BUF[0];
  57.         if(X_data<-50)Data=Data|0x10;
  58.         if(X_data>50) Data=Data|0x08;
  59. }
  60. void Input_Data_Process()
  61. {
  62.         unsigned char i;
  63.         for(i=0;i<5;i++)
  64.         {
  65.                 judge=Data&key_judge_tab[i];
  66.                 switch (judge)
  67.                 {
  68.                         case 0x00: break;
  69.                         case 0x01: key_buf[0]=key1;break;
  70.                         case 0x02: key_buf[1]=key2;break;
  71.                         case 0x04: key_buf[2]=key3;break;
  72.                         case 0x08: key_buf[3]=key4;break;
  73.                         case 0x10: key_buf[4]=key5;break;
  74.                         default:break;
  75.                 }
  76.         }        
  77. }
  78. void Multiple_read_ADXL345()
  79. {   
  80.         unsigned char i;
  81.     ADXL345_Start();                          //起始信号
  82.     ADXL345_SendByte(0xA6);           //发送设备地址+写信号
  83.     ADXL345_SendByte(0x32);                   //发送存储单元地址,从0x32开始        
  84.     ADXL345_Start();                          //起始信号
  85.     ADXL345_SendByte(0xA7);         //发送设备地址+读信号
  86.          for (i=0; i<6; i++)                      //连续读取6个地址数据,存储中BUF
  87.     {
  88.         BUF[i] = ADXL345_RecvByte();          //BUF[0]存储0x32地址中的数据
  89.         if (i == 5)ADXL345_SendACK(1);//最后一个数据需要回NOACK
  90.         else ADXL345_SendACK(0); //回应ACK
  91.    }
  92.     ADXL345_Stop();                          //停止信号
  93.     Delay5ms();
  94. }
  95. void Init_ADXL345()
  96. {
  97.    Single_Write_ADXL345(0x2C,0x08);   //速率设定为12.5
  98.    Single_Write_ADXL345(0x2D,0x08);   //选择电源模式   
  99.    Single_Write_ADXL345(0x31,0x0B);   //测量范围,正负16g,13位模式
  100. }
  101. void Single_Write_ADXL345(unsigned char REG_Address,unsigned char REG_data)
  102. {
  103.     ADXL345_Start();                  //起始信号
  104.     ADXL345_SendByte(0xA6);   //发送设备地址
  105.     ADXL345_SendByte(REG_Address);    //内部寄存器地址
  106.     ADXL345_SendByte(REG_data);       //内部寄存器数据
  107.     ADXL345_Stop();                   //发送停止信号
  108. }
  109. void ADXL345_Start()
  110. {
  111.     SDA = 1;                    //拉高数据线
  112.     SCL = 1;                    //拉高时钟线
  113.     Delay5us();                 //延时
  114.     SDA = 0;                    //产生下降沿
  115.     Delay5us();                 //延时
  116.     SCL = 0;                    //拉低时钟线
  117. }
  118. void ADXL345_Stop()
  119. {
  120.     SDA = 0;                    //拉低数据线
  121.     SCL = 1;                    //拉高时钟线
  122.     Delay5us();                 //延时
  123.     SDA = 1;                    //产生上升沿
  124.     Delay5us();                 //延时
  125. }
  126. void ADXL345_SendACK(bit ack)
  127. {
  128.     SDA = ack;                  //写应答信号
  129.     SCL = 1;                    //拉高时钟线
  130.     Delay5us();                 //延时
  131.     SCL = 0;                    //拉低时钟线
  132.     Delay5us();                 //延时
  133. }
  134. bit ADXL345_RecvACK()
  135. {
  136.     SCL = 1;                    //拉高时钟线
  137.     Delay5us();                 //延时
  138.     flag = SDA;                   //读应答信号
  139.     SCL = 0;                    //拉低时钟线
  140.     Delay5us();                 //延时

  141.     return flag;
  142. }
  143. void ADXL345_SendByte(unsigned char dat)
  144. {
  145.     unsigned char i;

  146.     for (i=0; i<8; i++)         //8位计数器
  147.     {
  148.                 SDA=dat&0x80;
  149.         SCL = 1;                //拉高时钟线
  150.         Delay5us();             //延时
  151.         SCL = 0;                //拉低时钟线
  152.         Delay5us();             //延时
  153.                 dat <<= 1;
  154.     }
  155.     ADXL345_RecvACK();
  156. }
  157. unsigned char ADXL345_RecvByte()
  158. {
  159.     unsigned char i;
  160.     unsigned char dat = 0;
  161.     SDA = 1;                    //使能内部上拉,准备读取数据,
  162.     for (i=0; i<8; i++)         //8位计数器
  163.     {
  164.         dat <<= 1;
  165.         SCL = 1;                //拉高时钟线
  166.         Delay5us();             //延时
  167.         dat |= SDA;             //读数据               
  168.         SCL = 0;                //拉低时钟线
  169.         Delay5us();             //延时
  170.     }
  171.     return dat;
  172. }
  173. void Send()                                
  174. {
  175.         unsigned char i;
  176.                 for(i=0;i<5;i++)
  177.                 {
  178.                         SBUF=key_buf[i];
  179.                         while(!TI);
  180.                         TI=0;
  181.                 }
  182. }
  183. void Clear()
  184. {
  185.         unsigned char i;
  186.         for(i=0;i<5;i++)
  187.         {
  188.                 key_buf[i]=0x00;
  189.         }
  190. }


  191. void UartInit(void)                //9600bps@11.0592MHz
  192. {
  193.         EA=1;
  194.         PCON &= 0x7F;                //波特率不倍速
  195.         SCON = 0x50;                //8位数据,可变波特率
  196.         AUXR |= 0x04;                //独立波特率发生器时钟为Fosc,即1T
  197.         BRT = 0xDC;                //设定独立波特率发生器重装值
  198.         AUXR |= 0x01;                //串口1选择独立波特率发生器为波特率发生器
  199.         AUXR |= 0x10;                //启动独立波特率发生器
  200. }


  201.                                                                                 
  202. void Delay5us()                //@11.0592MHz
  203. {
  204.         unsigned char i;

  205.         _nop_();
  206.         _nop_();
  207.         _nop_();
  208.         i = 10;
  209.         while (--i);
  210. }

  211. void Delay5ms()                //@11.0592MHz
  212. {
  213.         unsigned char i, j;

  214.         _nop_();
  215.         _nop_();
  216.         i = 54;
  217.         j = 198;
  218.         do
  219.         {
  220.                 while (--j);
  221.         } while (--i);
  222. }
  223. void Delay50ms()                //@11.0592MHz
  224. {
  225.         unsigned char i, j, k;

  226.         _nop_();
  227.         _nop_();
  228.         i = 3;
  229.         j = 26;
  230.         k = 223;
  231.         do
  232.         {
  233.                 do
  234.                 {
  235.                         while (--k);
  236.                 } while (--j);
  237.         } while (--i);
  238. }

  239. void Delay150ms()                //@11.0592MHz
  240. {
  241.         unsigned char i, j, k;

  242.         _nop_();
  243.         _nop_();
  244.         i = 7;
  245.         j = 78;
  246.         k = 167;
  247.         do
  248.         {
  249.                 do
  250.                 {
  251.                         while (--k);
  252.                 } while (--j);
  253.         } while (--i);
  254. }
复制代码


接收端程序:
  1. #include "STC12C5A60S2.h"
  2. #include "CH375INC.H"
  3. unsigned char CMD=0xff;
  4. sbit  CH375_INT_WIRE = P3^2;                        //P3.2, INT0, 连接CH375的INT#引脚,用于查询中断状态 */
  5. unsigned char idata buf[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
  6. unsigned char idata Recbuf[6]={0x00,0x00,0x00,0x00,0x00,0x00};
  7. unsigned char Rec_count=0;
  8. typedef        union _REQUEST_PACK{
  9.         unsigned char  buffer[8];
  10.         struct{
  11.                 unsigned char         bmReuestType;            //标准请求字
  12.                 unsigned char         bRequest;                           //请求代码
  13.                 unsigned int     wValue;                        //特性选择高
  14.                 unsigned int     wIndx;                                //索引
  15.                 unsigned int     wLength;                                //数据长度
  16.         }r;
  17. } mREQUEST_PACKET,        *mpREQUEST_PACKET;

  18. //设备描述符
  19. unsigned char  code DevDes[]={
  20.         0x12                        //描述符大小                        
  21. ,         0x01                        //常数DEVICE
  22. ,         0x10                        //USB规范版本信息
  23. ,         0x01
  24. ,   0x00                        //类别码,
  25. ,          0x00                        //子类别码        
  26. ,   0x00                        //协议码
  27. ,          0x08                        //端点0的最大信息包大小
  28. ,          0x3c                        //厂商ID
  29. ,   0x41
  30. ,   0x03                        //产品ID        
  31. ,   0x20
  32. ,   0x00                        //设备版本信息
  33. ,   0x02
  34. ,   0x01                        //索引值        
  35. ,   0x02
  36. ,   0x00
  37. ,   0x01                        //可能配置的数目        
  38. };
  39. //配置描述符
  40. unsigned char   code ConDes[]={                        //配置描述符
  41.                                            0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x04, 0xa0,  0x23,//配置描述符
  42.                                0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x01, 0x01, 0x05,//接口描述符
  43.                                            0x09, 0x21, 0x10, 0x01, 0x00, 0x01, 0x22, 0x41, 0x00,//HID类描述符
  44.                                0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x18   //端点描述符,只配置了输入端点,输出端点用0端点
  45.                                 };                //配置描述符

  46. /*报表描述符*/
  47. unsigned char code Hid_des[]={
  48. 0x05, 0x01, 0x09, 0x06,  0xa1, 0x01, 0x05, 0x07,  0x19, 0xe0,
  49. 0x29, 0xe7, 0x15, 0x00,  0x25, 0x01, 0x75, 0x01,  0x95, 0x08,
  50. 0x81, 0x02, 0x95, 0x01,  0x75, 0x08, 0x81, 0x01,  0x95, 0x03, 0x75, 0x01,        
  51. 0x05, 0x08, 0x19, 0x01,  0x29, 0x03, 0x91, 0x02,  0x95, 0x01, 0x75, 0x05,  
  52. 0x91, 0x01, 0x95, 0x06,  0x75, 0x08, 0x15, 0x00,  0x26, 0xff, 0x00, 0x05,
  53. 0x07, 0x19, 0x00, 0x2a,  0xff, 0x00, 0x81, 0x00,  0xc0
  54. };
  55. /*关于全局变量的定义*/
  56. unsigned char mVarSetupRequest;                                                //        ;USB请求码
  57. unsigned char mVarSetupLength;                                                //        后续数据长度
  58. unsigned char  code * VarSetupDescr;                                //描述符偏移地址
  59. unsigned char VarUsbAddress        ;                                                
  60. unsigned char idata UPDATA_FLAG;
  61. bit CH375FLAGERR;                                                                        //错误清0
  62. bit        CH375CONFLAG;

  63. mREQUEST_PACKET  request;

  64. /*硬件定义,根据硬件修改*/
  65. unsigned char volatile xdata CH375_CMD_PORT _at_ 0x81ff;                /* CH375命令端口的I/O地址 */
  66. unsigned char volatile xdata CH375_DAT_PORT _at_ 0x80ff;                /* CH375数据端口的I/O地址 */

  67. …………余下代码请下载附件…………
复制代码

工作室交流讨论群:231931086
视频中测试游戏为《极品飞车14》,若用于其他游戏,根据游戏的操作键修改Send程序中key1至Key5对应的键盘代码即可。受8位单片机机能限制,当前程序一次性最多发送6个不同键盘代码。


制作资料下载:
无线方向盘资料包.zip (1.65 MB, 下载次数: 57)
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏4 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:208443 发表于 2017-7-22 14:29 | 只看该作者
厉害了word姐
回复

使用道具 举报

板凳
ID:242127 发表于 2017-12-16 17:58 | 只看该作者
这两个程序会编译错误应该怎么改,急,谢谢
回复

使用道具 举报

地板
ID:242127 发表于 2017-12-16 18:00 | 只看该作者
这两个程序会编译错误应该怎么改,急,谢谢
回复

使用道具 举报

5#
ID:242127 发表于 2017-12-16 18:03 | 只看该作者
为什么我编译这两个程序时出错,。怎么改
回复

使用道具 举报

6#
ID:296398 发表于 2018-3-24 16:51 | 只看该作者
请教一下:你的摇杆方式就是模拟了两个键盘上的←和→的按下指令吗?
能不能做到根据摇杆的幅度去控制游戏里面车的方向盘摆幅?
回复

使用道具 举报

7#
ID:312929 发表于 2018-4-27 11:06 | 只看该作者
声卡才是亮点吧
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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