【CW32模块使用】双轴按键摇杆模块

    科创经济 朗峰江湖 2025-05-21 3137 次浏览

    双轴按键游戏摇杆模块,采用 PS2游戏手柄上金属按键摇杆电位器。模块特设二路模拟输出和一路数字输出接口、输出值分别对应(X、Y)双轴偏移量、其类型为模拟量、按键表示用户是否在Z轴上按下、其类型为数字开关量、用其可以轻松控制物体,在二维空间运动、因此可以通控制器编程传感器扩展板插接、完成具有创意性遥控互动作品。

    一、模块来源

    模块实物展示:

    wKgZPGflMoWASaIXAAAZ8BIZGZw925.jpg

    二、规格参数

    驱动电压: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