## 前言
這是一款基于立創(chuàng)梁山派設(shè)計的游戲機(jī)拓展板,官方的叫天魁星,交通燈拓展板叫天罡星,那我做的就叫它天機(jī)星吧!哈哈哈!
## 項目需求
1、具有UI界面,能夠通過選擇來玩多種游戲。
2、屏幕小巧、亮度可調(diào)節(jié)。
3、通過喇叭或者插入有線耳機(jī)輸出聲音、振動馬達(dá)給予使用者一定的反饋。
4、使用搖桿和按鍵結(jié)合的方式獲得良好游戲體驗。
5、獨立電源、Type-C可充電式設(shè)計、電量檢測以及支持長按開機(jī)與長按關(guān)機(jī)等功能。
## 器件選擇
1、屏幕:
![image.png]
使用1.69寸IPS屏幕
2、耳機(jī)孔、喇叭與功放IC:
![image.png]
![image.png]
喇叭需在淘寶購買。
![image.png]
8002A
3、3D搖桿
![image.png]
個人認(rèn)為這種3D搖桿比官方的手感體驗更好些。然后我在淘寶購買了一個搖桿按鍵帽安裝上去。
4、按鍵
![image.png]
綜合考量,這種開關(guān)雖然手感上沒有官方拓展板的體驗?zāi)敲春茫沁@種輕觸開關(guān)可以安上鍵帽,顯得更好看。
5、EEPROM
![image.png]
M24C02
6、震動馬達(dá)
![image.png]
7、充電IC
![image.png]
LP4056HSPF
8、升壓IC
![image.png]
ME2159AM6G
將鋰電池3.7V的電壓升壓到5V給板子供電。
## 原理圖設(shè)計說明
1、MOS開關(guān)電路:
![image.png]
長按開機(jī)功能:按下START輕觸開關(guān)時,PMOS管的柵極接低電位導(dǎo)致其源極和漏極導(dǎo)通,相當(dāng)于開關(guān)打開,這時單片機(jī)已經(jīng)上電,為了實現(xiàn)長按開機(jī)的效果,當(dāng)按下時間小于2S時,單片機(jī)控制屏幕不亮,且PE6端口輸出低電平,只要輕觸開關(guān)放開,源極和漏極就會截止。單片機(jī)斷電。當(dāng)按鍵按下大于2S時,PE6端口輸出高電平,使得S8050三極管發(fā)射級與集電極導(dǎo)通,無論按鍵是否按下,單片機(jī)都不會斷電。這樣就實現(xiàn)了長按開機(jī)的功能。
長按關(guān)機(jī)功能:PE5管腳使用外部中斷、上拉輸入的形式,當(dāng)按鍵按下時,PE5電平被拉低,單片機(jī)通過檢測按下時間,當(dāng)按下時間大于設(shè)定的閾值,PE6輸出低電平,熄滅屏幕,給用戶造成關(guān)機(jī)的感覺,但單片機(jī)其實還沒斷電,當(dāng)手從按鍵移開時,PMOS柵極電位拉高,源極和漏極截止,從何實現(xiàn)真正斷電。
2、充電電路:
![image.png]
![image.png]
充電IC使用LP4056HSPF,ISET引腳接的2K電阻,通過查找數(shù)據(jù)手冊知這樣充電電流為0.5A.STAT1與STAT2引腳在充電時與充電完成輸出的電平不同,將兩個引腳接到梁山派的相應(yīng)引腳上可以檢測游戲機(jī)是否正在充電以及是否充電完成。充電接口使用的是TYPE-C。由于VBAT網(wǎng)絡(luò)位于PMOS管的源極端,所以無論游戲機(jī)電源是否打開,都可以進(jìn)行充電。
3、升壓電路:
![image.png]
升壓IC采用ME2159AM6G,將3.7V的電壓升到5V給板子供電,當(dāng)充電時5V_CG網(wǎng)絡(luò)的電壓使MMBT3904三極管集電極與發(fā)射極導(dǎo)通,EN引腳置低,升壓IC停止升壓,這樣就可以避免電池與外接電源同時給板子通電的情況發(fā)生。采用兩個510K電阻的串聯(lián)分壓進(jìn)行電壓檢測,如上圖,由于VCC網(wǎng)絡(luò)位于PMOS管的漏極端,所以當(dāng)關(guān)閉游戲機(jī)時,ADC電壓檢測不會存在形成回路而導(dǎo)致放電的現(xiàn)象。
4、按鍵電路:
![image.png]
為了更方便布線,所以將部分按鍵引腳做了“非連接”處理。
其余電路設(shè)計與官方拓展板基本相同,不做一一贅述。
## PCB設(shè)計說明
![image.png]
考慮到使用了另一種3D搖桿,這種搖桿的高度比較高,如果仍把屏幕貼在主板子中間,效果可能不是特別好,因此這里把屏幕焊接在另一個小板子上,在通過焊盤將兩個板子焊接在一起。
## 軟件說明
1、控制開關(guān)機(jī)的PE5 PE6引腳的配置代碼如下:
```
void output_Init(void)
{
rcu_periph_clock_enable(RCU_GPIOE);
gpio_mode_set(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,GPIO_PIN_6);
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_6);
}
void On(void)
{
gpio_bit_set(GPIOE,GPIO_PIN_6);//PE6置高,無論按鍵是否按下,板子都會有供電
}
void Off(void)
{
gpio_bit_reset(GPIOE,GPIO_PIN_6);//PE6置低,手從按鍵上放開時,板子真正意義上斷電
}
void input_EXTI_Init(void)//檢測START按鍵是否按下
{
/* 開啟時鐘 */
rcu_periph_clock_enable(RCU_GPIOE);
rcu_periph_clock_enable(RCU_SYSCFG);
/* 配置GPIO的模式 */
gpio_mode_set(GPIOE,GPIO_MODE_INPUT,GPIO_PUPD_PULLUP,GPIO_PIN_5);//上拉輸入
nvic_irq_enable(EXTI5_9_IRQn,2U,0U);
syscfg_exti_line_config(EXTI_SOURCE_GPIOE,EXTI_SOURCE_PIN5);
exti_init(EXTI_5,EXTI_INTERRUPT,EXTI_TRIG_FALLING);
exti_interrupt_enable(EXTI_5);
exti_interrupt_flag_clear(EXTI_5);
}
```
2、延遲開機(jī)部分:當(dāng)按下START按鍵時,先執(zhí)行Off()函數(shù),延遲2S再執(zhí)行On()函數(shù),同時亮屏,提示用戶松開按鍵。下面是代碼放置的位置:
```
systick_config();
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
output_Init();
Off();//按鍵按下時間小于兩秒就移開,板子會斷電
delay_1ms(2000);//延遲2S
usart0_init();
adc_config();
adc_bat_init();
key_init();
led_init();
ui_main_set_init();
On();//由于下面的開機(jī)logo顯示函數(shù)里面也有延時部分,實現(xiàn)加載效果,所以O(shè)n()函數(shù)放在這一行執(zhí)行
ui_main_lcd_init();//開機(jī)logo顯示
//....省略之間的代碼.....//
ui_main_init_show();
input_EXTI_Init();//PE5引腳輸入初始化
while(1)
{
//....省略代碼.....//
}
```
當(dāng)要關(guān)閉游戲機(jī)時,按下START按鍵,PE5引腳產(chǎn)生下降沿,程序執(zhí)行立刻進(jìn)入外部中斷回調(diào)函數(shù),具體作用以及代碼上文已經(jīng)涉及,不再贅述,回調(diào)函數(shù)代碼如下:
```
void EXTI5_9_IRQHandler(void)//中斷回調(diào)函數(shù)
{
if(exti_interrupt_flag_get(EXTI_5) == SET)
{
delay_1ms(20);
if(gpio_input_bit_get(GPIOE,GPIO_PIN_5) == RESET)
{
uint8_t i;
for(i=0;i<10;i++)//2s長按關(guān)機(jī),每200ms檢測一次
{
delay_1ms(200);
if(gpio_input_bit_get(GPIOE,GPIO_PIN_5) == RESET && i==9)
{
Off();//PE6置低,手從按鍵上放開時,板子真正意義上斷電
LCD_Fill(0,0,240,280,0x0000);//屏幕熄滅,造成關(guān)機(jī)的現(xiàn)象
while(1);//死循環(huán)
}
else if(gpio_input_bit_get(GPIOE,GPIO_PIN_5) == SET)
{
break;//若不符合條件則退出循環(huán)
}
}
}
exti_interrupt_flag_clear(EXTI_5);//清除中斷標(biāo)志位
}
}
```
2、開機(jī)LOGO顯示與加載效果
LCD_ShowPicture1函數(shù)可顯示圖片,最后一個參數(shù)是圖片轉(zhuǎn)數(shù)組之后的數(shù)組名稱。
官方的示例程里的開機(jī)LOGO是立創(chuàng)開發(fā)板的字樣,我把他換成了自己設(shè)計的圖片。
```
//開機(jī)logo顯示
void ui_main_lcd_init(void)
{
LCD_Init();
LCD_timer_config();
LCD_ShowPicture1(0,0,LCD_W,LCD_H,START_BMP); //開機(jī)logo
LCD_ShowString(((240-strlen("Loading")*12)/2),0,"Loading!",LCEDA,WHITE,24,0);
delay_1ms(1200);
LCD_ShowString(((240-strlen("*Loading!*")*12)/2),0,"*Loading!*",LCEDA,WHITE,24,0);
delay_1ms(900);
LCD_ShowString(((240-strlen("**Loading!**")*12)/2),0,"**Loading!**",LCEDA,WHITE,24,0);
delay_1ms(600);
LCD_ShowString(((240-strlen("***Loading!***")*12)/2),0,"***Loading!***",LCEDA,WHITE,24,0);
delay_1ms(300);
timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_1,50+ui_set.luminance*10);
}
```
圖片轉(zhuǎn)數(shù)組可使用一個叫Image2Lcd的軟件進(jìn)行轉(zhuǎn)換:
![image.png]

