雙軸按鍵游戲搖桿模塊,采用 PS2游戲手柄上金屬按鍵搖桿電位器。模塊特設(shè)二路模擬輸出和一路數(shù)字輸出接口、輸出值分別對(duì)應(yīng)(X、Y)雙軸偏移量、其類型為模擬量、按鍵表示用戶是否在Z軸上按下、其類型為數(shù)字開關(guān)量、用其可以輕松控制物體,在二維空間運(yùn)動(dòng)、因此可以通控制器編程、傳感器擴(kuò)展板插接、完成具有創(chuàng)意性遙控互動(dòng)作品。
一模塊來源
模塊實(shí)物展示:
二規(guī)格參數(shù)
驅(qū)動(dòng)電壓:3.3V~5V
以上信息見廠家資料文件
三移植過程
我們的目標(biāo)是將例程移植至CW32F030C8T6開發(fā)板上【能夠控制電機(jī)旋轉(zhuǎn)速度的功能】。首先要獲取資料,查看數(shù)據(jù)手冊(cè)應(yīng)如何實(shí)現(xiàn)讀取數(shù)據(jù),再移植至我們的工程。
3.1查看資料
輸出信號(hào):模塊特設(shè)二路模擬輸出(VRX,VRY)和一路數(shù)字輸出接口(SW),二路模擬輸出值分別對(duì)應(yīng)(X,Y)雙軸偏移量,其類型為模擬量;按鍵表示用戶是否在Z軸上按下,其類型為數(shù)字開關(guān)量。
十字搖桿為一個(gè)雙向的10K電阻器,隨著搖桿方向不同,抽頭的阻值隨著變化。本模塊如果使用5V供電,原始狀態(tài)下X,Y讀出電壓為2.5V左右,當(dāng)隨箭頭方向按下,讀出電壓值減少,限小為0V。
3.2引腳選擇
VRX與VRY使用ADC功能。
想要使用ADC,需要確定使用的引腳是否有ADC外設(shè)功能。
當(dāng)前只有AO引腳需要使用到ADC接口,所以DO引腳可以使用開發(fā)板上其他的GPIO。這里選擇使用PA1和PA2的附加ADC功能。使用ADC的第1道和2通道。
ADC功能引腳
模塊接線圖
3.3移植至工程
移植步驟中的導(dǎo)入.c和.h文件與【CW32模塊使用】DHT11溫濕度傳感器相同,只是將.c和.h文件更改為bsp_joystick.c與bsp_joystick.h。這里不再過多講述,移植完成后面修改相關(guān)代碼。
在文件bsp_joystick.c中,編寫如下代碼。
/*
* Change Logs:
* Date Author Notes
* 2024-06-21 LCKFB-LP first version
*/
#include "drv_spi.h"
/** 硬件SPI */
#define SPI_WAIT_TIMEOUT ((uint16_t)0xFFFF)
/**
* @brief :SPI初始化(硬件)
* @param :無
* @note :無
* @retval:無
*/
void drv_spi_init( void )
{
GPIO_InitTypeDef GPIO_InitStruct1; // GPIO初始化結(jié)構(gòu)體
GPIO_InitTypeDef GPIO_InitStruct2; // GPIO初始化結(jié)構(gòu)體
SPI_GPIO_RCC(); // 使能GPIO時(shí)鐘
RCC_SPI_HARDWARE_ENABLE(); // 使能SPI1時(shí)鐘
// GPIO復(fù)用為SPI1
BSP_SPI_AF_SCK();
BSP_SPI_AF_MISO();
BSP_SPI_AF_MOSI();
GPIO_InitStruct1.Pins = SPI_NSS_GPIO_PIN|
SPI_CLK_GPIO_PIN|
SPI_MOSI_GPIO_PIN; // GPIO引腳
GPIO_InitStruct1.Mode = GPIO_MODE_OUTPUT_PP; // 推挽輸出
GPIO_InitStruct1.Speed = GPIO_SPEED_HIGH; // 輸出速度高
GPIO_Init(SPI_GPIO_PORT, &GPIO_InitStruct1); // 初始化
GPIO_InitStruct2.Pins = SPI_MISO_GPIO_PIN; // GPIO引腳
GPIO_InitStruct2.Mode = GPIO_MODE_INPUT_PULLUP; // 上拉輸入
GPIO_Init(SPI_GPIO_PORT, &GPIO_InitStruct2); // 初始化
spi_set_nss_high(); // 片選拉高
SPI_InitTypeDef SPI_InitStructure; // SPI 初始化結(jié)構(gòu)體
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // 雙線全雙工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; // 主機(jī)模式
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // 幀數(shù)據(jù)長(zhǎng)度為8bit
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; // 時(shí)鐘空閑電平為低
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; // 第1個(gè)邊沿采樣
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; // 片選信號(hào)由SSI寄存器控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; // 波特率為PCLK的8分頻
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; // 最高有效位 MSB 收發(fā)在前
SPI_InitStructure.SPI_Speed = SPI_Speed_Low; // 低速SPI
SPI_Init(PORT_SPI, &SPI_InitStructure); // 初始化
SPI_Cmd(PORT_SPI, ENABLE); // 使能SPI1
}
/**
* @brief :SPI收發(fā)一個(gè)字節(jié)
* @param :
* @TxByte: 發(fā)送的數(shù)據(jù)字節(jié)
* @note :非堵塞式,一旦等待超時(shí),函數(shù)會(huì)自動(dòng)退出
* @retval:接收到的字節(jié)
*/
uint16_t drv_spi_read_write_byte( uint8_t TxByte )
{
uint16_t l_Data = 0;
uint16_t l_WaitTime = 0;
while(RESET == SPI_GetFlagStatus(PORT_SPI, SPI_FLAG_TXE))//等待發(fā)送緩沖區(qū)為空
{
if( SPI_WAIT_TIMEOUT == ++l_WaitTime )
{
break; //如果等待超時(shí)則退出
}
}
l_WaitTime = SPI_WAIT_TIMEOUT / 2; //重新設(shè)置接收等待時(shí)間(因?yàn)镾PI的速度很快,正常情況下在發(fā)送完成之后會(huì)立即收到數(shù)據(jù),等待時(shí)間不需要過長(zhǎng))
SPI_SendData(PORT_SPI, TxByte);//發(fā)送數(shù)據(jù)
while(RESET == SPI_GetFlagStatus(PORT_SPI, SPI_FLAG_RXNE))//等待接收緩沖區(qū)非空
{
if( SPI_WAIT_TIMEOUT == ++l_WaitTime )
{
break; //如果等待超時(shí)則退出
}
}
l_Data = SPI_ReceiveData(PORT_SPI);//讀取接收數(shù)據(jù)
return l_Data; //返回
}
/**
* @brief :SPI收發(fā)字符串
* @param :
* @ReadBuffer: 接收數(shù)據(jù)緩沖區(qū)地址
* @WriteBuffer:發(fā)送字節(jié)緩沖區(qū)地址
* @Length:字節(jié)長(zhǎng)度
* @note :非堵塞式,一旦等待超時(shí),函數(shù)會(huì)自動(dòng)退出
* @retval:無
*/
void drv_spi_read_write_string( uint8_t* ReadBuffer, uint8_t* WriteBuffer, uint16_t Length )
{
spi_set_nss_low( );//拉低片選
while( Length-- )
{
*ReadBuffer = drv_spi_read_write_byte( *WriteBuffer ); //收發(fā)數(shù)據(jù)
ReadBuffer++;
WriteBuffer++; //讀寫地址加1
}
spi_set_nss_high( );//拉高片選
}
在文件bsp_joystick.h中,編寫如下代碼。
/*
* Change Logs:
* Date Author Notes
* 2024-06-21 LCKFB-LP first version
*/
#ifndef __DRV_SPI_H__
#define __DRV_SPI_H__
#include "board.h"
//SPI引腳定義
#define SPI_GPIO_RCC() __RCC_GPIOA_CLK_ENABLE() // GPIO時(shí)鐘
#define SPI_GPIO_PORT CW_GPIOA
#define SPI_CLK_GPIO_PIN GPIO_PIN_5
#define SPI_MISO_GPIO_PIN GPIO_PIN_6
#define SPI_MOSI_GPIO_PIN GPIO_PIN_7
#define SPI_NSS_GPIO_PIN GPIO_PIN_4
#define spi_set_nss_high( ) GPIO_WritePin(SPI_GPIO_PORT, SPI_NSS_GPIO_PIN, GPIO_Pin_SET) //片選置高
#define spi_set_nss_low( ) GPIO_WritePin(SPI_GPIO_PORT, SPI_NSS_GPIO_PIN, GPIO_Pin_RESET) //片選置低
/******** 硬件SPI修改此次 ********/
#define RCC_SPI_HARDWARE_ENABLE() __RCC_SPI1_CLK_ENABLE()
#define PORT_SPI CW_SPI1
//GPIO AF
#define BSP_SPI_AF_SCK() PA05_AFx_SPI1SCK()
#define BSP_SPI_AF_MISO() PA06_AFx_SPI1MISO()
#define BSP_SPI_AF_MOSI() PA07_AFx_SPI1MOSI()
void drv_spi_init( void );
uint16_t drv_spi_read_write_byte( uint8_t TxByte );
void drv_spi_read_write_string( uint8_t* ReadBuffer, uint8_t* WriteBuffer, uint16_t Length );
#endif
四移植驗(yàn)證
在自己工程中的main主函數(shù)中,編寫如下。
/*
* Change Logs:
* Date Author Notes
* 2024-06-25 LCKFB-LP first version
*/
#include "board.h"
#include "stdio.h"
#include "bsp_uart.h"
#include "bsp_joystick.h"
int32_t main(void)
{
board_init();
uart1_init(115200);
ADC_Joystick_Init();
printf("Demo Start.....rn");
while(1)
{
if( Get_SW_state() == 0 )
{
printf("按鈕按下!!rn");
}
printf("X = [%d]rn",Get_Joystick_Percentage_value(0));
printf("Y = [%d]rn",Get_Joystick_Percentage_value(1));
printf("n");
delay_ms(200);
}
}
移植現(xiàn)象:移動(dòng)搖桿并且按下,輸出搖桿移動(dòng)的數(shù)據(jù)。
模塊移植成功案例代碼:
鏈接:https://pan.baidu.com/s/1tubySHCtuFABDPQ1RjK40g?pwd=LCKF
提取碼:LCKF