摘要:第二點(diǎn)與是同時(shí)完成的,說明這是全雙工通信。上表中的表示數(shù)據(jù)線空閑,該數(shù)據(jù)線無數(shù)據(jù)傳送。設(shè)置震動(dòng)模式后用來控制右側(cè)的小電機(jī),表示關(guān),其他值為開。單片機(jī)發(fā)送了給手柄,此時(shí)手柄會(huì)返回給單片機(jī),意味著接收到了請(qǐng)求,即將返回?cái)?shù)據(jù)。
一、硬件準(zhǔn)備:戰(zhàn)艦開發(fā)板、PS2手柄接收器、PS2手柄、連接線
二、硬件連接:
PS2手柄接收器有六個(gè)引腳,和單片機(jī)連接IO口連接,如下圖:
接收器信號(hào) | 單片機(jī)IO |
---|---|
GND | GND |
VCC | 3.3V |
DI/DAT | PB12 |
DO/CMD | PB13 |
CS | PB14 |
CLK | PB15 |
三、PS2通信簡(jiǎn)介
通訊時(shí)序如下,感覺和SPI很像,也是四線
DI與DO是一對(duì)同時(shí)傳輸?shù)? bit串行數(shù)據(jù),傳輸?shù)臅r(shí)候需要CS為低電平,CLK由高變低。
DO是單片機(jī)發(fā)送給接收器的信號(hào)。
DI是接收器發(fā)送給單片機(jī)的信號(hào)。
第一點(diǎn):CS在數(shù)據(jù)輸出或者輸入的時(shí)候,都是低電平的,那么我們?cè)跀?shù)據(jù)傳輸?shù)臅r(shí)候先把CS拉高再拉低,然后數(shù)據(jù)進(jìn)行傳輸,傳輸完成之后再把CS拉高。
第二點(diǎn):DI(Data Input)與DO(Data Output)是同時(shí)完成的,說明這是全雙工通信。串口是全雙工通信。IIC是半雙工通信。
第三點(diǎn):在時(shí)鐘上降沿的時(shí)候,DI和DO的數(shù)據(jù)有交叉,也就是說數(shù)據(jù)進(jìn)行交換(數(shù)據(jù)只有0和1),這個(gè)時(shí)候我們是不能夠讀和寫數(shù)據(jù)的,因?yàn)閿?shù)據(jù)還不穩(wěn)定,我們讀到的數(shù)據(jù)不準(zhǔn)確。在時(shí)鐘為下降沿的時(shí)候,數(shù)據(jù)已經(jīng)穩(wěn)定了,我們?cè)谶@個(gè)時(shí)候開始讀和寫數(shù)據(jù)。
第四點(diǎn):由于是從0到7,可以知道有8位數(shù)據(jù),并且是從低位到高位進(jìn)行讀寫。我們可以把數(shù)據(jù)放到數(shù)組中。一個(gè)時(shí)鐘進(jìn)行一個(gè)數(shù)據(jù)位(也可以叫做比特位0或1)傳輸。
時(shí)鐘頻率250KHZ(4us),數(shù)據(jù)不穩(wěn)定可適當(dāng)增加頻率。
當(dāng)單片機(jī)發(fā)送0x01時(shí),接收器會(huì)回復(fù)它的ID“0X41表示綠燈模式”、“0x73表示紅燈模式”;在手柄發(fā)送ID的同時(shí),單片機(jī)將發(fā)送0X42,手柄會(huì)發(fā)送0X5A,高速單片機(jī)數(shù)據(jù)來了。
上表中的idle表示數(shù)據(jù)線空閑,該數(shù)據(jù)線無數(shù)據(jù)傳送。
所以Data[0]、Data[1]、Data[2]不能用來存放PS2搖桿的按鍵
Data[3]、Data[4]用來存放按鍵的值
Data[5]、Data[6]、Data[7]、Data[8]用來存放搖桿的模擬量
當(dāng)有按鍵下,對(duì)應(yīng)位為0,其他位為1
譬如,當(dāng)SELECT按下,Data[3]=1111 1110B
當(dāng)L3按下,Data[3]=1111 1101B
當(dāng)R3按下,Data[3]=1111 1011B
當(dāng)START按下,Data[3]=1111 0111B
當(dāng)UP按下,Data[3]=1110 1111B
當(dāng)RIGHT按下,Data[3]=1101 1111B
當(dāng)DOWN按下,Data[3]=1011 1111B
當(dāng)LEFT按下,Data[3]=0111 1111B
手柄有兩個(gè)模式,紅燈模式(手柄亮紅燈+綠燈)和綠燈模式(手柄只亮綠燈),可以通過按下MODE按鍵進(jìn)行切換。
紅燈模式:
1.按鍵L3/R3按下有效
2.推動(dòng)左右搖桿,根據(jù)行程不一樣,可輸出0x00-0xff的模擬量
綠燈模式:
1.按鍵L3/R3按下有效
2.左右搖桿不輸出模擬量,推動(dòng)到上下左右的極限值,左搖桿實(shí)現(xiàn)的效果和UP/DOWN/RIGHT/LEFT一樣,右搖桿實(shí)現(xiàn)的效果和和△/X/□/○一樣。
設(shè)置震動(dòng)模式后:
WW用來控制右側(cè)的小電機(jī),0x00表示關(guān),其他值為開。
YY用來控制左側(cè)的大電機(jī),0x40-0xff表示電機(jī)開,值越大,震感越強(qiáng)烈;其他值表示電機(jī)關(guān)。
四、代碼分析
1.配置IO口,將PB12設(shè)置為下拉輸入;PB13/14/15設(shè)置為推挽輸出
void PS2_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; //輸入 DI->PB12 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //使能PORTB時(shí)鐘 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //設(shè)置成上拉、下拉、浮空輸入皆可 GPIO_Init(GPIOB, &GPIO_InitStructure); //輸出 DO->PB13 CS->PB14 CLK->PB15 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //設(shè)置成推挽輸出 GPIO_Init(GPIOB, &GPIO_InitStructure);}
2.定義3個(gè)數(shù)組
u8 Comd[2]={0x01,0x42}; //開始命令。請(qǐng)求數(shù)據(jù)u8 Data[9]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //數(shù)據(jù)存儲(chǔ)數(shù)組//每個(gè)按鍵對(duì)應(yīng)一個(gè)數(shù)值u16 MASK[]={ PSB_SELECT, PSB_L3, PSB_R3 , PSB_START, PSB_PAD_UP, PSB_PAD_RIGHT, PSB_PAD_DOWN, PSB_PAD_LEFT, PSB_L2, PSB_R2, PSB_L1, PSB_R1 , PSB_GREEN, PSB_RED, PSB_BLUE, PSB_PINK};
3.給PB12/PB13/PB14/PB15這4個(gè)IO的狀態(tài)均進(jìn)行宏定義
#define DI PBin(12) //PB12 輸入#define DO_H PBout(13)=1 //命令位高#define DO_L PBout(13)=0 //命令位低#define CS_H PBout(14)=1 //CS拉高#define CS_L PBout(14)=0 //CS拉低#define CLK_H PBout(15)=1 //時(shí)鐘拉高#define CLK_L PBout(15)=0 //時(shí)鐘拉低
4.單片機(jī)向手柄發(fā)送命令
//向手柄發(fā)送命令void PS2_Cmd(u8 CMD){ volatile u16 ref=0x01; Data[1] = 0; for(ref=0x01;ref<0x0100;ref<<=1) { if(ref&CMD) { DO_H; //輸出以為控制位 } else DO_L; CLK_H; //產(chǎn)生時(shí)鐘 delay_us(50); CLK_L; delay_us(50); CLK_H; if(DI) Data[1] = ref|Data[1]; }}//假如單片機(jī)給接收器發(fā)送0x01=0000 0001B,接收器接受到0x01后給單片機(jī)發(fā)送了0x41=0100 0001B,ref=0x01=0000 0001B;Data[1] = 0;CMD=0000 0001BDI=0100 0001B/從低位到高位執(zhí)行8次循環(huán)第一次循環(huán):ref=0000 0001Bif(ref&CMD)為真,輸出PB13=1if(DI)為真,輸出Data[1] = ref|Data[1]=0000 0001|0000 0000=0000 0001第二次循環(huán):ref=0000 0010Bif(ref&CMD)為假,輸出PB13=0if(DI)為假,不執(zhí)行操作第三次循環(huán):ref=0000 0100Bif(ref&CMD)為假,輸出PB13=0if(DI)為假,不執(zhí)行操作第四次循環(huán):ref=0000 1000Bif(ref&CMD)為假,輸出PB13=0if(DI)為假,不執(zhí)行操作第五次循環(huán):ref=0001 0000Bif(ref&CMD)為假,輸出PB13=0if(DI)為假,不執(zhí)行操作第六次循環(huán):ref=0010 0000Bif(ref&CMD)為假,輸出PB13=0if(DI)為假,不執(zhí)行操作第七次循環(huán):ref=0100 0000Bif(ref&CMD)為假,輸出PB13=0if(DI)為真,輸出Data[1] = ref|Data[1]=0100 0000|0000 0001=0100 0001第八次循環(huán):ref=1000 0000Bif(ref&CMD)為假,輸出PB13=0if(DI)為假,不執(zhí)行操作/所以最后的結(jié)果就是單片機(jī)將0x01按位發(fā)送了出去接收機(jī)發(fā)送的數(shù)據(jù)0x41保存到了Data[1]里面
a…volatile修飾符可以保證ref每次開始都是0x01即0000 0001B
b.ref=0x01;ref<0x0100;ref<<=1
理解這句首先需要將十六進(jìn)制改為二進(jìn)制,即ref=0000 0001B;ref<0000 0001 0000 000B;ref<<=1
即將ref=0x01
每次左移一位,循環(huán)八次。
c.ref&CMD
即可以通過與運(yùn)算循環(huán)八次,將CMD 這個(gè)八位二進(jìn)制的數(shù)按位發(fā)送出去。
d.CLK電平進(jìn)行高-低-高可以產(chǎn)生一個(gè)周期,同時(shí)產(chǎn)生一個(gè)下降沿。在這個(gè)過程中,DO將信號(hào)從單片機(jī)(發(fā)送)給接收器(接收),DI將信號(hào)從接收器(發(fā)送)給單片機(jī)(接收)
e.單片機(jī)接收到的數(shù)據(jù)被保存在了Data[1]里面
5.判斷手柄是紅燈模式還是綠燈模式,通過單片機(jī)給手柄發(fā)送0x01 0x42后,手柄返回的值來判斷,如果返回的是0X41表示"綠燈模式"、0x73表示"紅燈模式"
//判斷是否為紅燈模式//返回值;0,紅燈模式//返回值;1,綠燈模式u8 PS2_RedLight(void){ CS_L; PS2_Cmd(Comd[0]); //開始命令0x01 PS2_Cmd(Comd[1]); //請(qǐng)求數(shù)據(jù)0x42 CS_H; if( Data[1] == 0X73) return 0 ; else return 1;}
5.單片機(jī)接收手柄數(shù)據(jù)
//讀取手柄數(shù)據(jù)void PS2_ReadData(void){ volatile u8 byte=0; volatile u16 ref=0x01; CS_L; PS2_Cmd(Comd[0]); //開始命令0x01 PS2_Cmd(Comd[1]); //請(qǐng)求數(shù)據(jù)0x42 for(byte=2;byte<9;byte++) //開始接受數(shù)據(jù) { for(ref=0x01;ref<0x100;ref<<=1) { CLK_H; CLK_L; delay_us(50); CLK_H; if(DI) Data[byte] = ref|Data[byte]; } delay_us(50); } CS_H; }
a.數(shù)據(jù)傳輸必須在CS拉低期間進(jìn)行,數(shù)據(jù)傳輸完成后,還要將CS拉回高電平,以便下一次的通訊。
b.單片機(jī)發(fā)送了0x01 0x42給手柄,此時(shí)手柄會(huì)返回0x5A給單片機(jī),意味著接收到了請(qǐng)求,即將返回?cái)?shù)據(jù)。所以Data[2]保存的就是手柄返回的0x5A。后面的Data[3]-Data[8]返回的都是按鍵和搖桿的狀態(tài)信息。
6.檢測(cè)按鍵狀態(tài)
//對(duì)讀出來的PS2的數(shù)據(jù)進(jìn)行處理 只處理了按鍵部分 默認(rèn)數(shù)據(jù)是紅燈模式 只有一個(gè)按鍵按下時(shí)//按下為0, 未按下為1u8 PS2_DataKey(){ u8 index; PS2_ClearData(); PS2_ReadData(); Handkey=(Data[4]<<8)|Data[3]; //這是16個(gè)按鍵 按下為0, 未按下為1 for(index=0;index<16;index++) { if((Handkey&(1<<(MASK[index]-1)))==0) return index+1; } return 0; //沒有任何按鍵按下}
a.上圖有給手柄按鍵標(biāo)號(hào),一共16個(gè)按鍵,包括兩個(gè)搖桿,不包括MODE鍵。16個(gè)按鍵剛好是兩個(gè)八位二進(jìn)制數(shù)。所以用Data[3]和Data[4]表示所有的按鍵的狀態(tài)。
b.u16 Handkey
,通過這個(gè)變量定義可以看出來Handkey是一個(gè)16位的二進(jìn)制數(shù),Handkey=(Data[4]<<8)|Data[3]
表示的是Handkey這個(gè)變量的高八位是Data[4],低八位是Data[3]
假如我SELECT按下了,那么Data[3]=1111 1110B
如果L2按下了,那么Data[4]=1111 1110B
所以Handkey表示的就是1111 1110 1111 1110B
c.for(index=0;index<16;index++)
因?yàn)橛?6個(gè)按鍵,所以進(jìn)行16次循環(huán),以此判斷是被按下的是哪個(gè)鍵。
if((Handkey&(1<<(MASK[index]-1)))==0)
這個(gè)函數(shù)由內(nèi)到外分析0<=index<=15
,所以1<=MASK[index]<=16
,所以0<=MASK[index]-1)<=15
,然后將1換算成16位的二進(jìn)制數(shù)為:0000 0000 0000 0001B
,所以1<<(MASK[index]-1)
就是每次左移一位,循環(huán)15次。然后和Handkey進(jìn)行與運(yùn)算,如果為0,則說明按鍵被按下。最后index+1
是因?yàn)閕ndex是從0開始算的,而按鍵是從1開始計(jì)算的,所以最后返回的值需要+1。但這個(gè)函數(shù)只能判斷單個(gè)按鍵按下。如果有多個(gè)按鍵按下,只能檢測(cè)按鍵數(shù)較小的那個(gè)值,譬如方向上(5)和START(4)同時(shí)被按下,則返回值就是4。
#define PSB_SELECT 1#define PSB_L3 2#define PSB_R3 3#define PSB_START 4#define PSB_PAD_UP 5#define PSB_PAD_RIGHT 6#define PSB_PAD_DOWN 7#define PSB_PAD_LEFT 8#define PSB_L2 9#define PSB_R2 10#define PSB_L1 11#define PSB_R1 12#define PSB_GREEN 13#define PSB_RED 14#define PSB_BLUE 15#define PSB_PINK 16u16 MASK[]={ PSB_SELECT, PSB_L3, PSB_R3 , PSB_START, PSB_PAD_UP, PSB_PAD_RIGHT, PSB_PAD_DOWN, PSB_PAD_LEFT, PSB_L2, PSB_R2, PSB_L1, PSB_R1 , PSB_GREEN, PSB_RED, PSB_BLUE, PSB_PINK};
7.檢測(cè)搖桿的狀態(tài)
#define PSS_RX 5 #define PSS_RY 6#define PSS_LX 7#define PSS_LY 8//得到一個(gè)搖桿的模擬量 范圍0~256u8 PS2_AnologData(u8 button){ return Data[button];}
a.四個(gè)搖桿反饋的是模擬量,范圍在0x00~0xFF,轉(zhuǎn)換成十進(jìn)制即為0-255。搖桿的數(shù)值存放在Data[5]、Data[6]、Data[7]、Data[8]中
b.注意只有紅燈模式下?lián)u桿才反饋模擬量,綠燈模式下?lián)u桿不反饋模擬量。
8.其他函數(shù)
8.1清除數(shù)據(jù)緩沖
//清除數(shù)據(jù)緩沖區(qū)void PS2_ClearData(){ u8 a; for(a=0;a<9;a++) Data[a]=0x00;}
8.2手柄震動(dòng)函數(shù)
/******************************************************motor1:右側(cè)小震動(dòng)電機(jī) 0x00關(guān),其他開motor2:左側(cè)大震動(dòng)電機(jī) 0x40~0xFF 電機(jī)開,值越大 震動(dòng)越大******************************************************/void PS2_Vibration(u8 motor1, u8 motor2){ CS_L; delay_us(16); PS2_Cmd(0x01); //開始命令 PS2_Cmd(0x42); //請(qǐng)求數(shù)據(jù) PS2_Cmd(0X00); PS2_Cmd(motor1); PS2_Cmd(motor2); PS2_Cmd(0X00); PS2_Cmd(0X00); PS2_Cmd(0X00); PS2_Cmd(0X00); CS_H; delay_us(16); }
8.3發(fā)送模式設(shè)置
a.第八行PS2_Cmd(0x01)
則為紅燈模式;PS2_Cmd(0x00)
則為綠燈模式;
b.第九行PS2_Cmd(0x03)
則只可以通過第八行的指令進(jìn)行紅綠燈模式切換;PS2_Cmd(0xEE)
則可以通過按MODE進(jìn)行紅綠燈模式切換。
//發(fā)送模式設(shè)置void PS2_TurnOnAnalogMode(void){ CS_L; PS2_Cmd(0x01); PS2_Cmd(0x44); PS2_Cmd(0X00); PS2_Cmd(0x01); //analog=0x01;digital=0x00 軟件設(shè)置發(fā)送模式 PS2_Cmd(0xEE); //Ox03鎖存設(shè)置,即不可通過按鍵“MODE”設(shè)置模式。 //0xEE不鎖存軟件設(shè)置,可通過按鍵“MODE”設(shè)置模式。 PS2_Cmd(0X00); PS2_Cmd(0X00); PS2_Cmd(0X00); PS2_Cmd(0X00); CS_H; delay_us(16);}
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/123289.html
摘要:基于開發(fā)的軟件包導(dǎo)師汪禮超學(xué)員崔林威摘要騰訊物聯(lián)網(wǎng)操作系統(tǒng)是騰訊面向物聯(lián)網(wǎng)領(lǐng)域開發(fā)的實(shí)時(shí)操作系統(tǒng),具有低功耗,低資源占用,模塊化,可裁剪等特性。圖中斷函數(shù)處理進(jìn)行生成工程配置,按如下界面進(jìn)行配置,最后點(diǎn)擊,并點(diǎn)擊。 ...
摘要:力矩控制模式電機(jī)在運(yùn)行過程的電流,始終等于給定的值。設(shè)定電流為零,彈簧不被拉伸。比如機(jī)械臂從點(diǎn)運(yùn)動(dòng)到點(diǎn),并限制揮舞過程中的最大速度和最大力矩。 目錄 說明一、電機(jī)...
摘要:使用庫讀寫環(huán)境光照度傳感器本文將教大家如何快速使用庫讀取光照度數(shù)據(jù)。五實(shí)驗(yàn)樣機(jī)測(cè)試展示通過之前配置好的面板,通過涂鴉智能進(jìn)行配網(wǎng)實(shí)時(shí)采集光照度傳感器的數(shù)據(jù)。 使用STM32 HAL庫讀寫環(huán)境光照度傳感器(BH1750) 本文將教大家如何快速使用STM32HAL庫讀取光照度數(shù)據(jù)。 實(shí)現(xiàn)功能:通...
摘要:基于的移植教程可以看這里二介紹是一種用于嵌入式應(yīng)用的圖形支持軟件。適用于使用任何控制和的任何尺寸的物理和虛擬顯示。一個(gè)層,稱作驅(qū)動(dòng)程序,包含了對(duì)的全部訪問。并在主函數(shù)里加入下面的代碼,測(cè)試移植是否成功。 一、環(huán)境介紹 keil:? ? 5.25 MCU:? STM32F103ZET6 UCG...
摘要:添加設(shè)備名和鑒權(quán)信息。記錄如下數(shù)據(jù)二引腳連接和接電源接地和連接至配置的串口三代碼編寫串口配置單片機(jī)需配置兩個(gè)串口,串口打印至串口助手,顯示連接狀態(tài)。串口用來發(fā)送信息至串口配置代碼如下系列配置和系列配置不同點(diǎn)在于口上拉和推挽配置略有不同。 ...
閱讀 3675·2021-11-15 11:37
閱讀 2323·2021-09-24 10:39
閱讀 2462·2021-07-25 21:37
閱讀 1455·2019-08-30 15:56
閱讀 2589·2019-08-30 15:55
閱讀 966·2019-08-30 15:54
閱讀 2130·2019-08-30 14:21
閱讀 861·2019-08-30 11:24