轉(zhuǎn)換完成后將數(shù)組復(fù)制粘貼到image.h相應(yīng)的位置上。
![image.png]

這張圖是我設(shè)計的開機(jī)LOGO
![image.png]

這張圖是“關(guān)于本機(jī)”的內(nèi)容。所以大家也可以根據(jù)自己的喜好導(dǎo)入想顯示的圖片。
3、顯示中文不亂碼的方法
由于一開始梁山派板載的SPI Flash里沒有中文字庫數(shù)據(jù),所以運行NES系統(tǒng)時顯示中文會亂碼,那么這時候就要導(dǎo)入中文字庫,第一步:使用一張SD卡(推薦使用32GB的,因為有群友表示選擇的SD卡內(nèi)存過大或過小可能會導(dǎo)致無法識別的現(xiàn)象)。在根目錄下新建一個名為font文件夾,將字庫文件放在里面;第二步:將其插入到已經(jīng)下載好NES系統(tǒng)程序的梁山派SD卡槽中,插電啟動時它自己就會將字庫數(shù)據(jù)刷到flash里面。之后不管是否插入內(nèi)存卡,都可以正常顯示中文了!
4、優(yōu)化在未玩游戲時喇叭或者耳機(jī)的沙沙聲
由于nes游戲的音頻輸出有一個0x80的直流偏置。如果這個輸出到喇叭或耳機(jī)的信號有突變,就會導(dǎo)致喇叭有一個非常令人難受的異響,所以可能官方的nes系統(tǒng)的程序為了兼容,在未玩游戲時也對音頻輸出了0x80的偏置,但這樣會造成一個很大的問題,就是會有沙沙聲,使體驗感不佳,因此,經(jīng)過我對代碼的研究,未進(jìn)入游戲時,音頻信號直接輸出零,進(jìn)入游戲時加入0->0x80,退出游戲時加入0x80->0的信號緩變,這樣就可以很好程度的解決沙沙聲的問題。
Timer3的初始化音頻就輸出零,然后Timer3的中斷回調(diào)函數(shù)改的比較多,這部分自己改的屎山代碼太長就不貼出來了,其余是一些細(xì)節(jié)部分,需要可以下載我上傳的程序,復(fù)制相關(guān)內(nèi)容到自己的代碼里。
![image.png]

