看看俺最近完成的“大作”----超酷游戏机,制作挺容易的。先在网上下载一个FC模拟器,
随便一种都行,然后把模拟器的按键设置改一下,具体是:上-下-左-右 对应 W-S-A-D,开始、选择、A键、
B键 对应 U-I-O-P,接下来做一块电路板,读取游戏手柄的按键,再通过USB发送到电脑上。电脑里也要有个上位机配合啦,比如按下手柄上的开始键,上位机就触发一个字母“I”的按下事件,达到控制模拟器的目的。
先看下截图吧~~
(原文件名:游戏.JPG)
图中上位机的主界面是一个大手柄,可以设置模拟器路径,这样每次打开我们这个超酷游戏机时,也会自动运行模拟器。插上电路板和手柄后,按下哪个键,屏幕上的手柄图里对应键上的字母会变颜 {MOD},也能控制模拟器玩游戏,太酷啦~~
下面我要详细讲下这个游戏机的制作过程了,后面有全部的源代码包括上位机和下位机的,还有免费的
技术支持哦~~ 赶紧做一个玩玩吧,重温下童年的感觉~
首先,在proteus里画出原理图,如下:
(原文件名:原理图.JPG)
ISIS里没有CH372芯片元件,估计将来也不可能有~~ 自己做个CH372元件吧。还有那个游戏手柄插座也
没有现成的,不过我试了下,可以用串口的DB9插座代替。然后生成飞线图,各个元件的位置仔细地调整下,
最后的飞线图:
(原文件名:飞线图.JPG)
然后选单层板自动布线,等了一分钟,终于布完了,我这个笔记本是在废品站一狠心花300块买回来的,
运行跟蜗牛似的,但是舍不得仍,穷学生啊~~ 不过玩模拟器游戏一点都不卡,这就很知足了。
因为是单层板,电路也挺繁琐,所以最后还剩几根飞线,用手动布线连上。OK,布好线的电路图如下:
(原文件名:PCB图.JPG)
接下来要打印到热转印纸上。如果你没有打印机,就要从网上下载一个虚拟打印机,生成一个PDF文件。
然后拿到打印店去。一般是5角钱一张。打印之前一定要让店里老板把打印缩放那项设置为“无”,否则打出来
大小不对。再裁一块合适的覆铜板,先放在腐蚀液里等十秒钟,拿出来擦干净,就不要用手碰啦。
把刚才打好的转印纸盖到覆铜板上对齐了,边上拿胶布粘住,用电熨斗加热压。因为是老古董的电熨斗,温度
也不知道多少度,稍微调高点,别把纸烫焦的温度就行,轻轻地压五分钟。然后自然冷却,慢慢撕下转印纸,
就差不多了。再检查下哪断了,用油性签字笔描通。剩下就是放到小盆里腐蚀了。等铜都化掉了,拿出来
冲干净,用钢丝球把上面的墨擦下去,我们的PCB板就做好啦,这样的:
(原文件名:PCB实物.JPG)
开始焊接了。先焊芯片。用热的烙铁尖沾点松香涂到芯片的焊盘上,再给每个焊盘镀上锡,然后把芯片
放到焊盘上对齐了,用烙铁尖垂直顶住芯片第一个引脚,稍微用力向下压,引脚下面的锡就化了,这时能
感觉到芯片引脚向下动了一下,把烙铁拿开,一个引脚就焊好了。再依次焊上其他引脚。当然还有其他
更好的方法的,大家慢慢摸索吧。做好的电路板如下:
(原文件名:实物1.JPG)
(原文件名:实物2.jpg)
(原文件名:实物3.jpg)
接下来就是软件部分了。 我要很为难的跟大家说,这个程序还是用我杜撰的那个unitedC编程语言,所以
在Keil里不能直接编译,您可以在我的博客主页myrobot.2ic.org下载相应的编译器去编译这个程序。
编译器支持MCS51、ATMEGA16和凌阳的SPCE061A。其中ATMEGA16的变量用堆栈存放,可以定义重入函数,
库函数中还有个超小的嵌入式操作系统uCORE,不过最近改了编译器,导致uCORE不能用了,在老版本uC IDE
可以用的。以后再改正。对于MCS51和SPCE061A,变量的分配采用覆盖算法,所以函数不可重入,其实
凌阳的单片机有基址寄存器,硬件上可以支持重入的。我还打算花些时间让这个编译器支持ARM。。。呵呵
幼稚的小孩啊~~
这是编译器界面:
(原文件名:编译器.JPG)
我后面要给的项目文档压缩包里有HEX文件,您可以直接写到芯片里。下面是完整的源程序:
//晶振: 11.0592MHz
#cpu "mcs51"
#include "mcs51_sfr.c"
#include "game_pad.c"
//********************************************
//游戏手柄配置元件
unit game_pad_config
{
public bit cp = @sfr.P2.0;
public bit reset = @sfr.P2.1;
public bit d = @sfr.P2.2;
}
//********************************************
//主控制元件
unit main
{
//主函数
void main()
{
//发光二极管初始化
led.init();
//游戏手柄初始化
game_pad.init();
//CH375初始化
ch375.init();
//发送CH375硬件复位命令
ch375.write_command( ch375.RESET_ALL );
time.delay_10ms( 10 );
//检查CH372存在
ch375.write_command( ch375.CHECK_EXIST );
ch375.write_data( 0xaa );
time.delay_10ms( 1 );
//判断模式设置是否成功
if( ch375.read_data() == 0x55 ) {
led.red_flash( 1 );
}
else {
led.red_flash( 10 );
}
time.delay_10ms( 5 );
//设置CH375工作在模式2
ch375.write_command( ch375.SET_USB_MODE );
ch375.write_data( 0x02 );
time.delay_10ms( 1 );
//判断模式设置是否成功
if( ch375.read_data() == 0x51 ) {
led.red_flash( 1 );
}
else {
led.red_flash( 10 );
}
time.delay_10ms( 50 );
//无限循环
uint8 i = 0;
forever {
uint8 d = game_pad.read();
ch375.write_command( ch375.WRITE_DATA2 );
ch375.write_data( 1 );
ch375.write_data( d );
while( ch375.INT == high ) {}
ch375.write_command( ch375.GET_STATUS );
uint8 d0 = ch375.read_data();
ch375.write_command( ch375.UNLOCK_USB );
}
}
}
//********************************************
//CH375元件
unit ch375
{
public const uint8 GET_IC_VER = 0x01;
public const uint8 ENTER_SLEEP = 0x03;
public const uint8 RESET_ALL = 0x05;
public const uint8 CHECK_EXIST = 0x06;
public const uint8 CHK_SUSPEND = 0x0b;
public const uint8 SET_USB_ID = 0x12;
public const uint8 SET_USB_MODE = 0x15;
public const uint8 GET_STATUS = 0x22;
public const uint8 UNLOCK_USB = 0x23;
public const uint8 READ_DATA_NOT_REL = 0x27;
public const uint8 READ_DATA_REL = 0x28;
public const uint8 WRITE_DATA1 = 0x2a;
public const uint8 WRITE_DATA2 = 0x2b;
//初始化
public void init()
{
WR = high;
RD = high;
A0 = low;
INT = high;
}
//写一个命令
public void write_command( uint8 cmd )
{
DATA = cmd;
A0 = high;
WR = low;
WR = high;
}
//写一个数据
public void write_data( uint8 data )
{
DATA = data;
A0 = low;
WR = low;
WR = high;
}
//读一个数据
public uint8 read_data()
{
A0 = low;
RD = low;
uint8 data = DATA;
RD = high;
return data;
}
uint8 DATA = @sfr.P0;
public bit INT = @sfr.P2.7;
bit WR = @sfr.P2.6;
bit RD = @sfr.P2.5;
bit A0 = @sfr.P2.4;
}
//********************************************
//延时类
unit time
{
//延时10ms
public void delay_10ms( uint8 data )
{
loop( data ) loop( 11 ) loop( 250 ) {}
}
}
//********************************************
//LED发光二极管元件
unit led
{
//初始化
public void init()
{
set_red_LED( false );
}
//红灯闪烁
public void red_flash( uint8 t )
{
loop( t ) {
set_red_LED( true );
time.delay_10ms( 10 );
set_red_LED( false );
time.delay_10ms( 10 );
}
}
//设置红 {MOD}LED状态
public void set_red_LED( bool is_light )
{
if( is_light ) {
RED_LED = low;
}
else {
RED_LED = high;
}
}
//端口
bit RED_LED = @sfr.P2.3;
}
最后是C#上位机编程了。这个就好说了,主程序中根据下位机发送的USB数据模拟Windows键盘按键事件,
就用SendKey函数,先用记事本验证下,打开一个记事本,当按下手柄的“上”键时,记事本的光标位置就多了一个字符“W”。但是不幸的事降临了,模拟器里却没有任何反应,超级玛丽就是不动啊~~ 试了一些别的
程序都行,比如可以用手柄控制幻灯片播放下一个等等,唯独模拟器对C#模拟的按键事件没反应。然后
在网上一搜,原来模拟器的键盘输入不是从Windows的标准按键事件里获取的,而是一个底层的什么openGL东东,反正没搞懂。后来在网上转了一圈,下载了一个Winio.dll,照猫画虎地改了几个地方,一运行,嘿嘿,
模拟器有反应了,魂斗罗战士会动了! 不过我现在还对这个Winio.dll感觉迷迷糊糊的,而且每次玩游戏,
360就报错,说有个dll绕过了Windows安全机制,。。。非要点允许才行。 哎,太深奥了,不懂。。
浅尝辄止,不去深究了,马马虎虎过日子。 祝朋友们天天喜乐,没有烦恼,哈哈
所有程序和资料:
点击此处下载
ourdev_600298O5G08M.rar(文件大小:4.32M) (原文件名:游戏机.rar)
一周热门 更多>