|
本作品Chinked-out工作室版权所有,给大家分享一款游戏用的无线方向盘的制作方法,是用51单片机加上ADXL345加速度传感器打造的,源码和原理图都有分享给51黑电子论坛的朋友们吧,大家先看下面的视频。
视频演示:
无线方向盘重要说明
蓝牙模块使用注意:
(1)当蓝牙模块连接到电路中后,会影响到单片机的程序下载,在下载程序之前,必须移除蓝牙串口模块。
(2)蓝牙串口模块在上单后会自行配对,但在配对过程中,蓝牙模块会自动溢出数据,从而影响到接收端单片机,进而导致单片机向PC机发送乱码。
为避免这种情况的发生,可上电后等待蓝牙模块配对成功后在打开单片机电源开关(原理图中已经是这样设计了)。
或在已经出现发送乱码的情况下,将单片机复位即可。
发送端原理图:
接收端原理图:
元件清单:
名称 | 规格 | 数量 | 备注 | 万能板 | 9x15cm | 2 |
| 单片机:STC12C5A60S2 | DIP40 | 2 |
| 40P单片机母座 |
| 2 |
| 晶振 | 11.0592Mhz | 2 |
| 陶瓷电容 | 22pF | 4 |
| 电解电容 | 22uF | 2 |
| 10K电阻 |
| 2 |
| 拨动开关 |
| 2 |
| 排针 | 1组40P | 1 |
| 杜邦线 | 1组40P | 1 |
| 6x6x7.3mm方头按键 |
| 7 |
| A44圆形按键帽 | 颜色自选 | 5 | 按键帽与按键需匹配 | 5P排针母座 |
| 2 | 用于固定ADXL345 | 4P排针母座 |
| 2 | 用于固定蓝牙模块 | ADXL345传感器 |
| 1 |
| USB转TTL下载器 | CH340系列 | 1 |
| USB线 | 母对母 | 1 |
| CH376S模块 |
| 2 |
| 蓝牙串口模块 | HC-05 | 2 |
|
无线方向盘发送端单片机源程序:
- #include "STC12C5A60S2.h"
- #include"intrins.h"
- #define key1 0x1d //黑色 刹车 Z
- #define key2 0xE1 //黄色 left shift
- #define key3 0x04 //红色 油门 A
- #define key4 0x4f //右 右转 →
- #define key5 0x50 //左 左转 ←
- sbit SCL=P0^6; //IIC时钟引脚定义
- sbit SDA=P0^7; //IIC数据引脚定义
- unsigned char idata BUF[6]; //接收数据缓存区 X轴高八位,X轴低八位; Y轴高八位,Y轴低八位; Z轴高八位,Z轴第低八位
- unsigned char idata key_buf[5]={0x00,0x00,0x00,0x00,0x00};
- unsigned char code key_judge_tab[]={0x01,0x02,0x04,0x08,0x10};
- void UartInit(void);
- void Send();
- void Clear();
- void Input_Data_Process();
- void Init_ADXL345(void); //初始化ADXL345
- void Single_Write_ADXL345(unsigned char REG_Address,unsigned char REG_data); //单个写入数据
- void Multiple_Read_ADXL345(); //连续的读取内部寄存器数据
- void ADXL345_Start();
- void ADXL345_Stop();
- void ADXL345_SendACK(bit ack);
- bit ADXL345_RecvACK();
- void ADXL345_SendByte(unsigned char dat);
- unsigned char ADXL345_RecvByte();
- void ADXL345_Data_Process();
- void Delay5us();
- void Delay5ms();
- void Delay50ms();
- void Delay150ms();
- signed int idata X_data;
- unsigned char Data,judge;
- bit key_flag=0,flag;
- void main()
- {
- Delay150ms();
- P0M1=0x00;
- P0M0=0x00;
- UartInit();
- Init_ADXL345();
- while(1)
- {
-
- Data=~P2&0x1f; //读取按键状态
-
- Multiple_Read_ADXL345(); //读取ADXL345数据
- ADXL345_Data_Process(); //ADXL345数据分析、处理
- Input_Data_Process(); //按键数据分析、处理
- Send(); //发送键盘代码
- Clear(); //清空缓存数据
- Delay50ms();
- }
- }
- void ADXL345_Data_Process()
- {
- X_data=BUF[1]<<8|BUF[0];
- if(X_data<-50)Data=Data|0x10;
- if(X_data>50) Data=Data|0x08;
- }
- void Input_Data_Process()
- {
- unsigned char i;
- for(i=0;i<5;i++)
- {
- judge=Data&key_judge_tab[i];
- switch (judge)
- {
- case 0x00: break;
- case 0x01: key_buf[0]=key1;break;
- case 0x02: key_buf[1]=key2;break;
- case 0x04: key_buf[2]=key3;break;
- case 0x08: key_buf[3]=key4;break;
- case 0x10: key_buf[4]=key5;break;
- default:break;
- }
- }
- }
- void Multiple_read_ADXL345()
- {
- unsigned char i;
- ADXL345_Start(); //起始信号
- ADXL345_SendByte(0xA6); //发送设备地址+写信号
- ADXL345_SendByte(0x32); //发送存储单元地址,从0x32开始
- ADXL345_Start(); //起始信号
- ADXL345_SendByte(0xA7); //发送设备地址+读信号
- for (i=0; i<6; i++) //连续读取6个地址数据,存储中BUF
- {
- BUF[i] = ADXL345_RecvByte(); //BUF[0]存储0x32地址中的数据
- if (i == 5)ADXL345_SendACK(1);//最后一个数据需要回NOACK
- else ADXL345_SendACK(0); //回应ACK
- }
- ADXL345_Stop(); //停止信号
- Delay5ms();
- }
- void Init_ADXL345()
- {
- Single_Write_ADXL345(0x2C,0x08); //速率设定为12.5
- Single_Write_ADXL345(0x2D,0x08); //选择电源模式
- Single_Write_ADXL345(0x31,0x0B); //测量范围,正负16g,13位模式
- }
- void Single_Write_ADXL345(unsigned char REG_Address,unsigned char REG_data)
- {
- ADXL345_Start(); //起始信号
- ADXL345_SendByte(0xA6); //发送设备地址
- ADXL345_SendByte(REG_Address); //内部寄存器地址
- ADXL345_SendByte(REG_data); //内部寄存器数据
- ADXL345_Stop(); //发送停止信号
- }
- void ADXL345_Start()
- {
- SDA = 1; //拉高数据线
- SCL = 1; //拉高时钟线
- Delay5us(); //延时
- SDA = 0; //产生下降沿
- Delay5us(); //延时
- SCL = 0; //拉低时钟线
- }
- void ADXL345_Stop()
- {
- SDA = 0; //拉低数据线
- SCL = 1; //拉高时钟线
- Delay5us(); //延时
- SDA = 1; //产生上升沿
- Delay5us(); //延时
- }
- void ADXL345_SendACK(bit ack)
- {
- SDA = ack; //写应答信号
- SCL = 1; //拉高时钟线
- Delay5us(); //延时
- SCL = 0; //拉低时钟线
- Delay5us(); //延时
- }
- bit ADXL345_RecvACK()
- {
- SCL = 1; //拉高时钟线
- Delay5us(); //延时
- flag = SDA; //读应答信号
- SCL = 0; //拉低时钟线
- Delay5us(); //延时
- return flag;
- }
- void ADXL345_SendByte(unsigned char dat)
- {
- unsigned char i;
- for (i=0; i<8; i++) //8位计数器
- {
- SDA=dat&0x80;
- SCL = 1; //拉高时钟线
- Delay5us(); //延时
- SCL = 0; //拉低时钟线
- Delay5us(); //延时
- dat <<= 1;
- }
- ADXL345_RecvACK();
- }
- unsigned char ADXL345_RecvByte()
- {
- unsigned char i;
- unsigned char dat = 0;
- SDA = 1; //使能内部上拉,准备读取数据,
- for (i=0; i<8; i++) //8位计数器
- {
- dat <<= 1;
- SCL = 1; //拉高时钟线
- Delay5us(); //延时
- dat |= SDA; //读数据
- SCL = 0; //拉低时钟线
- Delay5us(); //延时
- }
- return dat;
- }
- void Send()
- {
- unsigned char i;
- for(i=0;i<5;i++)
- {
- SBUF=key_buf[i];
- while(!TI);
- TI=0;
- }
- }
- void Clear()
- {
- unsigned char i;
- for(i=0;i<5;i++)
- {
- key_buf[i]=0x00;
- }
- }
- void UartInit(void) //9600bps@11.0592MHz
- {
- EA=1;
- PCON &= 0x7F; //波特率不倍速
- SCON = 0x50; //8位数据,可变波特率
- AUXR |= 0x04; //独立波特率发生器时钟为Fosc,即1T
- BRT = 0xDC; //设定独立波特率发生器重装值
- AUXR |= 0x01; //串口1选择独立波特率发生器为波特率发生器
- AUXR |= 0x10; //启动独立波特率发生器
- }
-
- void Delay5us() //@11.0592MHz
- {
- unsigned char i;
- _nop_();
- _nop_();
- _nop_();
- i = 10;
- while (--i);
- }
- void Delay5ms() //@11.0592MHz
- {
- unsigned char i, j;
- _nop_();
- _nop_();
- i = 54;
- j = 198;
- do
- {
- while (--j);
- } while (--i);
- }
- void Delay50ms() //@11.0592MHz
- {
- unsigned char i, j, k;
- _nop_();
- _nop_();
- i = 3;
- j = 26;
- k = 223;
- do
- {
- do
- {
- while (--k);
- } while (--j);
- } while (--i);
- }
- void Delay150ms() //@11.0592MHz
- {
- unsigned char i, j, k;
- _nop_();
- _nop_();
- i = 7;
- j = 78;
- k = 167;
- do
- {
- do
- {
- while (--k);
- } while (--j);
- } while (--i);
- }
复制代码
接收端程序:
- #include "STC12C5A60S2.h"
- #include "CH375INC.H"
- unsigned char CMD=0xff;
- sbit CH375_INT_WIRE = P3^2; //P3.2, INT0, 连接CH375的INT#引脚,用于查询中断状态 */
- unsigned char idata buf[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
- unsigned char idata Recbuf[6]={0x00,0x00,0x00,0x00,0x00,0x00};
- unsigned char Rec_count=0;
- typedef union _REQUEST_PACK{
- unsigned char buffer[8];
- struct{
- unsigned char bmReuestType; //标准请求字
- unsigned char bRequest; //请求代码
- unsigned int wValue; //特性选择高
- unsigned int wIndx; //索引
- unsigned int wLength; //数据长度
- }r;
- } mREQUEST_PACKET, *mpREQUEST_PACKET;
- //设备描述符
- unsigned char code DevDes[]={
- 0x12 //描述符大小
- , 0x01 //常数DEVICE
- , 0x10 //USB规范版本信息
- , 0x01
- , 0x00 //类别码,
- , 0x00 //子类别码
- , 0x00 //协议码
- , 0x08 //端点0的最大信息包大小
- , 0x3c //厂商ID
- , 0x41
- , 0x03 //产品ID
- , 0x20
- , 0x00 //设备版本信息
- , 0x02
- , 0x01 //索引值
- , 0x02
- , 0x00
- , 0x01 //可能配置的数目
- };
- //配置描述符
- unsigned char code ConDes[]={ //配置描述符
- 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x04, 0xa0, 0x23,//配置描述符
- 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x01, 0x01, 0x05,//接口描述符
- 0x09, 0x21, 0x10, 0x01, 0x00, 0x01, 0x22, 0x41, 0x00,//HID类描述符
- 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x18 //端点描述符,只配置了输入端点,输出端点用0端点
- }; //配置描述符
- /*报表描述符*/
- unsigned char code Hid_des[]={
- 0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x05, 0x07, 0x19, 0xe0,
- 0x29, 0xe7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08,
- 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, 0x95, 0x03, 0x75, 0x01,
- 0x05, 0x08, 0x19, 0x01, 0x29, 0x03, 0x91, 0x02, 0x95, 0x01, 0x75, 0x05,
- 0x91, 0x01, 0x95, 0x06, 0x75, 0x08, 0x15, 0x00, 0x26, 0xff, 0x00, 0x05,
- 0x07, 0x19, 0x00, 0x2a, 0xff, 0x00, 0x81, 0x00, 0xc0
- };
- /*关于全局变量的定义*/
- unsigned char mVarSetupRequest; // ;USB请求码
- unsigned char mVarSetupLength; // 后续数据长度
- unsigned char code * VarSetupDescr; //描述符偏移地址
- unsigned char VarUsbAddress ;
- unsigned char idata UPDATA_FLAG;
- bit CH375FLAGERR; //错误清0
- bit CH375CONFLAG;
- mREQUEST_PACKET request;
- /*硬件定义,根据硬件修改*/
- unsigned char volatile xdata CH375_CMD_PORT _at_ 0x81ff; /* CH375命令端口的I/O地址 */
- unsigned char volatile xdata CH375_DAT_PORT _at_ 0x80ff; /* CH375数据端口的I/O地址 */
- …………余下代码请下载附件…………
复制代码
工作室交流讨论群:231931086
视频中测试游戏为《极品飞车14》,若用于其他游戏,根据游戏的操作键修改Send程序中key1至Key5对应的键盘代码即可。受8位单片机机能限制,当前程序一次性最多发送6个不同键盘代码。
制作资料下载:
无线方向盘资料包.zip
(1.65 MB, 下载次数: 60)
|
|