![image.png]

![image.png]

![image.png]

## 實物展示
1、3D外殼實物展示
使用了嘉立創(chuàng)三維猴的3D打印,效果很好,表面非常光滑,滿滿的大贊!
![image.png]

![image.png]

2、面板展示
使用嘉立創(chuàng)EDA的繪制面板功能畫了一個面板,發(fā)給立創(chuàng)商城進(jìn)行打印,色彩效果也是非常棒,尺寸也非常對應(yīng),無偏差。面板文件在工程里面。
![image.png]

3、游戲機(jī)內(nèi)部展示
![image.png]

4、游戲機(jī)整體展示
![image.png]

## 創(chuàng)新點
1、未采用官方提供的
電源模塊方案,而是自己設(shè)計了MOS管開關(guān)電路,搭配充電與升壓電路,完成供電的硬件部分,在軟件層面加入相關(guān)代碼,實現(xiàn)了長按開機(jī)與長按關(guān)機(jī)功能,效果很不錯。
2、設(shè)計了3D外殼與面板,使得PCB有了一個好看的外衣,玩游戲的體驗感得到提升。
3、對NES系統(tǒng)的音頻部分的代碼進(jìn)行優(yōu)化,解決了在未玩游戲時的沙沙聲問題。
## 未來的計劃
由于最近很忙,未能將游戲的功能變得更加豐富多彩,但我希望在未來能夠增加、豐富程序內(nèi)容,加入有意思的部分,比如聽音樂、電子時鐘等功能。
## 致謝
首先十分感謝嘉立創(chuàng),為我們這些電子愛好者提供了大力的支持,“不以賣板賺錢,以培養(yǎng)中國工程師為己任”,的確,不管是PCB免費打樣,還是立創(chuàng)開發(fā)板,又或是立創(chuàng)
開源硬件平臺,都讓電子制作低成本化、普及化......為培養(yǎng)中國硬件工程師做出了很大的貢獻(xiàn)!
感謝吳工、小許,以及立創(chuàng)商城妮姐,雖然我經(jīng)常去煩他們,他們還是很熱心的為我解答問題,更重要的是他們給我發(fā)了券,降低了制作游戲機(jī)的成本,哈哈哈!
OK,就這樣,前前后后寫了好久,終于完成啦!