双轴按键游戏摇杆模块,采用 PS2游戏手柄上金属按键摇杆电位器。模块特设二路模拟输出和一路数字输出接口、输出值分别对应(X、Y)双轴偏移量、其类型为模拟量、按键表示用户是否在Z轴上按下、其类型为数字开关量、用其可以轻松控制物体,在二维空间运动、因此可以通控制器编程、传感器扩展板插接、完成具有创意性遥控互动作品。
一、模块来源
模块实物展示:
二、规格参数
驱动电压:3.3V~5V
控制方式:ADC+GPIO
以上信息见厂家资料文件
三、移植过程
我们的目标是将例程移植至CW32F030C8T6开发板上【能够控制电机旋转速度的功能】。首先要获取资料,查看数据手册应如何实现读取数据,再移植至我们的工程。
3.1查看资料
输出信号:模块特设二路模拟输出(VRX,VRY)和一路数字输出接口(SW),二路模拟输出值分别对应(X,Y)双轴偏移量,其类型为模拟量;按键表示用户是否在Z轴上按下,其类型为数字开关量。
十字摇杆为一个双向的10K电阻器,随着摇杆方向不同,抽头的阻值随着变化。本模块如果使用5V供电,原始状态下X,Y读出电压为2.5V左右,当随箭头方向按下,读出电压值减少,限小为0V。
3.2引脚选择
VRX与VRY使用ADC功能。
想要使用ADC,需要确定使用的引脚是否有ADC外设功能。
当前只有AO引脚需要使用到ADC接口,所以DO引脚可以使用开发板上其他的GPIO。这里选择使用PA1和PA2的附加ADC功能。使用ADC的第1道和2通道。
ADC功能引脚
模块接线图
3.3移植至工程
移植步骤中的导入.c和.h文件与【CW32模块使用】DHT11温湿度传感器相同,只是将.c和.h文件更改为bsp_joystick.c与bsp_joystick.h。这里不再过多讲述,移植完成后面修改相关代码。
在文件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初始化结构体 GPIO_InitTypeDef GPIO_InitStruct2; // GPIO初始化结构体 SPI_GPIO_RCC(); // 使能GPIO时钟 RCC_SPI_HARDWARE_ENABLE(); // 使能SPI1时钟 // GPIO复用为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 初始化结构体 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // 双线全双工 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; // 主机模式 SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // 帧数据长度为8bit SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; // 时钟空闲电平为低 SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; // 第1个边沿采样 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; // 片选信号由SSI寄存器控制 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; // 波特率为PCLK的8分频 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; // 最高有效位 MSB 收发在前 SPI_InitStructure.SPI_Speed = SPI_Speed_Low; // 低速SPI SPI_Init(PORT_SPI, &SPI_InitStructure); // 初始化 SPI_Cmd(PORT_SPI, ENABLE); // 使能SPI1 } /** * @brief :SPI收发一个字节 * @param : * @TxByte: 发送的数据字节 * @note :非堵塞式,一旦等待超时,函数会自动退出 * @retval:接收到的字节 */ 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))//等待发送缓冲区为空 { if( SPI_WAIT_TIMEOUT == ++l_WaitTime ) { break; //如果等待超时则退出 } } l_WaitTime = SPI_WAIT_TIMEOUT / 2; //重新设置接收等待时间(因为SPI的速度很快,正常情况下在发送完成之后会立即收到数据,等待时间不需要过长) SPI_SendData(PORT_SPI, TxByte);//发送数据 while(RESET == SPI_GetFlagStatus(PORT_SPI, SPI_FLAG_RXNE))//等待接收缓冲区非空 { if( SPI_WAIT_TIMEOUT == ++l_WaitTime ) { break; //如果等待超时则退出 } } l_Data = SPI_ReceiveData(PORT_SPI);//读取接收数据 return l_Data; //返回 } /** * @brief :SPI收发字符串 * @param : * @ReadBuffer: 接收数据缓冲区地址 * @WriteBuffer:发送字节缓冲区地址 * @Length:字节长度 * @note :非堵塞式,一旦等待超时,函数会自动退出 * @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 ); //收发数据 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时钟 #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
四、移植验证
在自己工程中的main主函数中,编写如下。
/* * 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); } }
移植现象:移动摇杆并且按下,输出摇杆移动的数据。
模块移植成功案例代码:
链接:https://pan.baidu.com/s/1tubySHCtuFABDPQ1RjK40g?pwd=LCKF
提取码:LCKF