双轴XY摇杆传感器是一种能将物理推摇动作,转换为控制二维空间移动(如上下、左右)电信号的装置
--deepseek
该双轴XY摇杆传感器配备5个引脚,分别是:
- GND(地线)
- +5V(电源)
- VRx(X轴模拟信号输出)
- VRy(Y轴模拟信号输出)
- SW(按键数字信号输出)
使用注意事项:
- GPIO配置时需将SW引脚设为输入模式
- VRx和VRy分别输出X/Y轴的模拟信号
通过主控芯片的ADC功能读取VRx和VRy引脚的电压值,就能确定摇杆的位置。当摇杆处于极限位置时,电压值会显示为0或最大值。
查看数据手册发现仅有一个ADC,且挂载在APB2上,不过可使用的通道还是挺多的。



我使用的是PC2和PC3,对应的通道号为12和13。至于SW(开关),只需选用任意一个空闲的IO口即可。

1,初始化代码
void Rocker_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure; // GPIO配置结构体
ADC_InitTypeDef ADC_InitStruct; // ADC配置结构体
ADC_CommonInitTypeDef ADC_CommonInitStruct; // ADC公共配置结构体
// 使能GPIOB和GPIOC时钟,使能ADC1时钟
RCC_AHB1PeriphClockCmd(ROCKER_SW_GPIO_CLK, ENABLE); // 使能摇杆按键引脚所在的时钟
RCC_AHB1PeriphClockCmd(ROCKER_URX_GPIO_CLK, ENABLE); // 使能摇杆X/Y轴引脚所在的时钟
RCC_APB2PeriphClockCmd(ROCKER_ADC_CLK, ENABLE); // 使能ADC1外设时钟
// 配置摇杆开关引脚 (PB7)
GPIO_InitStructure.GPIO_Pin = ROCKER_SW_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // 上拉输入
GPIO_Init(ROCKER_SW_GPIO_PORT, &GPIO_InitStructure);
// 配置摇杆X轴引脚 (PC2) / Y轴引脚 (PC3)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; // 模拟输入
GPIO_InitStructure.GPIO_Pin = ROCKER_URX_GPIO_PIN | ROCKER_UTY_GPIO_PIN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; // 模拟输入不需要上下拉
GPIO_Init(ROCKER_URX_GPIO_PORT, &GPIO_InitStructure);
// ADC公共配置
ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent; // 独立模式(只使用ADC1)
ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div4; // ADC时钟分频
ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; // 不使用DMA
ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; // 两个采样阶段之间的延迟周期
ADC_CommonInit(&ADC_CommonInitStruct);
ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b; // 12位分辨率(转换值范围0~4095)
ADC_InitStruct.ADC_ScanConvMode = DISABLE; // 禁止扫描模式(只转换1个通道)
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE; // 禁止连续转换模式(每次转换需要软件触发)
ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; // 不使用外部触发(使用软件触发)
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; // 数据右对齐(转换结果存放在低12位)
ADC_InitStruct.ADC_NbrOfConversion = 1; // 转换序列中的通道数量为1
ADC_Init(ROCKER_ADC, &ADC_InitStruct);
ADC_Cmd(ROCKER_ADC, ENABLE);
}
2,建议在获取指定通道ADC值时,对于包含while循环的代码段,应当增加超时处理机制以防止程序死锁。
static uint16_t Rocker_Read_ADC(uint32_t channel)
{
// 配置转换通道
ADC_RegularChannelConfig(ROCKER_ADC, channel, 1, ADC_SampleTime_56Cycles);
// 启动软件转换
ADC_SoftwareStartConv(ROCKER_ADC);
uint8_t timeout = 50; // 超时计数,避免死循环
// 等待转换完成
while(ADC_GetFlagStatus(ROCKER_ADC, ADC_FLAG_EOC) == RESET)
{
vTaskDelay(pdMS_TO_TICKS(2)); // 等待2ms,避免死循环占用CPU
timeout--;
if(timeout == 0)
{
// 超时处理
return 0; // 返回0表示读取失败
}
}
// 返回转换结果
return ADC_GetConversionValue(ROCKER_ADC);
}
3,封装获取X轴与Y轴的接口
uint16_t Rocker_Read_X(void)
{
return Rocker_Read_ADC(ROCKER_X_ADC_CHANNEL);
}
uint16_t Rocker_Read_Y(void)
{
return Rocker_Read_ADC(ROCKER_Y_ADC_CHANNEL);
}